Skip to content

Add shadcn registry component#445

Open
aidenybai wants to merge 2 commits into
mainfrom
cursor/add-shadcn-registry-b16d
Open

Add shadcn registry component#445
aidenybai wants to merge 2 commits into
mainfrom
cursor/add-shadcn-registry-b16d

Conversation

@aidenybai
Copy link
Copy Markdown
Owner

@aidenybai aidenybai commented Jun 1, 2026

Summary

  • Add a root shadcn GitHub registry.json with a react-grab registry item.
  • Add a client ReactGrab installer component with commented optional config.
  • Document the GitHub registry install command and usage under Manual Installation, including synced package READMEs.

Verification

  • pnpm dlx shadcn@latest registry validate registry.json
  • pnpm build
  • pnpm test
  • pnpm lint
  • pnpm typecheck
  • pnpm format
Open in Web Open in Cursor 

Summary by cubic

Adds a shadcn GitHub registry entry and a ReactGrab installer component so apps can install and initialize react-grab with one command and a single render. Also expands install docs and examples across all READMEs.

  • New Features
    • Added root registry.json for shadcn with a react-grab item targeting @components/react-grab.tsx.
    • Added client ReactGrab component that lazy-loads react-grab, sets a global API, and supports optional Options.
    • Updated root and package READMEs with npx shadcn@latest add aidenybai/react-grab/react-grab and a dev-only root render example.

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

Review in cubic

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jun 1, 2026

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

Project Deployment Actions Updated (UTC)
react-grab-storybook Ready Ready Preview, Comment Jun 1, 2026 8:18pm
react-grab-website Ready Ready Preview, Comment Jun 1, 2026 8:18pm

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 1, 2026

Open in StackBlitz

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

commit: 3634587

@aidenybai aidenybai marked this pull request as ready for review June 1, 2026 20:05
Comment thread registry/react-grab.tsx
Comment thread registry/react-grab.tsx
...props.options,
});

reactGrab.setGlobalApi(api);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Concurrent init overwrites global API

High Severity

Overlapping loadReactGrab runs can both pass the getGlobalApi() check before either calls setGlobalApi. The second init() then returns a noop API because hasInited is already true, and setGlobalApi may replace the working global instance with that noop, leaving React Grab inactive.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 094ba5b. Configure here.

Comment thread registry/react-grab.tsx
...props.options,
});

reactGrab.setGlobalApi(api);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pending plugins never flushed

Medium Severity

After manual init() and setGlobalApi(), the component never flushes plugins that were queued via registerPlugin() while the global API was still null. The default package import path runs flushPendingPlugins on auto-init, but this lazy-init path skips that step.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 094ba5b. Configure here.

Comment thread registry/react-grab.tsx
if (!isActive) return;

const existingApi = reactGrab.getGlobalApi();
if (existingApi) return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Updated options prop ignored

Medium Severity

The effect depends on props.options, but when getGlobalApi() is already set it returns early and never merges new options. Re-renders with different options therefore leave the original configuration in place.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 094ba5b. Configure here.

Comment thread registry/react-grab.tsx
});

reactGrab.setGlobalApi(api);
window.dispatchEvent(new CustomEvent("react-grab:init", { detail: api }));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Noop init published globally

High Severity

When init() returns a noop API (for example options.enabled === false), the component still calls setGlobalApi and dispatches react-grab:init. That noop is truthy, so later runs bail on getGlobalApi() and never install a real instance even if options change.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 094ba5b. Configure here.

Comment thread registry/react-grab.tsx

