Morphlex

repository·main·Indexed 42 days ago

https://github.com/yippee-fun/morphlex

A lightweight (~3KB gzipped) DOM morphing library written in TypeScript designed to transform one DOM tree into another while preserving element state and minimizing mutations. Version 1.4.0 provides functions like morph(), morphInner(), and morphDocument() to synchronize nodes, children, or entire documents, with configurable lifecycle hooks and options to preserve user input in form fields.

Tokens
1.8K
Snippets
7
Records
9
Agent score
3%

What's inside Morphlex

  1. Install Morphlex

    main

    You can install Morphlex via npm or use it directly in the browser via a CDN.

    Using npm:

    npm install morphlex

    Using a CDN (ES Module):

    <script type="module">
      import { morph } from "https://www.unpkg.com/morphlex@latest/dist/morphlex.min.js"
    </script>
    npm install morphlex
  2. Prevent attribute updates with beforeAttributeUpdated

    main

    You can use the beforeAttributeUpdated option to prevent specific attributes from being changed. This is useful for preserving UI state that the backend does not track, such as the open state of a <details> element.

    morph(currentNode, newNode, {
      beforeAttributeUpdated: (element, name) => {
        if (element.tagName === "DETAILS" && name === "open") return false
        return true
      },
    })
  3. Configure morph and morphInner options

    main

    Both morph and morphInner accept an optional third parameter for configuration. This allows you to control how nodes are added, removed, or updated, and to preserve specific UI states.

    morph(currentNode, newNode, {
      preserveChanges: true,
      beforeNodeAdded: (parent, node, insertionPoint) => {
        console.log("Adding node:", node)
        return true // return false to prevent addition
      },
    })
    morph(currentNode, newNode, {
      preserveChanges: true,
      beforeNodeAdded: (parent, node, insertionPoint) => {
        console.log("Adding node:", node)
        return true // return false to prevent addition
      },
    })
  4. Use morph, morphInner, and morphDocument

    main

    Morphlex provides three primary functions to transform DOM trees while preserving element state and minimizing mutations:

    • morph(currentNode, newNode): Transforms the entire currentNode to match newNode.
    • morphInner(currentNode, newNode): Transforms only the children of currentNode to match the children of newNode.
    • morphDocument(document, newDocument): Transforms the entire document.
    import { morph, morphInner } from "morphlex"
    
    // Morph the entire element
    morph(currentNode, newNode)
    
    // Morph only the children of the current node
    morphInner(currentNode, newNode)
    
    // Morph the entire document
    morphDocument(document, newDocument)
  5. Configure morphing behavior with `Options`

    main

    The Options interface allows you to hook into the morphing lifecycle and control how state (like form inputs) is preserved.

    Lifecycle Hooks

    • beforeNodeVisited(fromNode: Node, toNode: Node): boolean: Return false to skip morphing a specific node.
    • afterNodeVisited(fromNode: Node, toNode: Node): void: Called after a node is morphed.
    • beforeNodeAdded(parent: ParentNode, node: Node, insertionPoint: ChildNode | null): boolean: Return false to prevent adding a new node.
    • afterNodeAdded(node: Node): void: Called after a node is added.
    • beforeNodeRemoved(node: Node): boolean: Return false to prevent removing a node.
    • afterNodeRemoved(node: Node): void: Called after a node is removed.
    • beforeAttributeUpdated(element: Element, attributeName: string, newValue: string | null): boolean: Return false to prevent an attribute update.
    • afterAttributeUpdated(element: Element, attributeName: string, previousValue: string | null): void: Called after an attribute is updated.
    • beforeChildrenVisited(parent: ParentNode): boolean: Return false to skip visiting children of a node.
    • afterChildrenVisited(parent: ParentNode): void: Called after children have been morphed.

    Behavior Options

    • preserveChanges?: boolean: When true, prevents user-entered data in form inputs (like value, checked, or selected) from being overwritten by the morphing process. Defaults to false.
  6. Reference: Morphlex configuration options

    main

    The following options can be passed to morph and morphInner to hook into the morphing lifecycle or modify its behavior:

    OptionDescription
    preserveChangesWhen true, preserves modified form inputs during morphing. Prevents user-entered data from being overwritten. Default: false
    beforeNodeVisitedCalled before a node is visited. Return false to skip morphing this node.
    afterNodeVisitedCalled after a node has been visited and morphed.
    beforeNodeAddedCalled before a new node is added. Return false to prevent addition.
    afterNodeAddedCalled after a node has been added.
    beforeNodeRemovedCalled before a node is removed. Return false to prevent removal.
    afterNodeRemovedCalled after a node has been removed.
    beforeAttributeUpdatedCalled before an attribute is updated. Return false to prevent the update.
    afterAttributeUpdatedCalled after an attribute has been updated.
    beforeChildrenVisitedCalled before an element's children are visited. Return false to skip visiting children.
    afterChildrenVisitedCalled after an element's children have been visited and morphed.
  7. Morph inner content with `morphInner()`

    main

    Use morphInner() to synchronize the children of one ChildNode with the children of another.

    Constraints: Both the from and to nodes must be elements (ELEMENT_NODE_TYPE) and they must have matching localName and namespaceURI. If the to argument is a string, it must represent a single valid HTML element.

    Security Warning: When passing a string, the HTML is parsed and nodes are inserted into the live document. Inline event handlers (e.g., onclick) and resource-loading attributes (e.g., src, href) will execute/load once adopted. Always sanitize untrusted HTML before passing it to Morphlex.

    morphInner(originalDom, newDom)
  8. Morph a whole document with `morphDocument()`

    main

    Use morphDocument() to synchronize an existing Document with a new Document or an HTML string. If a string is provided, it is parsed using DOMParser.

    Security Warning: When passing a string, the HTML is parsed and nodes are inserted into the live document. Inline event handlers (e.g., onclick) and resource-loading attributes (e.g., src, href) will execute/load once adopted. Always sanitize untrusted HTML before passing it to Morphlex.

    morphDocument(document, "<html>...</html>", { preserveChanges: true })
  9. Morph a node or node list with `morph()`

    main

    Use morph() to synchronize a source ChildNode with a target ChildNode, a NodeListOf<ChildNode>, or an HTML string. If a string is provided, it is parsed using a <template> element.

    Security Warning: When passing a string, the HTML is parsed and nodes are inserted into the live document. Inline event handlers (e.g., onclick) and resource-loading attributes (e.g., src, href) will execute/load once adopted. Always sanitize untrusted HTML before passing it to Morphlex.

    morph(originalDom, newDom)