@ponchia/ui 0.4.1 → 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 +552 -8
- package/MIGRATIONS.json +106 -0
- package/README.md +34 -8
- package/annotations/index.d.ts +402 -0
- package/annotations/index.d.ts.map +1 -0
- package/annotations/index.js +792 -0
- package/behaviors/carousel.js +198 -0
- package/behaviors/combobox.js +226 -0
- package/behaviors/command.js +190 -0
- package/behaviors/connectors.js +95 -0
- package/behaviors/crosshair.js +57 -0
- package/behaviors/dialog.js +74 -0
- package/behaviors/disclosure.js +26 -0
- package/behaviors/dismissible.js +25 -0
- package/behaviors/forms.js +186 -0
- package/behaviors/glyph.js +108 -0
- package/behaviors/index.d.ts +79 -0
- package/behaviors/index.js +18 -1409
- package/behaviors/internal.js +97 -0
- package/behaviors/legend.js +67 -0
- package/behaviors/menu.js +47 -0
- package/behaviors/popover.js +179 -0
- package/behaviors/spotlight.js +52 -0
- package/behaviors/table.js +136 -0
- package/behaviors/tabs.js +103 -0
- package/behaviors/theme.js +84 -0
- package/behaviors/toast.js +164 -0
- package/classes/classes.json +1857 -0
- package/classes/index.d.ts +306 -13
- package/classes/index.js +339 -12
- package/classes/vscode.css-custom-data.json +12 -0
- package/connectors/index.d.ts +191 -0
- package/connectors/index.d.ts.map +1 -0
- package/connectors/index.js +275 -0
- package/css/analytical.css +21 -0
- package/css/annotations.css +292 -0
- package/css/app.css +43 -13
- package/css/base.css +15 -10
- package/css/command.css +97 -0
- package/css/connectors.css +110 -0
- package/css/content.css +7 -1
- package/css/crosshair.css +100 -0
- package/css/dataviz.css +5 -1
- package/css/disclosure.css +38 -6
- package/css/dots.css +57 -0
- package/css/feedback.css +111 -2
- package/css/fonts.css +11 -7
- package/css/forms.css +42 -1
- package/css/generated.css +117 -0
- package/css/legend.css +272 -0
- package/css/marks.css +174 -0
- package/css/motion.css +24 -44
- package/css/navigation.css +7 -0
- package/css/overlay.css +31 -1
- package/css/primitives.css +109 -5
- package/css/report.css +39 -81
- package/css/selection.css +46 -0
- package/css/site.css +16 -2
- package/css/sources.css +221 -0
- package/css/spotlight.css +104 -0
- package/css/state.css +121 -0
- package/css/tokens.css +60 -37
- package/css/workbench.css +83 -0
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -0
- package/dist/css/annotations.css +1 -0
- package/dist/css/app.css +1 -1
- package/dist/css/base.css +1 -1
- package/dist/css/command.css +1 -0
- package/dist/css/connectors.css +1 -0
- package/dist/css/content.css +1 -1
- package/dist/css/crosshair.css +1 -0
- package/dist/css/disclosure.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/fonts.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/generated.css +1 -0
- package/dist/css/legend.css +1 -0
- package/dist/css/marks.css +1 -0
- 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/selection.css +1 -0
- package/dist/css/site.css +1 -1
- package/dist/css/sources.css +1 -0
- package/dist/css/spotlight.css +1 -0
- package/dist/css/state.css +1 -0
- package/dist/css/tokens.css +1 -1
- package/dist/css/workbench.css +1 -0
- package/docs/adr/0003-theme-model.md +7 -4
- package/docs/annotations.md +425 -0
- package/docs/architecture.md +246 -0
- package/docs/command.md +95 -0
- package/docs/connectors.md +91 -0
- package/docs/contrast.md +116 -92
- package/docs/crosshair.md +63 -0
- package/docs/d2.md +195 -0
- package/docs/generated.md +91 -0
- package/docs/legends.md +184 -0
- package/docs/marks.md +93 -0
- package/docs/mermaid.md +152 -0
- package/docs/reference.md +385 -23
- package/docs/reporting.md +436 -63
- package/docs/selection.md +40 -0
- package/docs/sources.md +137 -0
- package/docs/spotlight.md +78 -0
- package/docs/stability.md +24 -2
- package/docs/state.md +85 -0
- package/docs/usage.md +123 -4
- package/docs/vega.md +225 -0
- package/docs/workbench.md +78 -0
- package/fonts/doto-400.woff2 +0 -0
- package/fonts/doto-500.woff2 +0 -0
- package/fonts/doto-600.woff2 +0 -0
- package/fonts/doto-700.woff2 +0 -0
- package/fonts/doto-800.woff2 +0 -0
- package/fonts/doto-900.woff2 +0 -0
- package/glyphs/glyphs.js +6 -4
- package/llms.txt +362 -14
- package/package.json +115 -12
- package/qwik/index.d.ts +42 -54
- package/qwik/index.d.ts.map +1 -0
- package/qwik/index.js +75 -3
- package/react/index.d.ts +39 -56
- package/react/index.d.ts.map +1 -0
- package/react/index.js +67 -3
- package/solid/index.d.ts +64 -56
- package/solid/index.d.ts.map +1 -0
- package/solid/index.js +70 -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 +23 -5
- 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/fonts/doto-400.ttf +0 -0
- package/fonts/doto-500.ttf +0 -0
- package/fonts/doto-600.ttf +0 -0
- package/fonts/doto-700.ttf +0 -0
- package/fonts/doto-800.ttf +0 -0
- package/fonts/doto-900.ttf +0 -0
package/docs/sources.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Sources, citations & provenance
|
|
2
|
+
|
|
3
|
+
`@ponchia/ui/css/sources.css` is an opt-in **trust layer** for generated
|
|
4
|
+
reports, AI output, audits, and docs — the grammar that answers _"where did
|
|
5
|
+
this come from?"_. Generic UI kits have tags and footnotes; this is a small,
|
|
6
|
+
explicit vocabulary for sources and their trust state.
|
|
7
|
+
|
|
8
|
+
```css
|
|
9
|
+
@import '@ponchia/ui';
|
|
10
|
+
@import '@ponchia/ui/css/sources.css';
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Bronto owns the visual grammar and the trust **states**. The host owns fetching,
|
|
14
|
+
citation numbering, permission checks, and whether a source is actually
|
|
15
|
+
trustworthy. The state is carried by a rationed tone **and** an author-written
|
|
16
|
+
label, so it never relies on colour alone (WCAG 1.4.1). Not in the core bundle.
|
|
17
|
+
|
|
18
|
+
## Trust states
|
|
19
|
+
|
|
20
|
+
A cross-cutting trust-state class — `ui-src--verified`, `ui-src--stale`, and the
|
|
21
|
+
rest in the table below — sets the tone on a citation chip, source card, or
|
|
22
|
+
provenance item. Always pair it with a word: the colour is a second channel, not
|
|
23
|
+
the only one.
|
|
24
|
+
|
|
25
|
+
| State | Class | Tone |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| Verified | `ui-src--verified` | success |
|
|
28
|
+
| Reviewed (by a human) | `ui-src--reviewed` | accent |
|
|
29
|
+
| Generated | `ui-src--generated` | info |
|
|
30
|
+
| Unverified | `ui-src--unverified` | muted |
|
|
31
|
+
| Stale | `ui-src--stale` | warning |
|
|
32
|
+
| Conflict | `ui-src--conflict` | danger |
|
|
33
|
+
|
|
34
|
+
A trust-state class **needs a host element** — on its own a tone class
|
|
35
|
+
(`ui-src--verified` and the rest) only sets a `--src-tone`, it does not draw
|
|
36
|
+
anything. The host is one of the elements below, or the standalone `.ui-src`
|
|
37
|
+
pill.
|
|
38
|
+
|
|
39
|
+
## Standalone trust pill — `.ui-src`
|
|
40
|
+
|
|
41
|
+
When you just need a bare labelled chip (a row of provenance tags, an inline
|
|
42
|
+
"verified" badge) with no surrounding card or citation, use `.ui-src` as the
|
|
43
|
+
host and add a tone. It draws a small pill with a leading trust dot:
|
|
44
|
+
|
|
45
|
+
```html
|
|
46
|
+
<span class="ui-src ui-src--verified">Verified</span>
|
|
47
|
+
<span class="ui-src ui-src--generated">AI-generated</span>
|
|
48
|
+
<span class="ui-src ui-src--stale">Stale · 14d</span>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The base `.ui-src` is required — `<span class="ui-src--verified">` alone
|
|
52
|
+
**validates against `classes.json` but renders nothing**, because the tone class
|
|
53
|
+
only carries the colour for a host to consume. The word inside is the channel
|
|
54
|
+
(WCAG 1.4.1); the dot and tint are reinforcement. Reach for `.ui-citation--chip`
|
|
55
|
+
instead when the pill is a real link/button to the source.
|
|
56
|
+
|
|
57
|
+
## Inline citation — `.ui-citation`
|
|
58
|
+
|
|
59
|
+
A reference marker on a real `<a>` or `<button>` (the visual index is never the
|
|
60
|
+
only label — give it an accessible name).
|
|
61
|
+
|
|
62
|
+
```html
|
|
63
|
+
<p>
|
|
64
|
+
Latency fell 38%<a class="ui-citation" href="#s1" aria-label="Source 1">[1]</a>.
|
|
65
|
+
</p>
|
|
66
|
+
|
|
67
|
+
<!-- Named-source pill, with a leading trust dot: -->
|
|
68
|
+
<a class="ui-citation ui-citation--chip ui-src--verified" href="#s1">
|
|
69
|
+
Q3 incident review
|
|
70
|
+
</a>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Source card — `.ui-source-card`
|
|
74
|
+
|
|
75
|
+
A single source preview: title, origin, time, excerpt, actions. The
|
|
76
|
+
`border-inline-start` carries the trust tone.
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<article class="ui-source-card ui-src--generated">
|
|
80
|
+
<h3 class="ui-source-card__title">Model output — pricing summary</h3>
|
|
81
|
+
<p class="ui-source-card__origin">gpt-x · internal</p>
|
|
82
|
+
<p class="ui-source-card__time">2026-06-01 09:42</p>
|
|
83
|
+
<p class="ui-source-card__excerpt">The migration cut p95 latency by 38%…</p>
|
|
84
|
+
<div class="ui-source-card__actions">
|
|
85
|
+
<button class="ui-button ui-button--subtle ui-button--sm" type="button">Open</button>
|
|
86
|
+
</div>
|
|
87
|
+
</article>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The parts are `__title`, `__origin`, `__time`, `__excerpt` (the body text — not
|
|
91
|
+
`__detail`/`__body`), and `__actions`. A card nests inside a
|
|
92
|
+
`ui-source-list__item` when it sits in a references section (below).
|
|
93
|
+
|
|
94
|
+
## Source list — `.ui-source-list`
|
|
95
|
+
|
|
96
|
+
A references section: a reset list of source cards (or rows).
|
|
97
|
+
|
|
98
|
+
```html
|
|
99
|
+
<ol class="ui-source-list">
|
|
100
|
+
<li class="ui-source-list__item"><article class="ui-source-card ui-src--verified">…</article></li>
|
|
101
|
+
<li class="ui-source-list__item"><article class="ui-source-card ui-src--stale">…</article></li>
|
|
102
|
+
</ol>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Provenance — `.ui-provenance`
|
|
106
|
+
|
|
107
|
+
A compact metadata row beside generated content — each `__item` carries a trust
|
|
108
|
+
dot and a label.
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<p class="ui-provenance">
|
|
112
|
+
<span class="ui-provenance__item ui-src--generated">Generated</span>
|
|
113
|
+
<span class="ui-provenance__item ui-src--verified">3 sources</span>
|
|
114
|
+
<span class="ui-provenance__item ui-src--reviewed">Human-reviewed</span>
|
|
115
|
+
</p>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Recipes
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
import { ui } from '@ponchia/ui/classes';
|
|
122
|
+
|
|
123
|
+
ui.citation({ chip: true, state: 'verified' });
|
|
124
|
+
// "ui-citation ui-citation--chip ui-src--verified"
|
|
125
|
+
ui.source({ state: 'generated' }); // "ui-source-card ui-src--generated"
|
|
126
|
+
ui.provenance({ state: 'reviewed' }); // "ui-provenance ui-src--reviewed"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Accessibility & print
|
|
130
|
+
|
|
131
|
+
- A citation must be a real link or button with a stable accessible name; the
|
|
132
|
+
bracketed index alone is not enough.
|
|
133
|
+
- The trust state must be readable as text — the tone dot/border is decorative
|
|
134
|
+
reinforcement. Under `forced-colors`, dots and borders fall back to
|
|
135
|
+
`CanvasText`, so the label remains the channel.
|
|
136
|
+
- Tone dots and the card's tone border carry `print-color-adjust: exact`, so
|
|
137
|
+
they survive printing; expand citation URLs in print where it helps the reader.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Spotlight (guided focus)
|
|
2
|
+
|
|
3
|
+
`@ponchia/ui/css/spotlight.css` is an opt-in **guided-focus overlay** — a
|
|
4
|
+
dimming layer with a cutout over a target element, an optional ring, and a
|
|
5
|
+
callout note. It's the *visual language* of a product tour or onboarding step.
|
|
6
|
+
|
|
7
|
+
```css
|
|
8
|
+
@import '@ponchia/ui';
|
|
9
|
+
@import '@ponchia/ui/css/spotlight.css';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Bronto is not a tour engine.** It owns the look and (via `initSpotlight`)
|
|
13
|
+
positions the cutout over a target. Step order, advancing, persistence, and
|
|
14
|
+
whether the overlay is shown are the host's job — Bronto deliberately stays out
|
|
15
|
+
of that state machine.
|
|
16
|
+
|
|
17
|
+
## Markup
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<div
|
|
21
|
+
class="ui-spotlight ui-spotlight--ring"
|
|
22
|
+
data-bronto-spotlight
|
|
23
|
+
data-target="save-button"
|
|
24
|
+
role="region"
|
|
25
|
+
aria-label="Tour"
|
|
26
|
+
>
|
|
27
|
+
<div class="ui-spotlight__hole"></div>
|
|
28
|
+
|
|
29
|
+
<div class="ui-tour-note" style="position: absolute; …place near the hole…">
|
|
30
|
+
<span class="ui-tour-note__step">Step 2 of 4</span>
|
|
31
|
+
<h2 class="ui-tour-note__title">Save your work</h2>
|
|
32
|
+
<p class="ui-tour-note__body">Changes autosave, but you can force a save here.</p>
|
|
33
|
+
<div class="ui-tour-note__actions">
|
|
34
|
+
<button class="ui-button ui-button--ghost" type="button">Skip</button>
|
|
35
|
+
<button class="ui-button" type="button">Next</button>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import { initSpotlight } from '@ponchia/ui/behaviors';
|
|
43
|
+
const stop = initSpotlight(); // positions the cutout; re-places on resize/scroll
|
|
44
|
+
// Advance the tour by pointing at the next target — the cutout follows:
|
|
45
|
+
document.querySelector('[data-bronto-spotlight]').dataset.target = 'next-thing';
|
|
46
|
+
// Hide it when the tour ends (host-owned):
|
|
47
|
+
document.querySelector('[data-bronto-spotlight]').hidden = true;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Pieces
|
|
51
|
+
|
|
52
|
+
| Class | Role |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `ui-spotlight` | The fixed overlay. Non-blocking (`pointer-events: none`) — a visual highlight, not a modal trap. |
|
|
55
|
+
| `ui-spotlight__hole` | The cutout. Dims the page via one box-shadow; positioned by `--spot-x/y/w/h`. |
|
|
56
|
+
| `ui-spotlight--ring` | Adds an accent ring around the cutout. |
|
|
57
|
+
| `ui-tour-note` | The callout card (re-enables pointer events for its controls). |
|
|
58
|
+
| `ui-tour-note__step` / `__title` / `__body` / `__actions` | Callout parts. |
|
|
59
|
+
|
|
60
|
+
`ui.spotlight({ ring })` builds the overlay class string.
|
|
61
|
+
|
|
62
|
+
## How positioning works
|
|
63
|
+
|
|
64
|
+
`initSpotlight` reads each `[data-bronto-spotlight]`'s `data-target` id, measures
|
|
65
|
+
that element with `getBoundingClientRect`, and sets `--spot-x/y/w/h` (viewport
|
|
66
|
+
coordinates) on the overlay. Because the overlay is `position: fixed`, those map
|
|
67
|
+
directly. It re-places on resize, scroll, and whenever `data-target` changes —
|
|
68
|
+
so stepping a tour is just updating `data-target`. `--spot-pad` insets the
|
|
69
|
+
cutout from the target; `--spot-radius` rounds it.
|
|
70
|
+
|
|
71
|
+
## Accessibility notes
|
|
72
|
+
|
|
73
|
+
- The overlay is **non-blocking by design** (the dim is a box-shadow, not an
|
|
74
|
+
interaction trap). If a step must block interaction, that's a host concern —
|
|
75
|
+
add your own inert/`aria-hidden` handling around it.
|
|
76
|
+
- Put the tour's real content in `.ui-tour-note` (a focusable region with a
|
|
77
|
+
heading), not in the visual dim, so screen-reader users get the same guidance.
|
|
78
|
+
- Keep the callout's label stable and move focus to it when a step opens (host).
|
package/docs/stability.md
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
# Public API Stability
|
|
2
2
|
|
|
3
3
|
`@ponchia/ui` is pre-1.0. Breaking changes ship in the minor (`0.x.0`), and
|
|
4
|
-
patches are non-breaking.
|
|
4
|
+
patches are non-breaking. In practical terms: **PATCH releases (`0.5.x`) are
|
|
5
|
+
non-breaking bug-fixes and additive changes — safe to upgrade without review;
|
|
6
|
+
MINOR releases (`0.x.0`) may include breaking changes and consumers should
|
|
7
|
+
review the CHANGELOG before upgrading.** Pin `~0.x` (tilde) to accept only
|
|
8
|
+
patches, or `^0.x` only if you accept minor-level churn. This policy holds
|
|
9
|
+
until `1.0.0` is tagged. This matrix defines what counts as public API.
|
|
5
10
|
|
|
6
11
|
| Surface | Stability | Contract |
|
|
7
12
|
| --- | --- | --- |
|
|
@@ -9,8 +14,11 @@ patches are non-breaking. This matrix defines what counts as public API.
|
|
|
9
14
|
| JS module format | Stable | JS subpaths are ESM-only. CommonJS consumers use dynamic `import()`. |
|
|
10
15
|
| CSS class names (`.ui-*`) | Stable | Names and documented modifier semantics are public. Internal selector structure and leaf-file boundaries may change. |
|
|
11
16
|
| Class recipes (`@ponchia/ui/classes`) | Stable | Exported `cls`, `ui`, `cx`, recipe names, and option unions are public. |
|
|
17
|
+
| Class vocabulary as data (`@ponchia/ui/classes.json`) | Stable additive | The JSON shape (`groups`/`classes`/`states`/`customProperties`) and its entries are public — for validating markup from a non-JS/non-TS host. Generated from `cls` (the `classes` list cannot drift from the CSS); `states`/`customProperties` are gated against the stylesheet. New classes/hooks are additive. |
|
|
12
18
|
| Design tokens | Stable names/roles | Token names and documented roles are public. Exact values and generated colour math outputs may change for visual tuning before 1.0. |
|
|
13
19
|
| `--accent-1..6` | Stable names/roles | A subtle-to-bold accent ramp derived from `--accent`. Exact resolved values are visual tuning; algorithm changes require release-note visibility and resolver/browser checks. |
|
|
20
|
+
| Tokens as data (`tokens.json`, `tokens.dtcg.json`, `tokens/resolved.json`) | Stable additive | The JSON shapes are public for non-CSS/non-JS consumers. `resolved.json` exposes `light`/`dark` (resolved colours) and `scale` (resolved non-colour scales). Token names/roles are stable; exact resolved values are visual tuning (pin `~0.x`). |
|
|
21
|
+
| Theme axes | Mixed | `data-theme` (light/dark) is the **contractual** base. `data-surface="oled"`, `data-density`, and `data-contrast` are **convenience presets** — best-effort visual variants, **not** part of the stability contract; their presence and exact values may change for tuning. (A computed-style smoke test guards the OLED `--bg` flip; the others are unverified.) |
|
|
14
22
|
| Behavior attributes (`data-bronto-*`) | Stable | Attribute names and documented markup relationships are public. Behavior internals are not. |
|
|
15
23
|
| Behavior functions (`@ponchia/ui/behaviors`) | Stable | Exported function names, option names, custom events, SSR no-op behavior, idempotency, and cleanup-returning contract are public. |
|
|
16
24
|
| Glyph registry/renderers (`@ponchia/ui/glyphs`) | Stable additive | Existing glyph names stay valid. New glyphs are additive. Renderer option names and accessibility defaults are public. |
|
|
@@ -18,7 +26,21 @@ patches are non-breaking. This matrix defines what counts as public API.
|
|
|
18
26
|
| React/Solid/Qwik bindings | Stable thin adapters | Hook/primitive names, optional peer behavior, root ref/signal/resolver support, and cleanup lifecycle are public. They remain wrappers over vanilla behaviors, not component APIs. |
|
|
19
27
|
| Skins (`@ponchia/ui/skins`, `css/skins.css`) | Stable additive | Existing skin names stay valid. New skins are additive. Skins are root-level choices. |
|
|
20
28
|
| Charts (`@ponchia/ui/charts`, `charts.json`, `css/dataviz.css`) | Stable additive | Token names, JSON shape, and 8 categorical slots are public. Exact palette values may tune if gates and release notes justify it. |
|
|
21
|
-
| Reports (`css/report.css`, `.ui-report*`,
|
|
29
|
+
| Reports (`css/report.css`, `.ui-report*`, print utilities) | Stable additive | Report class names, BEM part names, and print utility names are public. Report CSS is opt-in and not imported by the default bundle. The data key now lives in the standalone Legends layer (below), not `css/report.css`; charting is via the Vega theme target (`@ponchia/ui/vega`, see [vega](./vega.md)) or a token-themed inline SVG, not a shipped renderer. |
|
|
30
|
+
| Annotations (`@ponchia/ui/annotations`, `css/annotations.css`, `.ui-annotation*`) | Stable additive | SVG annotation class names, recipe option names, and helper function names are public. Helper internals and exact path-control heuristics may tune before 1.0. |
|
|
31
|
+
| Legends (`css/legend.css`, `.ui-legend*`, `@ponchia/ui/behaviors` `initLegend`) | Stable additive | Legend class names, recipe option names, and the `bronto:legend:toggle` event contract (`aria-pressed="true"` ⇒ shown) are public. Opt-in, not in the default bundle; swatch colours are gated to the `--chart-*` palette. |
|
|
32
|
+
| Marks (`css/marks.css`, `.ui-mark*`, `.ui-bracket-note*`) | Stable additive | Text-mark and bracket-note class names and recipe option names are public. Opt-in, not in the default bundle. Uses semantic tones only. |
|
|
33
|
+
| Connectors (`@ponchia/ui/connectors`, `css/connectors.css`, `.ui-connector*`, `initConnectors`) | Stable additive | Connector class names, the `data-bronto-connector` attribute contract, geometry helper function names, and recipe options are public. Helper internals/heuristics may tune before 1.0. Opt-in, not in the default bundle. |
|
|
34
|
+
| Spotlight (`css/spotlight.css`, `.ui-spotlight*`, `.ui-tour-note*`, `initSpotlight`) | Stable additive | Spotlight/tour-note class names, the `--spot-*` custom-property contract, and the `data-bronto-spotlight`/`data-target` attributes are public. Opt-in, not in the default bundle. Not a tour engine. |
|
|
35
|
+
| Crosshair (`css/crosshair.css`, `.ui-crosshair*`, `.ui-readout`, `initCrosshair`) | Stable additive | Crosshair/readout class names, the `--crosshair-x/y` properties, the `data-bronto-crosshair` attribute, and the `bronto:crosshair:move`/`:leave` event contract are public. Opt-in. Reports pointer position only — no data mapping. |
|
|
36
|
+
| Selection states (`css/selection.css`, `.ui-sel*`) | Stable additive | The `.ui-sel`/`--on`/`--off`/`--maybe` emphasis classes and recipe options are public. Opt-in, cross-cutting. The host owns selection logic; Bronto only styles the states. |
|
|
37
|
+
| Analytical roll-up (`css/analytical.css`) | Stable additive | A convenience `@import` of the seven analytical leaves (annotations, legend, marks, connectors, spotlight, crosshair, selection). The set of leaves it bundles may grow additively; each leaf also stays individually exported. Opt-in, not in the default bundle. |
|
|
38
|
+
| Sources / provenance (`css/sources.css`, `.ui-citation*`, `.ui-source-card*`, `.ui-source-list*`, `.ui-provenance*`, `.ui-src--*`) | Stable additive | Citation/source/provenance class names, the cross-cutting `.ui-src--*` trust-state modifiers (always paired with an author label), and the `ui.citation`/`ui.source`/`ui.provenance` recipes + `cls.sourceList` are public. Opt-in, not in the default bundle. |
|
|
39
|
+
| Lifecycle state (`css/state.css`, `.ui-state*`, `.ui-syncbar`) | Stable additive | The `.ui-state`/`__label`/`__detail`/`--busy` classes, the canonical lifecycle state modifiers, `.ui-syncbar`, and the `ui.state` recipe are public. Opt-in, not in the default bundle. |
|
|
40
|
+
| Generated / AI-trust (`css/generated.css`, `.ui-generated*`, `.ui-origin-label*`, `.ui-reasoning*`, `.ui-tool-log`, `.ui-tool-call*`) | Stable additive | The generated-content, origin-label (incl. `--ai`), reasoning-trace and tool-log/tool-call class names and the `ui.originLabel` recipe are public. Opt-in, not in the default bundle. Not a chat kit; no confidence widget. |
|
|
41
|
+
| Workbench (`css/workbench.css`, `.ui-inspector*`, `.ui-property*`, `.ui-selectionbar*`) | Stable additive | Inspector, property-row and selection-bar class + BEM part names are public (class-only — no recipe). Opt-in, not in the default bundle. Splitters/drag handles are out of scope. |
|
|
42
|
+
| Command palette (`css/command.css`, `.ui-command*`, `initCommand`, `useCommand`) | Stable additive | Command class/part names, the `data-bronto-command` attribute, and the event contract — `bronto:command:select` (`detail: { value, label }`) and `bronto:command:close` — are public, plus the `useCommand` binding hook. Bronto filters + navigates (APG combobox/listbox); the host owns the action registry/execution. Opt-in, not in the default bundle, no global hotkey. |
|
|
43
|
+
| Keyboard-shortcut hint (`.ui-shortcut`, `.ui-shortcut__sep`) | Stable additive | Class names for the chord/sequence hint over `.ui-kbd` are public. Ships in the core layer (class-only, no recipe). |
|
|
22
44
|
| Generated docs shipped in npm | Stable paths | `llms.txt` and exported docs paths stay shipped and resolvable within a compatible minor. Markdown/text assets are for reading unless your runtime has a loader. Generated content may change with the source contract. |
|
|
23
45
|
| Demo, examples, tests, scripts | Internal | Useful for learning and verification, but not shipped runtime API unless a path is explicitly exported in `package.json`. |
|
|
24
46
|
|
package/docs/state.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Lifecycle & system state
|
|
2
|
+
|
|
3
|
+
`@ponchia/ui/css/state.css` is an opt-in vocabulary for the states real apps
|
|
4
|
+
spend their time in — saving, saved, queued, offline, stale, conflicted, locked,
|
|
5
|
+
reviewed. These are usually improvised per product, so even good apps feel
|
|
6
|
+
inconsistent. This is the canonical set: a labelled state object with a rationed
|
|
7
|
+
tone, plus a page/document sync bar.
|
|
8
|
+
|
|
9
|
+
```css
|
|
10
|
+
@import '@ponchia/ui';
|
|
11
|
+
@import '@ponchia/ui/css/state.css';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Bronto ships the visual states and the canonical wording. The host owns the
|
|
15
|
+
state machine, retry policy, persistence, and announcements. **Persistent state
|
|
16
|
+
deserves persistent UI** — a toast is secondary, not the answer. The tone is a
|
|
17
|
+
second channel; the **label is the state**, so it survives forced-colors and
|
|
18
|
+
screen readers (WCAG 1.4.1).
|
|
19
|
+
|
|
20
|
+
## `.ui-state`
|
|
21
|
+
|
|
22
|
+
A leading tone dot, a `__label`, and an optional `__detail`. Add `--busy` to
|
|
23
|
+
pulse the indicator for an in-progress state (reduced-motion-safe).
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<span class="ui-state ui-state--saving ui-state--busy">
|
|
27
|
+
<span class="ui-state__label">Saving…</span>
|
|
28
|
+
</span>
|
|
29
|
+
|
|
30
|
+
<span class="ui-state ui-state--saved">
|
|
31
|
+
<span class="ui-state__label">Saved</span>
|
|
32
|
+
<span class="ui-state__detail">2m ago</span>
|
|
33
|
+
</span>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## State matrix
|
|
37
|
+
|
|
38
|
+
Use the canonical label; the modifier bakes in the tone.
|
|
39
|
+
|
|
40
|
+
| State | Class | Canonical label | Tone | Busy? |
|
|
41
|
+
| --- | --- | --- | --- | --- |
|
|
42
|
+
| Saving | `ui-state--saving` | "Saving…" | accent | yes |
|
|
43
|
+
| Saved | `ui-state--saved` | "Saved" / "All changes saved" | success | — |
|
|
44
|
+
| Queued | `ui-state--queued` | "Queued" / "Pending" | muted | — |
|
|
45
|
+
| Offline | `ui-state--offline` | "Offline" | warning | — |
|
|
46
|
+
| Stale | `ui-state--stale` | "Out of date" | warning | — |
|
|
47
|
+
| Conflict | `ui-state--conflict` | "Conflict" | danger | — |
|
|
48
|
+
| Error | `ui-state--error` | "Failed" / "Couldn't save" | danger | — |
|
|
49
|
+
| Locked | `ui-state--locked` | "Locked" / "Read-only" | muted | — |
|
|
50
|
+
| Reviewed | `ui-state--reviewed` | "Reviewed" | success | — |
|
|
51
|
+
| Needs review | `ui-state--needs-review` | "Needs review" | warning | — |
|
|
52
|
+
|
|
53
|
+
"Syncing" and "Retrying" are the saving tone with their own label — use
|
|
54
|
+
`ui-state--saving ui-state--busy` and write the word.
|
|
55
|
+
|
|
56
|
+
## `.ui-syncbar`
|
|
57
|
+
|
|
58
|
+
A page- or document-level status strip: a state on one side, optional actions on
|
|
59
|
+
the other.
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<div class="ui-syncbar">
|
|
63
|
+
<span class="ui-state ui-state--saved">
|
|
64
|
+
<span class="ui-state__label">All changes saved</span>
|
|
65
|
+
<span class="ui-state__detail">just now</span>
|
|
66
|
+
</span>
|
|
67
|
+
<button class="ui-button ui-button--subtle ui-button--sm" type="button">View history</button>
|
|
68
|
+
</div>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Recipe
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
import { ui } from '@ponchia/ui/classes';
|
|
75
|
+
|
|
76
|
+
ui.state({ state: 'saving', busy: true }); // "ui-state ui-state--saving ui-state--busy"
|
|
77
|
+
ui.state({ state: 'conflict' }); // "ui-state ui-state--conflict"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Scope
|
|
81
|
+
|
|
82
|
+
CSS only — there is no JS yet. Auto-updating elapsed time ("2m ago") or live
|
|
83
|
+
progress text is the host's job; a small optional behavior may come later if a
|
|
84
|
+
real consumer needs it. Background-job progress and conflict-resolution
|
|
85
|
+
affordances are deliberately deferred until then.
|
package/docs/usage.md
CHANGED
|
@@ -39,6 +39,14 @@ All three are small. They are **not** interchangeable:
|
|
|
39
39
|
Rule of thumb: state → dot, classification → badge, user-controlled value
|
|
40
40
|
→ chip.
|
|
41
41
|
|
|
42
|
+
**Tone vocabulary varies by family — by design.** Colour is rationed, so not
|
|
43
|
+
every component carries every tone: `--info`/`--muted` exist on some families
|
|
44
|
+
(badge, dot, state) and not others (alert/toast/meter lead with
|
|
45
|
+
`--success`/`--warning`/`--danger`). The authoritative per-component tone list is
|
|
46
|
+
each base's `modifiers` array in
|
|
47
|
+
[`@ponchia/ui/classes.json`](../classes/classes.json) — read it rather than
|
|
48
|
+
extrapolating a tone you saw on one component onto another.
|
|
49
|
+
|
|
42
50
|
## Numbers: `ui-num` vs the table state classes
|
|
43
51
|
|
|
44
52
|
- Inside `.ui-table`, a numeric cell is `.is-num` (+ `.is-pos` /
|
|
@@ -70,10 +78,11 @@ for narrative body content you do not fully control.
|
|
|
70
78
|
|
|
71
79
|
Do not turn every report block into a card. Use `ui-report__summary`,
|
|
72
80
|
`ui-report__finding`, and `ui-report__evidence` for document structure; use
|
|
73
|
-
`ui-card` only when the block is genuinely a repeated card item.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
`ui-card` only when the block is genuinely a repeated card item. bronto ships
|
|
82
|
+
**no chart component**: for a chart, theme Vega-Lite (`@ponchia/ui/vega`, see
|
|
83
|
+
[vega.md](vega.md)) or hand-author a token-themed inline SVG painted from the
|
|
84
|
+
data-viz palette tokens. Always wrap it in a `ui-report__figure` with a caption,
|
|
85
|
+
a `.ui-legend` key, and fallback data. Full LLM/static report cookbook:
|
|
77
86
|
[reporting.md](reporting.md).
|
|
78
87
|
|
|
79
88
|
## Buttons: variant and size
|
|
@@ -102,6 +111,13 @@ destructive action).
|
|
|
102
111
|
| toast | transient, out-of-flow, system-initiated. Danger toasts route to an assertive live region; everything else polite. |
|
|
103
112
|
| tooltip | supplemental, hover/focus, never essential info (it's not announced reliably; don't hide required content in it). |
|
|
104
113
|
|
|
114
|
+
The CSS `ui-tooltip` is hover/focus-only and CSS can't wire it to assistive
|
|
115
|
+
tech for you — associate the bubble with its trigger yourself, or it conveys
|
|
116
|
+
nothing to a screen reader: give `.ui-tooltip__bubble` an `id`, point the
|
|
117
|
+
trigger's `aria-describedby` at it, and keep the bubble `role="tooltip"`. For a
|
|
118
|
+
tooltip that must stay visible near a viewport edge or inside a scroll
|
|
119
|
+
container, use `initPopover` (a real focus-managed panel) instead.
|
|
120
|
+
|
|
105
121
|
## Meter vs progress
|
|
106
122
|
|
|
107
123
|
Both are a thin horizontal bar; they mean different things.
|
|
@@ -135,6 +151,37 @@ this much* → meter.
|
|
|
135
151
|
(`aria-hidden`) and the input keeps its full width. Don't hand-roll an
|
|
136
152
|
absolute overlay.
|
|
137
153
|
|
|
154
|
+
## Navigation: the landmarks and names the classes don't carry
|
|
155
|
+
|
|
156
|
+
The navigation classes are styling only — the ARIA scaffolding is yours, and
|
|
157
|
+
without it these widgets are unlabelled or unannounced:
|
|
158
|
+
|
|
159
|
+
- **`ui-breadcrumb`** — wrap it in `<nav aria-label="Breadcrumb">` and mark the
|
|
160
|
+
last (current) crumb with `aria-current="page"`.
|
|
161
|
+
- **`ui-pagination`** — wrap it in `<nav aria-label="Pagination">`; give the
|
|
162
|
+
current page `aria-current="page"`; label icon-only prev/next controls
|
|
163
|
+
(`aria-label="Previous page"`). Disable a control with native `disabled`
|
|
164
|
+
(a `<button>`) **or** `aria-disabled="true"` — both now render disabled and
|
|
165
|
+
are non-interactive; don't ship an `aria-disabled` control that still acts.
|
|
166
|
+
- **`ui-tabs`** — `initTabs` adds the full APG wiring (roles, roving tabindex,
|
|
167
|
+
`aria-selected`, panel `hidden`, focusable panel). If you wire tabs yourself,
|
|
168
|
+
name the `ui-tabs__list` (`role="tablist"` + an `aria-label`) and pair each
|
|
169
|
+
tab with its panel via `aria-controls`/`aria-labelledby`.
|
|
170
|
+
- **`ui-sitenav` / `ui-app-nav`** — signal the current link with
|
|
171
|
+
`aria-current="page"` (both honour it; `ui-app-nav` also accepts the
|
|
172
|
+
visual-only `.is-active`, but prefer `aria-current`).
|
|
173
|
+
- **`ui-skiplink`** — keep it the first focusable element and point its `href`
|
|
174
|
+
at the `id` of your main landmark.
|
|
175
|
+
|
|
176
|
+
## Avatar: it's an unlabelled blob until you name it
|
|
177
|
+
|
|
178
|
+
`ui-avatar` is a presentation box. Give it an accessible name yourself: an
|
|
179
|
+
image avatar needs real `alt` text (`alt=""` only if it's purely decorative
|
|
180
|
+
beside a visible name); an initials avatar needs an accessible name on the
|
|
181
|
+
element (e.g. `aria-label="Ada Lovelace"`) because the initials alone don't
|
|
182
|
+
convey identity to AT. Keep initials to ~2 characters — the box is
|
|
183
|
+
`overflow: hidden` and silently clips a third.
|
|
184
|
+
|
|
138
185
|
## Modal: native `<dialog>` vs `is-open`
|
|
139
186
|
|
|
140
187
|
Prefer the **native `<dialog>`** path — you get top-layer, backdrop and
|
|
@@ -181,6 +228,13 @@ that fuses the cells into a square, gapless pixel glyph that stays crisp and
|
|
|
181
228
|
legible down to **~16px** — so the same set doubles as real inline UI icons,
|
|
182
229
|
not just decoration. (Below the dot fragments into dot-soup; solid does not.)
|
|
183
230
|
|
|
231
|
+
One caveat on ink: `solid` cells inherit the dot palette (`--field-dot-hot`,
|
|
232
|
+
~40% alpha), so at small sizes a solid glyph reads as a soft grey, not full
|
|
233
|
+
ink. When you want a crisp, full-strength small icon (toolbar, button affordance),
|
|
234
|
+
use the one-node mask renderer instead — `renderGlyph(name, { render: 'mask' })`
|
|
235
|
+
paints the glyph in `currentColor` on a `.ui-icon`, so it tracks text colour at
|
|
236
|
+
any size.
|
|
237
|
+
|
|
184
238
|
`renderGlyph(name, { label })` returns an SSR-safe string: decorative
|
|
185
239
|
(`aria-hidden`) by default, or `role="img"` + `aria-label` when you pass a
|
|
186
240
|
`label` — which is how it conveys meaning to assistive tech. Prefer the
|
|
@@ -263,6 +317,71 @@ dashboards: `--chart-1..8` (categorical), `--chart-seq-*` (sequential),
|
|
|
263
317
|
Cap a chart at ~8 series. Full detail in [theming.md](theming.md) →
|
|
264
318
|
"Data-viz palette".
|
|
265
319
|
|
|
320
|
+
## SVG annotations: subject, connector, note
|
|
321
|
+
|
|
322
|
+
`@ponchia/ui/css/annotations.css` (opt-in) adds Bronto-styled SVG annotations
|
|
323
|
+
for reports and chart figures. It is a visual grammar, not a charting or
|
|
324
|
+
authoring engine.
|
|
325
|
+
|
|
326
|
+
- Compose each callout from `ui-annotation` plus a subject
|
|
327
|
+
(`ui-annotation__subject`), connector (`ui-annotation__connector`), and note
|
|
328
|
+
(`ui-annotation__note`, `ui-annotation__title`, `ui-annotation__label`).
|
|
329
|
+
- Use `ui.annotation({ variant, tone, motion })` when building class strings in
|
|
330
|
+
JS. The default is a callout in the accent tone; motion is always opt-in.
|
|
331
|
+
- Use `@ponchia/ui/annotations` when you want deterministic SVG path strings
|
|
332
|
+
for circle, rect, threshold, bracket, band, slope, comparison, cluster, axis,
|
|
333
|
+
timeline, line, elbow, or curve annotations. Use `notePlacement()` for a
|
|
334
|
+
single bounded note when you need a conservative first placement pass.
|
|
335
|
+
- Status tones are only for status-bearing callouts; otherwise use `accent` for
|
|
336
|
+
the main insight and `muted` for secondary labels.
|
|
337
|
+
- Keep annotated charts sparse. Dense figures need a scrollable SVG, a
|
|
338
|
+
simplified mobile SVG, or complete caption/fallback text.
|
|
339
|
+
- Annotation text must be visible or represented in the figure caption, SVG
|
|
340
|
+
`<desc>`, or fallback table. Full detail in [annotations.md](annotations.md).
|
|
341
|
+
|
|
342
|
+
## Forms: the contracts the markup alone won't tell you
|
|
343
|
+
|
|
344
|
+
- **Disabled — pick one mechanism.** Use the native `disabled` attribute for a
|
|
345
|
+
genuinely inert control (`ui-input`, `ui-select`, `ui-textarea`, `ui-switch`
|
|
346
|
+
/`ui-check`/`ui-segmented` wrapping a native input, `ui-range`, `ui-file`,
|
|
347
|
+
`ui-button`): the browser greys it, blocks activation, and skips it in tab
|
|
348
|
+
order, and bronto styles the disabled cue. Use `aria-disabled="true"` **only**
|
|
349
|
+
when the control must stay focusable/announced — bronto then adds
|
|
350
|
+
`pointer-events: none` to `ui-button`/`ui-link` so it can't be activated, but
|
|
351
|
+
you still own removing it from the submit logic.
|
|
352
|
+
- **Combobox** (`data-bronto-combobox`) reads its options from the DOM at
|
|
353
|
+
`initCombobox()` time — re-run it after you replace the option list. The
|
|
354
|
+
`<input>` owns the value; the listbox is a view.
|
|
355
|
+
- **Validation** is opt-in via `data-bronto-validate` on the form plus
|
|
356
|
+
`initFormValidation()`; it surfaces messages into a `ui-error-summary` you
|
|
357
|
+
provide. The summary's title is the legible sans, not the display face — it's
|
|
358
|
+
meant to be read.
|
|
359
|
+
|
|
360
|
+
## Reveal: `ui-reveal` needs JS, `ui-scroll-reveal` doesn't
|
|
361
|
+
|
|
362
|
+
`ui-scroll-reveal` is scroll-driven and **zero-JS** — reach for it in a static
|
|
363
|
+
or LLM-authored report. `ui-reveal` is the JS variant: it starts hidden and you
|
|
364
|
+
toggle `is-visible` (e.g. from an `IntersectionObserver` you own) to play it in.
|
|
365
|
+
With scripting disabled it degrades to fully visible, but if scripting is *on*
|
|
366
|
+
and nothing toggles `is-visible`, the content stays hidden — so only use
|
|
367
|
+
`ui-reveal` when you are wiring that toggle.
|
|
368
|
+
|
|
369
|
+
## Loading affordances need a role you supply
|
|
370
|
+
|
|
371
|
+
`ui-spinner`, `ui-dotspinner`, `ui-skeleton`, and an indeterminate `ui-progress`
|
|
372
|
+
are decorative animations — bronto can't know their semantics. Give the busy
|
|
373
|
+
region `aria-busy="true"` (or `role="status"` with an `aria-live` text label like
|
|
374
|
+
"Loading…"), and mark a purely decorative spinner `aria-hidden="true"`. Without
|
|
375
|
+
one of these a screen reader announces nothing while the user waits.
|
|
376
|
+
|
|
377
|
+
## Popover: prefer the native top layer
|
|
378
|
+
|
|
379
|
+
`initPopover()` shows a `.ui-popover` in the browser **top layer** when the panel
|
|
380
|
+
carries the native `popover` attribute (never clipped by `overflow`/stacking);
|
|
381
|
+
without it, it falls back to an `is-open` class that a clipping ancestor can cut
|
|
382
|
+
off. Add `popover` to the panel for the robust path — the `is-open` form is a
|
|
383
|
+
fallback, not the default to copy.
|
|
384
|
+
|
|
266
385
|
## When to add a behavior
|
|
267
386
|
|
|
268
387
|
The CSS is the framework; `@ponchia/ui/behaviors` is the *sanctioned*
|