export const ReactGrab = (props: ReactGrabProps) => {
useEffect(() => {
if (props.enabled === false) return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Enabled prop never deactivates

Medium Severity

Setting enabled={false} only skips starting a new load; it does not disable or dispose an already-initialized React Grab instance. After the prop becomes false, the overlay and listeners keep running.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 094ba5b. Configure here.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.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.

5 issues found across 3 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="registry/react-grab.tsx">

<violation number="1" location="registry/react-grab.tsx:29">
P2: When `enabled` becomes false, disable the existing global API instead of returning immediately; otherwise an already initialized instance keeps running.</violation>

<violation number="2" location="registry/react-grab.tsx:35">
P2: The `import("react-grab")` call is inside a `try` block but there is no `catch` clause. If the dynamic import fails (e.g., package not installed, network error in dev), the error is silently swallowed with no console warning or user feedback, making debugging difficult.</violation>

<violation number="3" location="registry/react-grab.tsx:41">
P2: Existing global instance short-circuits the effect, so `enabled`/`options` prop changes are ignored after first init.</violation>

<violation number="4" location="registry/react-grab.tsx:43">
P1: Guard against `options.enabled === false` before calling `init()`. Initializing with disabled options can produce a no-op API and block later creation of a real instance.</violation>

<violation number="5" location="registry/react-grab.tsx:60">
P3: `props.options` is an object included in the `useEffect` dependency array. If the parent passes an inline object literal (e.g., `options={{ activationMode: 'toggle' }}`), the reference changes every render, causing the effect to fire on every render — re-importing the module, checking the global API, and running through the try/finally block each time.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread registry/react-grab.tsx
Comment on lines +43 to +46
const api = reactGrab.init({
...reactGrabOptions,
...props.options,
});
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.

P1: Guard against options.enabled === false before calling init(). Initializing with disabled options can produce a no-op API and block later creation of a real instance.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At registry/react-grab.tsx, line 43:

<comment>Guard against `options.enabled === false` before calling `init()`. Initializing with disabled options can produce a no-op API and block later creation of a real instance.</comment>

<file context>
@@ -0,0 +1,63 @@
+        const existingApi = reactGrab.getGlobalApi();
+        if (existingApi) return;
+
+        const api = reactGrab.init({
+          ...reactGrabOptions,
+          ...props.options,
</file context>
Suggested change
const api = reactGrab.init({
...reactGrabOptions,
...props.options,
});
if (props.options?.enabled === false) return;
const api = reactGrab.init({
...reactGrabOptions,
...props.options,
});

Comment thread registry/react-grab.tsx

const loadReactGrab = async () => {
window.__REACT_GRAB_DISABLED__ = true;
try {
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.

P2: The import("react-grab") call is inside a try block but there is no catch clause. If the dynamic import fails (e.g., package not installed, network error in dev), the error is silently swallowed with no console warning or user feedback, making debugging difficult.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At registry/react-grab.tsx, line 35:

<comment>The `import("react-grab")` call is inside a `try` block but there is no `catch` clause. If the dynamic import fails (e.g., package not installed, network error in dev), the error is silently swallowed with no console warning or user feedback, making debugging difficult.</comment>

<file context>
@@ -0,0 +1,63 @@
+
+    const loadReactGrab = async () => {
+      window.__REACT_GRAB_DISABLED__ = true;
+      try {
+        const reactGrab = await import("react-grab");
+
</file context>

Comment thread registry/react-grab.tsx
if (!isActive) return;

const existingApi = reactGrab.getGlobalApi();
if (existingApi) return;
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.

P2: Existing global instance short-circuits the effect, so enabled/options prop changes are ignored after first init.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At registry/react-grab.tsx, line 41:

<comment>Existing global instance short-circuits the effect, so `enabled`/`options` prop changes are ignored after first init.</comment>

<file context>
@@ -0,0 +1,63 @@
+        if (!isActive) return;
+
+        const existingApi = reactGrab.getGlobalApi();
+        if (existingApi) return;
+
+        const api = reactGrab.init({
</file context>

Comment thread registry/react-grab.tsx

export const ReactGrab = (props: ReactGrabProps) => {
useEffect(() => {
if (props.enabled === false) return;
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.

P2: When enabled becomes false, disable the existing global API instead of returning immediately; otherwise an already initialized instance keeps running.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At registry/react-grab.tsx, line 29:

<comment>When `enabled` becomes false, disable the existing global API instead of returning immediately; otherwise an already initialized instance keeps running.</comment>

<file context>
@@ -0,0 +1,63 @@
+
+export const ReactGrab = (props: ReactGrabProps) => {
+  useEffect(() => {
+    if (props.enabled === false) return;
+
+    let isActive = true;
</file context>

Comment thread registry/react-grab.tsx
return () => {
isActive = false;
};
}, [props.enabled, props.options]);
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.

P3: props.options is an object included in the useEffect dependency array. If the parent passes an inline object literal (e.g., options={{ activationMode: 'toggle' }}), the reference changes every render, causing the effect to fire on every render — re-importing the module, checking the global API, and running through the try/finally block each time.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At registry/react-grab.tsx, line 60:

<comment>`props.options` is an object included in the `useEffect` dependency array. If the parent passes an inline object literal (e.g., `options={{ activationMode: 'toggle' }}`), the reference changes every render, causing the effect to fire on every render — re-importing the module, checking the global API, and running through the try/finally block each time.</comment>

<file context>
@@ -0,0 +1,63 @@
+    return () => {
+      isActive = false;
+    };
+  }, [props.enabled, props.options]);
+
+  return null;
</file context>

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.

There are 7 total unresolved issues (including 5 from previous reviews).

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit 3634587. Configure here.

Comment thread registry/react-grab.tsx
if (!isActive) return;

const existingApi = reactGrab.getGlobalApi();
if (existingApi) return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Disposed API blocks reinitialization

Medium Severity

After dispose() on the global API, window.__REACT_GRAB__ can still hold the old instance while hasInited is reset, so ReactGrab treats getGlobalApi() as already initialized and never runs init again.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3634587. Configure here.

Comment thread registry/react-grab.tsx

return () => {
isActive = false;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unmount leaves grab running

Medium Severity

The effect cleanup only clears a local isActive flag and never calls dispose on the initialized global API, so removing ReactGrab from the tree leaves listeners, overlay, and other grab resources active.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3634587. Configure here.

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 4 files (changes from recent commits).

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/README.md">

<violation number="1" location="packages/react-grab/README.md:36">
P3: The new `### shadcn Registry` heading accidentally nests the existing manual framework sections under the registry subsection.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic


## Manual Installation

### shadcn Registry
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.

P3: The new ### shadcn Registry heading accidentally nests the existing manual framework sections under the registry subsection.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/react-grab/README.md, line 36:

<comment>The new `### shadcn Registry` heading accidentally nests the existing manual framework sections under the registry subsection.</comment>

<file context>
@@ -33,6 +33,29 @@ The copied context includes the selected element and its component stack with so
 
 ## Manual Installation
 
+### shadcn Registry
+
+Install the React Grab component from this GitHub registry:
</file context>
Suggested change
### shadcn Registry
#### shadcn Registry

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.

2 participants