@ponchia/ui 0.6.0 → 0.6.3

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.
Files changed (156) hide show
  1. package/CHANGELOG.md +64 -4
  2. package/README.md +1 -1
  3. package/annotations/index.d.ts.map +1 -1
  4. package/annotations/index.js +36 -33
  5. package/behaviors/carousel.d.ts +28 -0
  6. package/behaviors/carousel.d.ts.map +1 -0
  7. package/behaviors/carousel.js +3 -0
  8. package/behaviors/combobox.d.ts +40 -0
  9. package/behaviors/combobox.d.ts.map +1 -0
  10. package/behaviors/combobox.js +71 -20
  11. package/behaviors/command.d.ts +41 -0
  12. package/behaviors/command.d.ts.map +1 -0
  13. package/behaviors/command.js +9 -0
  14. package/behaviors/connectors.d.ts +17 -0
  15. package/behaviors/connectors.d.ts.map +1 -0
  16. package/behaviors/connectors.js +3 -0
  17. package/behaviors/crosshair.d.ts +42 -0
  18. package/behaviors/crosshair.d.ts.map +1 -0
  19. package/behaviors/crosshair.js +19 -1
  20. package/behaviors/dialog.d.ts +20 -0
  21. package/behaviors/dialog.d.ts.map +1 -0
  22. package/behaviors/dialog.js +3 -0
  23. package/behaviors/disclosure.d.ts +10 -0
  24. package/behaviors/disclosure.d.ts.map +1 -0
  25. package/behaviors/disclosure.js +3 -0
  26. package/behaviors/dismissible.d.ts +10 -0
  27. package/behaviors/dismissible.d.ts.map +1 -0
  28. package/behaviors/dismissible.js +3 -0
  29. package/behaviors/forms.d.ts +27 -0
  30. package/behaviors/forms.d.ts.map +1 -0
  31. package/behaviors/forms.js +18 -5
  32. package/behaviors/glyph.d.ts +14 -0
  33. package/behaviors/glyph.d.ts.map +1 -0
  34. package/behaviors/glyph.js +24 -0
  35. package/behaviors/index.d.ts +31 -237
  36. package/behaviors/index.d.ts.map +1 -0
  37. package/behaviors/index.js +17 -0
  38. package/behaviors/inert.d.ts +20 -0
  39. package/behaviors/inert.d.ts.map +1 -0
  40. package/behaviors/inert.js +46 -0
  41. package/behaviors/internal.d.ts +25 -0
  42. package/behaviors/internal.d.ts.map +1 -0
  43. package/behaviors/internal.js +30 -1
  44. package/behaviors/legend.d.ts +35 -0
  45. package/behaviors/legend.d.ts.map +1 -0
  46. package/behaviors/legend.js +9 -0
  47. package/behaviors/menu.d.ts +16 -0
  48. package/behaviors/menu.d.ts.map +1 -0
  49. package/behaviors/menu.js +3 -0
  50. package/behaviors/modal.d.ts +41 -0
  51. package/behaviors/modal.d.ts.map +1 -0
  52. package/behaviors/modal.js +124 -0
  53. package/behaviors/popover.d.ts +28 -0
  54. package/behaviors/popover.d.ts.map +1 -0
  55. package/behaviors/popover.js +17 -17
  56. package/behaviors/spotlight.d.ts +17 -0
  57. package/behaviors/spotlight.d.ts.map +1 -0
  58. package/behaviors/spotlight.js +3 -0
  59. package/behaviors/table.d.ts +36 -0
  60. package/behaviors/table.d.ts.map +1 -0
  61. package/behaviors/table.js +48 -8
  62. package/behaviors/tabs.d.ts +20 -0
  63. package/behaviors/tabs.d.ts.map +1 -0
  64. package/behaviors/tabs.js +3 -0
  65. package/behaviors/theme.d.ts +54 -0
  66. package/behaviors/theme.d.ts.map +1 -0
  67. package/behaviors/theme.js +17 -0
  68. package/behaviors/toast.d.ts +49 -0
  69. package/behaviors/toast.d.ts.map +1 -0
  70. package/behaviors/toast.js +34 -2
  71. package/classes/classes.json +683 -13
  72. package/classes/index.d.ts +106 -2
  73. package/classes/index.js +249 -65
  74. package/connectors/index.d.ts +12 -0
  75. package/connectors/index.d.ts.map +1 -1
  76. package/connectors/index.js +23 -2
  77. package/css/app.css +26 -0
  78. package/css/bullet.css +108 -0
  79. package/css/code.css +98 -0
  80. package/css/content.css +15 -2
  81. package/css/crosshair.css +7 -7
  82. package/css/diff.css +153 -0
  83. package/css/disclosure.css +18 -4
  84. package/css/dots.css +37 -7
  85. package/css/feedback.css +39 -7
  86. package/css/forms.css +71 -3
  87. package/css/legend.css +5 -2
  88. package/css/motion.css +79 -14
  89. package/css/overlay.css +59 -2
  90. package/css/primitives.css +67 -8
  91. package/css/report.css +40 -0
  92. package/css/sidenote.css +67 -0
  93. package/css/spark.css +62 -0
  94. package/css/table.css +9 -2
  95. package/css/term.css +110 -0
  96. package/css/textref.css +63 -0
  97. package/css/toc.css +91 -0
  98. package/css/tokens.css +14 -1
  99. package/css/tree.css +134 -0
  100. package/dist/bronto.css +1 -1
  101. package/dist/css/analytical.css +1 -1
  102. package/dist/css/app.css +1 -1
  103. package/dist/css/bullet.css +1 -0
  104. package/dist/css/code.css +1 -0
  105. package/dist/css/content.css +1 -1
  106. package/dist/css/crosshair.css +1 -1
  107. package/dist/css/diff.css +1 -0
  108. package/dist/css/disclosure.css +1 -1
  109. package/dist/css/dots.css +1 -1
  110. package/dist/css/feedback.css +1 -1
  111. package/dist/css/forms.css +1 -1
  112. package/dist/css/legend.css +1 -1
  113. package/dist/css/motion.css +1 -1
  114. package/dist/css/overlay.css +1 -1
  115. package/dist/css/primitives.css +1 -1
  116. package/dist/css/report.css +1 -1
  117. package/dist/css/sidenote.css +1 -0
  118. package/dist/css/spark.css +1 -0
  119. package/dist/css/table.css +1 -1
  120. package/dist/css/term.css +1 -0
  121. package/dist/css/textref.css +1 -0
  122. package/dist/css/toc.css +1 -0
  123. package/dist/css/tokens.css +1 -1
  124. package/dist/css/tree.css +1 -0
  125. package/docs/annotations.md +39 -0
  126. package/docs/architecture.md +2 -3
  127. package/docs/bullet.md +78 -0
  128. package/docs/code.md +76 -0
  129. package/docs/d2.md +4 -3
  130. package/docs/diff.md +146 -0
  131. package/docs/legends.md +8 -4
  132. package/docs/mermaid.md +21 -4
  133. package/docs/reference.md +127 -8
  134. package/docs/reporting.md +35 -14
  135. package/docs/sidenote.md +64 -0
  136. package/docs/spark.md +78 -0
  137. package/docs/stability.md +1 -0
  138. package/docs/term.md +81 -0
  139. package/docs/textref.md +78 -0
  140. package/docs/theming.md +44 -5
  141. package/docs/toc.md +83 -0
  142. package/docs/tree.md +74 -0
  143. package/docs/usage.md +264 -23
  144. package/docs/vega.md +22 -3
  145. package/glyphs/glyphs.js +7 -1
  146. package/llms.txt +159 -13
  147. package/package.json +47 -7
  148. package/qwik/index.d.ts +4 -2
  149. package/qwik/index.d.ts.map +1 -1
  150. package/qwik/index.js +10 -0
  151. package/react/index.d.ts +4 -2
  152. package/react/index.d.ts.map +1 -1
  153. package/react/index.js +6 -0
  154. package/solid/index.d.ts +6 -2
  155. package/solid/index.d.ts.map +1 -1
  156. package/solid/index.js +6 -0
