@ponchia/ui 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +322 -0
- package/MIGRATIONS.json +14 -0
- package/README.md +28 -5
- package/annotations/index.d.ts +398 -276
- package/annotations/index.d.ts.map +1 -0
- package/annotations/index.js +315 -45
- package/behaviors/carousel.js +17 -16
- package/behaviors/combobox.js +47 -16
- package/behaviors/command.js +18 -15
- package/behaviors/connectors.js +4 -5
- package/behaviors/crosshair.js +4 -5
- package/behaviors/dialog.js +3 -2
- package/behaviors/disclosure.js +3 -2
- package/behaviors/dismissible.js +3 -2
- package/behaviors/forms.js +41 -13
- package/behaviors/glyph.js +4 -5
- package/behaviors/internal.js +47 -0
- package/behaviors/legend.js +23 -2
- package/behaviors/menu.js +3 -2
- package/behaviors/popover.js +78 -7
- package/behaviors/spotlight.js +4 -5
- package/behaviors/table.js +39 -12
- package/behaviors/tabs.js +14 -14
- package/behaviors/theme.js +5 -3
- package/behaviors/toast.js +13 -1
- package/classes/classes.json +1857 -0
- package/classes/index.d.ts +28 -13
- package/classes/index.js +34 -18
- package/classes/vscode.css-custom-data.json +12 -0
- package/connectors/index.d.ts +189 -69
- package/connectors/index.d.ts.map +1 -0
- package/connectors/index.js +120 -24
- package/css/app.css +43 -13
- package/css/base.css +15 -10
- package/css/connectors.css +17 -0
- package/css/content.css +7 -1
- package/css/dataviz.css +5 -1
- package/css/disclosure.css +38 -6
- package/css/dots.css +57 -0
- package/css/feedback.css +60 -2
- package/css/forms.css +42 -1
- package/css/legend.css +11 -7
- package/css/marks.css +38 -8
- package/css/motion.css +24 -44
- package/css/navigation.css +7 -0
- package/css/overlay.css +31 -1
- package/css/primitives.css +91 -5
- package/css/report.css +40 -63
- package/css/site.css +16 -2
- package/css/sources.css +43 -1
- package/css/spotlight.css +1 -1
- package/css/tokens.css +36 -1
- package/css/workbench.css +1 -1
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -1
- package/dist/css/app.css +1 -1
- package/dist/css/base.css +1 -1
- package/dist/css/connectors.css +1 -1
- package/dist/css/content.css +1 -1
- package/dist/css/disclosure.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/legend.css +1 -1
- package/dist/css/marks.css +1 -1
- package/dist/css/motion.css +1 -1
- package/dist/css/navigation.css +1 -1
- package/dist/css/overlay.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/report.css +1 -1
- package/dist/css/site.css +1 -1
- package/dist/css/sources.css +1 -1
- package/dist/css/spotlight.css +1 -1
- package/dist/css/tokens.css +1 -1
- package/dist/css/workbench.css +1 -1
- package/docs/adr/0003-theme-model.md +1 -1
- package/docs/annotations.md +94 -14
- package/docs/architecture.md +50 -6
- package/docs/contrast.md +116 -92
- package/docs/d2.md +195 -0
- package/docs/legends.md +18 -2
- package/docs/marks.md +9 -2
- package/docs/mermaid.md +152 -0
- package/docs/reference.md +78 -22
- package/docs/reporting.md +395 -57
- package/docs/sources.md +27 -0
- package/docs/stability.md +9 -2
- package/docs/usage.md +101 -4
- package/docs/vega.md +225 -0
- package/docs/workbench.md +7 -1
- package/glyphs/glyphs.js +6 -4
- package/llms.txt +139 -14
- package/package.json +50 -12
- package/qwik/index.d.ts +42 -59
- package/qwik/index.d.ts.map +1 -0
- package/qwik/index.js +55 -3
- package/react/index.d.ts +39 -61
- package/react/index.d.ts.map +1 -0
- package/react/index.js +57 -3
- package/solid/index.d.ts +64 -61
- package/solid/index.d.ts.map +1 -0
- package/solid/index.js +60 -3
- package/tokens/d2.d.ts +38 -0
- package/tokens/d2.js +71 -0
- package/tokens/d2.json +43 -0
- package/tokens/index.d.ts +5 -5
- package/tokens/index.js +15 -1
- package/tokens/index.json +9 -0
- package/tokens/mermaid.d.ts +23 -0
- package/tokens/mermaid.js +181 -0
- package/tokens/mermaid.json +163 -0
- package/tokens/resolved.json +45 -1
- package/tokens/skins.js +3 -2
- package/tokens/tokens.dtcg.json +26 -0
- package/tokens/vega.d.ts +34 -0
- package/tokens/vega.js +155 -0
- package/tokens/vega.json +179 -0
package/docs/architecture.md
CHANGED
|
@@ -61,7 +61,7 @@ on top of the CSS, none of which require a framework commitment**:
|
|
|
61
61
|
not in three places (the two CSS dark blocks are now identical by
|
|
62
62
|
construction), resolving the duplication ADR-0003 flagged. The CSS-only
|
|
63
63
|
presets (density / contrast / OLED) stay hand-authored below a marker and are
|
|
64
|
-
preserved across regeneration. `scripts/check-
|
|
64
|
+
preserved across regeneration. `scripts/check-fresh.mjs` fails CI if
|
|
65
65
|
`css/tokens.css` drifts from the model.
|
|
66
66
|
- **classes/** — `cls` is the flat registry; recipes only emit from it;
|
|
67
67
|
`scripts/check-classes.mjs` enforces a bidirectional match with the
|
|
@@ -79,6 +79,51 @@ on top of the CSS, none of which require a framework commitment**:
|
|
|
79
79
|
- **react/** / **solid/** / **qwik/** — optional lifecycle adapters over `behaviors/`.
|
|
80
80
|
They do not define markup, own state, or fork behavior logic; they only run
|
|
81
81
|
the vanilla initializers on mount and cleanup on unmount/dispose.
|
|
82
|
+
- **`css/analytical.css` — the analytical roll-up.** This convenience file
|
|
83
|
+
`@import`s exactly **seven** analytical-figure leaves: `annotations`,
|
|
84
|
+
`legend`, `marks`, `connectors`, `spotlight`, `crosshair`, and `selection`.
|
|
85
|
+
The adjacent opt-in leaves — `sources`, `state`, `generated`, `workbench`,
|
|
86
|
+
and `command` — are report/tooling/trust surfaces that are intentionally
|
|
87
|
+
**not** part of the analytical roll-up and must be imported individually.
|
|
88
|
+
Importing `analytical.css` does not pull in any of those five.
|
|
89
|
+
- **Root export (`.`) is CSS-only.** `exports["."]` resolves to the CSS
|
|
90
|
+
bundle (`dist/bronto.css`). It is a CSS side-effect import for CSS-aware
|
|
91
|
+
bundlers (`@import '@ponchia/ui'` in CSS, or a side-effect
|
|
92
|
+
`import '@ponchia/ui'` in Vite/Astro/SvelteKit). There is no runtime JS at
|
|
93
|
+
the package root — Node/runtime JS imports of `.` are not supported. All JS
|
|
94
|
+
entrypoints are explicit subpaths (`/behaviors`, `/classes`, `/tokens`,
|
|
95
|
+
`/glyphs`, `/react`, `/solid`, `/qwik`, `/skins`, `/charts`). This is a
|
|
96
|
+
permanent, intentional contract.
|
|
97
|
+
|
|
98
|
+
## Repository layout
|
|
99
|
+
|
|
100
|
+
The repo root mixes five kinds of directory that look alike but follow very
|
|
101
|
+
different rules. Two distinctions matter most: several are **path-frozen
|
|
102
|
+
published subpaths** — the directory name _is_ the public import specifier
|
|
103
|
+
(`@ponchia/ui/react` resolves to `./react/`), so they cannot be moved or
|
|
104
|
+
renamed — and several are **generated** and must never be hand-edited (a
|
|
105
|
+
generator overwrites them and a drift gate fails CI).
|
|
106
|
+
|
|
107
|
+
| Path | Kind | Edit here? | Notes |
|
|
108
|
+
| --- | --- | --- | --- |
|
|
109
|
+
| `css/` | source | yes | The framework. Hand-authored `@layer bronto` CSS. (`css/tokens.css` palette blocks and `css/generated.css` are generated — see below.) |
|
|
110
|
+
| `tokens/index.js` | source | yes | The single source of truth for token **values** (`cssVars`). |
|
|
111
|
+
| `classes/index.js`, `behaviors/`, `annotations/`, `connectors/`, `react/`, `solid/`, `qwik/`, `glyphs/`, `shiki/` | source · published-subpath (path-frozen) | yes — but **do not move** | Authored ESM shipped as-is; the dir name is the public import path. The `.d.ts` beside them are generated/drift-checked: `connectors`/`annotations`/`react`/`solid`/`qwik` are emitted from JSDoc by `tsc` (`npm run dts:emit`), `classes`/`tokens`/`glyphs` from the runtime; only `behaviors/index.d.ts` is still hand-maintained (its barrel + destructured-param shape emit poorly), guarded by `check-behaviors`. |
|
|
112
|
+
| `dist/` | generated | no | Build of `css/` (`npm run dist:build`); byte-checked by `check:dist`. |
|
|
113
|
+
| `tokens/index.json`, `tokens/resolved.json`, `tokens/tokens.dtcg.json`, `tokens/charts.json`, `classes/index.d.ts`, `tokens/index.d.ts`, `tokens/{skins,charts}.d.ts`, `glyphs/glyphs.d.ts`, `classes/vscode.css-custom-data.json`, `docs/reference.md` | generated | no | Committed build artifacts; regenerate with `npm run prepack`, never hand-edit. Drift-checked in `npm run check`. |
|
|
114
|
+
| `fonts/` | vendored | — | The Doto webfont (woff2) + its OFL license. |
|
|
115
|
+
| `scripts/` | tooling | yes | `gen-*` regenerate artifacts, `check-*` are the drift/contract gates wired into `npm run check`, plus `build-dist`, `serve`, `size-report`. |
|
|
116
|
+
| `docs/` | source (mostly) | yes | Hand-authored docs + ADRs; the curated subset in `package.json` `files` ships in the tarball. `docs/reference.md` is generated. |
|
|
117
|
+
| `demo/`, `test/`, `examples/` | fixtures | yes | The self-driving demo/showcase, the unit + Playwright e2e suite, and consumer example apps built against the packed tarball. |
|
|
118
|
+
| `.github/`, `*.config.mjs`, `.prettierrc`, `.stylelintrc.json`, `tsconfig.json`, `.editorconfig` | config | yes | CI workflows and tool config. |
|
|
119
|
+
| `package.json`, `llms.txt`, `CHANGELOG.md`, `MIGRATIONS.json`, `README.md`, `CONTRIBUTING.md`, `ROADMAP.md`, `LICENSE` | meta | yes | Manifest, the agent entrypoint, the curated changelog, the rename map, and project docs. |
|
|
120
|
+
|
|
121
|
+
The **path-frozen** dirs are the cost of zero-build, path-stable publishing:
|
|
122
|
+
`files` map 1:1 to published paths and the consumer's own bundler tree-shakes
|
|
123
|
+
the ESM, so there is no `src/` indirection (and no JS bundler — see the
|
|
124
|
+
distribution decision below). **Generated** files are regenerated from their
|
|
125
|
+
source and policed by a drift gate — edit the source, run the generator, commit
|
|
126
|
+
the result.
|
|
82
127
|
|
|
83
128
|
## Drift control
|
|
84
129
|
|
|
@@ -89,12 +134,11 @@ gating" below), so a version that fails any invariant never reaches npm.
|
|
|
89
134
|
| Invariant | Enforced by |
|
|
90
135
|
| ----------------------------------------------- | ------------------- |
|
|
91
136
|
| exports / import graph / `files` consistent | `check-exports.mjs` |
|
|
92
|
-
| `tokens.css`
|
|
137
|
+
| pure generated mirrors fresh — `tokens.css`/`index.json`, `dtcg.json`, `resolved.json`, `classes`/`tokens` `.d.ts`, `reference.md`, vscode data — each byte-equal to its generator (registry: `scripts/lib/artifacts.mjs`) | `check-fresh.mjs` |
|
|
93
138
|
| `classes` `cls` ⇄ `.ui-*` selectors | `check-classes.mjs` |
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
139
|
+
| `connectors`/`annotations`/`react`/`solid`/`qwik` `.d.ts` (+ maps) == fresh `tsc` emit of their JSDoc | `check-dts-emit.mjs` |
|
|
140
|
+
| `behaviors/index.d.ts` ⇄ `behaviors/*` exports (the one hand-maintained leaf `.d.ts`) | `check-behaviors.mjs` |
|
|
96
141
|
| legend swatch colours ⊆ `charts.js` · opt-in | `check-legend.mjs` |
|
|
97
|
-
| `tokens.dtcg.json` ⇄ token model | `check-dtcg.mjs` |
|
|
98
142
|
| color tokens tiered · no raw chromatic color in components | `check-color-policy.mjs` |
|
|
99
143
|
| `css/skins.css` ⇄ `tokens/skins.js` · colorways opt-in | `check-skins.mjs` |
|
|
100
144
|
| every shipped colorway accent meets its WCAG floor | `check-contrast.mjs` |
|
|
@@ -116,7 +160,7 @@ payload contract, raised only intentionally with a CHANGELOG note.
|
|
|
116
160
|
`test/types.test-d.ts`, whose `@ts-expect-error`s would fail to compile
|
|
117
161
|
if the generated literal `cls`/token types stopped rejecting typos —
|
|
118
162
|
so the *value* of the generated `.d.ts` is itself gated, not just their
|
|
119
|
-
freshness (`check-
|
|
163
|
+
freshness (`check-fresh`).
|
|
120
164
|
|
|
121
165
|
## Release gating
|
|
122
166
|
|
package/docs/contrast.md
CHANGED
|
@@ -40,51 +40,57 @@ Overall: **all contractual pairings meet their floor ✅**.
|
|
|
40
40
|
|
|
41
41
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
42
42
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
43
|
-
| `--text` | `--bg` | Body text on page background | AA text (4.5:1) | 17.98:1 | Lc 99 | ✅ pass |
|
|
44
|
-
| `--text` | `--surface` | Body text on a card/panel | AA text (4.5:1) | 19.80:1 | Lc
|
|
45
|
-
| `--text` | `--surface-muted` | Body text on a muted panel | AA text (4.5:1) | 16.74:1 | Lc 94 | ✅ pass |
|
|
46
|
-
| `--text-soft` | `--bg` | Secondary text on page background | AA text (4.5:1) | 11.16:1 | Lc 91 | ✅ pass |
|
|
47
|
-
| `--text-soft` | `--surface` | Secondary text on a card | AA text (4.5:1) | 12.29:1 | Lc 98 | ✅ pass |
|
|
48
|
-
| `--text-soft` | `--surface-muted` | Secondary text on a muted panel | AA text (4.5:1) | 10.39:1 | Lc
|
|
49
|
-
| `--text-dim` | `--bg` | Dim/meta text on page background | AA text (4.5:1) | 5.09:1 | Lc 71 | ✅ pass |
|
|
50
|
-
| `--text-dim` | `--surface` | Dim/meta text on a card | AA text (4.5:1) | 5.60:1 | Lc 78 | ✅ pass |
|
|
51
|
-
| `--text-dim` | `--surface-muted` | Dim/meta text on a muted panel | AA text (4.5:1) | 4.74:1 | Lc
|
|
52
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.32:1 | Lc 75 | ✅ pass |
|
|
53
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 6.96:1 | Lc 82 | ✅ pass |
|
|
54
|
-
| `--
|
|
55
|
-
| `--
|
|
56
|
-
| `--
|
|
57
|
-
| `--accent` | `--
|
|
58
|
-
| `--
|
|
59
|
-
| `--
|
|
60
|
-
| `--
|
|
61
|
-
| `--
|
|
62
|
-
| `--
|
|
43
|
+
| `--text` | `--bg` | Body text on page background | AA text (4.5:1) | 17.98:1 | Lc 99.2 | ✅ pass |
|
|
44
|
+
| `--text` | `--surface` | Body text on a card/panel | AA text (4.5:1) | 19.80:1 | Lc 105.8 | ✅ pass |
|
|
45
|
+
| `--text` | `--surface-muted` | Body text on a muted panel | AA text (4.5:1) | 16.74:1 | Lc 94.5 | ✅ pass |
|
|
46
|
+
| `--text-soft` | `--bg` | Secondary text on page background | AA text (4.5:1) | 11.16:1 | Lc 91.4 | ✅ pass |
|
|
47
|
+
| `--text-soft` | `--surface` | Secondary text on a card | AA text (4.5:1) | 12.29:1 | Lc 98.1 | ✅ pass |
|
|
48
|
+
| `--text-soft` | `--surface-muted` | Secondary text on a muted panel | AA text (4.5:1) | 10.39:1 | Lc 86.7 | ✅ pass |
|
|
49
|
+
| `--text-dim` | `--bg` | Dim/meta text on page background | AA text (4.5:1) | 5.09:1 | Lc 71.4 | ✅ pass |
|
|
50
|
+
| `--text-dim` | `--surface` | Dim/meta text on a card | AA text (4.5:1) | 5.60:1 | Lc 78.0 | ✅ pass |
|
|
51
|
+
| `--text-dim` | `--surface-muted` | Dim/meta text on a muted panel | AA text (4.5:1) | 4.74:1 | Lc 66.7 | ✅ pass |
|
|
52
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.32:1 | Lc 75.4 | ✅ pass |
|
|
53
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 6.96:1 | Lc 82.1 | ✅ pass |
|
|
54
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 5.91:1 | Lc 71.0 | ℹ️ not gated |
|
|
55
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 6.31:1 | Lc 75.3 | ℹ️ not gated |
|
|
56
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 5.18:1 | Lc 78.9 | ✅ pass |
|
|
57
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 5.18:1 | Lc 78.9 | ✅ pass |
|
|
58
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 4.71:1 | Lc 66.8 | ✅ pass |
|
|
59
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 5.18:1 | Lc 73.5 | ✅ pass |
|
|
60
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 4.71:1 | Lc 66.8 | ✅ pass |
|
|
61
|
+
| `--success` | `--surface` | Success indicator vs a card | UI / large (3:1) | 5.04:1 | Lc 74.6 | ✅ pass |
|
|
62
|
+
| `--warning` | `--surface` | Warning indicator vs a card | UI / large (3:1) | 5.60:1 | Lc 77.8 | ✅ pass |
|
|
63
|
+
| `--danger` | `--surface` | Danger indicator vs a card | UI / large (3:1) | 6.21:1 | Lc 78.9 | ✅ pass |
|
|
64
|
+
| `--info` | `--surface` | Info indicator vs a card | UI / large (3:1) | 5.77:1 | Lc 78.3 | ✅ pass |
|
|
65
|
+
| `--line-strong` | `--surface` | Strong hairline vs a card | Decorative (1.4.11-exempt) | 2.39:1 | Lc 47.1 | ℹ️ not gated |
|
|
63
66
|
|
|
64
67
|
## Dark theme
|
|
65
68
|
|
|
66
69
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
67
70
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
68
|
-
| `--text` | `--bg` | Body text on page background | AA text (4.5:1) | 15.01:1 | Lc 91 | ✅ pass |
|
|
69
|
-
| `--text` | `--surface` | Body text on a card/panel | AA text (4.5:1) | 13.65:1 | Lc 90 | ✅ pass |
|
|
70
|
-
| `--text` | `--surface-muted` | Body text on a muted panel | AA text (4.5:1) | 12.44:1 | Lc
|
|
71
|
-
| `--text-soft` | `--bg` | Secondary text on page background | AA text (4.5:1) | 11.20:1 | Lc
|
|
72
|
-
| `--text-soft` | `--surface` | Secondary text on a card | AA text (4.5:1) | 10.19:1 | Lc
|
|
73
|
-
| `--text-soft` | `--surface-muted` | Secondary text on a muted panel | AA text (4.5:1) | 9.28:1 | Lc
|
|
74
|
-
| `--text-dim` | `--bg` | Dim/meta text on page background | AA text (4.5:1) | 7.16:1 | Lc 50 | ✅ pass |
|
|
75
|
-
| `--text-dim` | `--surface` | Dim/meta text on a card | AA text (4.5:1) | 6.52:1 | Lc 49 | ✅ pass |
|
|
76
|
-
| `--text-dim` | `--surface-muted` | Dim/meta text on a muted panel | AA text (4.5:1) | 5.94:1 | Lc 48 | ✅ pass |
|
|
77
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.14:1 | Lc
|
|
78
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 5.58:1 | Lc
|
|
79
|
-
| `--
|
|
80
|
-
| `--
|
|
81
|
-
| `--
|
|
82
|
-
| `--accent` | `--
|
|
83
|
-
| `--
|
|
84
|
-
| `--
|
|
85
|
-
| `--
|
|
86
|
-
| `--
|
|
87
|
-
| `--
|
|
71
|
+
| `--text` | `--bg` | Body text on page background | AA text (4.5:1) | 15.01:1 | Lc 91.1 | ✅ pass |
|
|
72
|
+
| `--text` | `--surface` | Body text on a card/panel | AA text (4.5:1) | 13.65:1 | Lc 90.1 | ✅ pass |
|
|
73
|
+
| `--text` | `--surface-muted` | Body text on a muted panel | AA text (4.5:1) | 12.44:1 | Lc 88.9 | ✅ pass |
|
|
74
|
+
| `--text-soft` | `--bg` | Secondary text on page background | AA text (4.5:1) | 11.20:1 | Lc 72.7 | ✅ pass |
|
|
75
|
+
| `--text-soft` | `--surface` | Secondary text on a card | AA text (4.5:1) | 10.19:1 | Lc 71.7 | ✅ pass |
|
|
76
|
+
| `--text-soft` | `--surface-muted` | Secondary text on a muted panel | AA text (4.5:1) | 9.28:1 | Lc 70.6 | ✅ pass |
|
|
77
|
+
| `--text-dim` | `--bg` | Dim/meta text on page background | AA text (4.5:1) | 7.16:1 | Lc 50.3 | ✅ pass |
|
|
78
|
+
| `--text-dim` | `--surface` | Dim/meta text on a card | AA text (4.5:1) | 6.52:1 | Lc 49.3 | ✅ pass |
|
|
79
|
+
| `--text-dim` | `--surface-muted` | Dim/meta text on a muted panel | AA text (4.5:1) | 5.94:1 | Lc 48.1 | ✅ pass |
|
|
80
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.14:1 | Lc 44.9 | ✅ pass |
|
|
81
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 5.58:1 | Lc 43.9 | ✅ pass |
|
|
82
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 2.53:1 | Lc 43.8 | ℹ️ not gated |
|
|
83
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 2.75:1 | Lc 49.1 | ℹ️ not gated |
|
|
84
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 5.95:1 | Lc 42.9 | ✅ pass |
|
|
85
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 5.95:1 | Lc 42.9 | ✅ pass |
|
|
86
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 5.31:1 | Lc 40.0 | ✅ pass |
|
|
87
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 4.83:1 | Lc 39.0 | ✅ pass |
|
|
88
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 5.31:1 | Lc 40.0 | ✅ pass |
|
|
89
|
+
| `--success` | `--surface` | Success indicator vs a card | UI / large (3:1) | 7.58:1 | Lc 56.6 | ✅ pass |
|
|
90
|
+
| `--warning` | `--surface` | Warning indicator vs a card | UI / large (3:1) | 9.29:1 | Lc 66.6 | ✅ pass |
|
|
91
|
+
| `--danger` | `--surface` | Danger indicator vs a card | UI / large (3:1) | 5.23:1 | Lc 41.5 | ✅ pass |
|
|
92
|
+
| `--info` | `--surface` | Info indicator vs a card | UI / large (3:1) | 7.33:1 | Lc 54.8 | ✅ pass |
|
|
93
|
+
| `--line-strong` | `--surface` | Strong hairline vs a card | Decorative (1.4.11-exempt) | 2.29:1 | Lc 14.5 | ℹ️ not gated |
|
|
88
94
|
|
|
89
95
|
## Display colorways (skins)
|
|
90
96
|
|
|
@@ -101,67 +107,85 @@ palette untouched). Accents are authored in OKLCH; `--accent-text` is the
|
|
|
101
107
|
|
|
102
108
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
103
109
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
104
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.75:1 | Lc
|
|
105
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 7.44:1 | Lc
|
|
106
|
-
| `--
|
|
107
|
-
| `--
|
|
108
|
-
| `--
|
|
109
|
-
| `--accent` | `--
|
|
110
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.75:1 | Lc 78.9 | ✅ pass |
|
|
111
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 7.44:1 | Lc 85.6 | ✅ pass |
|
|
112
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 6.31:1 | Lc 74.5 | ℹ️ not gated |
|
|
113
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 6.74:1 | Lc 78.8 | ℹ️ not gated |
|
|
114
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 5.66:1 | Lc 83.3 | ✅ pass |
|
|
115
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 5.66:1 | Lc 83.3 | ✅ pass |
|
|
116
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 5.14:1 | Lc 71.4 | ✅ pass |
|
|
117
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 5.66:1 | Lc 78.0 | ✅ pass |
|
|
118
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 5.14:1 | Lc 71.4 | ✅ pass |
|
|
110
119
|
|
|
111
120
|
### Amber CRT — dark
|
|
112
121
|
|
|
113
122
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
114
123
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
115
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 11.57:1 | Lc
|
|
116
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 10.52:1 | Lc
|
|
117
|
-
| `--
|
|
118
|
-
| `--
|
|
119
|
-
| `--
|
|
120
|
-
| `--accent` | `--
|
|
124
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 11.57:1 | Lc 74.8 | ✅ pass |
|
|
125
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 10.52:1 | Lc 73.8 | ✅ pass |
|
|
126
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 1.34:1 | Lc 15.1 | ℹ️ not gated |
|
|
127
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 1.46:1 | Lc 20.3 | ℹ️ not gated |
|
|
128
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 11.88:1 | Lc 71.6 | ✅ pass |
|
|
129
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 11.88:1 | Lc 71.6 | ✅ pass |
|
|
130
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 10.60:1 | Lc 69.9 | ✅ pass |
|
|
131
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 9.64:1 | Lc 68.9 | ✅ pass |
|
|
132
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 10.60:1 | Lc 69.9 | ✅ pass |
|
|
121
133
|
|
|
122
134
|
### E-ink — light
|
|
123
135
|
|
|
124
136
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
125
137
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
126
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 12.23:1 | Lc 93 | ✅ pass |
|
|
127
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 13.47:1 | Lc
|
|
128
|
-
| `--
|
|
129
|
-
| `--
|
|
130
|
-
| `--
|
|
131
|
-
| `--accent` | `--
|
|
138
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 12.23:1 | Lc 93.3 | ✅ pass |
|
|
139
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 13.47:1 | Lc 99.9 | ✅ pass |
|
|
140
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 11.43:1 | Lc 88.8 | ℹ️ not gated |
|
|
141
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 12.22:1 | Lc 93.2 | ℹ️ not gated |
|
|
142
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 11.74:1 | Lc 100.6 | ✅ pass |
|
|
143
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 11.74:1 | Lc 100.6 | ✅ pass |
|
|
144
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 10.66:1 | Lc 90.4 | ✅ pass |
|
|
145
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 11.74:1 | Lc 97.0 | ✅ pass |
|
|
146
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 10.66:1 | Lc 90.4 | ✅ pass |
|
|
132
147
|
|
|
133
148
|
### E-ink — dark
|
|
134
149
|
|
|
135
150
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
136
151
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
137
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 12.47:1 | Lc 79 | ✅ pass |
|
|
138
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 11.35:1 | Lc 78 | ✅ pass |
|
|
139
|
-
| `--
|
|
140
|
-
| `--
|
|
141
|
-
| `--
|
|
142
|
-
| `--accent` | `--
|
|
152
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 12.47:1 | Lc 79.1 | ✅ pass |
|
|
153
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 11.35:1 | Lc 78.1 | ✅ pass |
|
|
154
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 1.25:1 | Lc 11.0 | ℹ️ not gated |
|
|
155
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 1.35:1 | Lc 16.3 | ℹ️ not gated |
|
|
156
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 12.86:1 | Lc 75.6 | ✅ pass |
|
|
157
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 12.86:1 | Lc 75.6 | ✅ pass |
|
|
158
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 11.48:1 | Lc 74.1 | ✅ pass |
|
|
159
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 10.44:1 | Lc 73.1 | ✅ pass |
|
|
160
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 11.48:1 | Lc 74.1 | ✅ pass |
|
|
143
161
|
|
|
144
162
|
### Phosphor Green — light
|
|
145
163
|
|
|
146
164
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
147
165
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
148
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.22:1 | Lc
|
|
149
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 6.85:1 | Lc 83 | ✅ pass |
|
|
150
|
-
| `--
|
|
151
|
-
| `--
|
|
152
|
-
| `--
|
|
153
|
-
| `--accent` | `--
|
|
166
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 6.22:1 | Lc 76.6 | ✅ pass |
|
|
167
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 6.85:1 | Lc 83.3 | ✅ pass |
|
|
168
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 5.81:1 | Lc 72.2 | ℹ️ not gated |
|
|
169
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 6.21:1 | Lc 76.5 | ℹ️ not gated |
|
|
170
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 5.19:1 | Lc 80.7 | ✅ pass |
|
|
171
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 5.19:1 | Lc 80.7 | ✅ pass |
|
|
172
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 4.71:1 | Lc 68.6 | ✅ pass |
|
|
173
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 5.19:1 | Lc 75.3 | ✅ pass |
|
|
174
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 4.71:1 | Lc 68.6 | ✅ pass |
|
|
154
175
|
|
|
155
176
|
### Phosphor Green — dark
|
|
156
177
|
|
|
157
178
|
| Foreground | Background | Role | Held to | Ratio | APCA _(advisory)_ | Verdict |
|
|
158
179
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
159
|
-
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 12.97:1 | Lc
|
|
160
|
-
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 11.80:1 | Lc
|
|
161
|
-
| `--
|
|
162
|
-
| `--
|
|
163
|
-
| `--
|
|
164
|
-
| `--accent` | `--
|
|
180
|
+
| `--accent-text` | `--bg` | Accent text on page background | AA text (4.5:1) | 12.97:1 | Lc 81.8 | ✅ pass |
|
|
181
|
+
| `--accent-text` | `--surface` | Accent text on a card | AA text (4.5:1) | 11.80:1 | Lc 80.8 | ✅ pass |
|
|
182
|
+
| `--accent-text` | `--accent-soft` | Accent text on an accent tint | Advisory (translucent tint — not gated) | 1.20:1 | Lc 8.4 | ℹ️ not gated |
|
|
183
|
+
| `--accent-text` | `--bg-accent` | Accent text on an accent-tinted surface | Advisory (translucent tint — not gated) | 1.30:1 | Lc 13.7 | ℹ️ not gated |
|
|
184
|
+
| `--button-text` | `--accent` | Label on the primary button | AA text (4.5:1) | 13.75:1 | Lc 79.7 | ✅ pass |
|
|
185
|
+
| `--on-accent` | `--accent` | Ink on an accent fill | AA text (4.5:1) | 13.75:1 | Lc 79.7 | ✅ pass |
|
|
186
|
+
| `--focus-ring` | `--bg` | Focus ring vs page background | UI / large (3:1) | 12.27:1 | Lc 78.5 | ✅ pass |
|
|
187
|
+
| `--focus-ring` | `--surface` | Focus ring vs a card | UI / large (3:1) | 11.16:1 | Lc 77.5 | ✅ pass |
|
|
188
|
+
| `--accent` | `--bg` | Accent fill vs page background | UI / large (3:1) | 12.27:1 | Lc 78.5 | ✅ pass |
|
|
165
189
|
|
|
166
190
|
## Data-viz palette (advisory)
|
|
167
191
|
|
|
@@ -178,27 +202,27 @@ the brand accent.
|
|
|
178
202
|
|
|
179
203
|
| Series | Colour | Ratio _(advisory)_ | APCA _(advisory)_ |
|
|
180
204
|
| --- | --- | --- | --- |
|
|
181
|
-
| 1 _(accent)_ | `#d71921` | 4.71:1 | Lc
|
|
182
|
-
| 2 | `#e69f00` | 2.05:1 | Lc 37 |
|
|
183
|
-
| 3 | `#56b4e9` | 2.10:1 | Lc
|
|
184
|
-
| 4 | `#009e73` | 3.11:1 | Lc 54 |
|
|
185
|
-
| 5 | `#f0e442` | 1.20:1 | Lc 9 |
|
|
186
|
-
| 6 | `#0072b2` | 4.71:1 | Lc 68 |
|
|
187
|
-
| 7 | `#cc79a7` | 2.78:1 | Lc
|
|
188
|
-
| 8 | `#4d5358` | 7.08:1 | Lc 80 |
|
|
205
|
+
| 1 _(accent)_ | `#d71921` | 4.71:1 | Lc 66.8 |
|
|
206
|
+
| 2 | `#e69f00` | 2.05:1 | Lc 37.4 |
|
|
207
|
+
| 3 | `#56b4e9` | 2.10:1 | Lc 38.6 |
|
|
208
|
+
| 4 | `#009e73` | 3.11:1 | Lc 54.4 |
|
|
209
|
+
| 5 | `#f0e442` | 1.20:1 | Lc 9.1 |
|
|
210
|
+
| 6 | `#0072b2` | 4.71:1 | Lc 68.4 |
|
|
211
|
+
| 7 | `#cc79a7` | 2.78:1 | Lc 50.6 |
|
|
212
|
+
| 8 | `#4d5358` | 7.08:1 | Lc 80.4 |
|
|
189
213
|
|
|
190
214
|
### Dark theme — categorical vs `--bg`
|
|
191
215
|
|
|
192
216
|
| Series | Colour | Ratio _(advisory)_ | APCA _(advisory)_ |
|
|
193
217
|
| --- | --- | --- | --- |
|
|
194
|
-
| 1 _(accent)_ | `#ff3b41` | 5.31:1 | Lc 40 |
|
|
195
|
-
| 2 | `#e69f00` | 8.32:1 | Lc
|
|
196
|
-
| 3 | `#56b4e9` | 8.12:1 | Lc 56 |
|
|
197
|
-
| 4 | `#009e73` | 5.48:1 | Lc 40 |
|
|
198
|
-
| 5 | `#f0e442` | 14.17:1 | Lc 87 |
|
|
199
|
-
| 6 | `#0072b2` | 3.61:1 | Lc 26 |
|
|
200
|
-
| 7 | `#cc79a7` | 6.12:1 | Lc
|
|
201
|
-
| 8 | `#4d5358` | 2.40:1 | Lc 14 |
|
|
218
|
+
| 1 _(accent)_ | `#ff3b41` | 5.31:1 | Lc 40.0 |
|
|
219
|
+
| 2 | `#e69f00` | 8.32:1 | Lc 57.5 |
|
|
220
|
+
| 3 | `#56b4e9` | 8.12:1 | Lc 56.3 |
|
|
221
|
+
| 4 | `#009e73` | 5.48:1 | Lc 40.0 |
|
|
222
|
+
| 5 | `#f0e442` | 14.17:1 | Lc 87.4 |
|
|
223
|
+
| 6 | `#0072b2` | 3.61:1 | Lc 26.1 |
|
|
224
|
+
| 7 | `#cc79a7` | 6.12:1 | Lc 43.9 |
|
|
225
|
+
| 8 | `#4d5358` | 2.40:1 | Lc 14.4 |
|
|
202
226
|
|
|
203
227
|
## Scope & caveats
|
|
204
228
|
|
package/docs/d2.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# D2
|
|
2
|
+
|
|
3
|
+
[D2](https://d2lang.com) compiles a diagram script to **SVG** (Go CLI or the
|
|
4
|
+
`@terrastruct/d2` WASM build). Like the [Mermaid integration](./mermaid.md),
|
|
5
|
+
`@ponchia/ui` doesn't render diagrams — it **themes** them from your tokens and
|
|
6
|
+
lets you **annotate** the result. Two things ship:
|
|
7
|
+
|
|
8
|
+
- `@ponchia/ui/d2` — helpers that produce on-brand D2 theme overrides.
|
|
9
|
+
- `@ponchia/ui/d2.json` — the resolved slot → hex maps, for any consumer.
|
|
10
|
+
|
|
11
|
+
D2 stays the consumer's renderer; this is config only, and D2 is **not** a
|
|
12
|
+
dependency.
|
|
13
|
+
|
|
14
|
+
## Theme a diagram
|
|
15
|
+
|
|
16
|
+
D2's theme is a compact set of named colour slots. Override them with the bronto
|
|
17
|
+
palette by prepending a `vars` block to your diagram source — `brontoD2Vars()`
|
|
18
|
+
returns exactly that block (both light and dark):
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
import { brontoD2Vars } from '@ponchia/ui/d2';
|
|
22
|
+
|
|
23
|
+
const source = brontoD2Vars() + `
|
|
24
|
+
api -> db: query
|
|
25
|
+
db: Store { shape: cylinder }
|
|
26
|
+
`;
|
|
27
|
+
// → render `source` with the D2 CLI or @terrastruct/d2
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If you render through D2's Go or WASM API instead of source, pass the slot map to
|
|
31
|
+
its `themeOverrides` / `darkThemeOverrides`:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { brontoD2Overrides } from '@ponchia/ui/d2';
|
|
35
|
+
brontoD2Overrides('dark'); // { N1: '#e6e6e6', B1: '#555555', … }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For a build step or non-JS host, read `@ponchia/ui/d2.json` directly.
|
|
39
|
+
|
|
40
|
+
> **file:// portability.** A report opened from disk (`file://`) cannot
|
|
41
|
+
> `import` the `@ponchia/ui/d2` module **nor** `fetch('…/d2.json')` — the browser
|
|
42
|
+
> blocks both across the `null`/file origin (CORS), exactly as with
|
|
43
|
+
> [Vega](./vega.md#from-a-cdn-no-bundler) and [Mermaid](./mermaid.md#theme-a-diagram).
|
|
44
|
+
> This is rarely an issue for D2, whose native path is **build-time
|
|
45
|
+
> pre-rendering** to a frozen SVG (no client runtime — see below), but if you do
|
|
46
|
+
> theme D2 in the browser over `file://`, **inline** the slot map (paste the
|
|
47
|
+
> object from `d2.json`) rather than importing it. Over `http(s)` the
|
|
48
|
+
> `import`/`fetch` forms both work.
|
|
49
|
+
|
|
50
|
+
### Why resolved colours, not `var(--x)`
|
|
51
|
+
|
|
52
|
+
D2 compiles to a **frozen SVG** in Go/WASM — there is no client CSS cascade, so a
|
|
53
|
+
`var(--accent)` could never resolve. The maps therefore ship **resolved hex per
|
|
54
|
+
theme**, projected from the same token source as
|
|
55
|
+
[`tokens/resolved.json`](./architecture.md) / `charts.json`. Each slot is set
|
|
56
|
+
explicitly (D2 does not derive a ramp from one seed). Because the output is a
|
|
57
|
+
static SVG, **build-time pre-rendering is D2's native path** — ideal for the
|
|
58
|
+
[report layer](./reporting.md).
|
|
59
|
+
|
|
60
|
+
### What the slots paint
|
|
61
|
+
|
|
62
|
+
The mapping keeps a diagram **monochrome by default** — the rationed accent is
|
|
63
|
+
not spent on borders, edges, or shapes the author never marked:
|
|
64
|
+
|
|
65
|
+
| Slots | Paint | bronto mapping |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| `N1`–`N3` | Text · muted · subtle | `--text` · `--text-soft` · `--text-dim` |
|
|
68
|
+
| `N4`–`N5` | Strong / regular lines | `--line-strong` · `--line` |
|
|
69
|
+
| `N6`–`N7` | Subtle background · canvas | `--panel-soft` · `--bg` |
|
|
70
|
+
| `B1` | Shape borders **and** connections (edges) | `--line-strong` |
|
|
71
|
+
| `B2`–`B3` | Muted borders | `--line` |
|
|
72
|
+
| `B4`–`B6` | Container fills (outer → leaf) | `--panel-soft` · `--bg-elevated` · `--panel` |
|
|
73
|
+
| `AA*` / `AB*` | Alternative-accent ramps (special-shape fills, class/sql headers) | kept **neutral** |
|
|
74
|
+
|
|
75
|
+
The alt-accent ramps are deliberately neutral: D2 spends them on special shapes
|
|
76
|
+
(cylinders, class/sql-table headers) by default, so mapping them to the accent
|
|
77
|
+
would colour shapes you never marked. Keeping them neutral is what holds the
|
|
78
|
+
monochrome default.
|
|
79
|
+
|
|
80
|
+
### Spending the accent
|
|
81
|
+
|
|
82
|
+
To emphasise a node, opt it into a class that sets the accent explicitly — the
|
|
83
|
+
accent appears only where you ask for it:
|
|
84
|
+
|
|
85
|
+
```d2
|
|
86
|
+
classes: {
|
|
87
|
+
accent: {
|
|
88
|
+
style: { fill: "#d71921"; font-color: "#ffffff"; stroke: "#b2151b" }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
alert: Alert { class: accent }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Use the resolved `--accent` / `--accent-strong` hex (from
|
|
96
|
+
[`tokens/resolved.json`](./architecture.md), per theme) for the `fill` / `stroke`
|
|
97
|
+
so the emphasis matches the rest of the surface. Reserve it for the one thing a
|
|
98
|
+
reader must not miss.
|
|
99
|
+
|
|
100
|
+
> **The label on an accent fill uses `--on-accent`, not `--accent-text`.** A
|
|
101
|
+
> filled-accent node needs **on-accent ink** for its `font-color` — the resolved
|
|
102
|
+
> `--on-accent` token (white on the light accent, black on the dark accent;
|
|
103
|
+
> ≥ 4.5:1, gated in [contrast.md](./contrast.md)). Do **not** reach for
|
|
104
|
+
> `--accent-text` by name: that is the inverse token — _accent-coloured text for
|
|
105
|
+
> a neutral background_ (it resolves to `--accent-strong`, ~1.3:1 on the accent
|
|
106
|
+
> fill, an unreadable label). The literal `#ffffff` above is `--on-accent` for
|
|
107
|
+
> the light theme; pull the per-theme hex from `tokens/resolved.json`.
|
|
108
|
+
|
|
109
|
+
### Frozen inline SVG (no D2 runtime)
|
|
110
|
+
|
|
111
|
+
A static, PDF-first report often has no D2 binary in its pipeline. When you only
|
|
112
|
+
need a few boxes and arrows, **hand-author a token-themed inline `<svg>`** instead
|
|
113
|
+
of running D2 — the same frozen-figure route the [report chart
|
|
114
|
+
recipe](./reporting.md#chart-figure-recipe) uses. Paint each element from the
|
|
115
|
+
token that the live theme map would have resolved, so the frozen diagram still
|
|
116
|
+
re-skins (drive fills from `var(--token)` in the inline `style`/attributes, or
|
|
117
|
+
paste the resolved hex from [`tokens/resolved.json`](./architecture.md) for a
|
|
118
|
+
`file://` PDF):
|
|
119
|
+
|
|
120
|
+
| Diagram element | bronto token | (live D2 slot it mirrors) |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| Node fill | `--panel` | `B4`–`B6` container fills |
|
|
123
|
+
| Node border | `--line-strong` | `B1` |
|
|
124
|
+
| Node label | `--text` | `N1` |
|
|
125
|
+
| Edge / connector + arrowhead | `--line-strong` | `B1` |
|
|
126
|
+
| Edge label | `--text-soft` | `N2` |
|
|
127
|
+
| Cluster / container fill | `--panel-soft` | `B4` |
|
|
128
|
+
| Accent (emphasised) node fill · its label | `--accent` · `--on-accent` | the `accent` class above |
|
|
129
|
+
|
|
130
|
+
```html
|
|
131
|
+
<svg viewBox="0 0 320 120" role="img" aria-labelledby="flow-title">
|
|
132
|
+
<title id="flow-title">Ingest → Queue → Worker</title>
|
|
133
|
+
<!-- edge -->
|
|
134
|
+
<line x1="92" y1="40" x2="128" y2="40" stroke="var(--line-strong)" marker-end="url(#arrow)" />
|
|
135
|
+
<line x1="220" y1="40" x2="256" y2="40" stroke="var(--line-strong)" marker-end="url(#arrow)" />
|
|
136
|
+
<defs>
|
|
137
|
+
<marker id="arrow" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="6" markerHeight="6" orient="auto">
|
|
138
|
+
<path d="M0,0 L8,4 L0,8 z" fill="var(--line-strong)" />
|
|
139
|
+
</marker>
|
|
140
|
+
</defs>
|
|
141
|
+
<!-- neutral node -->
|
|
142
|
+
<rect x="16" y="22" width="76" height="36" rx="6" fill="var(--panel)" stroke="var(--line-strong)" />
|
|
143
|
+
<text x="54" y="44" text-anchor="middle" fill="var(--text)" font-size="12">Ingest</text>
|
|
144
|
+
<!-- accent (emphasised) node: on-accent ink on the accent fill -->
|
|
145
|
+
<rect x="128" y="22" width="92" height="36" rx="6" fill="var(--accent)" stroke="var(--accent-strong)" />
|
|
146
|
+
<text x="174" y="44" text-anchor="middle" fill="var(--on-accent)" font-size="12">Queue</text>
|
|
147
|
+
<rect x="256" y="22" width="64" height="36" rx="6" fill="var(--panel)" stroke="var(--line-strong)" />
|
|
148
|
+
<text x="288" y="44" text-anchor="middle" fill="var(--text)" font-size="12">Worker</text>
|
|
149
|
+
</svg>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
For anything larger or graph-laid-out, run D2 with the theme map and freeze its
|
|
153
|
+
output — don't hand-lay a complex graph.
|
|
154
|
+
|
|
155
|
+
### Fit to small screens
|
|
156
|
+
|
|
157
|
+
D2 emits an SVG with explicit `width`/`height` from its layout, so on a narrow
|
|
158
|
+
screen it overflows unless you make it fluid. Two build-time options:
|
|
159
|
+
|
|
160
|
+
- **Scale to fit** — drop the fixed `width`/`height` attributes (keep the
|
|
161
|
+
`viewBox`) so the SVG shrinks to its container. Best for diagrams that stay
|
|
162
|
+
legible at smaller sizes.
|
|
163
|
+
- **Scroll a wide diagram** — wrap it in `overflow-x: auto` so a large diagram
|
|
164
|
+
scrolls inside its box instead of pushing the page wide, the same pattern the
|
|
165
|
+
report layer uses for wide figures.
|
|
166
|
+
|
|
167
|
+
```css
|
|
168
|
+
.diagram-scroll {
|
|
169
|
+
overflow-x: auto;
|
|
170
|
+
}
|
|
171
|
+
.diagram-scroll svg {
|
|
172
|
+
max-inline-size: 100%;
|
|
173
|
+
block-size: auto;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Render **non-sketch** at a fixed `scale` for predictable boxes.
|
|
178
|
+
|
|
179
|
+
## Annotate a diagram
|
|
180
|
+
|
|
181
|
+
D2 output is SVG, so the [annotation layer](./annotations.md) composes onto it
|
|
182
|
+
exactly as in the [Mermaid recipe](./mermaid.md#annotate-a-diagram): render to a
|
|
183
|
+
frozen SVG (the D2 CLI `d2 in.d2 out.svg`, or `@terrastruct/d2` in a build
|
|
184
|
+
script), read the target shape's box, and paste a `<g class="ui-annotation">`
|
|
185
|
+
computed with `@ponchia/ui/annotations`. The same caveats apply — D2's internal
|
|
186
|
+
SVG (element ids, the root transform) is not a public contract, so pin your D2
|
|
187
|
+
version, render **non-sketch**, account for `pad` / `scale`, and avoid
|
|
188
|
+
`animate-interval` (a multi-board animated SVG would not track a single overlay).
|
|
189
|
+
|
|
190
|
+
## Scope
|
|
191
|
+
|
|
192
|
+
bronto owns the theme map (gated: every slot resolves to a colour, both themes,
|
|
193
|
+
no `var()` leaks) and the annotation geometry. It does not own D2's rendering,
|
|
194
|
+
its internal SVG, or its CLI — those stay D2's, and the overlay is a documented
|
|
195
|
+
composition, not a shipped runtime binding.
|
package/docs/legends.md
CHANGED
|
@@ -13,8 +13,9 @@ drifts from the series it describes.
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Bronto **paints and positions** the key; it owns no scales, no data→pixel
|
|
16
|
-
mapping, and no series state. Pair it with
|
|
17
|
-
SVG
|
|
16
|
+
mapping, and no series state. Pair it with any chart — a token-themed inline
|
|
17
|
+
SVG, or an external engine like [Vega-Lite](./vega.md) — the host owns the
|
|
18
|
+
chart.
|
|
18
19
|
|
|
19
20
|
## What it is not
|
|
20
21
|
|
|
@@ -89,6 +90,21 @@ chart mark uses, or with a `--N` index helper for the categorical palette.
|
|
|
89
90
|
`ui-legend__swatch--circle` and `ui-legend__swatch--line` change the chip shape
|
|
90
91
|
(dot series, line series).
|
|
91
92
|
|
|
93
|
+
A `ui-legend__symbol` chip is an `.ui-icon` mask — it needs a `--icon-mask`
|
|
94
|
+
(e.g. `style="--icon-mask: var(--glyph-dot)"`) or it paints a solid square, like
|
|
95
|
+
any [icon](./reference.md). And an **interactive** legend entry must be a real
|
|
96
|
+
`<button>` (as in the example below) — a non-button `ui-legend__item` carrying
|
|
97
|
+
`data-series` is not keyboard-reachable.
|
|
98
|
+
|
|
99
|
+
**Keying the de-emphasised series.** In an accent-rationed chart — one mark
|
|
100
|
+
painted with [`brontoVegaAccent`](./vega.md#spending-the-accent), the rest left
|
|
101
|
+
quiet with `brontoVegaNeutral` — the quiet neutral **is** the last categorical
|
|
102
|
+
series, `--chart-8` (`#4d5358`). So a legend that honestly mirrors that chart
|
|
103
|
+
uses `ui-legend__swatch--1` for the highlighted entry and
|
|
104
|
+
`ui-legend__swatch--8` for the "everything else" entry — both are real palette
|
|
105
|
+
tokens, so the key never drifts from the marks and `check:legend` stays happy.
|
|
106
|
+
Don't hand-roll a grey: `--chart-8` is the neutral by construction.
|
|
107
|
+
|
|
92
108
|
## Variants
|
|
93
109
|
|
|
94
110
|
| Modifier | Effect |
|