upgrade: migrate to Solid 2.0 and latest MotionOne - #22
Open
davedbase wants to merge 7 commits into
Open
Conversation
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.
This is a two-part migration:
Solid.js 1.x → 2.0-rc.3. Solid 2.0 removes
use:directives,Context.ProviderJSX,batch(), andsolid-js/web/solid-js/storeimport paths, and changes effect/context semantics in ways that touched every file insrc/:use:motionis now a ref factory:<div ref={motion(() => ({...}))} />instead of<div use:motion={{...}} />.ParentContext/PresenceContextnow use direct-call JSX (<Context value={...}>) instead of.Provider, and are read via a smalltryUseContexthelper since Solid 2.0'suseContextnow throws instead of returningundefinedwhen there's no provider.@solid-primitives/{props,refs,transition-group}bumped to their Solid-2-compatiblenextprereleases;babel-preset-solidpinned to2.0.0-rc.2via apnpm.overridesentry (tsup-preset-solid's bundledesbuild-plugin-solidotherwise hardcodes the 1.x preset and would silently ship a broken build importing the now-removedsolid-js/webpath).Motion engine:
@motionone/dom→ Motion 13.1.1. The old engine is unmaintained (frozen since June 2024) and its core primitives (createMotionState,createStyles,mountedStates) have no equivalent in modern Motion — that package now centers on a much heavierVisualElement/animationStatesystem built for React. Rather than pull in that whole machinery,src/engine.tsis a new, lean hand-rolled adapter built onmotion-dom/framer-motion/dom's stable primitives (animate(),hover(),press(),inView()), reproducing the same mount/update/exit lifecycle, variant resolution, and gesture composition the old engine provided — same public API, sameeasingprop name (translated internally to modern Motion'sease).One confirmed behavior change: SSR/style output no longer uses
@motionone/dom's CSS-custom-property trick for independent transforms (--motion-translateX: 100px; transform: translateX(var(--motion-translateX))); modern Motion composes a direct transform string instead (transform: translateX(100px)). Functionally equivalent, but byte-different output if anything was depending on those--motion-*variable names directly.New: Storybook rig.
.storybook/+stories/add 28 interactive stories (storybook-solidjs-vite@10.7.1+ the new@solidjs/vite-plugin, since the legacyvite-plugin-soliddoesn't support Solid 2.0) covering every documented feature — includinghover+presscomposition,inView, and nested variant inheritance, none of which had prior test coverage. Run withpnpm run storybook.Notable fix
Found and fixed a real bug via the Storybook/real-browser verification pass (not caught by the jsdom test suite): a sibling
Motioncomponent can get constructed and briefly mount/unmount before its real mount, as a structural side effect of how<Show>/createSwitchTransitionread reactive sources during aPresenceexitBeforeEntercycle. The engine's animation-cancellation state was previously a single shared closure per component, so that phantom cycle's stale cleanup could silently cancel the real mount's in-flight animation with no error — hangingexitBeforeEnterindefinitely. Fixed by scoping cleanup state to a per-mount-generation context inengine.ts, so a superseded mount cycle can never reach into a newer one.Breaking changes
solid-js@^2.0.0-rc.0(Solid 2.0 is currently in beta/RC).use:motion={{...}}→ref={motion(() => ({...}))}for the raw directive API (the<Motion>/<Presence>component API is unchanged).