package/docs/code.md ADDED
@@ -0,0 +1,76 @@
1
+ # Code
2
+
3
+ `@ponchia/ui/css/code.css` is an opt-in chrome for **fenced code** — the surface
4
+ for code-as-evidence in changelogs, version history, config snippets, and
5
+ generated reports. It paints the frame, an optional line-number gutter, and
6
+ add / remove / highlight line states. Its sibling is [diff.css](diff.md)
7
+ (multi-column line/row diffs); the two share one change vocabulary —
8
+ `--add` / `--remove` (`ui-code__line--remove` ↔ `ui-diff__row--remove`).
9
+
10
+ ```css
11
+ @import '@ponchia/ui';
12
+ @import '@ponchia/ui/css/code.css';
13
+ ```
14
+
15
+ ## Boundary — it never parses
16
+
17
+ Bronto owns the chrome; it does **not** tokenize or highlight syntax. The host
18
+ supplies the coloured token spans — hand-written, or from a real highlighter.
19
+ The shipped [`shiki/nothing.json`](../shiki/nothing.json) theme makes Shiki emit
20
+ spans with bronto token colours, so Shiki output drops straight in. A bronto
21
+ class that tried to parse source would cross the same line that removed the
22
+ chart renderer in 0.6.0.
23
+
24
+ ## Markup
25
+
26
+ ```html
27
+ <figure class="ui-code ui-code--numbered">
28
+ <figcaption class="ui-code__head">theme.css</figcaption>
29
+ <pre class="ui-code__body"><code><span class="ui-code__line">.ui-diff {</span>
30
+ <span class="ui-code__line ui-code__line--remove"> font-size: var(--text-sm);</span>
31
+ <span class="ui-code__line ui-code__line--add"> font-size: var(--text-xs);</span>
32
+ <span class="ui-code__line ui-code__line--hl"> line-height: 1.6;</span>
33
+ <span class="ui-code__line">}</span></code></pre>
34
+ </figure>
35
+ ```
36
+
37
+ - `ui-code--numbered` turns on the gutter; it numbers each `.ui-code__line` with
38
+ a CSS counter (no host bookkeeping).
39
+ - Each token span the host emits lives **inside** `.ui-code__line`; Bronto never
40
+ touches it.
41
+ - Plain text inside `.ui-code__body` (no `.ui-code__line` wrappers) renders as an
42
+ unnumbered code block — the line grammar is opt-in.
43
+
44
+ ## Class reference
45
+
46
+ | Class | Role |
47
+ | --- | --- |
48
+ | `.ui-code` | The `<figure>` frame. |
49
+ | `.ui-code--numbered` | Show the line-number gutter. |
50
+ | `.ui-code__head` | A filename / language bar (use on `<figcaption>`). |
51
+ | `.ui-code__body` | The `<pre>` scroll/wrap region. |
52
+ | `.ui-code__line` | One line — the unit numbered + state-tinted. |
53
+ | `.ui-code__line--add` | Added line (green wash). |
54
+ | `.ui-code__line--remove` | Removed line (red wash). |
55
+ | `.ui-code__line--hl` | Neutral highlight / call-out (accent wash, not a change). |
56
+
57
+ ## Recipes
58
+
59
+ ```js
60
+ import { ui } from '@ponchia/ui/classes';
61
+
62
+ ui.code({ numbered: true }); // "ui-code ui-code--numbered"
63
+ ui.codeLine({ change: 'add' }); // "ui-code__line ui-code__line--add"
64
+ ui.codeLine({ change: 'hl' }); // "ui-code__line ui-code__line--hl"
65
+ ui.codeLine(); // "ui-code__line"
66
+ ```
67
+
68
+ ## Accessibility & robustness
69
+
70
+ - **Line states never rely on colour.** In forced-colors mode each
71
+ add/remove/hl line gains an inline-start border, and the tints are forced through
72
+ `print-color-adjust: exact`.
73
+ - **Long lines wrap** rather than scroll, so the block prints cleanly.
74
+ - **Line numbers** are generated content (`user-select: none`), so copying the
75
+ block yields clean code with no line numbers.
76
+ - Keep real text in the `<code>`; don't encode meaning only in a tint.
package/docs/d2.md CHANGED
@@ -43,9 +43,10 @@ For a build step or non-JS host, read `@ponchia/ui/d2.json` directly.
43
43
  > [Vega](./vega.md#from-a-cdn-no-bundler) and [Mermaid](./mermaid.md#theme-a-diagram).
44
44
  > This is rarely an issue for D2, whose native path is **build-time
45
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.
46
+ > theme D2 in the browser over `file://`, **inline** the slot map (generate the
47
+ > paste-ready literal with `npm run emit:theme d2 light` / `dark`, and guard it
48
+ > against token drift with `npm run emit:theme:check <file>`) rather than
49
+ > importing it. Over `http(s)` the `import`/`fetch` forms both work.
49
50
 
50
51
  ### Why resolved colours, not `var(--x)`
51
52
 
package/docs/diff.md ADDED
@@ -0,0 +1,146 @@
1
+ # Diff
2
+
3
+ `@ponchia/ui/css/diff.css` is an opt-in change-review grammar — the surface for
4
+ showing what **changed**: code review, changelogs, version history, config
5
+ diffs, and generated reports. Marks call out a sentence; diff calls out a line.
6
+ Its sibling is [code.css](code.md) (single-file fenced code); the two share one
7
+ change vocabulary — `--add` / `--remove` (`ui-diff__row--remove` ↔
8
+ `ui-code__line--remove`).
9
+
10
+ ```css
11
+ @import '@ponchia/ui';
12
+ @import '@ponchia/ui/css/diff.css';
13
+ ```
14
+
15
+ ```html
16
+ <!-- node_modules / CDN: source css/ → built dist/css/ -->
17
+ <link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/diff.css" />
18
+ ```
19
+
20
+ ## Boundary — what Bronto owns vs. what you own
21
+
22
+ Bronto paints the gutter grammar. **You** pre-classify each row (`add` /
23
+ `remove` / `context`), compute the hunks, and align the two sides in split
24
+ view. Bronto never parses or diffs source — that needs your tokenizer and your
25
+ alignment, the same line that removed the local chart renderer in `0.6.0`. Feed
26
+ it rows that are already classified by your diff engine (`jsdiff`, `git`, a
27
+ language server, …).
28
+
29
+ ## Unified view — `.ui-diff`
30
+
31
+ Rows are direct children of `.ui-diff` (optionally grouped in a
32
+ `.ui-diff__hunk`). Columns are `[old-ln] [new-ln] [code]`. Mark each changed row
33
+ `--add` / `--remove`, and leave unchanged rows `--context`. Line numbers are
34
+ decorative — keep them `aria-hidden`; the `__code` cell carries the content.
35
+
36
+ ```html
37
+ <div class="ui-diff">
38
+ <div class="ui-diff__hunk">
39
+ <div class="ui-diff__head">@@ -12,6 +12,6 @@ .ui-diff</div>
40
+
41
+ <div class="ui-diff__row ui-diff__row--context">
42
+ <span class="ui-diff__ln" aria-hidden="true">12</span>
43
+ <span class="ui-diff__ln" aria-hidden="true">12</span>
44
+ <code class="ui-diff__code"> border: 1px solid var(--line);</code>
45
+ </div>
46
+
47
+ <div class="ui-diff__row ui-diff__row--remove">
48
+ <span class="ui-diff__ln" aria-hidden="true">13</span>
49
+ <span class="ui-diff__ln" aria-hidden="true"></span>
50
+ <code class="ui-diff__code"> font-size: var(--text-sm);</code>
51
+ </div>
52
+
53
+ <div class="ui-diff__row ui-diff__row--add">
54
+ <span class="ui-diff__ln" aria-hidden="true"></span>
55
+ <span class="ui-diff__ln" aria-hidden="true">13</span>
56
+ <code class="ui-diff__code"> font-size: var(--text-xs);</code>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ ```
61
+
62
+ A removed row leaves the **new** line-number cell empty; an added row leaves the
63
+ **old** one empty. The `+` / `−` gutter glyph is painted for you from the row
64
+ modifier.
65
+
66
+ ## Split view — `.ui-diff--split`
67
+
68
+ `.ui-diff--split` lays two `.ui-diff__pane` columns side by side (old | new),
69
+ each its own `[ln] [code]` grid. Put `--remove` / `--context` rows in the left
70
+ pane and `--add` / `--context` rows in the right. You align the panes by
71
+ emitting matching row counts (filler `--context` rows where one side is empty).
72
+
73
+ ```html
74
+ <div class="ui-diff ui-diff--split">
75
+ <div class="ui-diff__pane">
76
+ <div class="ui-diff__row ui-diff__row--context">
77
+ <span class="ui-diff__ln" aria-hidden="true">1</span>
78
+ <code class="ui-diff__code">retries: 3</code>
79
+ </div>
80
+ <div class="ui-diff__row ui-diff__row--remove">
81
+ <span class="ui-diff__ln" aria-hidden="true">2</span>
82
+ <code class="ui-diff__code">timeout: 30</code>
83
+ </div>
84
+ </div>
85
+ <div class="ui-diff__pane">
86
+ <div class="ui-diff__row ui-diff__row--context">
87
+ <span class="ui-diff__ln" aria-hidden="true">1</span>
88
+ <code class="ui-diff__code">retries: 3</code>
89
+ </div>
90
+ <div class="ui-diff__row ui-diff__row--add">
91
+ <span class="ui-diff__ln" aria-hidden="true">2</span>
92
+ <code class="ui-diff__code">timeout: 10</code>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ ```
97
+
98
+ For a hard before/after of two whole files, you can also drop two plain
99
+ `.ui-diff` blocks into a [`.ui-compare--2up`](./reporting.md) layout.
100
+
101
+ ## Class reference
102
+
103
+ | Class | Role |
104
+ | --- | --- |
105
+ | `.ui-diff` | The grid container (unified view). |
106
+ | `.ui-diff--split` | Two-pane (old \| new) layout modifier. |
107
+ | `.ui-diff__pane` | One column in split view; its own `[ln] [code]` grid. |
108
+ | `.ui-diff__hunk` | Optional `role="rowgroup"` wrapper for a hunk (layout-transparent). |
109
+ | `.ui-diff__head` | A hunk / file header row, spanning all columns. |
110
+ | `.ui-diff__row` | A line row (layout-transparent; the cells are the grid items). |
111
+ | `.ui-diff__row--add` | Added line — green tint + `+` gutter glyph. |
112
+ | `.ui-diff__row--remove` | Removed line — red tint + `−` gutter glyph. |
113
+ | `.ui-diff__row--context` | Unchanged line — no tint, blank gutter. |
114
+ | `.ui-diff__ln` | A line-number gutter cell (`tabular-nums`, `user-select:none`; keep it `aria-hidden`). |
115
+ | `.ui-diff__code` | A code cell. Long lines wrap (no horizontal scroll), so it prints cleanly. |
116
+
117
+ ## Recipes
118
+
119
+ ```js
120
+ import { ui } from '@ponchia/ui/classes';
121
+
122
+ ui.diff(); // "ui-diff"
123
+ ui.diff({ split: true }); // "ui-diff ui-diff--split"
124
+ ui.diffRow({ change: 'add' }); // "ui-diff__row ui-diff__row--add"
125
+ ui.diffRow({ change: 'remove' }); // "ui-diff__row ui-diff__row--remove"
126
+ ui.diffRow(); // "ui-diff__row" (use --context for an explicit unchanged row)
127
+ ```
128
+
129
+ ## Accessibility & robustness
130
+
131
+ - **Redundant channel (WCAG 1.4.1).** Add/remove is never colour-only: the
132
+ `+` / `−` gutter glyph is generated content, so it survives **forced colours**
133
+ and **print**, where the tone tint is dropped. In forced-colors mode the
134
+ changed code cell also gains an inline-start border.
135
+ - **Print.** Tints are forced through with `print-color-adjust: exact`, and long
136
+ lines wrap rather than clip — the diff survives the PDF pipeline.
137
+ - **Line numbers** are decorative: `aria-hidden` them and they stay out of a
138
+ copy selection (`user-select: none`), so copying the diff yields clean code.
139
+ - **Semantics** live in your markup. By default the surface is role-free: with
140
+ the line numbers `aria-hidden`, a screen reader reads the `__code` lines in
141
+ DOM order, which is a faithful reading of the diff. If you want grid/table
142
+ semantics, use a real `<table>` or add the full ARIA chain
143
+ (`role="table" > rowgroup > row > cell`) — a bare `role="row"` without
144
+ `role="cell"` children is an ARIA violation. If the change kind itself must be
145
+ announced, add an off-screen label per changed row; do not rely on the glyph
146
+ alone.
package/docs/legends.md CHANGED
@@ -48,7 +48,7 @@ Recommended structure: wrap the figure and its key in a `<figure>` with a
48
48
  <li class="ui-legend__item">
49
49
  <span
50
50
  class="ui-legend__swatch"
51
- style="--chart-color: var(--chart-1); --chart-pattern: var(--chart-pattern-1)"
51
+ style="--chart-color: var(--chart-3); --chart-pattern: var(--chart-pattern-3)"
52
52
  aria-hidden="true"
53
53
  ></span>
54
54
  <span class="ui-legend__label">Research</span>
@@ -90,9 +90,13 @@ chart mark uses, or with a `--N` index helper for the categorical palette.
90
90
  `ui-legend__swatch--circle` and `ui-legend__swatch--line` change the chip shape
91
91
  (dot series, line series).
92
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
93
+ A `ui-legend__symbol` chip is an `.ui-icon` mask — it needs a `--icon-mask` or it
94
+ paints a solid square, like any [icon](./reference.md). There is **no `--glyph-*`
95
+ token**: build the mask value with
96
+ [`renderGlyph(name, { render: 'mask' })`](./reference.md) from `@ponchia/ui/glyphs`,
97
+ e.g. `el.style.setProperty('--icon-mask', renderGlyph('circle', { render: 'mask' }).match(/--icon-mask:([^"]+)/)[1])`,
98
+ or render the whole chip with `renderGlyph('circle', { render: 'mask', label })` and
99
+ add the `ui-legend__symbol` class to it. And an **interactive** legend entry must be a real
96
100
  `<button>` (as in the example below) — a non-button `ui-legend__item` carrying
97
101
  `data-series` is not keyboard-reachable.
98
102
 
package/docs/mermaid.md CHANGED
@@ -38,14 +38,31 @@ or read the raw maps (`import { mermaid } from '@ponchia/ui/mermaid'` →
38
38
  `{ light, dark }`). For a build step or non-JS host, read
39
39
  `@ponchia/ui/mermaid.json` directly.
40
40
 
41
+ **Over `http(s)`, import the helper from a CDN as an ES module** — no bundler.
42
+ `tokens/mermaid.js` (the `@ponchia/ui/mermaid` entry) has **zero dependencies**,
43
+ so it loads directly as a browser ES module; you get `brontoMermaidTheme(theme)`
44
+ itself, not a frozen object to keep in sync. Pin the package version; this needs
45
+ a real origin (not `file://` — inline or pre-render to SVG there, per the note
46
+ below):
47
+
48
+ ```html
49
+ <script type="module">
50
+ import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
51
+ import { brontoMermaidTheme } from 'https://cdn.jsdelivr.net/npm/@ponchia/ui@VERSION/tokens/mermaid.js';
52
+ mermaid.initialize(brontoMermaidTheme('light'));
53
+ await mermaid.run();
54
+ </script>
55
+ ```
56
+
41
57
  > **file:// portability.** A report opened straight from disk (`file://`) cannot
42
58
  > `import` the `@ponchia/ui/mermaid` module **nor** `fetch('…/mermaid.json')` —
43
59
  > the browser blocks both across the `null`/file origin (CORS), exactly as with
44
60
  > [Vega](./vega.md#from-a-cdn-no-bundler). So for a double-clickable or PDF-bound
45
- > report either **inline the theme variables** (paste the object for your theme
46
- > from `mermaid.json` into the init directive) or, better, **pre-render to a
47
- > frozen SVG** with the Mermaid CLI (`mmdc`, below) so there is no runtime at
48
- > all. Over an `http(s)` origin the `import`/`fetch` forms both work.
61
+ > report either **inline the theme variables** (generate the paste-ready literal
62
+ > with `npm run emit:theme mermaid light` / `dark` guard it from token drift
63
+ > with `npm run emit:theme:check <file>`) or, better, **pre-render to a frozen
64
+ > SVG** with the Mermaid CLI (`mmdc`, below) so there is no runtime at all. Over
65
+ > an `http(s)` origin the `import`/`fetch` forms both work.
49
66
 
50
67
  The result is monochrome surfaces and lines with the rationed accent reserved
51
68
  for notes — a diagram that looks like the rest of a bronto surface and
package/docs/reference.md CHANGED
@@ -9,7 +9,7 @@ rendering of every class is the kitchen-sink demo:
9
9
  **<https://ponchia.github.io/bronto-ui/>**. Theming knobs and the token
10
10
  contract: [docs/theming.md](theming.md).
11
11
 
12
- - 477 classes across 149 component groups
12
+ - 529 classes across 161 component groups
13
13
  - Import the typed registry: `import { cls, ui, cx } from '@ponchia/ui/classes'`
14
14
  - Validate markup as data (no JS/TS): `@ponchia/ui/classes.json` — the same
15
15
  vocabulary as language-neutral JSON (`groups`, `classes`, `states`,
@@ -37,7 +37,7 @@ each one matches a real selector in the stylesheet.
37
37
  | --- | --- | --- |
38
38
  | `cls.alert` | `ui-alert` | base |
39
39
  | `cls.alertBody` | `ui-alert__body` | part |
40
- | `cls.alertDismiss` | `ui-alert__dismiss` | part |
40
+ | `cls.alertClose` | `ui-alert__close` | part |
41
41
  | `cls.alertTitle` | `ui-alert__title` | part |
42
42
  | `cls.alertAccent` | `ui-alert--accent` | modifier |
43
43
  | `cls.alertDanger` | `ui-alert--danger` | modifier |
@@ -245,6 +245,18 @@ each one matches a real selector in the stylesheet.
245
245
  | --- | --- | --- |
246
246
  | `cls.breakBefore` | `ui-break-before` | base |
247
247
 
248
+ ### `.ui-bullet`
249
+
250
+ | Registry key | Class | Kind |
251
+ | --- | --- | --- |
252
+ | `cls.bullet` | `ui-bullet` | base |
253
+ | `cls.bulletLabel` | `ui-bullet__label` | part |
254
+ | `cls.bulletMeasure` | `ui-bullet__measure` | part |
255
+ | `cls.bulletMeasureAccent` | `ui-bullet__measure--accent` | modifier |
256
+ | `cls.bulletMeasureNeg` | `ui-bullet__measure--neg` | modifier |
257
+ | `cls.bulletMeasurePos` | `ui-bullet__measure--pos` | modifier |
258
+ | `cls.bulletTarget` | `ui-bullet__target` | part |
259
+
248
260
  ### `.ui-button`
249
261
 
250
262
  | Registry key | Class | Kind |
@@ -319,6 +331,19 @@ each one matches a real selector in the stylesheet.
319
331
  | `cls.cluster` | `ui-cluster` | base |
320
332
  | `cls.clusterBetween` | `ui-cluster--between` | modifier |
321
333
 
334
+ ### `.ui-code`
335
+
336
+ | Registry key | Class | Kind |
337
+ | --- | --- | --- |
338
+ | `cls.code` | `ui-code` | base |
339
+ | `cls.codeBody` | `ui-code__body` | part |
340
+ | `cls.codeHead` | `ui-code__head` | part |
341
+ | `cls.codeLine` | `ui-code__line` | part |
342
+ | `cls.codeLineAdd` | `ui-code__line--add` | modifier |
343
+ | `cls.codeLineHl` | `ui-code__line--hl` | modifier |
344
+ | `cls.codeLineRemove` | `ui-code__line--remove` | modifier |
345
+ | `cls.codeNumbered` | `ui-code--numbered` | modifier |
346
+
322
347
  ### `.ui-combobox`
323
348
 
324
349
  | Registry key | Class | Kind |
@@ -392,6 +417,12 @@ each one matches a real selector in the stylesheet.
392
417
  | `cls.crosshairLineY` | `ui-crosshair__line--y` | modifier |
393
418
  | `cls.crosshairMuted` | `ui-crosshair--muted` | modifier |
394
419
 
420
+ ### `.ui-def`
421
+
422
+ | Registry key | Class | Kind |
423
+ | --- | --- | --- |
424
+ | `cls.def` | `ui-def` | base |
425
+
395
426
  ### `.ui-delta`
396
427
 
397
428
  | Registry key | Class | Kind |
@@ -402,6 +433,22 @@ each one matches a real selector in the stylesheet.
402
433
  | `cls.deltaInvert` | `ui-delta--invert` | modifier |
403
434
  | `cls.deltaUp` | `ui-delta--up` | modifier |
404
435
 
436
+ ### `.ui-diff`
437
+
438
+ | Registry key | Class | Kind |
439
+ | --- | --- | --- |
440
+ | `cls.diff` | `ui-diff` | base |
441
+ | `cls.diffCode` | `ui-diff__code` | part |
442
+ | `cls.diffHead` | `ui-diff__head` | part |
443
+ | `cls.diffHunk` | `ui-diff__hunk` | part |
444
+ | `cls.diffLn` | `ui-diff__ln` | part |
445
+ | `cls.diffPane` | `ui-diff__pane` | part |
446
+ | `cls.diffRow` | `ui-diff__row` | part |
447
+ | `cls.diffRowAdd` | `ui-diff__row--add` | modifier |
448
+ | `cls.diffRowContext` | `ui-diff__row--context` | modifier |
449
+ | `cls.diffRowRemove` | `ui-diff__row--remove` | modifier |
450
+ | `cls.diffSplit` | `ui-diff--split` | modifier |
451
+
405
452
  ### `.ui-display`
406
453
 
407
454
  | Registry key | Class | Kind |
@@ -519,6 +566,14 @@ each one matches a real selector in the stylesheet.
519
566
  | `cls.generated` | `ui-generated` | base |
520
567
  | `cls.generatedLabel` | `ui-generated__label` | part |
521
568
 
569
+ ### `.ui-glossary`
570
+
571
+ | Registry key | Class | Kind |
572
+ | --- | --- | --- |
573
+ | `cls.glossary` | `ui-glossary` | base |
574
+ | `cls.glossaryDef` | `ui-glossary__def` | part |
575
+ | `cls.glossaryTerm` | `ui-glossary__term` | part |
576
+
522
577
  ### `.ui-grid`
523
578
 
524
579
  | Registry key | Class | Kind |
@@ -639,6 +694,12 @@ each one matches a real selector in the stylesheet.
639
694
  | `cls.linkArrow` | `ui-link--arrow` | modifier |
640
695
  | `cls.linkCta` | `ui-link--cta` | modifier |
641
696
 
697
+ ### `.ui-marginnote`
698
+
699
+ | Registry key | Class | Kind |
700
+ | --- | --- | --- |
701
+ | `cls.marginnote` | `ui-marginnote` | base |
702
+
642
703
  ### `.ui-mark`
643
704
 
644
705
  | Registry key | Class | Kind |
@@ -689,6 +750,9 @@ each one matches a real selector in the stylesheet.
689
750
  | --- | --- | --- |
690
751
  | `cls.meter` | `ui-meter` | base |
691
752
  | `cls.meterFill` | `ui-meter__fill` | part |
753
+ | `cls.meterLabel` | `ui-meter__label` | part |
754
+ | `cls.meterRow` | `ui-meter__row` | part |
755
+ | `cls.meterValue` | `ui-meter__value` | part |
692
756
  | `cls.meterAccent` | `ui-meter--accent` | modifier |
693
757
  | `cls.meterDanger` | `ui-meter--danger` | modifier |
694
758
  | `cls.meterInfo` | `ui-meter--info` | modifier |
@@ -936,6 +1000,13 @@ each one matches a real selector in the stylesheet.
936
1000
  | --- | --- | --- |
937
1001
  | `cls.sidebar` | `ui-sidebar` | base |
938
1002
 
1003
+ ### `.ui-sidenote`
1004
+
1005
+ | Registry key | Class | Kind |
1006
+ | --- | --- | --- |
1007
+ | `cls.sidenote` | `ui-sidenote` | base |
1008
+ | `cls.sidenoteRef` | `ui-sidenote__ref` | part |
1009
+
939
1010
  ### `.ui-sitefooter`
940
1011
 
941
1012
  | Registry key | Class | Kind |
@@ -995,6 +1066,16 @@ each one matches a real selector in the stylesheet.
995
1066
  | `cls.sourceList` | `ui-source-list` | base |
996
1067
  | `cls.sourceListItem` | `ui-source-list__item` | part |
997
1068
 
1069
+ ### `.ui-spark`
1070
+
1071
+ | Registry key | Class | Kind |
1072
+ | --- | --- | --- |
1073
+ | `cls.spark` | `ui-spark` | base |
1074
+ | `cls.sparkBar` | `ui-spark__bar` | part |
1075
+ | `cls.sparkBarAccent` | `ui-spark__bar--accent` | modifier |
1076
+ | `cls.sparkBarNeg` | `ui-spark__bar--neg` | modifier |
1077
+ | `cls.sparkBarPos` | `ui-spark__bar--pos` | modifier |
1078
+
998
1079
  ### `.ui-spinner`
999
1080
 
1000
1081
  | Registry key | Class | Kind |
@@ -1126,7 +1207,6 @@ each one matches a real selector in the stylesheet.
1126
1207
  | `cls.tableComfortable` | `ui-table--comfortable` | modifier |
1127
1208
  | `cls.tableDense` | `ui-table--dense` | modifier |
1128
1209
  | `cls.tableLined` | `ui-table--lined` | modifier |
1129
- | `cls.tableLoading` | `ui-table--loading` | modifier |
1130
1210
  | `cls.tableSelectable` | `ui-table--selectable` | modifier |
1131
1211
 
1132
1212
  ### `.ui-table-wrap`
@@ -1134,6 +1214,7 @@ each one matches a real selector in the stylesheet.
1134
1214
  | Registry key | Class | Kind |
1135
1215
  | --- | --- | --- |
1136
1216
  | `cls.tableWrap` | `ui-table-wrap` | base |
1217
+ | `cls.tableLoading` | `ui-table-wrap--loading` | modifier |
1137
1218
 
1138
1219
  ### `.ui-tabs`
1139
1220
 
@@ -1156,12 +1237,24 @@ each one matches a real selector in the stylesheet.
1156
1237
  | --- | --- | --- |
1157
1238
  | `cls.tags` | `ui-tags` | base |
1158
1239
 
1240
+ ### `.ui-term`
1241
+
1242
+ | Registry key | Class | Kind |
1243
+ | --- | --- | --- |
1244
+ | `cls.term` | `ui-term` | base |
1245
+
1159
1246
  ### `.ui-textarea`
1160
1247
 
1161
1248
  | Registry key | Class | Kind |
1162
1249
  | --- | --- | --- |
1163
1250
  | `cls.textarea` | `ui-textarea` | base |
1164
1251
 
1252
+ ### `.ui-textref`
1253
+
1254
+ | Registry key | Class | Kind |
1255
+ | --- | --- | --- |
1256
+ | `cls.textref` | `ui-textref` | base |
1257
+
1165
1258
  ### `.ui-themetoggle`
1166
1259
 
1167
1260
  | Registry key | Class | Kind |
@@ -1200,6 +1293,15 @@ each one matches a real selector in the stylesheet.
1200
1293
  | `cls.toastStack` | `ui-toast-stack` | base |
1201
1294
  | `cls.toastStackAssertive` | `ui-toast-stack--assertive` | modifier |
1202
1295
 
1296
+ ### `.ui-toc`
1297
+
1298
+ | Registry key | Class | Kind |
1299
+ | --- | --- | --- |
1300
+ | `cls.toc` | `ui-toc` | base |
1301
+ | `cls.tocLink` | `ui-toc__link` | part |
1302
+ | `cls.tocList` | `ui-toc__list` | part |
1303
+ | `cls.tocTitle` | `ui-toc__title` | part |
1304
+
1203
1305
  ### `.ui-tool-call`
1204
1306
 
1205
1307
  | Registry key | Class | Kind |
@@ -1232,6 +1334,16 @@ each one matches a real selector in the stylesheet.
1232
1334
  | `cls.tourNoteStep` | `ui-tour-note__step` | part |
1233
1335
  | `cls.tourNoteTitle` | `ui-tour-note__title` | part |
1234
1336
 
1337
+ ### `.ui-tree`
1338
+
1339
+ | Registry key | Class | Kind |
1340
+ | --- | --- | --- |
1341
+ | `cls.tree` | `ui-tree` | base |
1342
+ | `cls.treeBranch` | `ui-tree__branch` | part |
1343
+ | `cls.treeLabel` | `ui-tree__label` | part |
1344
+ | `cls.treeLeaf` | `ui-tree__leaf` | part |
1345
+ | `cls.treeSummary` | `ui-tree__summary` | part |
1346
+
1235
1347
  ### `.ui-visually-hidden`
1236
1348
 
1237
1349
  | Registry key | Class | Kind |
@@ -1283,8 +1395,11 @@ works in any framework without a binding layer:
1283
1395
  - **Button loading** — set `aria-busy="true"` (and `disabled`) on
1284
1396
  `ui-button`; the leading spinner is injected by CSS with no extra
1285
1397
  markup or class. `ui-button--sm`/`--lg` size it.
1286
- - **Badge tone** — `ui.badge({ tone })` emits the framework tone
1287
- (`accent|success|warning|danger|info|muted`). Mapping an app's own variant
1398
+ - **Badge tone** — `ui.badge({ tone })` emits the badge tone
1399
+ (`accent|success|warning|danger|info|muted`). The set is badge-specific, not a
1400
+ universal vocabulary — `muted` is a badge/neutral tone, absent from the status
1401
+ families (`ui-alert`/`ui-toast`/`ui-meter`/`ui-dot`); the builders warn on an
1402
+ out-of-set tone (see usage.md). Mapping an app's own variant
1288
1403
  vocabulary onto a tone is application logic, not a framework class.
1289
1404
  - **Modal** — native `<dialog>` gets backdrop + top-layer + focus-trap
1290
1405
  free. For a controlled/portal modal, add `is-open`
@@ -1302,7 +1417,9 @@ works in any framework without a binding layer:
1302
1417
  back to the field's `.ui-hint`, restoring the help text when valid again); a
1303
1418
  `[data-bronto-error-summary]` (`.ui-error-summary`) block. The combobox
1304
1419
  reads `[data-bronto-combobox]` + per-option `data-value` and emits
1305
- `bronto:change` (`{ detail: { value } }`) on selection; the interactive
1420
+ `bronto:change` (`{ detail: { value, label } }`) on selection — `label` is the
1421
+ chosen option's text, so a live region can announce it without re-reading the DOM;
1422
+ the interactive
1306
1423
  legend emits `bronto:legend:toggle` (`{ detail: { series, active } }`).
1307
1424
  - **Status indicator** — `ui-status` carries no dot of its own: compose it with
1308
1425
  a `.ui-dot` child + a text label, e.g.
@@ -1321,8 +1438,10 @@ works in any framework without a binding layer:
1321
1438
  lights a segment with `<i class="is-on">`. A childless
1322
1439
  `<span class="ui-dotspinner">` renders nothing.
1323
1440
  - **`ui-caret` is a typing cursor**, not a dropdown chevron — a blinking block
1324
- caret (driven by `initDotGlyph`/`uiBlink`). For a disclosure/affordance
1325
- arrow use `ui-link--arrow` (`ui.link({ arrow: true })`).
1441
+ caret. It is **pure CSS** (a `uiBlink` keyframe on `::after`); it needs no
1442
+ behavior do NOT call `initDotGlyph` to animate it — and it is decorative, so
1443
+ keep it out of the a11y tree (`aria-hidden`). For a disclosure/affordance arrow
1444
+ use `ui-link--arrow` (`ui.link({ arrow: true })`).
1326
1445
 
1327
1446
  ## Tokens
1328
1447
 
package/docs/reporting.md CHANGED
@@ -37,11 +37,11 @@ No install? Link the same files from a CDN. Pin the version — pre-1.0, breakin
37
37
  changes ship in the minor (see [stability.md](./stability.md)):
38
38
 
39
39
  ```html
40
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.0/dist/bronto.css" />
41
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.0/dist/css/report.css" />
42
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.0/dist/css/dataviz.css" />
43
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.0/dist/css/annotations.css" />
44
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.0/dist/css/legend.css" />
40
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.3/dist/bronto.css" />
41
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.3/dist/css/report.css" />
42
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.3/dist/css/dataviz.css" />
43
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.3/dist/css/annotations.css" />
44
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.3/dist/css/legend.css" />
45
45
  ```
46
46
 
47
47
  The CDN serves the package's own `fonts/` next to the CSS, so font URLs resolve
@@ -218,13 +218,17 @@ Direction tone follows the common case (up = good, green; down = bad, red). When
218
218
 
219
219
  The arrow is visual; always include the number and unit in the text.
220
220
 
221
- A stat card's own `ui-stat__delta is-pos` / `is-neg` carries **tone only** (good
222
- vs bad, as colour). That is fine on screen, but tone is a single channel: in a
223
- greyscale PDF or for a colour-blind reader a positive and a negative delta look
224
- identical, and the tone is deliberately decoupled from direction (a *dropped*
225
- latency is `is-pos`). When the change must read without colour — most printed
226
- reports prefer `ui-delta` for the card's delta line, because its `--up`/`--down`
227
- arrow is a real non-colour channel:
221
+ A stat card's own `ui-stat__delta is-pos` / `is-neg` carries **tone** (good vs
222
+ bad, as colour) and auto-prepends a `▲`/`▼` glyph but that glyph follows the
223
+ **tone**, not the real direction: `is-pos` always renders `▲` and `is-neg`
224
+ always `▼`, regardless of whether the number went up or down. The tone is
225
+ deliberately decoupled from direction (a *dropped* latency is good, so `is-pos`),
226
+ so the auto-arrow can contradict the words: write `is-pos` on a "−48 ms" and it
227
+ prints `▲ −48 ms`. Do **not** add your own direction word/arrow on top, or you
228
+ double it. When the change must read by direction — most printed reports —
229
+ prefer `ui-delta` for the card's delta line, because its `--up`/`--down` arrow is
230
+ a real (author-controlled) non-colour channel; reach for the arrow-free `ui-num`
231
+ if you want neither tone nor glyph:
228
232
 
229
233
  ```html
230
234
  <span class="ui-stat__label">p95 latency</span>
@@ -343,8 +347,9 @@ raster).
343
347
  > and even then `import`/`fetch` of the config only works over an `http(s)`
344
348
  > origin. A static report **opened from disk (`file://`) cannot import the module
345
349
  > nor fetch `vega.json`** (CORS) — load Vega + Vega-Lite + vega-embed from pinned
346
- > `/build/*.min.js` CDN tags and **inline the resolved `config` object**, the
347
- > file://-safe recipe in [vega.md](./vega.md#from-a-cdn-no-bundler). For a report
350
+ > `/build/*.min.js` CDN tags and **inline the resolved `config` object**
351
+ > (generate it with `npm run emit:theme vega light`), the file://-safe recipe in
352
+ > [vega.md](./vega.md#from-a-cdn-no-bundler). For a report
348
353
  > you intend to **print/PDF**, prefer the frozen inline `<svg>` below — it has no
349
354
  > runtime, prints exactly, and sidesteps all of this.
350
355
 
@@ -478,6 +483,22 @@ it (never rely on the bar alone — WCAG 1.4.1):
478
483
  reading (e.g. 112 % of plan) shows a full bar — put the true figure in the
479
484
  written label beside it (`ui-num`), which is the data of record anyway.
480
485
 
486
+ For a block of meters — SLO burn, error budgets, capacity — lay each out as
487
+ **label | bar | value** with `ui-meter__row`; `ui-meter__label` names it and
488
+ `ui-meter__value` carries the reading (the data of record — never the bar
489
+ alone). The row collapses to a stack on a narrow screen, so you don't hand-roll
490
+ the grid:
491
+
492
+ ```html
493
+ <div class="ui-meter__row">
494
+ <span class="ui-meter__label">Write availability</span>
495
+ <div class="ui-meter ui-meter--danger" role="presentation">
496
+ <span class="ui-meter__fill" style="--value: 90"></span>
497
+ </div>
498
+ <span class="ui-meter__value ui-num">90% of budget burned</span>
499
+ </div>
500
+ ```
501
+
481
502
  A **pull-quote** lifts a source sentence out of the prose — `ui-quote` is the
482
503
  block, `ui-quote__cite` attributes it:
483
504