Skip to content

feat: make notebook cell state clear without visual noise - #10624

Draft
Light2Dark wants to merge 1 commit into
mainfrom
codex/cell-state-ui
Draft

feat: make notebook cell state clear without visual noise#10624
Light2Dark wants to merge 1 commit into
mainfrom
codex/cell-state-ui

Conversation

@Light2Dark

Copy link
Copy Markdown
Member

This pull request was authored by a coding agent.

📝 Summary

Cell state was communicated through several independent styling paths, which made combinations such as disabled plus outdated or failed plus outdated ambiguous. Broad yellow cell treatments also made notebooks visually noisy, while running status and selection could be easy to miss.

This centralizes runtime state into a semantic model and derives badges, actions, accessible descriptions, output freshness, column summaries, and cell emphasis from it. State is now communicated through compact labels and non-layout semantic rails instead of full-cell tinting. Execution, availability, freshness, prior outcome, and command-mode selection remain independent, so combined states stay visible without shifting cell geometry. Multi-column notebooks use compact status treatments with stable space for the drag handle and live timer.

Screen.Recording.2026-08-21.at.11.21.26.PM.mov

📋 Pre-Review Checklist

  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • Video or media evidence is provided for any visual changes (optional).

✅ Merge Checklist

  • I have read the contributor guidelines.
  • Documentation has been updated where applicable, including docstrings for API changes.
  • Tests have been added for the changes made.

Written by GPT-5 on Codex

@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview Aug 21, 2026 4:12pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@Light2Dark Light2Dark added enhancement New feature or request includes-media Description includes multimedia provided to illustrate functionality. javascript Pull requests that update javascript code labels Aug 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for ./frontend

Status Category Percentage Covered / Total
🔵 Lines 78.84% 82404 / 104511
🔵 Statements 78.84% 82404 / 104511
🔵 Functions 71.65% 708 / 988
🔵 Branches 79.79% 5078 / 6364
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
frontend/src/components/editor/Output.tsx 59.65% 57.14% 0% 59.65% 93, 132-133, 164-168, 175-184, 188-192, 195-200, 206-218, 221-225, 228-241, 263-340, 436-452, 455-475
frontend/src/components/editor/RecoveryButton.tsx 100% 100% 100% 100%
frontend/src/components/editor/SortableCell.tsx 92.38% 30% 100% 92.38% 42-43, 117-122
frontend/src/components/editor/notebook-cell.tsx 88.17% 66.66% 0% 88.17% 110-117, 126-147, 190-203, 206-209, 510-527, 582-583, 589-596, 604, 727-782, 859, 863
frontend/src/components/editor/cell/CellStatus.tsx 95.28% 91.89% 66.66% 95.28% 45, 132, 140, 192-201
frontend/src/components/editor/cell/RunButton.tsx 94.44% 20% 100% 94.44% 88, 90, 92-93
frontend/src/components/editor/cell/StopButton.tsx 100% 0% 100% 100%
frontend/src/components/editor/cell/collapse.tsx 42.66% 0% 100% 42.66% 69-125
frontend/src/components/editor/cell/toolbar.tsx 100% 100% 100% 100%
frontend/src/components/editor/columns/cell-column.tsx 100% 100% 100% 100%
frontend/src/components/editor/columns/sortable-column.tsx 95.62% 50% 0% 95.62% 73-78, 113, 126
frontend/src/components/editor/controls/Controls.tsx 0% 100% 100% 0% 3-230
frontend/src/components/editor/header/status.tsx 100% 75% 100% 100%
frontend/src/components/editor/inputs/Inputs.styles.ts 100% 100% 100% 100%
frontend/src/components/editor/navigation/navigation.ts 100% 97.29% 75% 100%
frontend/src/components/editor/renderers/cell-array.tsx 0% 100% 100% 0% 3-395
frontend/src/components/editor/renderers/grid-layout/grid-layout.tsx 78.02% 22.22% 100% 78.02% 177-181, 332-367, 387-429, 528-585
frontend/src/components/editor/renderers/vertical-layout/vertical-layout.tsx 66.76% 85.71% 50% 66.76% 89, 125-130, 328-456
frontend/src/components/scratchpad/scratchpad.tsx 0% 100% 100% 0% 4-301
frontend/src/components/slides/slide-cell-view.tsx 100% 50% 100% 100%
frontend/src/components/slides/slide.tsx 100% 100% 100% 100%
frontend/src/core/cells/cell.ts 98.4% 84.61% 100% 98.4% 67, 71
frontend/src/core/cells/cells.ts 97.77% 93.47% 60% 97.77% 1727, 1738-1765, 1770, 1854-1858, 1864, 1867, 1990
frontend/src/core/cells/semantic-state.ts 99.66% 96.55% 100% 99.66% 348
frontend/src/core/cells/utils.ts 100% 93.75% 100% 100%
frontend/src/core/hotkeys/hotkeys.ts 100% 100% 100% 100%
frontend/src/core/saving/save-component.tsx 73.26% 100% 100% 73.26% 102-154, 158-166, 178-189
frontend/src/hooks/useElapsedTime.ts 92.3% 100% 100% 92.3% 20
frontend/src/stories/cell-status.stories.tsx 0% 100% 100% 0% 3-92
frontend/src/stories/editor-inputs.stories.tsx 0% 100% 100% 0% 3-47
Generated in workflow #20688 for commit 6319bb9 by the Vitest Coverage Report Action

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

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.

