Repository navigation
feat(interact): let a plugin refresh when its output is replaced - #386
Closed
ameerf-wix wants to merge 4 commits into
Closed
ameerf-wix wants to merge 4 commits into
ameerf-wix wants to merge 4 commits into
Conversation
Interact resolves an effect's targets once, right after the plugins run on connect. If something later replaces a plugin's output, e.g. a framework hydration that doesn't match the split DOM and renders the element again, the effects keep targeting the detached elements and nothing re-runs the plugin. The plugin context gets `refresh()`, which reconnects the controller: it runs the cleanups, re-applies the plugins and re-resolves the targets. It runs in a microtask, once for all the calls before it, and does nothing once the plugin's cleanup has run. The plugin decides when to call it, since only it knows which elements its output depends on. `splitTextPlugin` watches its root and calls `refresh()` when a container it split is replaced. Its own split keeps the containers, so it doesn't trigger it. With an Interact that passes no `refresh`, it splits as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Generated
|
The plugin observed its whole root (`childList` + `subtree`), so the browser queued a record for every node added or removed anywhere in it, including the plugin's own re-splits and unrelated content. A container leaves the document only when it or one of its ancestors is removed from its parent. Observe `childList` on each node from the containers' parents up to the root, without `subtree`: the split and other changes inside the root no longer reach the observer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Interact runs the plugins on connect, and right after that resolves the effects' targets: the plugin's output, such as
@wix/splittext's.split-cspans. If something replaces that output later, nothing runs the plugin again:React 18 hydration can cause this. When a component is hydrated only once it enters the viewport, the plugin has already split the server-rendered DOM. React finds that the DOM doesn't match and renders the component again, without the split. On a server-rendered page with three split-text titles, all three ended up un-split once they hydrated, and their sequences had no visible targets.
SplitTextResult.split()and theautoSplitre-split can't help here. Both re-splitresult.element, which is the element that was replaced.Change
Who acts: the plugin notices, and Interact does the refresh.
@wix/interact: the plugin context getsrefresh(). It reconnects the controller the plugin was applied to (update()), which:It runs in a microtask, so a plugin can call it while it runs. Calls before it run once, and it does nothing once the plugin's cleanup has run (a disconnect replaces
_appliedPlugins, whichrefreshchecks).@wix/splittext: when a container it split is no longer in the document,splitTextPlugincallsrefresh().MutationObserverwatcheschildListon each node from the containers' parents up to the root, withoutsubtree: typically a few nodes.autoSplitre-splits, only changes nodes inside the containers, so it doesn't reach the observer. Neither do other changes in the root, unless they add or remove a direct child of one of those ancestors.refreshis optional in the plugin's structural context type. With an Interact version that doesn't pass it, the plugin splits as before.Docs: the plugins guide,
InteractPluginContextin the types reference,rules/plugins.md, the interactor skill's plugin reference, the splittext README, and the CHANGELOG (@wix/interact2.5.26,@wix/splittext0.2.2).Verification
tscpasses for both packages and the demo (whosesplitText.tschecks the plugin is still assignable toInteractPlugin). Without the source change, the new tests that check refresh behaviour fail:refresh()re-applies the plugin and the trigger binds to the new element.refresh()does nothing after the cleanup, or after a reconnect that happened in between.refreshwhen a re-render replaces its container or an ancestor between it and the root, but not for its own split, not for other changes in the root, and not after its cleanup.subtree.data-splittext-ready.@wix/interactand@wix/splittextbuilds swapped for this branch's.flickeron 21 characters, and aletter-riseon 22 and on 54.slot-spinon characters) and a split paragraph (line-riseon lines) at the top. Before, both lose their split when they hydrate. After, the heading has 12 characters and the paragraph 2 lines, and both animations run.Not covered
If a re-render replaces a container's contents but keeps the container element, the split is lost and the plugin doesn't notice. Only replacing the container itself, which is what hydration does here, triggers a refresh.
🤖 Generated with Claude Code