LearnNewsExamplesServices
Frontmatter
id19985
titleWorkstation's grid column drag proxy paints the theme's default colors
stateClosed
labels
bugdesignaigrid
assigneesneo-opus-vega
createdAtOct 22, 2026, 11:26 AM
updatedAtOct 22, 2026, 4:50 PM
githubUrlhttps://github.com/neomjs/neo/issues/19985
authorneo-opus-ada
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtOct 22, 2026, 4:50 PM

Workstation's grid column drag proxy paints the theme's default colors

Closed Backlog/active-chunk-10 bugdesignaigrid
neo-opus-ada
neo-opus-ada commented on Oct 22, 2026, 11:26 AM

Context

Found in manual testing of apps/workstation on dev (2026-10-22), in the same pass as #19982 and #19984. Dragging a column header of the 100k Matrix grid (here Throughput) shows a drag proxy whose header and cells use the neo theme's default grid colors: a blue header and near-black cells. Workstation's own palette is gone. A screenshot follows in a comment.

Measurements

Headless Chromium, 1440×900, at 8bb3574d0f (its src/, apps/ and resources/scss/ are identical to dev at 84b711878a). A real pointer drag on the Throughput header, with computed styles read while the proxy is live:

skin property source grid drag proxy
dark header background / text rgb(26,33,44) / rgb(214,220,230) #182449 / rgb(240,242,240)
dark cell background rgb(20,26,35) #0E0F0D
light header background / text rgb(247,249,252) / rgb(31,39,51) #5d83a7 / #fff
light cell background #fff #fff

The proxy is a direct child of document.body with neo-grid-container neo-theme-neo-{dark,light} neo-dragproxy. Its theme class is the live one in both skins. What is missing is Workstation's own skin.

The Problem

Workstation skins grids with an app-scoped token bridge, not with a theme. Viewport.scss maps --grid-* onto its --workstation-* palette under :root .workstation-viewport[class*="neo-theme-"], :root .workstation-viewport [class*="neo-theme-"], and sets the header tokens under .workstation-viewport .neo-grid-header-button.

The column-drag proxy is mounted outside that subtree. No bridge rule matches it, so every grid token on it resolves to the theme's default.

The Architectural Reality

  • src/draggable/DragZone.mjs: proxyParentId_ defaults to 'document.body', and the source's theme class is pushed onto the proxy.
  • src/draggable/grid/header/toolbar/SortZone.mjs createDragProxy(): cls = ['neo-grid-container', owner.getTheme()]. Inside, the proxy nests a neo-grid-container carrying the source grid's own cls, a header toolbar and cloned rows and cells.
  • resources/scss/src/apps/workstation/Viewport.scss: the viewport bridge. Its comment explains why the selector mirrors the theme's own reach. For an inherited custom property the nearest declaring ancestor wins, and inner grid primitives carry skin classes too (#17984).
  • Design authority: Workstation's own precedent for a body-mounted embodiment, the overflow menu in Workspace.scss. "The generic menu is a second floating direct-body embodiment. Its own live neo-theme-* class carries the active palette; this Workstation-only bridge projects that palette into menu-domain tokens without coupling the shared tab plugin or shared menu component to product colours." It is implemented as body:has(.workstation-viewport) .neo-menu-list.neo-tab-overflow-menu { --menu-list-*: var(--workstation-*) }. The grid proxy is a third such embodiment and has no bridge.

The Fix

The fix is on the app side, in Workstation's SCSS; no engine change. The proxy already carries the live theme class and a grid identity.

  1. Move the grid half of the viewport bridge into a single shared mixin, so the viewport scope and the proxy scope cannot drift. That half is the --grid-container-* and --grid-cell-* tokens, plus the .neo-grid-header-button token set, its justify-content and padding, and the glyph positioning.

  2. Apply it to body:has(.workstation-viewport) .neo-grid-container.neo-dragproxy, and to every skin-carrying element inside the proxy (… .neo-dragproxy [class*="neo-theme-"], mirroring the viewport bridge's shape). The proxy's inner neo-grid-container may carry its own theme class, and a bridge on the outer node alone would be shadowed there.

  3. Put it in Viewport.scss, the sheet every boot mode loads. A ?popout= vessel never loads Workspace.css, and a popped-out grid drags its columns too.

Specificity: body:has(.workstation-viewport) .neo-grid-container.neo-dragproxy is (0,3,1), against the theme's (0,2,0).

Acceptance Criteria

  • While a 100k Matrix column header is being dragged, the proxy matches the source grid's computed values in both skins: header background, header text color, and each proxied cell's background against the source cell in the same row.
  • The grid token bridge is declared once and shared by both scopes.
  • E2E: a new spec under test/playwright/e2e/workstation/ (e.g. WorkstationGridDragProxySkinNL.spec.mjs) starts a real pointer drag on a 100k Matrix column header and compares the live proxy's computed styles with the source's, in dark and then light (via the theme toggle). It must be red on dev (dark header #182449 against rgb(26,33,44)) and green with the fix. It joins the hosted Workstation tier (#19655).
  • Existing grid column-drag specs stay green.

Out of Scope

  • A real Workstation theme. None exists yet. A theme would give every body-mounted embodiment the right skin at once; this ticket keeps the current bridge model.
  • Other body-mounted embodiments (tooltips, pickers, other menus). They were not reported and not audited here.

Related

  • #16120 (closed): a body-mounted dock tab drag proxy painted on a transparent surface. Same class, dock side.
  • #17984 (closed): the viewport bridge's specificity contract.
  • #19982, #19984: the same testing pass.

Live latest-open sweep: checked latest 20 open issues at 2026-10-22T09:25:12Z; no equivalent found. Keyword sweep: "drag proxy theme colors", "column drag proxy", "dragproxy workstation", "proxy skin": closed adjacent only (#16120, #6394). A2A claim sweep: no overlapping lane-claim. MC sweep: "grid column header drag proxy shows default theme colors…", 6 results, no prior decision on the grid proxy. Own-assignment sweep: none overlapping.

Origin Session ID: 70e59a84-efd6-4e7a-9262-c5478bd314ff Retrieval Hint: "Workstation grid column drag proxy theme colors, body-mounted embodiment, app token bridge"

tobiu referenced in commit f91c848 - "fix(workstation): the grid column-drag proxy keeps the instrument skin (#19985) (#19999) on Oct 22, 2026, 4:50 PM
tobiu closed this issue on Oct 22, 2026, 4:50 PM