Skip to content

feat: add commit widget with prompt, spotlight, and text-morph feedback#205

Open
ben-million wants to merge 1 commit intoaidenybai:mainfrom
ben-million:commit-widget
Open

feat: add commit widget with prompt, spotlight, and text-morph feedback#205
ben-million wants to merge 1 commit intoaidenybai:mainfrom
ben-million:commit-widget

Conversation

@ben-million
Copy link
Collaborator

@ben-million ben-million commented Mar 1, 2026

Adds a persistent commit widget (Dynamic Island-style) at the bottom of the viewport.

Features

  • TextMorph label — shows the latest grabbed element as ComponentName.tagName, morphing between states
  • Prompt input — expandable input that copies text to clipboard on submit, with "Copied" → "Prompt" morph feedback
  • Spotlight effect — hides text/SVGs/images across the page, applies grayscale + subtle overlay, leaving only the target element in full color
  • Dynamic Island animation — widget scales up 1.2× with spring easing when prompt opens
  • Light/dark mode — adapts via prefers-color-scheme
  • History label — shows element name after grab, ⌃Z copies an undo prompt
  • Legacy UI suppression — hides selection labels, overlay canvas, and toolbar while prompt is open

New files

  • src/components/commit-widget.tsx — SolidJS component
  • src/components/text-morph.tsx — SolidJS wrapper for torph's TypeScript TextMorph class

Modified files

  • renderer.tsx — wires CommitWidget, hides legacy labels/overlay during prompt
  • core/index.tsx — adds handleActivateForCopy, passes latestGrabbedElement
  • types.ts — adds onActivateForCopy, latestGrabbedElement to renderer props
  • constants.ts — adds feedback duration and prompt width constants
  • styles.css — commit widget styles with light mode overrides
  • tsup.config.ts — adds torph to noExternal
  • package.json — adds torph dependency

Note

Medium Risk
Adds a new always-on widget that manipulates global DOM styles/visibility and clipboard behavior (including a global Ctrl+Z handler) and temporarily suppresses existing overlays while open, which could impact page UX/performance if edge cases aren’t handled.

Overview
Introduces a persistent bottom-of-viewport CommitWidget that opens after copy events to show the latest grabbed element label, provides an expandable prompt input that copies to clipboard with "Copied" feedback, and supports a Ctrl+Z shortcut that copies an undo prompt.

When the prompt is open, the widget applies a spotlight effect by temporarily hiding/grayscaling surrounding page content and drawing a fixed overlay around the target element; the renderer also hides the existing overlay canvas/toolbar UI while the prompt is active. Adds torph-backed TextMorph animations (plus shadow-DOM compatible styles), new widget constants/CSS, and wires new renderer props (onActivateForCopy, latestGrabbedElement) through core and build config.

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


Summary by cubic

Adds a persistent commit widget that streamlines copying prompts and focuses the selected element with a spotlight for clearer context. It temporarily hides legacy UI while active and adapts to light/dark mode.

  • New Features

    • Bottom “Dynamic Island”-style CommitWidget that scales up when the prompt opens.
    • TextMorph label shows the latest grabbed element as Component.tagName.
    • Expandable prompt input; Enter copies to clipboard with “Copied” → “Prompt” feedback.
    • Spotlight effect: grays out the page and hides text/SVGs/images, leaving the target in full color with a subtle overlay.
    • History/undo: label updates after grabs; ⌃Z copies an undo prompt.
    • Suppresses selection labels, overlay canvas, toolbar, and history dropdown while the prompt is open.
  • Dependencies

    • Added torph (^0.0.5) for text morphing and included it in tsup noExternal.
    • Added commit widget styles and constants; wired new props (onActivateForCopy, latestGrabbedElement).

Written for commit 8a0bb71. Summary will update on new commits.

Adds a persistent commit widget (Dynamic Island-style) at the bottom of the viewport with:

- TextMorph-powered label showing the latest grabbed element (ComponentName.tagName)
- Expandable prompt input that copies text to clipboard on submit
- Spotlight effect: hides text/SVGs/images on the rest of the page, applies grayscale
  and a subtle overlay, leaving only the target element in full color
- Dynamic Island scale-up animation when prompt opens
- Light/dark mode support via prefers-color-scheme
- History button with ⌃Z shortcut to copy an undo prompt
- Suppresses legacy selection labels and overlay canvas while prompt is open

New files:
- src/components/commit-widget.tsx (SolidJS component)
- src/components/text-morph.tsx (SolidJS wrapper for torph TextMorph class)

Modified:
- renderer.tsx: wires CommitWidget, hides legacy labels/overlay during prompt
- core/index.tsx: adds handleActivateForCopy, passes latestGrabbedElement
- types.ts: adds onActivateForCopy, latestGrabbedElement to renderer props
- constants.ts: adds COMMIT_WIDGET_FEEDBACK_DURATION_MS, COMMIT_WIDGET_PROMPT_WIDTH_PX
- styles.css: adds commit widget styles with light mode overrides
- tsup.config.ts: adds torph to noExternal
- package.json: adds torph dependency
@pullfrog
Copy link
Contributor

pullfrog bot commented Mar 1, 2026

This run croaked 😵

The workflow encountered an error before any progress could be reported. Please check the link below for details.

Pullfrog  | Rerun failed job ➔View workflow run | Triggered by Pullfrogpullfrog.com𝕏

@vercel
Copy link
Contributor

vercel bot commented Mar 1, 2026

@ben-million is attempting to deploy a commit to the Million Team on Vercel.

A member of the Team first needs to authorize it.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 1, 2026

