Skip to content

fix(styles): tokenise editor chrome colours and guard component styles - #20

Merged
betterthanclay merged 1 commit into
mainfrom
ns-5fb05a19-1c46-43ec-995e-dfd077718b66
Sep 18, 2026
Merged

betterthanclay merged 1 commit into
mainfrom
ns-5fb05a19-1c46-43ec-995e-dfd077718b66

Conversation

@betterthanclay

Copy link
Copy Markdown
Contributor

What

The slash palette painted linear-gradient(rgba(15, 23, 42, 0.98), rgba(15, 23, 42, 0.94)) over
var(--nightfire-color-surface) and let the shipped light theme's dark text sit on top. Measured
from the composited layers in the triage note, the search input was 1.00:1 and the command labels
1.23:1 — illegible in the theme this package ships, in a published release.

This makes the palette light chrome, as contract 003 already described the editor layer, and adds
the guard that stops the next literal.

  • Literals removed (8, two files). SlashCommandPalette.svelte: the gradient, its
    box-shadow rgba(15, 23, 42, 0.28), the input background rgba(15, 23, 42, 0.82), and the
    selection pair rgba(96, 165, 250, 0.32) / rgba(59, 130, 246, 0.14).
    editor/NightfireMultiBlockItem.svelte: #f87171, rgba(239, 68, 68, 0.15),
    rgba(239, 68, 68, 0.4).
  • One token added. --nightfire-color-selection: #3b82f6 in ts/src/styles.css, used for the
    selected item's border and background at the alphas the component already used
    (color-mix(... 32%, transparent) and ... 14% ...). The danger state reuses the existing
    --nightfire-color-danger the same way. The palette root sets
    color: var(--nightfire-color-text) explicitly, so the items' color: inherit cannot take the
    host page's text colour.
  • The check. ts/scripts/check-style-literals.ts fails on a colour literal (hex, functional
    notation with literal arguments, CSS named colours) in any ts/src/**/*.svelte style block.
    Exceptions: transparent, currentColor, inherit. Wired into health as
    check:style-literals, so every lane runs it. ts/tests/nightfire/style-literals.test.ts holds
    the guard biting and the shipped tree passing.
  • Two counts. docs/architecture/core-package-vocabulary.md and
    docs/contracts/003-styling-and-restyling.md read 25, and the test fails if either disagrees
    with styles.css. PROVENANCE.md records the token as locally authored beside
    --nightfire-color-focus. Radii, spacing and font literals remain unguarded; the triage note
    keeps that gap open.

Interaction oracle

Invariant Proof
The palette is legible in the shipped default its style block references the text and surface tokens and holds no colour literal; the root sets the text colour
No component style carries a colour literal planted #ff0000, rgb(15 23 42) and rebeccapurple are all reported, exit 1; the shipped head passes
One declared value per token 25 declarations, all consumed, and both documents read 25
The danger state keeps its meaning the multi-block item references --nightfire-color-danger
Renderers are untouched no renderer references a token or a scoped style
Nothing else regressed the component suite and its a11y assertions pass untouched

jsdom does not composite backgrounds, so the component suite cannot assert rendered contrast; the
token-reference assertion plus the no-literal check is the honest floor here. Computed from the
declared values: --nightfire-color-text on --nightfire-color-surface 17.74:1, the muted token on
it 4.83:1, and --nightfire-color-text on the selected item's 14% tint 15.17:1. The danger icon's
hover tint gives --nightfire-color-danger 3.10:1, above the 3:1 WCAG non-text floor.

effigy qa

effigy qa passed (exit 0) at beb9ccaa5387974945c0c03bc8875afeb76f8cf0:

  • export proof passed: 23 explicit subpaths resolve
  • boundary proof passed: forbidden graph absent; core 3995 bytes; validation 3977 bytes; renderer 5716 bytes/4 inputs and editor-free
  • schema proof passed: 11 documents, 7 core payloads, 4 positive cases, 3 negative cases
  • style literal proof passed: no colour literal in any ts/src/**/*.svelte style block
  • version sync passed: npm and Cargo 0.2.0; both languages and Cargo packaging consume root wire v1
  • pack proof passed: 87 files, 56125 bytes
  • Cargo package proof passed: unpacked nightfire 0.2.0 tests consume the root fixture
  • npm Git-consumer proof passed at beb9ccaa5387974945c0c03bc8875afeb76f8cf0
  • cargo Git-consumer proof passed at beb9ccaa5387974945c0c03bc8875afeb76f8cf0
  • docs paths/links/index/forbidden/contains/heading checks passed; release-automation verified
  • svelte-check: 0 errors, 3 pre-existing warnings in ts/src/video/VideoEditor.svelte

Unit, component, sanitization and Rust suites passed. The palette's existing component suite is
untouched.

Out of scope

No renderer, schema, payload, export map, version or consumer change. No merge, tag or publish.

The slash palette painted a near-opaque dark gradient over the shipped light
surface, so its search input and command labels measured 1.00:1 and 1.23:1 in
the theme this package ships. The palette is light chrome now: the gradient and
its shadow go, the surface, field, border and text tokens take over, and the
root sets the text colour explicitly so the items' `color: inherit` cannot take
the host page's text colour.

The two blue alphas become `--nightfire-color-selection`, one named token used
for the selected item's border and background at the alphas the component
already used. The multi-block item's three red literals use the existing
`--nightfire-color-danger` the same way.

`check:style-literals` reads every `ts/src/**/*.svelte` style block and fails on
a colour literal, with `transparent`, `currentColor` and `inherit` as the only
exceptions, and runs in `health`. Radii, spacing and font literals remain
unguarded.

Both documents that state the token count read 25, and `PROVENANCE.md` records
the new token as locally authored beside `--nightfire-color-focus`.
@betterthanclay

Copy link
Copy Markdown
Contributor Author

Approved for merge at exact head beb9cca.

Findings: none.

Review scope:

  • Confirmed the diff is limited to the editor color-literal repair, the selection token, the component-style guard and tests, token-count/provenance/changelog updates, and related canonical documentation.
  • Confirmed no renderer, schema, payload, export, Rust, version, release, or consumer changes.
  • Confirmed SlashCommandPalette now uses the shipped surface, field, border, selection, and text tokens; its root explicitly sets the text color.
  • Confirmed NightfireMultiBlockItem reuses the existing danger token for its danger state.
  • Confirmed the guard scans all ts/src/**/*.svelte style blocks and the tests cover planted hex, functional, and named-color literals, token references, keyword exceptions, shipped-tree coverage, renderer isolation, token counts, and text/surface contrast.
  • The repository's review-oracle contract defines this package's in-repo interaction/token checks as the acceptance surface; the absent demo surface is therefore not a review blocker.

Validation:

  • effigy check:style-literals passed.
  • effigy test:components passed, including slash-palette filtering, keyboard navigation, empty state, and Escape behavior.
  • effigy test:unit passed.
  • effigy test:sanitization passed.
  • effigy health passed.
  • effigy qa passed, including all configured tests, package proofs, both Git consumers, and docs QA.
  • GitHub Release gate passed.
  • Worktree was clean before and after review; HEAD remained beb9cca.

The three svelte-check warnings in VideoEditor.svelte are pre-existing and unrelated to this PR. Radii, spacing, and font literals remain explicitly outside this lane's guard and are not merge blockers here.

@betterthanclay
betterthanclay merged commit 30ee892 into main Sep 18, 2026
1 check passed
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