feat: add commit widget with prompt, spotlight, and text-morph feedback#205
feat: add commit widget with prompt, spotlight, and text-morph feedback#205ben-million wants to merge 1 commit intoaidenybai:mainfrom
Conversation
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
|
This run croaked 😵 The workflow encountered an error before any progress could be reported. Please check the link below for details. |
|
@ben-million is attempting to deploy a commit to the Million Team on Vercel. A member of the Team first needs to authorize it. |
@react-grab/cli
grab
@react-grab/ami
@react-grab/amp
@react-grab/claude-code
@react-grab/codex
@react-grab/copilot
@react-grab/cursor
@react-grab/droid
@react-grab/gemini
@react-grab/opencode
react-grab
@react-grab/relay
@react-grab/utils
commit: |
|
|
||
| return ( | ||
| <> | ||
| <Show when={!isCommitPromptOpen()}> |
| }; | ||
|
|
||
| const restorePageText = (modifiedElements: ModifiedElement[]) => { | ||
| for (const { |
| window.addEventListener("keydown", handleWindowKeyDown); | ||
| onCleanup(() => { | ||
| window.removeEventListener("keydown", handleWindowKeyDown); |
There was a problem hiding this comment.
| 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
There was a problem hiding this comment.
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()}> |
There was a problem hiding this comment.
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>
| }; | ||
|
|
||
| const handleWindowKeyDown = (event: KeyboardEvent) => { | ||
| if (event.ctrlKey && event.key === "z") { |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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)
| setPromptLabel("Prompt"); | ||
| setIsPromptOpen(false); | ||
| }, COMMIT_WIDGET_FEEDBACK_DURATION_MS); | ||
| }; |
There was a problem hiding this comment.
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)
| window.addEventListener("keydown", handleWindowKeyDown); | ||
| onCleanup(() => { | ||
| window.removeEventListener("keydown", handleWindowKeyDown); | ||
| }); |
There was a problem hiding this comment.
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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|



Adds a persistent commit widget (Dynamic Island-style) at the bottom of the viewport.
Features
ComponentName.tagName, morphing between statesprefers-color-schemeNew files
src/components/commit-widget.tsx— SolidJS componentsrc/components/text-morph.tsx— SolidJS wrapper for torph's TypeScriptTextMorphclassModified files
renderer.tsx— wires CommitWidget, hides legacy labels/overlay during promptcore/index.tsx— addshandleActivateForCopy, passeslatestGrabbedElementtypes.ts— addsonActivateForCopy,latestGrabbedElementto renderer propsconstants.ts— adds feedback duration and prompt width constantsstyles.css— commit widget styles with light mode overridestsup.config.ts— adds torph tonoExternalpackage.json— addstorphdependencyNote
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
CommitWidgetthat 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-backedTextMorphanimations (plus shadow-DOM compatible styles), new widget constants/CSS, and wires new renderer props (onActivateForCopy,latestGrabbedElement) throughcoreand 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
Dependencies
Written for commit 8a0bb71. Summary will update on new commits.