Open in StackBlitz

@react-grab/cli

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

grab

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

@react-grab/ami

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

@react-grab/amp

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

@react-grab/claude-code

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

@react-grab/codex

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

@react-grab/copilot

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

@react-grab/cursor

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

@react-grab/droid

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

@react-grab/gemini

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

@react-grab/opencode

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

react-grab

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

@react-grab/relay

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

@react-grab/utils

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

commit: 7cef1b4


return (
<>
<Show when={!isCommitPromptOpen()}>
Copy link
Contributor

Choose a reason for hiding this comment

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

SelectionLabel components were completely removed from the renderer, preventing users from seeing any selection labels for hovered/selected elements

Fix on Vercel

};

const restorePageText = (modifiedElements: ModifiedElement[]) => {
for (const {
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing previousFilter in destructuring pattern causes undefined filter restoration in restorePageText function

Fix on Vercel

Comment on lines +240 to +242
window.addEventListener("keydown", handleWindowKeyDown);
onCleanup(() => {
window.removeEventListener("keydown", handleWindowKeyDown);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
window.addEventListener("keydown", handleWindowKeyDown);
onCleanup(() => {
window.removeEventListener("keydown", handleWindowKeyDown);
createEffect(() => {
window.addEventListener("keydown", handleWindowKeyDown);
onCleanup(() => {
window.removeEventListener("keydown", handleWindowKeyDown);
});

The keydown event listener registration is placed in the component body outside of any reactive context, violating SolidJS best practices

Fix on Vercel

Copy link
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.

2 issues found across 13 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/commit-widget.tsx">

<violation number="1" location="packages/react-grab/src/components/commit-widget.tsx:227">
P2: Global Ctrl+Z handling overrides normal undo in editable fields because the listener always calls `preventDefault()`.</violation>
</file>

<file name="packages/react-grab/src/components/renderer.tsx">

<violation number="1" location="packages/react-grab/src/components/renderer.tsx:23">
P1: Non-agent selection labels were effectively removed, so standard selection/status UI no longer renders even when the commit prompt is closed.</violation>
</file>

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


return (
<>
<Show when={!isCommitPromptOpen()}>
Copy link
Contributor

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

Choose a reason for hiding this comment

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

P1: Non-agent selection labels were effectively removed, so standard selection/status UI no longer renders even when the commit prompt is closed.

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/renderer.tsx, line 23:

<comment>Non-agent selection labels were effectively removed, so standard selection/status UI no longer renders even when the commit prompt is closed.</comment>

<file context>
@@ -1,24 +1,26 @@
+
   return (
     <>
+      <Show when={!isCommitPromptOpen()}>
       <OverlayCanvas
         crosshairVisible={props.crosshairVisible}
</file context>
Fix with Cubic

};

const handleWindowKeyDown = (event: KeyboardEvent) => {
if (event.ctrlKey && event.key === "z") {
Copy link
Contributor

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

Choose a reason for hiding this comment

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

P2: Global Ctrl+Z handling overrides normal undo in editable fields because the listener always calls preventDefault().

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/commit-widget.tsx, line 227:

<comment>Global Ctrl+Z handling overrides normal undo in editable fields because the listener always calls `preventDefault()`.</comment>

<file context>
@@ -0,0 +1,315 @@
+  };
+
+  const handleWindowKeyDown = (event: KeyboardEvent) => {
+    if (event.ctrlKey && event.key === "z") {
+      event.preventDefault();
+      void navigator.clipboard.writeText(UNDO_CLIPBOARD_PROMPT);
</file context>
Fix with Cubic

Copy link

@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 3 potential issues.

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

previousTextShadow,
previousVisibility,
didHideVisibility,
} of modifiedElements) {
Copy link

Choose a reason for hiding this comment

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

Missing previousFilter in destructuring breaks style restoration

High Severity

The restorePageText function destructures six fields from each ModifiedElement but omits previousFilter. Line 111 then references previousFilter as an undeclared variable. Since hideTextInSubtree applies grayscale(1) to every element's filter style, failing to restore this property means the page will remain grayscaled after the spotlight effect is dismissed.

Additional Locations (1)

Fix in Cursor Fix in Web

setPromptLabel("Prompt");
setIsPromptOpen(false);
}, COMMIT_WIDGET_FEEDBACK_DURATION_MS);
};
Copy link

Choose a reason for hiding this comment

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

Stale timeout in submit closes prompt unexpectedly

Medium Severity

handlePromptSubmit schedules a setTimeout that calls setIsPromptOpen(false) after 1500ms, but this timer is never cancelled. If copyCount changes within that window (e.g., the user grabs another element), the createEffect reopens the prompt, and then the stale timeout fires and closes it unexpectedly. The timeout reference needs to be stored and cleared when a new copy event arrives.

Additional Locations (1)

Fix in Cursor Fix in Web

window.addEventListener("keydown", handleWindowKeyDown);
onCleanup(() => {
window.removeEventListener("keydown", handleWindowKeyDown);
});
Copy link

Choose a reason for hiding this comment

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

Global Ctrl+Z handler blocks undo in all inputs

Medium Severity

The handleWindowKeyDown listener unconditionally intercepts every Ctrl+Z keypress page-wide with event.preventDefault(), regardless of the event target. This breaks native undo in all text inputs on the page — including the widget's own prompt input — and fires even when there are no history items, copying a meaningless undo prompt to the clipboard.

Fix in Cursor Fix in Web

@vercel
Copy link
Contributor

vercel bot commented Mar 1, 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 1, 2026 5:50am

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