11 issues found across 43 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="frontend/src/components/editor/cell/cell-status.css">

<violation number="1" location="frontend/src/components/editor/cell/cell-status.css:62">
P3: The compact-mode spinner-hide rule only matches a direct `<svg>` child of `.contents`. When a cell is running in combination with an error or outdated modifier, `CellStatusIcon` renders a `MultiIcon` (whose first icon is the `Loader2Icon` spinner) instead of a bare svg, so the running spinner is not hidden in compact mode. If the intent is to always replace the loader with the live timer in compact state, the selector needs to also account for the MultiIcon case.</violation>
</file>

<file name="frontend/src/components/editor/cell/RunButton.tsx">

<violation number="1" location="frontend/src/components/editor/cell/RunButton.tsx:71">
P2: When a blocked cell has edited code, the semantic model marks it actionable and this button remains enabled with the active variant, but this unconditional branch tells users it cannot be run. Restrict the blocked-only presentation to unedited blocked cells so edited cells use the normal runnable button and shortcut tooltip.</violation>
</file>

<file name="frontend/src/css/app/Cell.css">

<violation number="1" location="frontend/src/css/app/Cell.css:327">
P3: In dark mode, paused and blocked cells match these generic selectors, overriding their state border colors and weakening the intended state treatment. Exclude `.cell-paused` and `.cell-blocked` from both dark-mode selectors.</violation>
</file>

<file name="frontend/src/components/editor/cell/CellStatus.tsx">

<violation number="1" location="frontend/src/components/editor/cell/CellStatus.tsx:139">
P2: When a paused or blocked cell has both an error and outdated inputs, the compact badge renders only the error modifier, so the outdated state disappears. Render both modifiers, or otherwise encode both states in the compact icon.</violation>

<violation number="2" location="frontend/src/components/editor/cell/CellStatus.tsx:178">
P2: For statuses whose reason is in `status.description`, this element exposes only the terse `label` to assistive technology and relies on a hover-only tooltip for the explanation. Expose `status.description` through an accessible description or persistent text.</violation>
</file>

<file name="frontend/src/components/editor/controls/Controls.tsx">

<violation number="1" location="frontend/src/components/editor/controls/Controls.tsx:188">
P3: Setting `disabled` on the run button makes the "Nothing to run" tooltip never appear. A natively disabled `<button>` stops dispatching pointer events, so the Radix TooltipTrigger wrapping it never shows its content. The same applies to the stop button when `showInterrupt` is false ("No cells running" tooltip). Previously the run button was only disabled while the app was not interactive, so the tooltip showed in the common case; it now regresses to always-hidden. To keep the tooltip, keep the button non-disabled and drive interactivity via `onClick`/`aria-disabled`, or wrap the disabled button in a span that receives the hover events.</violation>
</file>

