Skip to content

Integrate morphdom for surgical DOM patching in LiveComponents#59

Merged
kainovaii merged 1 commit intomainfrom
dev
Mar 20, 2026
Merged

Integrate morphdom for surgical DOM patching in LiveComponents#59
kainovaii merged 1 commit intomainfrom
dev

Conversation

@kainovaii
Copy link
Member

Pull Request: Integrate morphdom for surgical DOM patching in LiveComponents

Summary

Replaces the brute-force replaceChild strategy in ObsidianComponents.updateComponent() with [morphdom](https://github.com/patrick-steele-idem/morphdom) for surgical DOM diffing/patching. Only the nodes that actually changed are mutated — focus, cursor position, scroll state, CSS animations, and event listeners on unchanged nodes are preserved automatically. Morphdom is inlined (~4 KB minified) at the top of the file — zero external dependency.


Changes

1. Morphdom inlined at top of file

Modified: livecomponents.js

  • Morphdom 2.7.4 minified bundle added as IIFE at the top of the file
  • Exposes global morphdom() function — no CDN, no bundler required

2. updateComponent() — rewritten with morphdom

Modified: ObsidianComponents.updateComponent()

  • Removed replaceChild + manual focus/cursor/value restoration (~30 lines)
  • Removed post-update attachModelBindings() and attachSubmit() re-binding calls
  • Now calls morphdom(component.element, html, options) with two callbacks:
    • onBeforeElUpdated — skips the actively focused input/textarea/select to preserve typing
    • onNodeAdded — attaches live:model and live:submit bindings on freshly created nodes only

3. Anti-duplicate binding guards

Modified: attachModelBindings(), attachSubmit()

  • Added _liveModelBound flag on inputs to prevent re-attaching listeners on morphdom-preserved nodes
  • Added _liveSubmitBound flag on forms for the same reason

4. Stale reference fix in call()

Modified: ObsidianComponents.call()

  • After updateComponent(), morphdom may replace the root element — component.element becomes stale
  • displayValidationErrors, showError, and hideLoading now re-fetch the reference via this.components.get(componentId) after each update
  • Applies to success block, error block, catch block, and finally block

5. mountLazyComponents() — minor cleanup

Modified: ObsidianComponents.mountLazyComponents()

  • Removed unused skeleton variable

No Backend Changes

The server contract is unchanged — POST → JSON { success, html, event, state }. Morphdom operates entirely client-side on the same data.html payload.


Breaking Changes

None. This is a transparent upgrade — all existing live: attributes, actions, and server responses work identically.

@kainovaii kainovaii merged commit f438af6 into main Mar 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant