Skip to content

feat: migrate to Solid 2.0 beta#255

Open
aidenybai wants to merge 5 commits intomainfrom
feat/solid-2.0
Open

feat: migrate to Solid 2.0 beta#255
aidenybai wants to merge 5 commits intomainfrom
feat/solid-2.0

Conversation

@aidenybai
Copy link
Copy Markdown
Owner

@aidenybai aidenybai commented Mar 19, 2026

Summary

  • Upgrade solid-js, @solidjs/web, babel-preset-solid to 2.0.0-beta.3
  • Migrate all SolidJS APIs to 2.0 equivalents: createEffect split form, onSettled, For keyed={false}, class arrays, draft-first setStore, storePath
  • Replace createResource with createSignal + createEffect (with stale-request guards and .catch() handlers)
  • Remove deprecated APIs: batch, on, solid-js/store, solid-js/web

Test plan

  • pnpm typecheck passes
  • pnpm build succeeds
  • Manual smoke test of overlay, toolbar, context menu, history dropdown
  • E2E tests pass (pnpm test)

Stacked on #254

🤖 Generated with Claude Code


Note

Medium Risk
Large framework upgrade to solid-js@2.0.0-beta.3 with widespread lifecycle/reactivity and store-update refactors across interactive UI components, which may introduce subtle rendering/timing regressions. No auth/security or persistent data changes, but runtime behavior and cleanup semantics change broadly.

Overview
Upgrades react-grab and design-system to Solid 2.0 beta by bumping solid-js, adding @solidjs/web, and updating babel-preset-solid; build configs now keep @solidjs/web non-external in tsup.

Refactors Solid usage across components/core to Solid 2 APIs: render imports switch to @solidjs/web, onMount/onCleanup patterns are replaced with onSettled returning cleanups, createEffect is migrated to the new split signature, and list rendering is updated (e.g., Index to For with keyed={false} and accessor-based item reads).

Reworks state management and async derivations for Solid 2: store updates move to draft-first setStore/storePath (removing produce usage), and createResource callsites are replaced with createSignal + createEffect including stale-request guards and error handling. Minor JSX/a11y tweaks include readonly casing and aria-pressed/aria-expanded string values.

Written by Cursor Bugbot for commit b631052. This will update automatically on new commits. Configure here.


Summary by cubic

Migrate react-grab and design-system to Solid 2.0 beta to modernize APIs, align builds, and prevent unhandled promise rejections.

  • Refactors

    • Updated to Solid 2 APIs across both packages: split createEffect (compute/apply), replace onMount with onSettled (return cleanup), switch IndexFor (keyed={false}), use class arrays/objects, and adopt draft-first setStore with storePath; removed batch, on, solid-js/store, and solid-js/web (now using @solidjs/web for render).
    • Replaced createResource with createSignal + createEffect, adding stale-request guards and .catch() to avoid unhandled rejections.
    • Fixed a11y/attrs: aria-pressed/aria-expanded use string values; corrected readonly casing.
    • Build: added @solidjs/web to tsup noExternal in react-grab and design-system.
  • Dependencies

    • Upgraded solid-js to 2.0.0-beta.3 and added @solidjs/web@2.0.0-beta.3 in both packages.
    • Upgraded babel-preset-solid to 2.0.0-beta.3.

Written for commit b631052. Summary will update on new commits.

aidenybai and others added 4 commits March 19, 2026 03:45
Simplify cn utility to use clsx only, fix tailwindcss import with
source("."), and gitignore meta.json.

Made-with: Cursor
Rename "Cursor Cloud specific instructions" to "Development instructions"
and remove outdated "Known flaky test" section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Upgrade solid-js, @solidjs/web, babel-preset-solid to 2.0.0-beta.3
- Split all createEffect calls into (compute, apply) form
- Replace onMount with onSettled (return cleanup)
- Replace Index with For keyed={false}
- Replace classList with class array/object form
- Replace produce/path-style setStore with draft-first and storePath
- Replace createResource with createSignal + createEffect
- Remove batch (automatic in 2.0), on helper, solid-js/store, solid-js/web
- Add stale-request guards for async createResource replacements
- Add defer: true to 5 effects that require deferred initial execution
- Fix aria-pressed/aria-expanded to use string literals
- Fix readOnly to lowercase readonly
The createResource→createEffect migration left promise chains
without .catch() handlers, risking unhandled rejections for
contextMenuComponentName and contextMenuFilePath.

Made-with: Cursor
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-grab-website Ready Ready Preview, Comment Mar 19, 2026 11:45pm

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 19, 2026

Open in StackBlitz

@react-grab/cli

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/cli@255

grab

npm i https://pkg.pr.new/aidenybai/react-grab/grab@255

@react-grab/amp

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/amp@255