<file name="frontend/src/core/cells/semantic-state.ts">

<violation number="1" location="frontend/src/core/cells/semantic-state.ts:343">
P2: When a cell is outdated while running, queued, interrupted, stopped, or not yet run, the visual refresh modifier is omitted from its accessible label and description. Include the outdated modifier whenever `primary !== "outdated"` so assistive technology receives the same combined state shown visually.</violation>
</file>

<file name="frontend/src/components/editor/cell/collapse.tsx">

<violation number="1" location="frontend/src/components/editor/cell/collapse.tsx:95">
P2: When a descendant was interrupted without edited code or changed inputs, this summary reports it only as `Has cells to run` and hides the interrupted outcome. Add a separate interrupted summary/icon or use an interrupted-specific label here.</violation>

<violation number="2" location="frontend/src/components/editor/cell/collapse.tsx:100">
P2: When a collapsed range contains a directly disabled cell, this banner does not show that paused state because it only renders the upstream-blocked flag. Add a paused descendant summary and render its status so collapsed cells do not hide direct availability state.</violation>
</file>

<file name="frontend/src/components/editor/renderers/cell-array.tsx">

<violation number="1" location="frontend/src/components/editor/renderers/cell-array.tsx:198">
P2: In single-column layouts, this hook computes and subscribes to a full column summary even though `Column` discards `statusSummary`. Restrict the subscription to multi-column layouts, such as by moving it into the columns-only rendering path or adding an enabled variant to the hook.</violation>
</file>

<file name="frontend/src/components/editor/cell/toolbar.tsx">

<violation number="1" location="frontend/src/components/editor/cell/toolbar.tsx:16">
P3: The new `active` variant declares an explicit border color (`border-[var(--blue-6)]`) but the equally-new filled `stop` variant does not, so its 1px border falls back to the base `border` (currentColor). The two filled states render with visibly different borders, which undercuts the PR's goal of consistent semantic styling. Add a matching border color to `stop` (e.g. `border-[var(--red-7)]`) or drop the explicit border on `active`.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant User
    participant UI as Notebook Cell UI
    participant Store as Jotai Store (Notebook State)
    participant Logic as NEW: Semantic State Logic
    participant Kernel as Python Kernel

    Note over User, Kernel: Runtime Request & State Derivation Flow

    User->>UI: Edits code or clicks "Run"
    
    alt User Edited Code
        UI->>Store: Update cell code & set edited=true
    else User Clicked Run
        UI->>Kernel: Request cell execution
        Kernel-->>Store: Update status (queued/running)
    end

    Store->>UI: Trigger re-render with raw data
    
    Note over UI, Logic: Centralized Derivation
    UI->>Logic: NEW: deriveCellSemanticState(data, runtime)
    
    Logic->>Logic: Calculate availability (paused/blocked)
    Logic->>Logic: Calculate freshness (outdated/not-run)
    Logic->>Logic: Calculate execution phase (idle/queued/running)
    
    Logic-->>UI: Return CellSemanticState object

    Note over UI: UI Components consume semantic state

    UI->>UI: CHANGED: Render semantic rails (CSS classes)
    UI->>UI: NEW: Render CellStatusComponent (Badges/Timers)
    
    opt Output Handling
        UI->>UI: CHANGED: OutputArea(state: updating|previous|current)
        Note right of UI: Output dims or shows loader<br/>based on semantic freshness
    end

    opt Action Controls
        UI->>UI: CHANGED: RunButton (evaluates semantic needsRun)
        UI->>UI: CHANGED: StopButton (evaluates semantic phase)
    end

    alt Multi-column Layout
        UI->>UI: NEW: presentCellStatus(state, "compact")
        Note right of UI: Stable layout for drag handles<br/>while showing live timer
    end

    Note over UI, Store: Global State Summary
    Store->>Logic: NEW: summarizeCellStates(allCells)
    Logic-->>UI: Update Header/Column Status Badges
