BottomThreadBar's stop pills have no remove affordance — user can only remove a thread stop from the right panel's 3-dot menu, but the bottom bar is the primary surface for browsing stops #190

Closed
opened 2026-10-03 23:47:49 +00:00 by Mark · 1 comment
Owner

Finding

src/components/workspace/BottomThreadBar.tsx renders a horizontal list of "stop pills" (each is a small colored chip with the catalog name). The pills are clickable (to select the stop and highlight matching objects on the canvas) and the bar has an + Add button. There is no × remove button on the pills themselves.

A user who wants to remove a stop:

  • Sees 7 stops in the bottom bar after digitizing
  • Wants to remove the 3rd one (some thread they don't want)
  • Has to scroll up to the right panel
  • Find the "Thread Stops" section
  • Click the 3-dot menu on the right row
  • Click "Remove"

grep -n 'onRemove\|removeStop' src/components/workspace/BottomThreadBar.tsx returns 0 hits — the affordance is missing.

grep -n 'REMOVE_THREAD_STOP' src/components/workspace/RightPanel.tsx:507 confirms the only consumer is the right panel's per-row 3-dot menu.

Where

  • BottomThreadBar pills: src/components/workspace/BottomThreadBar.tsx:80-180 (approx, the stop pill section)
  • No remove: src/components/workspace/BottomThreadBar.tsx (no onRemove prop, no remove button)
  • Right panel has remove: src/components/workspace/RightPanel.tsx:507

Suggested fix shape

Add an × button on each stop pill, visible on hover:

<button
  data-testid={`remove-stop-${stop.id}`}
  onClick={(e) => {
    e.stopPropagation();
    onRemoveStop(stop.id);
  }}
  className="opacity-0 group-hover:opacity-100 w-4 h-4 flex items-center justify-center rounded"
  title="Remove this stop"
>
  <X size={10} />
</button>

Plumb onRemoveStop from the workspace reducer (the existing REMOVE_THREAD_STOP action in useWorkspace.ts:459).

Optionally: add a keyboard shortcut to remove the selected stop (Backspace or Delete when a stop pill is focused). Currently the only way to delete is via the right panel; the bottom bar — which is the more discoverable surface — is read-only.

Severity

Low. The user can remove via the right panel. Bottom bar is more discoverable but the action is available.

Discovered by

Gap analysis (2026-10-02) of thread stop affordances.

  • #92 (closed) — REMOVE_THREAD_STOP pushes history (undo works for the right panel path).
  • #165 (closed) — BottomThreadBar reorder via drag. Same surface, missing piece.
  • #177 (closed) — Right panel GripVertical drag handle. Companion fix in the right panel.
## Finding `src/components/workspace/BottomThreadBar.tsx` renders a horizontal list of "stop pills" (each is a small colored chip with the catalog name). The pills are clickable (to select the stop and highlight matching objects on the canvas) and the bar has an `+ Add` button. There is no `×` remove button on the pills themselves. A user who wants to remove a stop: - Sees 7 stops in the bottom bar after digitizing - Wants to remove the 3rd one (some thread they don't want) - Has to scroll up to the right panel - Find the "Thread Stops" section - Click the 3-dot menu on the right row - Click "Remove" `grep -n 'onRemove\|removeStop' src/components/workspace/BottomThreadBar.tsx` returns 0 hits — the affordance is missing. `grep -n 'REMOVE_THREAD_STOP' src/components/workspace/RightPanel.tsx:507` confirms the only consumer is the right panel's per-row 3-dot menu. ## Where - BottomThreadBar pills: `src/components/workspace/BottomThreadBar.tsx:80-180` (approx, the stop pill section) - No remove: `src/components/workspace/BottomThreadBar.tsx` (no `onRemove` prop, no remove button) - Right panel has remove: `src/components/workspace/RightPanel.tsx:507` ## Suggested fix shape Add an `×` button on each stop pill, visible on hover: ```tsx <button data-testid={`remove-stop-${stop.id}`} onClick={(e) => { e.stopPropagation(); onRemoveStop(stop.id); }} className="opacity-0 group-hover:opacity-100 w-4 h-4 flex items-center justify-center rounded" title="Remove this stop" > <X size={10} /> </button> ``` Plumb `onRemoveStop` from the workspace reducer (the existing `REMOVE_THREAD_STOP` action in `useWorkspace.ts:459`). Optionally: add a keyboard shortcut to remove the selected stop (Backspace or Delete when a stop pill is focused). Currently the only way to delete is via the right panel; the bottom bar — which is the more discoverable surface — is read-only. ## Severity Low. The user can remove via the right panel. Bottom bar is more discoverable but the action is available. ## Discovered by Gap analysis (2026-10-02) of thread stop affordances. ## Related - #92 (closed) — REMOVE_THREAD_STOP pushes history (undo works for the right panel path). - #165 (closed) — BottomThreadBar reorder via drag. Same surface, missing piece. - #177 (closed) — Right panel GripVertical drag handle. Companion fix in the right panel.
Author
Owner

Shipped in fe8d556 on main.

  • BottomThreadBar.tsx accepts an optional onRemoveStop(stopId) prop (mirroring the existing onReorderStops opt-in pattern) and renders an × button on each chip wrapper, hidden at rest and fading in on hover to match the drag handle.
  • Workspace.tsx plumbs the dispatcher: clicking × fires REMOVE_THREAD_STOP, which already pushes history so Cmd+Z still undoes a removal triggered from the bottom bar.
  • 5 regression tests in src/components/workspace/issue-190.test.tsx (render-with/without-prop, correct id passed, no spurious chip-select on click, coexistence with onReorderStops). Full suite: 863/863 passing.
  • The e.stopPropagation() on the button's onClick + onMouseDown ensures a click on × removes the stop without first selecting its chip (no canvas flicker).

Untouched in this commit: the editor's right panel is unaffected; the right-panel 3-dot Remove path still works.

Shipped in fe8d556 on main. - `BottomThreadBar.tsx` accepts an optional `onRemoveStop(stopId)` prop (mirroring the existing `onReorderStops` opt-in pattern) and renders an `×` button on each chip wrapper, hidden at rest and fading in on hover to match the drag handle. - `Workspace.tsx` plumbs the dispatcher: clicking `×` fires `REMOVE_THREAD_STOP`, which already pushes history so Cmd+Z still undoes a removal triggered from the bottom bar. - 5 regression tests in `src/components/workspace/issue-190.test.tsx` (render-with/without-prop, correct id passed, no spurious chip-select on click, coexistence with `onReorderStops`). Full suite: 863/863 passing. - The `e.stopPropagation()` on the button's onClick + onMouseDown ensures a click on `×` removes the stop without first selecting its chip (no canvas flicker). Untouched in this commit: the editor's right panel is unaffected; the right-panel 3-dot Remove path still works.
Mark closed this issue 2026-10-04 00:27:30 +00:00
Sign in to join this conversation.
No description provided.