@ponchia/ui 0.6.3 → 0.6.4

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.
@@ -1 +1 @@
1
- @layer bronto{.ui-table-wrap{border: 1px solid var(--line);border-radius: var(--radius-md);overflow: auto}.ui-table{border-collapse: collapse;font-family: var(--mono);font-size: var(--text-sm);min-inline-size: 100%;inline-size: 100%}.ui-table th,.ui-table td{border-block-end: 1px solid var(--line);overflow-wrap: anywhere;padding: 0.7rem 0.85rem;text-align: start;vertical-align: top}.ui-table th{background: var(--panel);color: var(--text-dim);font-size: var(--text-2xs);font-weight: 700;letter-spacing: var(--tracking-wide);position: sticky;text-transform: uppercase;inset-block-start: 0;z-index: 1}.ui-table td{color: var(--text-soft)}.ui-table tbody tr:last-child td{border-block-end: 0}.ui-table tbody tr{transition: background-color var(--duration-fast) var(--ease-standard)}@media (hover: hover){.ui-table tbody tr:hover td{background: var(--bg-accent)}}.ui-table--dense th,.ui-table--dense td{font-size: var(--text-xs);padding: 0.42rem 0.6rem}.ui-table--comfortable th,.ui-table--comfortable td{padding: 0.95rem 1.1rem}.ui-table--lined td{border-inline-end: 1px solid var(--line)}.ui-table--lined td:last-child{border-inline-end: 0}.ui-table .is-num,.ui-table th.is-num{font-variant-numeric: tabular-nums;text-align: end}.ui-table .is-pos{color: var(--success)}.ui-table .is-neg{color: var(--danger)}.ui-table .is-key{color: var(--text);font-weight: 600}.ui-table__empty td{color: var(--text-dim);padding: 2rem;text-align: center}.ui-table__sort{align-items: center;background: none;border: 0;color: inherit;cursor: pointer;display: flex;font: inherit;gap: 0.4rem;letter-spacing: inherit;padding: 0;text-transform: inherit;inline-size: 100%}.ui-table__sort::after{content: '↕';opacity: 0.4}.ui-table th[aria-sort='ascending'] .ui-table__sort::after{content: '↑';opacity: 1}.ui-table th[aria-sort='descending'] .ui-table__sort::after{content: '↓';opacity: 1}.ui-table__select{inline-size: 1px;white-space: nowrap}.ui-table--selectable tbody tr[aria-selected='true'] td{background: var(--bg-accent)}.ui-table__toolbar{align-items: center;border: 1px solid var(--line);border-block-end: 0;border-start-start-radius: var(--radius-md);border-start-end-radius: var(--radius-md);display: flex;gap: var(--space-sm);padding: var(--space-sm) var(--space-md)}.ui-table-wrap--loading{opacity: 0.6;pointer-events: none}}
1
+ @layer bronto{.ui-table-wrap{border: 1px solid var(--line);border-radius: var(--radius-md);overflow: auto}.ui-table{border-collapse: collapse;font-family: var(--mono);font-size: var(--text-sm);min-inline-size: 100%;inline-size: 100%}.ui-table th,.ui-table td{border-block-end: 1px solid var(--line);overflow-wrap: break-word;padding: 0.7rem 0.85rem;text-align: start;vertical-align: top;word-break: normal}.ui-table th{background: var(--panel);color: var(--text-dim);font-size: var(--text-2xs);font-weight: 700;letter-spacing: var(--tracking-wide);position: sticky;text-transform: uppercase;inset-block-start: 0;z-index: 1}.ui-table td{color: var(--text-soft)}.ui-table tbody tr:last-child td{border-block-end: 0}.ui-table tbody tr{transition: background-color var(--duration-fast) var(--ease-standard)}@media (hover: hover){.ui-table tbody tr:hover td{background: var(--bg-accent)}}.ui-table--dense th,.ui-table--dense td{font-size: var(--text-xs);padding: 0.42rem 0.6rem}.ui-table--comfortable th,.ui-table--comfortable td{padding: 0.95rem 1.1rem}.ui-table--lined td{border-inline-end: 1px solid var(--line)}.ui-table--lined td:last-child{border-inline-end: 0}.ui-table--break-anywhere th,.ui-table--break-anywhere td{overflow-wrap: anywhere}.ui-table .is-num,.ui-table th.is-num{font-variant-numeric: tabular-nums;text-align: end}.ui-table .is-pos{color: var(--success)}.ui-table .is-neg{color: var(--danger)}.ui-table .is-key{color: var(--text);font-weight: 600}.ui-table__empty td{color: var(--text-dim);padding: 2rem;text-align: center}.ui-table__sort{align-items: center;background: none;border: 0;color: inherit;cursor: pointer;display: flex;font: inherit;gap: 0.4rem;letter-spacing: inherit;padding: 0;text-transform: inherit;inline-size: 100%}.ui-table__sort::after{content: '↕';opacity: 0.4}.ui-table th[aria-sort='ascending'] .ui-table__sort::after{content: '↑';opacity: 1}.ui-table th[aria-sort='descending'] .ui-table__sort::after{content: '↓';opacity: 1}.ui-table__select{inline-size: 1px;white-space: nowrap}.ui-table--selectable tbody tr[aria-selected='true'] td{background: var(--bg-accent)}.ui-table__toolbar{align-items: center;border: 1px solid var(--line);border-block-end: 0;border-start-start-radius: var(--radius-md);border-start-end-radius: var(--radius-md);display: flex;gap: var(--space-sm);padding: var(--space-sm) var(--space-md)}.ui-table-wrap--loading{opacity: 0.6;pointer-events: none}}
package/docs/dots.md ADDED
@@ -0,0 +1,146 @@
1
+ # Dot surfaces
2
+
3
+ The dot-matrix is the library's signature: one lit/dim/accent dot vocabulary
4
+ expressed across backgrounds, dividers, indicators, loaders, and a family of
5
+ data-bound reporting surfaces. Everything here lives in the core stylesheet
6
+ (`@ponchia/ui` / `@ponchia/ui/css`); the glyph icon set built on the same
7
+ primitive is documented in `docs/glyphs.md`.
8
+
9
+ All classes are in the typed registry (`@ponchia/ui/classes`) and the
10
+ language-neutral `classes.json`; those are authoritative.
11
+
12
+ ## Tokens
13
+
14
+ Density and expression are token-driven, so a surface re-skins without new CSS:
15
+
16
+ | Token | Role |
17
+ | --- | --- |
18
+ | `--field-dot` | the dim (unlit) dot |
19
+ | `--field-dot-hot` | a lit cell |
20
+ | `--field-dot-accent` | the accented lit cell |
21
+ | `--dot-gap` / `--dot-size` | `.ui-dotgrid` background density |
22
+ | `--dotmatrix-cols` / `--dotmatrix-gap` / `--dotmatrix-dot` | matrix density |
23
+ | `--dotmatrix-dot-radius` | `0` fuses dots into crisp pixels |
24
+
25
+ The Tier-3 **display-expression** knobs speak in brightness + time rather than
26
+ hue (a dot-matrix display has no decorative colour). They default to a no-op, so
27
+ the base render is unchanged; the opt-in colorways (`@ponchia/ui/css/skins.css`)
28
+ set them:
29
+
30
+ | Knob | Default | Effect |
31
+ | --- | --- | --- |
32
+ | `--dotmatrix-glow` | `0` (off) | phosphor bloom around lit cells |
33
+ | `--dotmatrix-pulse-min` | `0.55` | the floor the `--pulse` animation dips to |
34
+ | `--dotmatrix-reveal-step` | `3ms` | per-cell cadence of the `--reveal` scan |
35
+
36
+ ## Decorative surfaces
37
+
38
+ - `.ui-dotgrid` — a tiled dot-grid background (`--accent`, `--dense` modifiers).
39
+ - `.ui-dotfield` — a fixed full-bleed dot backdrop.
40
+ - `.ui-dotrule` — a dotted divider in place of a plain rule.
41
+ - `.ui-halftone` — render host content (an `<img>` or a box with its own
42
+ background) through a dot lattice, so a thumbnail takes on the dot look. A
43
+ **style filter**, not a data viz — the dots are a fixed lattice, not
44
+ value-modulated. Tune with `--halftone-dot` / `--halftone-gap`.
45
+
46
+ ## Indicators & loaders
47
+
48
+ - `.ui-dot` — a status dot with tones (`--accent/--success/--warning/--danger/--info`)
49
+ and a `--live` pulse ring; `.ui-status` is the dot + label row.
50
+ - `.ui-dotloader` — three blinking dots.
51
+ - `.ui-dotspinner` — the signature comet loader (`--sm` / `--lg`).
52
+ - `.ui-dotbar` — a segmented LED progress bar; light a segment with `is-on`,
53
+ or `--indeterminate` for the sweep.
54
+
55
+ ## Data-bound reporting surfaces
56
+
57
+ These map data onto the dot vocabulary. The boundary is the same as `ui-spark`
58
+ and `ui-meter`: **the host normalises the data** (lights `is-on`, sets
59
+ `data-level`, or writes `--v` 0..1) and the leaf only lays out + tones. None
60
+ compute a scale, bin, or threshold. Each is opaque to assistive tech, so the
61
+ container MUST carry a host-written `role="img"` + `aria-label` with the exact
62
+ value — rounding to whole cells is presentation-only, so keep the figure in the
63
+ label (WCAG 1.4.1).
64
+
65
+ ### `.ui-matrix` cell grid
66
+
67
+ `.ui-dotmatrix` is the raw data-bound grid (the one the glyphs render on): a grid
68
+ of `.ui-dotmatrix__cell` (with `--hot` / `--accent` tones) plus the `--reveal` /
69
+ `--pulse` animations. You map data → cell class.
70
+
71
+ ### `.ui-waffle` — unit / part-to-whole
72
+
73
+ An N×N field of dots ("73 of 100"). The host marks the lit cells with `is-on`.
74
+
75
+ ```html
76
+ <div class="ui-waffle" role="img" aria-label="73 of 100 quota met" style="--waffle-cols: 10">
77
+ <i class="is-on"></i><i class="is-on"></i><!-- … 73 lit, 27 dim … --><i></i>
78
+ </div>
79
+ ```
80
+
81
+ Knobs: `--waffle-cols` (default 10), `--waffle-gap`, `--waffle-size`.
82
+
83
+ ### `.ui-activity` — contribution / calendar heatmap
84
+
85
+ A GitHub-style density-over-time grid. Day cells flow down each weekday column
86
+ (`grid-auto-flow: column`); intensity is `data-level="0..4"`, a 5-step ramp the
87
+ host bins the data into.
88
+
89
+ ```html
90
+ <div class="ui-activity" role="img" aria-label="commits, last 12 weeks">
91
+ <i data-level="0"></i><i data-level="3"></i><i data-level="4"></i><!-- … -->
92
+ </div>
93
+ ```
94
+
95
+ Knobs: `--activity-rows` (default 7), `--activity-cell`, `--activity-gap`.
96
+
97
+ ### `.ui-level` — LED level / VU meter
98
+
99
+ A vertical column of discrete segments lit to a threshold (signal, load, VU). It
100
+ fills from the bottom; the host lights segments with `is-on`. `--warn` /
101
+ `--danger` re-point the lit colour for the whole meter when the host crosses a
102
+ threshold (the host owns the threshold).
103
+
104
+ ```html
105
+ <div class="ui-level ui-level--warn" role="img" aria-label="CPU 82%, high">
106
+ <i class="is-on"></i><i class="is-on"></i><i></i><!-- … --></div>
107
+ ```
108
+
109
+ Knobs: `--level-segments` count is up to your markup; `--level-height`,
110
+ `--level-size`, `--level-gap`.
111
+
112
+ ### `.ui-dotgauge` — radial dot gauge
113
+
114
+ A 0..1 reading (`--v`) drawn as a ring of dots filling along an arc.
115
+
116
+ ```html
117
+ <div class="ui-dotgauge" role="img" aria-label="Health 64%" style="--v: .64"></div>
118
+ ```
119
+
120
+ Knobs: `--v`, `--gauge-size`, `--gauge-sweep` (default 270deg), `--gauge-from`,
121
+ `--gauge-dot`.
122
+
123
+ ### `.ui-readout` — big dot-matrix numeric
124
+
125
+ The row wrapper produced by `renderReadout` (see `docs/glyphs.md`) — a Nothing-style
126
+ hero numeric composed from digit glyphs. Tune character spacing with
127
+ `--readout-gap`; spaces render as a `.ui-readout__spacer` of width `--readout-space`.
128
+
129
+ ### `.ui-spark--dots`
130
+
131
+ A modifier on the inline `ui-spark` dataword (`@ponchia/ui/css/spark.css`) that
132
+ renders each bar as a stack of dots instead of a solid bar — same `--v` contract.
133
+
134
+ ## Responsive density — `.ui-dotfit`
135
+
136
+ Wrap a dot surface in `.ui-dotfit` to make it respond to its **container** (the
137
+ card) rather than the viewport, via a container query — so the same component
138
+ reads well in a wide hero and a narrow tile without per-instance overrides.
139
+
140
+ ## Accessibility, forced colors & print
141
+
142
+ Lit/dim/accent encode meaning via background-color, which Windows High Contrast
143
+ Mode flattens — the dot surfaces opt out of forced-color remapping and pin lit
144
+ states to distinct system colours (the activity ramp collapses to present vs
145
+ absent). The data surfaces also set `print-color-adjust: exact` so their fills
146
+ survive printing. Animations honour `prefers-reduced-motion`.
package/docs/glyphs.md ADDED
@@ -0,0 +1,114 @@
1
+ # Display glyphs
2
+
3
+ `@ponchia/ui/glyphs` is a small, frozen bitmap icon set rendered on the same
4
+ `.ui-dotmatrix` dot primitive as every other dot surface (see `docs/dots.md`).
5
+ CSS-first to the core: a glyph is just a grid of dot cells — `.` off, `#` hot,
6
+ `*` accent — so it re-skins with the same `--field-dot*` tokens and the Tier-3
7
+ display knobs as the rest of the dot family. No icon font, no SVG sprite, no
8
+ runtime dependency. The module is side-effect-free and SSR-safe (`renderGlyph`
9
+ returns a string; nothing touches the DOM).
10
+
11
+ ```js
12
+ import { renderGlyph } from '@ponchia/ui/glyphs';
13
+ el.innerHTML = renderGlyph('check', { label: 'Done' });
14
+ ```
15
+
16
+ The authoritative API is the generated, CI-drift-checked `glyphs/glyphs.d.ts`.
17
+ Read it before guessing a name — `GlyphName` is a literal union, so a typo is a
18
+ type error.
19
+
20
+ ## Three render paths
21
+
22
+ A glyph can be drawn three ways; pick by size regime.
23
+
24
+ | Path | Call | DOM | When |
25
+ | --- | --- | --- | --- |
26
+ | Dot display | `renderGlyph(name)` | `GLYPH_SIZE²` cells (256) | the signature dot-matrix look at display sizes |
27
+ | Solid pixel | `renderGlyph(name, { solid: true })` | 256 cells, fused | legible crisp icon at small/inline sizes (~16–24px) |
28
+ | Mask icon | `renderGlyph(name, { render: 'mask' })` | **one** `.ui-icon` node | icon-at-scale (e.g. one per table row): inherits `currentColor`, scales with the text |
29
+
30
+ The mask path is the lightest — one node instead of 256 — and the right default
31
+ for an icon repeated many times. It is single-tone: an accent `*` cell renders
32
+ the same as a hot `#` cell (both become opaque mask regions).
33
+
34
+ > Pixel-crisp sizes: the bitmap is a 16-unit grid, so the dot/solid paths look
35
+ > sharpest at integer multiples (16/32/48/64px). The mask path scales smoothly
36
+ > with the text; arbitrary `em` sizes soften the edges slightly, which is fine
37
+ > for inline use.
38
+
39
+ ### `renderGlyph(name, options)`
40
+
41
+ | Option | Type | Default | Effect |
42
+ | --- | --- | --- | --- |
43
+ | `grid` | boolean | `true` | show the unlit panel dots; `false` → glyph-only |
44
+ | `solid` | boolean | `false` | square, gapless pixels (implies glyph-only) |
45
+ | `anim` | `'reveal' \| 'pulse'` | — | decorative animation (reduced-motion-safe) |
46
+ | `label` | string | — | expose as `role="img"` with this name; omit → decorative (`aria-hidden`) |
47
+ | `dot` | CSS length | `0.08em` | one dot size (`--dotmatrix-dot`; sanitized) |
48
+ | `gap` | CSS length | — | gap between dots (`--dotmatrix-gap`; sanitized) |
49
+ | `render` | `'mask'` | — | the one-node `.ui-icon` path |
50
+ | `size` | CSS length | `1em` | with `render: 'mask'`, the icon size (`--icon-size`) |
51
+
52
+ ## Big numeric readout — `renderReadout`
53
+
54
+ Compose digits and punctuation into a row of dot-matrix glyphs — the
55
+ Nothing-style hero numeric for a KPI, clock, countdown, or percentage.
56
+
57
+ ```js
58
+ import { renderReadout } from '@ponchia/ui/glyphs';
59
+ el.innerHTML = renderReadout('12:48', { label: '12:48 remaining' });
60
+ el.innerHTML = renderReadout('73%', { label: '73 percent of quota', render: 'mask' });
61
+ ```
62
+
63
+ Recognised characters: `0-9`, `:`, `,`, `.`, `%`, `-`, `+`, and space (a blank
64
+ advance). Anything else is skipped. Every per-glyph option (`solid`, `render`,
65
+ `dot`, `gap`, `anim`) passes through to each character; `gap` sets the spacing
66
+ between characters. The digits are decorative — the readout's **value** is its
67
+ accessible name, so pass a `label` (it defaults to the raw text). Output wraps
68
+ in `.ui-readout` (see `docs/dots.md`).
69
+
70
+ ## Finding a glyph — `findGlyphs` / `GLYPH_TAGS`
71
+
72
+ Names follow the "depict, don't name the purpose" convention (`trash`, not
73
+ `delete`). `findGlyphs(query)` resolves an intent word to real names by matching
74
+ the name OR a curated search alias (`GLYPH_TAGS`), case-insensitively:
75
+
76
+ ```js
77
+ import { findGlyphs } from '@ponchia/ui/glyphs';
78
+ findGlyphs('delete'); // → ['trash']
79
+ findGlyphs('chart'); // → ['bar-chart']
80
+ findGlyphs(''); // → every name
81
+ ```
82
+
83
+ ## DOM placeholders — `initDotGlyph`
84
+
85
+ When you would rather drop a placeholder than inline markup, the optional
86
+ `initDotGlyph` behavior (`@ponchia/ui/behaviors`) expands
87
+ `[data-bronto-glyph="name"]` in place. It is idempotent and returns a cleanup.
88
+
89
+ | Attribute | Value | Effect |
90
+ | --- | --- | --- |
91
+ | `data-bronto-glyph` | glyph name | expand into a `.ui-dotmatrix` grid |
92
+ | `data-bronto-glyph-label` | text | expose as `role="img"`; omit → decorative |
93
+ | `data-bronto-glyph-solid` | — | square, gapless pixel glyph |
94
+ | `data-bronto-glyph-anim` | `reveal \| pulse` | decorative animation |
95
+ | `data-bronto-glyph-render` | `mask` | the one-node `.ui-icon` path (not 256 cells) |
96
+ | `data-bronto-glyph-size` | CSS length | with `render="mask"`, sets `--icon-size` |
97
+
98
+ An unknown name is left untouched.
99
+
100
+ ## Accessibility
101
+
102
+ - A glyph next to a text label is redundant → keep it decorative (`aria-hidden`,
103
+ the default).
104
+ - An icon-only control labels the **control** (`aria-label` on the `<button>`),
105
+ not the glyph.
106
+ - A standalone meaningful glyph passes `label` → `role="img"` + `aria-label`.
107
+ - A cell-mode glyph is a sea of 256 nodes; the wrapper carries the single
108
+ `role="img"`/`aria-hidden`, so assistive tech never walks the cells.
109
+
110
+ ## Two-tone glyphs
111
+
112
+ The accent (`*`) tone lifts one feature of a glyph onto `--field-dot-accent`.
113
+ The curated two-tone set is `spark`, `warning`, and `info`; every other glyph is
114
+ monotone. Two-tone only shows in the cell render — the mask path is single-tone.
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
- - 529 classes across 161 component groups
12
+ - 540 classes across 167 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`,
@@ -31,6 +31,12 @@ each one matches a real selector in the stylesheet.
31
31
  | `cls.accordionItem` | `ui-accordion__item` | part |
32
32
  | `cls.accordionSummary` | `ui-accordion__summary` | part |
33
33
 
34
+ ### `.ui-activity`
35
+
36
+ | Registry key | Class | Kind |
37
+ | --- | --- | --- |
38
+ | `cls.activity` | `ui-activity` | base |
39
+
34
40
  ### `.ui-alert`
35
41
 
36
42
  | Registry key | Class | Kind |
@@ -486,6 +492,18 @@ each one matches a real selector in the stylesheet.
486
492
  | --- | --- | --- |
487
493
  | `cls.dotfield` | `ui-dotfield` | base |
488
494
 
495
+ ### `.ui-dotfit`
496
+
497
+ | Registry key | Class | Kind |
498
+ | --- | --- | --- |
499
+ | `cls.dotfit` | `ui-dotfit` | base |
500
+
501
+ ### `.ui-dotgauge`
502
+
503
+ | Registry key | Class | Kind |
504
+ | --- | --- | --- |
505
+ | `cls.dotgauge` | `ui-dotgauge` | base |
506
+
489
507
  ### `.ui-dotgrid`
490
508
 
491
509
  | Registry key | Class | Kind |
@@ -580,6 +598,12 @@ each one matches a real selector in the stylesheet.
580
598
  | --- | --- | --- |
581
599
  | `cls.grid` | `ui-grid` | base |
582
600
 
601
+ ### `.ui-halftone`
602
+
603
+ | Registry key | Class | Kind |
604
+ | --- | --- | --- |
605
+ | `cls.halftone` | `ui-halftone` | base |
606
+
583
607
  ### `.ui-hint`
584
608
 
585
609
  | Registry key | Class | Kind |
@@ -679,6 +703,14 @@ each one matches a real selector in the stylesheet.
679
703
  | `cls.legendVertical` | `ui-legend--vertical` | modifier |
680
704
  | `cls.legendWithValues` | `ui-legend--with-values` | modifier |
681
705
 
706
+ ### `.ui-level`
707
+
708
+ | Registry key | Class | Kind |
709
+ | --- | --- | --- |
710
+ | `cls.level` | `ui-level` | base |
711
+ | `cls.levelDanger` | `ui-level--danger` | modifier |
712
+ | `cls.levelWarn` | `ui-level--warn` | modifier |
713
+
682
714
  ### `.ui-lightbox`
683
715
 
684
716
  | Registry key | Class | Kind |
@@ -893,6 +925,7 @@ each one matches a real selector in the stylesheet.
893
925
  | Registry key | Class | Kind |
894
926
  | --- | --- | --- |
895
927
  | `cls.readout` | `ui-readout` | base |
928
+ | `cls.readoutSpacer` | `ui-readout__spacer` | part |
896
929
 
897
930
  ### `.ui-reasoning`
898
931
 
@@ -1075,6 +1108,7 @@ each one matches a real selector in the stylesheet.
1075
1108
  | `cls.sparkBarAccent` | `ui-spark__bar--accent` | modifier |
1076
1109
  | `cls.sparkBarNeg` | `ui-spark__bar--neg` | modifier |
1077
1110
  | `cls.sparkBarPos` | `ui-spark__bar--pos` | modifier |
1111
+ | `cls.sparkDots` | `ui-spark--dots` | modifier |
1078
1112
 
1079
1113
  ### `.ui-spinner`
1080
1114
 
@@ -1204,6 +1238,7 @@ each one matches a real selector in the stylesheet.
1204
1238
  | `cls.tableSelect` | `ui-table__select` | part |
1205
1239
  | `cls.tableSort` | `ui-table__sort` | part |
1206
1240
  | `cls.tableToolbar` | `ui-table__toolbar` | part |
1241
+ | `cls.tableBreakAnywhere` | `ui-table--break-anywhere` | modifier |
1207
1242
  | `cls.tableComfortable` | `ui-table--comfortable` | modifier |
1208
1243
  | `cls.tableDense` | `ui-table--dense` | modifier |
1209
1244
  | `cls.tableLined` | `ui-table--lined` | modifier |
@@ -1356,6 +1391,12 @@ each one matches a real selector in the stylesheet.
1356
1391
  | --- | --- | --- |
1357
1392
  | `cls.vt` | `ui-vt` | base |
1358
1393
 
1394
+ ### `.ui-waffle`
1395
+
1396
+ | Registry key | Class | Kind |
1397
+ | --- | --- | --- |
1398
+ | `cls.waffle` | `ui-waffle` | base |
1399
+
1359
1400
  ## Table-local state classes
1360
1401
 
1361
1402
  Not in `cls` by design — these are plain `is-*` state hooks scoped to
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.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" />
40
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/bronto.css" />
41
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/css/report.css" />
42
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/css/dataviz.css" />
43
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/css/annotations.css" />
44
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/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
@@ -150,6 +150,10 @@ they are all safe in the static, PDF-first report path.
150
150
  `ui-alert` for persistent notices, `ui-table` for structured evidence,
151
151
  `ui-timeline` for events, `ui-meter` for measured values, and `ui-num` for
152
152
  non-table numeric values.
153
+ - In alerts, put the readable message in `<p class="ui-alert__body">…</p>`
154
+ and use `ui-alert__title` only for a separate title line. `ui-alert` is a
155
+ grid with a leading status dot; raw text or loose inline children such as
156
+ `<strong>` / `<code>` become separate grid items and can fragment in print.
153
157
  - Give `ui-report__finding` blocks an accessible name so the visual grouping is
154
158
  also programmatic: point `aria-labelledby` at the block's `ui-eyebrow` label
155
159
  (give it an `id`), or lead with a real heading. Do the same for a
@@ -167,6 +171,10 @@ they are all safe in the static, PDF-first report path.
167
171
  inside `ui-prose`; use `.ui-table` for curated evidence tables. If a
168
172
  `ui-report__evidence` block contains only a `ui-table-wrap`, the report layer
169
173
  removes the inner frame so evidence tables do not look double-boxed.
174
+ Report tables preserve words by default so identifiers and headings do not
175
+ split into unreadable fragments in PDF. Add `ui-table--break-anywhere` only
176
+ for machine-token tables where avoiding horizontal overflow matters more than
177
+ preserving words.
170
178
  - Every `<figure>` should include a `figcaption` using `ui-report__caption`.
171
179
  - Do not use raw color values. Theme with `--accent`; use status tones for
172
180
  status; use chart tokens only in chart figures.
@@ -589,9 +597,10 @@ need a full automatable browser, only a Chromium-class layout+print pass.
589
597
  - **By hand:** open the report in Chrome/Edge → Print (Cmd/Ctrl+P) → "Save as
590
598
  PDF". In **More settings**, enable **Background graphics** (the dialog's
591
599
  equivalent of `printBackground` — without it chart fills and swatches drop
592
- out), and pick the paper size there. Paper size is a browser print setting,
593
- not a token; the layer only themes the page _margin_ via
594
- `--report-page-margin`.
600
+ out), and pick the paper size there. Paper size and page margins are browser
601
+ print settings; the report stylesheet uses a fixed 18mm `@page` margin because
602
+ Chromium-class print engines do not reliably resolve custom properties inside
603
+ `@page` rules.
595
604
  - **Headless, lightweight:** use **`chrome-headless-shell`** — the minimal
596
605
  headless-Chromium binary built for exactly this, a fraction of a full
597
606
  browser's weight. Drive it through Playwright/Puppeteer (or raw CDP) and
@@ -662,3 +671,5 @@ Before returning a report, an LLM should verify:
662
671
  - No raw chromatic colors appear in inline styles.
663
672
  - No remote scripts, styles, iframes, or images are required for the report.
664
673
  - Generated/untrusted body HTML was sanitized before insertion.
674
+ - Alert text is wrapped in `.ui-alert__body`; no loose text or inline-only
675
+ elements are direct children of `.ui-alert`.
@@ -8,7 +8,9 @@ export type GlyphName =
8
8
  | 'arrow-left'
9
9
  | 'arrow-right'
10
10
  | 'arrow-up'
11
+ | 'bar-chart'
11
12
  | 'bell'
13
+ | 'calendar'
12
14
  | 'check'
13
15
  | 'check-circle'
14
16
  | 'chevron-down'
@@ -18,14 +20,30 @@ export type GlyphName =
18
20
  | 'circle'
19
21
  | 'clock'
20
22
  | 'close'
23
+ | 'colon'
24
+ | 'comma'
25
+ | 'copy'
26
+ | 'database'
27
+ | 'digit-0'
28
+ | 'digit-1'
29
+ | 'digit-2'
30
+ | 'digit-3'
31
+ | 'digit-4'
32
+ | 'digit-5'
33
+ | 'digit-6'
34
+ | 'digit-7'
35
+ | 'digit-8'
36
+ | 'digit-9'
21
37
  | 'download'
22
38
  | 'edit'
23
39
  | 'eye'
24
40
  | 'eye-off'
25
41
  | 'file'
42
+ | 'filter'
26
43
  | 'folder'
27
44
  | 'gear'
28
45
  | 'grid'
46
+ | 'hash'
29
47
  | 'heart'
30
48
  | 'home'
31
49
  | 'info'
@@ -39,11 +57,16 @@ export type GlyphName =
39
57
  | 'more-horizontal'
40
58
  | 'more-vertical'
41
59
  | 'pause'
60
+ | 'percent'
61
+ | 'period'
42
62
  | 'play'
43
63
  | 'plus'
44
64
  | 'plus-circle'
45
65
  | 'refresh'
46
66
  | 'search'
67
+ | 'share'
68
+ | 'sliders'
69
+ | 'sort'
47
70
  | 'spark'
48
71
  | 'star'
49
72
  | 'sun'
@@ -111,5 +134,43 @@ export declare function glyph(name: GlyphNameInput): Glyph | undefined;
111
134
  /** 256 cell descriptors (row-major), or `[]` if unknown. */
112
135
  export declare function glyphCells(name: GlyphNameInput): GlyphCell[];
113
136
 
137
+ /** The CSS `mask-image` `url()` for a glyph (the `--icon-mask` value on a
138
+ * `.ui-icon`), or `''` if unknown. Single-tone. */
139
+ export declare function glyphMask(name: GlyphNameInput): string;
140
+
114
141
  /** A full `.ui-dotmatrix` HTML string for a glyph (`''` if unknown). */
115
142
  export declare function renderGlyph(name: GlyphNameInput, options?: RenderGlyphOptions): string;
143
+
144
+ /** Hand-curated intent→glyph search aliases (e.g. `trash`→`delete`/`remove`).
145
+ * Keys are real glyph names; values are extra search terms. */
146
+ export declare const GLYPH_TAGS: Readonly<Partial<Record<GlyphName, readonly string[]>>>;
147
+
148
+ /** Glyph names whose name OR a search alias contains `query` (case-insensitive),
149
+ * sorted. `findGlyphs('')` returns every name. */
150
+ export declare function findGlyphs(query: string): GlyphName[];
151
+
152
+ /** Options for renderReadout. The per-glyph fields pass through to renderGlyph
153
+ * for each character; `gap` sets `--readout-gap` on the row. */
154
+ export interface RenderReadoutOptions {
155
+ /** Accessible name for the whole readout (defaults to the raw text). The dot
156
+ * digits are decorative; this carries the real value. */
157
+ label?: string;
158
+ /** CSS length between characters (sets `--readout-gap`; sanitized). */
159
+ gap?: string;
160
+ /** Render each character as square gapless pixels (legible small). */
161
+ solid?: boolean;
162
+ /** Show the unlit panel dots behind each character (default true). */
163
+ grid?: boolean;
164
+ /** Decorative per-character animation (reduced-motion-safe). */
165
+ anim?: 'reveal' | 'pulse';
166
+ /** CSS length for one dot of each character (sets `--dotmatrix-dot`). */
167
+ dot?: string;
168
+ /** `'mask'` renders each character as a single `.ui-icon` node (lightest). */
169
+ render?: 'mask';
170
+ /** With `render: 'mask'`, the per-character icon size. */
171
+ size?: string;
172
+ }
173
+
174
+ /** A row of dot-matrix glyphs for a numeric string (digits + `: , . % - +` and
175
+ * space) — the big Nothing-style readout. `''` for empty input. */
176
+ export declare function renderReadout(text: string, options?: RenderReadoutOptions): string;