@react-grab/claude-code

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/claude-code@255

@react-grab/codex

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/codex@255

@react-grab/copilot

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/copilot@255

@react-grab/cursor

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/cursor@255

@react-grab/droid

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/droid@255

@react-grab/gemini

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/gemini@255

@react-grab/opencode

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/opencode@255

react-grab

npm i https://pkg.pr.new/aidenybai/react-grab@255

@react-grab/relay

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/relay@255

@react-grab/utils

npm i https://pkg.pr.new/aidenybai/react-grab/@react-grab/utils@255

commit: b631052

The design-system bundles react-grab/src via noExternal, so it needs
matching Solid 2.0 dependencies to avoid babel-preset-solid 1.x
generating "solid-js/web" imports (removed in 2.0).

- Upgrade solid-js, @solidjs/web, babel-preset-solid to 2.0.0-beta.3
- Add @solidjs/web to noExternal in tsup config
- Replace solid-js/web import with @solidjs/web
- Replace onMount with onSettled (return cleanup)
- Unwrap For callback accessors (Solid 2.0 always passes Accessor<T>)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 21 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/react-grab/src/components/selection-label/index.tsx">

<violation number="1" location="packages/react-grab/src/components/selection-label/index.tsx:190">
P2: Returning a function from `createEffect` does not register a cleanup handler in SolidJS (unlike React's `useEffect`). The returned function simply becomes the `prev` argument for the next execution. You must use `onCleanup` to properly clear the timeout (you will also need to re-import it).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

autoResizeTextarea(inputRef, TEXTAREA_MAX_HEIGHT_PX);
}
}, 0);
return () => clearTimeout(focusTimeout);
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Returning a function from createEffect does not register a cleanup handler in SolidJS (unlike React's useEffect). The returned function simply becomes the prev argument for the next execution. You must use onCleanup to properly clear the timeout (you will also need to re-import it).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/react-grab/src/components/selection-label/index.tsx, line 190:

<comment>Returning a function from `createEffect` does not register a cleanup handler in SolidJS (unlike React's `useEffect`). The returned function simply becomes the `prev` argument for the next execution. You must use `onCleanup` to properly clear the timeout (you will also need to re-import it).</comment>

<file context>
@@ -157,36 +155,42 @@ export const SelectionLabel: Component<SelectionLabelProps> = (props) => {
+            autoResizeTextarea(inputRef, TEXTAREA_MAX_HEIGHT_PX);
+          }
+        }, 0);
+        return () => clearTimeout(focusTimeout);
+      }
+    },
</file context>
Fix with Cubic

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

setStore(
storePath("labelInstances", index, "errorMessage", errorMessage),
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-atomic store update splits single produce into two calls

Low Severity

The updateLabelInstance method was refactored from a single atomic produce call (updating both status and errorMessage together) into two separate setStore(storePath(...)) calls. If Solid 2.0's auto-batching doesn't cover this synchronous sequence, effects could observe an intermediate state where status is updated but errorMessage is not yet set, potentially causing brief UI inconsistencies.

Fix in Cursor Fix in Web

viewportChangeFrameId = null;
}
},
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bounds recalc interval missing cleanup return from effect

Low Severity

The bounds recalc interval createEffect creates a setInterval when shouldRunInterval is true but does not return a cleanup function from the apply callback. The interval is only cleaned up manually when shouldRunInterval becomes false, or via a separate onCleanup. If Solid 2.0's effect disposal runs the apply's returned cleanup before the separate onCleanup, the interval could briefly leak during cleanup ordering edge cases.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

babel-preset-solid for Solid 2.0 generates imports from wrong package (solid-js/web instead of @solidjs/web), causing build failures

Fix on Vercel

autoResizeTextarea(inputRef, TEXTAREA_MAX_HEIGHT_PX);
}
}, 0);
return () => clearTimeout(focusTimeout);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Solid.js 2.0-beta.3 split form createEffect, returning a function from the effect handler does not register a cleanup handler; instead, the returned function becomes the 'prev' argument for the next effect execution.

Fix on Vercel

(previousIndex) => (previousIndex + 1) % SELECTION_HINT_COUNT,
);
}, SELECTION_HINT_CYCLE_INTERVAL_MS);
return () => clearInterval(intervalId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid.js 2.0 split form createEffect uses incorrect cleanup pattern - returning cleanup functions instead of using onCleanup()

Fix on Vercel

}
actions.activate();
}, store.keyHoldDuration);
return () => clearHoldTimer();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Solid.js 2.0, returning cleanup functions from the split form of createEffect is broken - cleanup functions are never called, causing memory leaks from uncleaned timers and intervals.

Fix on Vercel

@aidenybai aidenybai changed the base branch from chore/remove-tailwind-merge to main March 20, 2026 09:08
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