Loading

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

Re-trigger cubic

);
}
if (!config.disabled && blockedStatus && !edited) {
if (blocked) {

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 a blocked cell has edited code, the semantic model marks it actionable and this button remains enabled with the active variant, but this unconditional branch tells users it cannot be run. Restrict the blocked-only presentation to unedited blocked cells so edited cells use the normal runnable button and shortcut tooltip.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/cell/RunButton.tsx, line 71:

<comment>When a blocked cell has edited code, the semantic model marks it actionable and this button remains enabled with the active variant, but this unconditional branch tells users it cannot be run. Restrict the blocked-only presentation to unedited blocked cells so edited cells use the normal runnable button and shortcut tooltip.</comment>

<file context>
@@ -69,7 +68,7 @@ export const RunButton = (props: {
     );
   }
-  if (!config.disabled && blockedStatus && !edited) {
+  if (blocked) {
     return (
       <ToolbarItem
</file context>
Suggested change
if (blocked) {
if (blocked && !state.codeEdited) {

data-testid="cell-status"
data-status={state}
data-display={display}
aria-label={label}

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: For statuses whose reason is in status.description, this element exposes only the terse label to assistive technology and relies on a hover-only tooltip for the explanation. Expose status.description through an accessible description or persistent text.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/cell/CellStatus.tsx, line 178:

<comment>For statuses whose reason is in `status.description`, this element exposes only the terse `label` to assistive technology and relies on a hover-only tooltip for the explanation. Expose `status.description` through an accessible description or persistent text.</comment>

<file context>
@@ -1,325 +1,241 @@
+      data-testid="cell-status"
+      data-status={state}
+      data-display={display}
+      aria-label={label}
+      role="status"
+      aria-atomic={true}
</file context>

const CellStatusIcon = ({ status }: { status: CellStatusPresentation }) => {
const primary = primaryStatusIcon(status.primary);
const modifier =
status.modifiers.hasError && status.primary !== "error" ? (

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 a paused or blocked cell has both an error and outdated inputs, the compact badge renders only the error modifier, so the outdated state disappears. Render both modifiers, or otherwise encode both states in the compact icon.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/cell/CellStatus.tsx, line 139:

<comment>When a paused or blocked cell has both an error and outdated inputs, the compact badge renders only the error modifier, so the outdated state disappears. Render both modifiers, or otherwise encode both states in the compact icon.</comment>

<file context>
@@ -1,325 +1,241 @@
+const CellStatusIcon = ({ status }: { status: CellStatusPresentation }) => {
+  const primary = primaryStatusIcon(status.primary);
+  const modifier =
+    status.modifiers.hasError && status.primary !== "error" ? (
+      <AlertCircleIcon className="size-2.5 bg-inherit" />
+    ) : status.modifiers.outdated && status.primary !== "outdated" ? (
</file context>

labels.push("Error");
descriptions.push("This cell also has an error.");
}
if ((showModifiers || primary === "error") && outdated) {

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 a cell is outdated while running, queued, interrupted, stopped, or not yet run, the visual refresh modifier is omitted from its accessible label and description. Include the outdated modifier whenever primary !== "outdated" so assistive technology receives the same combined state shown visually.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/core/cells/semantic-state.ts, line 343:

<comment>When a cell is outdated while running, queued, interrupted, stopped, or not yet run, the visual refresh modifier is omitted from its accessible label and description. Include the outdated modifier whenever `primary !== "outdated"` so assistive technology receives the same combined state shown visually.</comment>

<file context>
@@ -0,0 +1,456 @@
+    labels.push("Error");
+    descriptions.push("This cell also has an error.");
+  }
+  if ((showModifiers || primary === "error") && outdated) {
+    labels.push("Outdated");
+    descriptions.push(
</file context>

{states.stale && (
<Tooltip content="Has stale cells" delayDuration={100}>
<RefreshCcw className="w-4 h-4 shrink-0 text-(--yellow-11)" />
{states.outdated && (

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 a descendant was interrupted without edited code or changed inputs, this summary reports it only as Has cells to run and hides the interrupted outcome. Add a separate interrupted summary/icon or use an interrupted-specific label here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/cell/collapse.tsx, line 95:

<comment>When a descendant was interrupted without edited code or changed inputs, this summary reports it only as `Has cells to run` and hides the interrupted outcome. Add a separate interrupted summary/icon or use an interrupted-specific label here.</comment>

<file context>
@@ -84,19 +87,34 @@ export const CollapsedCellBanner: React.FC<{
-            {states.stale && (
-              <Tooltip content="Has stale cells" delayDuration={100}>
-                <RefreshCcw className="w-4 h-4 shrink-0 text-(--yellow-11)" />
+            {states.outdated && (
+              <Tooltip content="Has cells to run" delayDuration={100}>
+                <RefreshCcw className="w-4 h-4 shrink-0 text-(--slate-11)" />
</file context>

const cellIds = useCellIds();
const column = cellIds.get(columnId);
invariant(column, `Expected column for: ${columnId}`);
const statusSummary = useColumnStateSummary(columnId);

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: In single-column layouts, this hook computes and subscribes to a full column summary even though Column discards statusSummary. Restrict the subscription to multi-column layouts, such as by moving it into the columns-only rendering path or adding an enabled variant to the hook.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/renderers/cell-array.tsx, line 198:

<comment>In single-column layouts, this hook computes and subscribes to a full column summary even though `Column` discards `statusSummary`. Restrict the subscription to multi-column layouts, such as by moving it into the columns-only rendering path or adding an enabled variant to the hook.</comment>

<file context>
@@ -194,6 +195,7 @@ const CellColumn: React.FC<{
   const cellIds = useCellIds();
   const column = cellIds.get(columnId);
   invariant(column, `Expected column for: ${columnId}`);
+  const statusSummary = useColumnStateSummary(columnId);
 
   const hasOnlyOneCell = cellIds.hasOnlyOneId();
</file context>

display: none;
}

.cell-status-indicator[data-display="compact"][data-status^="running"]

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 compact-mode spinner-hide rule only matches a direct <svg> child of .contents. When a cell is running in combination with an error or outdated modifier, CellStatusIcon renders a MultiIcon (whose first icon is the Loader2Icon spinner) instead of a bare svg, so the running spinner is not hidden in compact mode. If the intent is to always replace the loader with the live timer in compact state, the selector needs to also account for the MultiIcon case.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/cell/cell-status.css, line 62:

<comment>The compact-mode spinner-hide rule only matches a direct `<svg>` child of `.contents`. When a cell is running in combination with an error or outdated modifier, `CellStatusIcon` renders a `MultiIcon` (whose first icon is the `Loader2Icon` spinner) instead of a bare svg, so the running spinner is not hidden in compact mode. If the intent is to always replace the loader with the live timer in compact state, the selector needs to also account for the MultiIcon case.</comment>

<file context>
@@ -1,21 +1,78 @@
+  display: none;
+}
+
+.cell-status-indicator[data-display="compact"][data-status^="running"]
+  > .contents
+  > svg {
</file context>


&:hover {
border: 1px solid var(--gray-9);
&:not(.cell-active, .cell-failed, [data-cell-freshness="outdated"]) {

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: In dark mode, paused and blocked cells match these generic selectors, overriding their state border colors and weakening the intended state treatment. Exclude .cell-paused and .cell-blocked from both dark-mode selectors.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/css/app/Cell.css, line 327:

<comment>In dark mode, paused and blocked cells match these generic selectors, overriding their state border colors and weakening the intended state treatment. Exclude `.cell-paused` and `.cell-blocked` from both dark-mode selectors.</comment>

<file context>
@@ -327,14 +324,12 @@
-
-  &:hover {
-    border: 1px solid var(--gray-9);
+  &:not(.cell-active, .cell-failed, [data-cell-freshness="outdated"]) {
+    border-color: var(--border);
   }
</file context>

size="medium"
shape="circle"
disabled={!canInteractWithApp}
disabled={true}

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: Setting disabled on the run button makes the "Nothing to run" tooltip never appear. A natively disabled <button> stops dispatching pointer events, so the Radix TooltipTrigger wrapping it never shows its content. The same applies to the stop button when showInterrupt is false ("No cells running" tooltip). Previously the run button was only disabled while the app was not interactive, so the tooltip showed in the common case; it now regresses to always-hidden. To keep the tooltip, keep the button non-disabled and drive interactivity via onClick/aria-disabled, or wrap the disabled button in a span that receives the hover events.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/controls/Controls.tsx, line 188:

<comment>Setting `disabled` on the run button makes the "Nothing to run" tooltip never appear. A natively disabled `<button>` stops dispatching pointer events, so the Radix TooltipTrigger wrapping it never shows its content. The same applies to the stop button when `showInterrupt` is false ("No cells running" tooltip). Previously the run button was only disabled while the app was not interactive, so the tooltip showed in the common case; it now regresses to always-hidden. To keep the tooltip, keep the button non-disabled and drive interactivity via `onClick`/`aria-disabled`, or wrap the disabled button in a span that receives the hover events.</comment>

<file context>
@@ -179,11 +180,12 @@ const RunControlButton = ({
         size="medium"
         shape="circle"
-        disabled={!canInteractWithApp}
+        disabled={true}
       >
         <PlayIcon strokeWidth={1.5} size={16} />
</file context>

Comment on lines +16 to 19
active:
"bg-(--blue-3) hover:bg-(--blue-4) text-(--blue-11) border-[var(--blue-6)]",
green:
"hover:bg-(--grass-2) hover:text-(--grass-11) hover:border-[var(--grass-7)],",

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 active variant declares an explicit border color (border-[var(--blue-6)]) but the equally-new filled stop variant does not, so its 1px border falls back to the base border (currentColor). The two filled states render with visibly different borders, which undercuts the PR's goal of consistent semantic styling. Add a matching border color to stop (e.g. border-[var(--red-7)]) or drop the explicit border on active.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/cell/toolbar.tsx, line 16:

<comment>The new `active` variant declares an explicit border color (`border-[var(--blue-6)]`) but the equally-new filled `stop` variant does not, so its 1px border falls back to the base `border` (currentColor). The two filled states render with visibly different borders, which undercuts the PR's goal of consistent semantic styling. Add a matching border color to `stop` (e.g. `border-[var(--red-7)]`) or drop the explicit border on `active`.</comment>

<file context>
@@ -13,11 +13,13 @@ const toolbarItemVariants = cva(
       variant: {
         default: "hover:bg-accent hover:text-accent-foreground",
-        stale: "bg-(--yellow-3) hover:bg-(--yellow-4) text-(--yellow-11)",
+        active:
+          "bg-(--blue-3) hover:bg-(--blue-4) text-(--blue-11) border-[var(--blue-6)]",
         green:
</file context>
Suggested change
active:
"bg-(--blue-3) hover:bg-(--blue-4) text-(--blue-11) border-[var(--blue-6)]",
green:
"hover:bg-(--grass-2) hover:text-(--grass-11) hover:border-[var(--grass-7)],",
active:
"bg-(--blue-3) hover:bg-(--blue-4) text-(--blue-11) border-[var(--blue-6)]",
green:
"hover:bg-(--grass-2) hover:text-(--grass-11) hover:border-[var(--grass-7)],",
disabled: "opacity-50 cursor-not-allowed",
danger: "hover:bg-(--red-3) hover:text-(--red-11)",
stop: "bg-(--red-3) hover:bg-(--red-4) text-(--red-11) border-[var(--red-6)]",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request includes-media Description includes multimedia provided to illustrate functionality. javascript Pull requests that update javascript code team-draft

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant