@ponchia/ui 0.4.0 → 0.5.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 +352 -12
- package/MIGRATIONS.json +92 -0
- package/README.md +27 -17
- package/annotations/index.d.ts +280 -0
- package/annotations/index.js +522 -0
- package/behaviors/carousel.js +197 -0
- package/behaviors/combobox.js +195 -0
- package/behaviors/command.js +187 -0
- package/behaviors/connectors.js +96 -0
- package/behaviors/crosshair.js +58 -0
- package/behaviors/dialog.js +73 -0
- package/behaviors/disclosure.js +25 -0
- package/behaviors/dismissible.js +24 -0
- package/behaviors/forms.js +158 -0
- package/behaviors/glyph.js +109 -0
- package/behaviors/index.d.ts +82 -1
- package/behaviors/index.js +18 -1336
- package/behaviors/internal.js +50 -0
- package/behaviors/legend.js +46 -0
- package/behaviors/menu.js +46 -0
- package/behaviors/popover.js +108 -0
- package/behaviors/spotlight.js +53 -0
- package/behaviors/table.js +109 -0
- package/behaviors/tabs.js +103 -0
- package/behaviors/theme.js +82 -0
- package/behaviors/toast.js +152 -0
- package/classes/index.d.ts +318 -0
- package/classes/index.js +352 -0
- package/classes/vscode.css-custom-data.json +18 -14
- package/connectors/index.d.ts +71 -0
- package/connectors/index.js +179 -0
- package/css/analytical.css +21 -0
- package/css/annotations.css +292 -0
- package/css/command.css +97 -0
- package/css/connectors.css +93 -0
- package/css/crosshair.css +100 -0
- package/css/disclosure.css +29 -0
- package/css/dots.css +2 -0
- package/css/feedback.css +104 -0
- package/css/fonts.css +11 -7
- package/css/generated.css +117 -0
- package/css/legend.css +268 -0
- package/css/marks.css +144 -0
- package/css/motion.css +88 -0
- package/css/overlay.css +52 -1
- package/css/primitives.css +18 -0
- package/css/report.css +363 -0
- package/css/selection.css +46 -0
- package/css/sources.css +179 -0
- package/css/spotlight.css +104 -0
- package/css/state.css +121 -0
- package/css/tokens.css +78 -60
- 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/command.css +1 -0
- package/dist/css/connectors.css +1 -0
- 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/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/overlay.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/report.css +1 -0
- package/dist/css/selection.css +1 -0
- 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/0001-color-system.md +26 -27
- package/docs/adr/0002-scope-and-2026-baseline.md +104 -0
- package/docs/adr/0003-theme-model.md +97 -0
- package/docs/annotations.md +345 -0
- package/docs/architecture.md +202 -0
- package/docs/command.md +95 -0
- package/docs/connectors.md +91 -0
- package/docs/contrast.md +42 -42
- package/docs/crosshair.md +63 -0
- package/docs/generated.md +91 -0
- package/docs/legends.md +168 -0
- package/docs/marks.md +86 -0
- package/docs/reference.md +418 -15
- package/docs/reporting.md +305 -0
- package/docs/selection.md +40 -0
- package/docs/sources.md +110 -0
- package/docs/spotlight.md +78 -0
- package/docs/stability.md +52 -0
- package/docs/state.md +85 -0
- package/docs/theming.md +18 -6
- package/docs/usage.md +43 -3
- package/docs/workbench.md +72 -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/llms.txt +288 -8
- package/package.json +95 -5
- package/qwik/index.d.ts +60 -0
- package/qwik/index.js +149 -0
- package/react/index.d.ts +40 -14
- package/react/index.js +32 -5
- package/solid/index.d.ts +40 -14
- package/solid/index.js +31 -3
- package/tokens/index.d.ts +3 -3
- package/tokens/index.js +25 -19
- package/tokens/index.json +32 -28
- package/tokens/resolved.json +34 -32
- package/tokens/tokens.dtcg.json +22 -14
- 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
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Static reports
|
|
2
|
+
|
|
3
|
+
`@ponchia/ui` can dress static, LLM-authored HTML reports without a component
|
|
4
|
+
runtime. Load the normal bundle, then opt in to the report layer, chart palette,
|
|
5
|
+
and annotation layer only when the report needs them.
|
|
6
|
+
|
|
7
|
+
In a bundled app, package specifiers are fine because Vite or another bundler
|
|
8
|
+
rewrites them:
|
|
9
|
+
|
|
10
|
+
```css
|
|
11
|
+
@import '@ponchia/ui';
|
|
12
|
+
@import '@ponchia/ui/css/report.css';
|
|
13
|
+
@import '@ponchia/ui/css/dataviz.css';
|
|
14
|
+
@import '@ponchia/ui/css/annotations.css';
|
|
15
|
+
@import '@ponchia/ui/css/legend.css';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For standalone browser HTML, use real stylesheet URLs. Package specifiers like
|
|
19
|
+
`@ponchia/ui/css/report.css` do not resolve in a saved `.html` file:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/bronto.css" />
|
|
23
|
+
<link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/report.css" />
|
|
24
|
+
<link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/dataviz.css" />
|
|
25
|
+
<link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/annotations.css" />
|
|
26
|
+
<link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/legend.css" />
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If you copy the built CSS next to the report, keep the same relationship between
|
|
30
|
+
`dist/bronto.css`, `dist/css/report.css`, `dist/css/dataviz.css`,
|
|
31
|
+
`dist/css/annotations.css`, `dist/css/legend.css`, and `fonts/` so font URLs
|
|
32
|
+
continue to resolve.
|
|
33
|
+
|
|
34
|
+
The report layer is static and PDF-first. It does not initialize behaviors and
|
|
35
|
+
does not sanitize content. If a report includes arbitrary LLM, CMS, or user HTML,
|
|
36
|
+
sanitize that content before rendering it and do not initialize
|
|
37
|
+
`data-bronto-*` behaviors on the generated region.
|
|
38
|
+
|
|
39
|
+
## Canonical skeleton
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<main class="ui-report ui-report--numbered">
|
|
43
|
+
<header class="ui-report__cover">
|
|
44
|
+
<p class="ui-eyebrow">Quarterly review</p>
|
|
45
|
+
<h1 class="ui-report__title">Personal systems report</h1>
|
|
46
|
+
<p class="ui-report__subtitle">A static report generated from trusted data.</p>
|
|
47
|
+
<ul class="ui-report__meta">
|
|
48
|
+
<li><time datetime="2026-06-01">2026-06-01</time></li>
|
|
49
|
+
<li>Static HTML</li>
|
|
50
|
+
<li>Chromium PDF-ready</li>
|
|
51
|
+
</ul>
|
|
52
|
+
</header>
|
|
53
|
+
|
|
54
|
+
<nav class="ui-report__toc" aria-label="Report contents">
|
|
55
|
+
<p class="ui-eyebrow ui-eyebrow--muted">Contents</p>
|
|
56
|
+
<ol>
|
|
57
|
+
<li><a href="#summary">Executive summary</a></li>
|
|
58
|
+
<li><a href="#findings">Findings</a></li>
|
|
59
|
+
</ol>
|
|
60
|
+
</nav>
|
|
61
|
+
|
|
62
|
+
<section id="summary" class="ui-report__section">
|
|
63
|
+
<h2 class="ui-report__section-head">Executive summary</h2>
|
|
64
|
+
<div class="ui-report__summary">
|
|
65
|
+
<p>The summary block is for the decision-level conclusion.</p>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="ui-statgrid">
|
|
68
|
+
<div class="ui-stat">
|
|
69
|
+
<span class="ui-stat__label">Open risks</span>
|
|
70
|
+
<span class="ui-stat__value">3</span>
|
|
71
|
+
<span class="ui-stat__delta is-neg">+1 this week</span>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</section>
|
|
75
|
+
|
|
76
|
+
<section id="findings" class="ui-report__section">
|
|
77
|
+
<h2 class="ui-report__section-head">Findings</h2>
|
|
78
|
+
<article class="ui-report__finding" aria-labelledby="finding-1">
|
|
79
|
+
<p class="ui-eyebrow" id="finding-1">Finding 1 — short title</p>
|
|
80
|
+
<div class="ui-prose">
|
|
81
|
+
<p>Use prose only for narrative body content.</p>
|
|
82
|
+
</div>
|
|
83
|
+
</article>
|
|
84
|
+
</section>
|
|
85
|
+
</main>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Composition rules
|
|
89
|
+
|
|
90
|
+
- Use `ui-report` as the page-level wrapper. Add `ui-report--numbered` when
|
|
91
|
+
section headings should auto-number. Add `ui-report--compact` to tighten the
|
|
92
|
+
whole report's vertical rhythm (gap + page padding) for dense briefs — this
|
|
93
|
+
is the document-level density toggle, distinct from `ui-report__cover--compact`
|
|
94
|
+
below, which only shrinks the cover.
|
|
95
|
+
- Use `ui-report__cover` for title, subtitle, author/date, and generation
|
|
96
|
+
metadata. Add `ui-report__cover--compact` for short screen-first reports.
|
|
97
|
+
Use `ui-report__header` for a compact in-page header instead of a full cover
|
|
98
|
+
(same role, no tall hero block). Author `ui-report__meta` as a `<ul>` — the
|
|
99
|
+
facts it lists are unordered.
|
|
100
|
+
- Use `ui-report__section` and `ui-report__section-head` for report chapters.
|
|
101
|
+
Keep one `h1` for the report title; use ordered `h2`/`h3` headings after it.
|
|
102
|
+
- Add `ui-report__section--unnumbered` to appendices, sources, or footnotes
|
|
103
|
+
when the report uses `ui-report--numbered` but the section should not count as
|
|
104
|
+
a numbered chapter.
|
|
105
|
+
- Use `ui-prose` only around narrative HTML you do not fully control, such as
|
|
106
|
+
Markdown output. Do not wrap structured app/report UI in `ui-prose`.
|
|
107
|
+
- Use existing primitives for shared meanings: `ui-statgrid` for KPIs,
|
|
108
|
+
`ui-alert` for persistent notices, `ui-table` for structured evidence,
|
|
109
|
+
`ui-timeline` for events, `ui-meter` for measured values, and `ui-num` for
|
|
110
|
+
non-table numeric values.
|
|
111
|
+
- Give `ui-report__finding` blocks an accessible name so the visual grouping is
|
|
112
|
+
also programmatic: point `aria-labelledby` at the block's `ui-eyebrow` label
|
|
113
|
+
(give it an `id`), or lead with a real heading. Do the same for a
|
|
114
|
+
multi-part `ui-report__evidence` block; a single evidence table is already
|
|
115
|
+
named by its own `<caption>`.
|
|
116
|
+
- Name the `ui-report__sources` and `ui-report__footnotes` blocks
|
|
117
|
+
(`aria-labelledby` on their `ui-eyebrow`), and link footnotes both ways:
|
|
118
|
+
an in-text `<sup><a id="fnref1" href="#fn1">1</a></sup>` to an
|
|
119
|
+
`<ol><li id="fn1">… <a href="#fnref1">↩</a></li></ol>`. They are real
|
|
120
|
+
regions, not decoration.
|
|
121
|
+
- Every `<table>` that carries report data should have a `<caption>`, header
|
|
122
|
+
cells, and `.is-num` on numeric columns. (`.is-num`, `.is-pos`, `.is-neg`
|
|
123
|
+
and `.is-key` only take effect inside `.ui-table` cells and `.ui-stat`
|
|
124
|
+
deltas — they are not free-standing utilities.) Keep raw Markdown tables
|
|
125
|
+
inside `ui-prose`; use `.ui-table` for curated evidence tables. If a
|
|
126
|
+
`ui-report__evidence` block contains only a `ui-table-wrap`, the report layer
|
|
127
|
+
removes the inner frame so evidence tables do not look double-boxed.
|
|
128
|
+
- Every `<figure>` should include a `figcaption` using
|
|
129
|
+
`ui-chart__caption` (chart figures) or `ui-report__caption` (any other
|
|
130
|
+
report figure); the two are interchangeable in style.
|
|
131
|
+
- Do not use raw color values. Theme with `--accent`; use status tones for
|
|
132
|
+
status; use chart tokens only in chart figures.
|
|
133
|
+
|
|
134
|
+
## Chart figure recipe
|
|
135
|
+
|
|
136
|
+
The report layer supplies chart containers and a small static bar pattern, not a
|
|
137
|
+
chart engine. The data key is the standalone, portable `.ui-legend`
|
|
138
|
+
(`@ponchia/ui/css/legend.css`) — see [legends.md](./legends.md). For
|
|
139
|
+
CSS/HTML/SVG charts, pair each chart color with a direct label, a pattern, or a
|
|
140
|
+
fallback table.
|
|
141
|
+
|
|
142
|
+
```html
|
|
143
|
+
<figure class="ui-report__figure ui-chart ui-print-exact" role="group" aria-labelledby="chart-title">
|
|
144
|
+
<figcaption id="chart-title" class="ui-chart__caption">
|
|
145
|
+
Fig 1 - Weekly focus split
|
|
146
|
+
</figcaption>
|
|
147
|
+
<ul class="ui-legend" aria-label="Series">
|
|
148
|
+
<li class="ui-legend__item">
|
|
149
|
+
<span
|
|
150
|
+
class="ui-legend__swatch"
|
|
151
|
+
style="--chart-color: var(--chart-1); --chart-pattern: var(--chart-pattern-1)"
|
|
152
|
+
aria-hidden="true"
|
|
153
|
+
></span>
|
|
154
|
+
<span class="ui-legend__label">Research</span>
|
|
155
|
+
</li>
|
|
156
|
+
<li class="ui-legend__item">
|
|
157
|
+
<span
|
|
158
|
+
class="ui-legend__swatch"
|
|
159
|
+
style="--chart-color: var(--chart-2); --chart-pattern: var(--chart-pattern-2)"
|
|
160
|
+
aria-hidden="true"
|
|
161
|
+
></span>
|
|
162
|
+
<span class="ui-legend__label">Delivery</span>
|
|
163
|
+
</li>
|
|
164
|
+
</ul>
|
|
165
|
+
<div class="ui-chart__plot" aria-hidden="true">
|
|
166
|
+
<div
|
|
167
|
+
class="ui-chart__bar"
|
|
168
|
+
style="--chart-value: 72%; --chart-color: var(--chart-1); --chart-pattern: var(--chart-pattern-1)"
|
|
169
|
+
>
|
|
170
|
+
<div class="ui-chart__label"><span>Research</span><span>18 h</span></div>
|
|
171
|
+
<div class="ui-chart__track"><div class="ui-chart__fill"></div></div>
|
|
172
|
+
</div>
|
|
173
|
+
<div
|
|
174
|
+
class="ui-chart__bar"
|
|
175
|
+
style="--chart-value: 44%; --chart-color: var(--chart-2); --chart-pattern: var(--chart-pattern-2)"
|
|
176
|
+
>
|
|
177
|
+
<div class="ui-chart__label"><span>Delivery</span><span>11 h</span></div>
|
|
178
|
+
<div class="ui-chart__track"><div class="ui-chart__fill"></div></div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
<div class="ui-chart__fallback">
|
|
182
|
+
<div class="ui-table-wrap">
|
|
183
|
+
<table class="ui-table ui-table--dense">
|
|
184
|
+
<caption>Chart source data</caption>
|
|
185
|
+
<thead>
|
|
186
|
+
<tr><th>Series</th><th class="is-num">Hours</th></tr>
|
|
187
|
+
</thead>
|
|
188
|
+
<tbody>
|
|
189
|
+
<tr><td>Research</td><td class="is-num">18</td></tr>
|
|
190
|
+
<tr><td>Delivery</td><td class="is-num">11</td></tr>
|
|
191
|
+
</tbody>
|
|
192
|
+
</table>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</figure>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
For canvas or SVG libraries, import resolved series colors from
|
|
199
|
+
`@ponchia/ui/charts.json` and keep the same legend/caption/fallback structure in
|
|
200
|
+
the surrounding HTML.
|
|
201
|
+
|
|
202
|
+
## Annotation recipe
|
|
203
|
+
|
|
204
|
+
When a report chart needs an explicit callout, import
|
|
205
|
+
`@ponchia/ui/css/annotations.css` and layer SVG annotations inside the same
|
|
206
|
+
`ui-report__figure`. Keep the subject/connector/note text visible in the SVG or
|
|
207
|
+
represented by the figure caption/fallback data.
|
|
208
|
+
|
|
209
|
+
```html
|
|
210
|
+
<svg viewBox="0 0 360 160" role="img" aria-labelledby="annotated-title annotated-desc">
|
|
211
|
+
<title id="annotated-title">Weekly focus chart with peak callout</title>
|
|
212
|
+
<desc id="annotated-desc">The annotation marks the research peak.</desc>
|
|
213
|
+
<g class="ui-annotation ui-annotation--circle ui-annotation--accent" transform="translate(210, 58)">
|
|
214
|
+
<path class="ui-annotation__subject" d="M0,-18A18,18 0 1 1 0,18A18,18 0 1 1 0,-18Z" />
|
|
215
|
+
<path class="ui-annotation__connector" d="M15.556,-7.424L84,-40" />
|
|
216
|
+
<g class="ui-annotation__note" transform="translate(84, -40)">
|
|
217
|
+
<path class="ui-annotation__note-line" d="M0,0H92" />
|
|
218
|
+
<text class="ui-annotation__title" y="-8">Peak</text>
|
|
219
|
+
<text class="ui-annotation__label" y="12">18 research hours</text>
|
|
220
|
+
</g>
|
|
221
|
+
</g>
|
|
222
|
+
</svg>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
For generated SVG, use `@ponchia/ui/annotations` to compute connector and
|
|
226
|
+
subject path strings. Full annotation recipes and the complete variant list are
|
|
227
|
+
in `docs/annotations.md`; the shipped `demo/annotations.html` page is the
|
|
228
|
+
visual specimen.
|
|
229
|
+
|
|
230
|
+
## Timeline recipe
|
|
231
|
+
|
|
232
|
+
Incident reviews and research logs should use the existing timeline primitive
|
|
233
|
+
with its required item and time parts. Do not emit a bare list and expect it to
|
|
234
|
+
style itself.
|
|
235
|
+
|
|
236
|
+
```html
|
|
237
|
+
<ol class="ui-timeline">
|
|
238
|
+
<li class="ui-timeline__item">
|
|
239
|
+
<time class="ui-timeline__time" datetime="2026-06-01T09:12:00">09:12</time>
|
|
240
|
+
<span>Latency alert fired for p95 over threshold.</span>
|
|
241
|
+
</li>
|
|
242
|
+
<li class="ui-timeline__item" aria-current="step">
|
|
243
|
+
<time class="ui-timeline__time" datetime="2026-06-01T09:54:00">09:54</time>
|
|
244
|
+
<span>Latency returned to baseline.</span>
|
|
245
|
+
</li>
|
|
246
|
+
</ol>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Common templates
|
|
250
|
+
|
|
251
|
+
- Executive brief: compact cover, one summary block, KPI `ui-statgrid`, short
|
|
252
|
+
findings, and sources.
|
|
253
|
+
- Research brief: compact header, decision frame, evidence table, quotes or
|
|
254
|
+
prose excerpts, and sources.
|
|
255
|
+
- Incident review: compact cover, summary, `ui-timeline`, corrective-action
|
|
256
|
+
evidence table, and footnotes.
|
|
257
|
+
- Project status: compact header, KPI `ui-statgrid`, chart figure with fallback
|
|
258
|
+
data, print-only notes, and unnumbered appendix.
|
|
259
|
+
|
|
260
|
+
## Print and PDF
|
|
261
|
+
|
|
262
|
+
The supported export target is modern Chromium print/PDF. Two ways to produce
|
|
263
|
+
the file:
|
|
264
|
+
|
|
265
|
+
- **By hand:** open the report in Chrome/Edge → Print (Cmd/Ctrl+P) → "Save as
|
|
266
|
+
PDF". In **More settings**, enable **Background graphics** (the dialog's
|
|
267
|
+
equivalent of `printBackground` — without it chart fills and swatches drop
|
|
268
|
+
out), and pick the paper size there. Paper size is a browser print setting,
|
|
269
|
+
not a token; the layer only themes the page _margin_ via
|
|
270
|
+
`--report-page-margin`.
|
|
271
|
+
- **Headless (agents/CI):** `await page.pdf({ format: 'A4', printBackground: true })`
|
|
272
|
+
with Playwright or Puppeteer.
|
|
273
|
+
|
|
274
|
+
The report prints ink-on-white regardless of the on-screen theme. Older
|
|
275
|
+
HTML-to-PDF engines are not part of the browser floor and may not support
|
|
276
|
+
cascade layers, `oklch()`, `color-mix()`, `:has()`, or modern paged-media
|
|
277
|
+
behavior.
|
|
278
|
+
|
|
279
|
+
- Use `ui-print-only` for content that should appear only in print.
|
|
280
|
+
- Use `ui-screen-only` for navigation or helper content that should not print.
|
|
281
|
+
- Use `ui-break-before` and `ui-break-after` for deliberate page boundaries.
|
|
282
|
+
- Use `ui-keep` on short figures, findings, and summary blocks that should not
|
|
283
|
+
split across pages.
|
|
284
|
+
- Use `ui-print-exact` on charts whose fills and patterns must survive PDF
|
|
285
|
+
export.
|
|
286
|
+
- External links inside `ui-prose` print their URL automatically through the
|
|
287
|
+
base print stylesheet.
|
|
288
|
+
|
|
289
|
+
**Not provided** (use the browser's paged-media features, or author the markup
|
|
290
|
+
yourself): running headers/footers with "Page X of Y", automatic table-of-contents
|
|
291
|
+
pagination, multi-column layout, and automatic citation/footnote numbering. The
|
|
292
|
+
report layer is a document grammar, not a paged-media or citation engine — do not
|
|
293
|
+
fake page numbers with inert markup.
|
|
294
|
+
|
|
295
|
+
## LLM checklist
|
|
296
|
+
|
|
297
|
+
Before returning a report, an LLM should verify:
|
|
298
|
+
|
|
299
|
+
- All `ui-*` classes exist in `@ponchia/ui/classes`.
|
|
300
|
+
- The document has one `h1`, ordered headings, and a single main report region.
|
|
301
|
+
- Tables have captions and header cells.
|
|
302
|
+
- Charts have captions, direct labels or legends, and fallback data.
|
|
303
|
+
- No raw chromatic colors appear in inline styles.
|
|
304
|
+
- No remote scripts, styles, iframes, or images are required for the report.
|
|
305
|
+
- Generated/untrusted body HTML was sanitized before insertion.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Selection states
|
|
2
|
+
|
|
3
|
+
`@ponchia/ui/css/selection.css` is a tiny, **cross-cutting selection-emphasis
|
|
4
|
+
vocabulary** — the carve-out from "brush/lasso". Bronto does **not** do region
|
|
5
|
+
selection or hit-testing (that needs your scales and geometry). It ships only
|
|
6
|
+
the *states* an item can be in once your code has decided what's selected, so
|
|
7
|
+
the same emphasis works on a chart mark, a table row, a list item, or a map
|
|
8
|
+
region.
|
|
9
|
+
|
|
10
|
+
```css
|
|
11
|
+
@import '@ponchia/ui';
|
|
12
|
+
@import '@ponchia/ui/css/selection.css';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
| Class | State |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `ui-sel` | Base — opt the element into the emphasis transitions. |
|
|
18
|
+
| `ui-sel--on` | In the selection (accent outline). |
|
|
19
|
+
| `ui-sel--off` | Excluded / filtered out (dimmed). |
|
|
20
|
+
| `ui-sel--maybe` | A live-brush candidate (dashed outline). |
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<rect class="ui-sel ui-sel--on" … />
|
|
24
|
+
<tr class="ui-sel ui-sel--off">…</tr>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { ui } from '@ponchia/ui/classes';
|
|
29
|
+
el.className = ui.sel({ state: inBrush ? 'maybe' : selected ? 'on' : 'off' });
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Your code adds/removes these classes from its own brush, filter, or selection
|
|
33
|
+
logic — Bronto only styles them. `--off` uses `opacity` (which survives
|
|
34
|
+
forced-colors), and `--on` falls back to the system `Highlight` color in
|
|
35
|
+
forced-colors so the selection stays visible.
|
|
36
|
+
|
|
37
|
+
> **Why no brush behavior?** A rectangular brush or lasso must translate a
|
|
38
|
+
> dragged region into a data domain (or test points against a polygon), which
|
|
39
|
+
> requires owning the chart's scales/geometry — across Bronto's line. Bring your
|
|
40
|
+
> own selection logic; use these classes to render the result.
|
package/docs/sources.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
## Inline citation — `.ui-citation`
|
|
35
|
+
|
|
36
|
+
A reference marker on a real `<a>` or `<button>` (the visual index is never the
|
|
37
|
+
only label — give it an accessible name).
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<p>
|
|
41
|
+
Latency fell 38%<a class="ui-citation" href="#s1" aria-label="Source 1">[1]</a>.
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<!-- Named-source pill, with a leading trust dot: -->
|
|
45
|
+
<a class="ui-citation ui-citation--chip ui-src--verified" href="#s1">
|
|
46
|
+
Q3 incident review
|
|
47
|
+
</a>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Source card — `.ui-source-card`
|
|
51
|
+
|
|
52
|
+
A single source preview: title, origin, time, excerpt, actions. The
|
|
53
|
+
`border-inline-start` carries the trust tone.
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<article class="ui-source-card ui-src--generated">
|
|
57
|
+
<h3 class="ui-source-card__title">Model output — pricing summary</h3>
|
|
58
|
+
<p class="ui-source-card__origin">gpt-x · internal</p>
|
|
59
|
+
<p class="ui-source-card__time">2026-06-01 09:42</p>
|
|
60
|
+
<p class="ui-source-card__excerpt">The migration cut p95 latency by 38%…</p>
|
|
61
|
+
<div class="ui-source-card__actions">
|
|
62
|
+
<button class="ui-button ui-button--subtle ui-button--sm" type="button">Open</button>
|
|
63
|
+
</div>
|
|
64
|
+
</article>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Source list — `.ui-source-list`
|
|
68
|
+
|
|
69
|
+
A references section: a reset list of source cards (or rows).
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<ol class="ui-source-list">
|
|
73
|
+
<li class="ui-source-list__item"><article class="ui-source-card ui-src--verified">…</article></li>
|
|
74
|
+
<li class="ui-source-list__item"><article class="ui-source-card ui-src--stale">…</article></li>
|
|
75
|
+
</ol>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Provenance — `.ui-provenance`
|
|
79
|
+
|
|
80
|
+
A compact metadata row beside generated content — each `__item` carries a trust
|
|
81
|
+
dot and a label.
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<p class="ui-provenance">
|
|
85
|
+
<span class="ui-provenance__item ui-src--generated">Generated</span>
|
|
86
|
+
<span class="ui-provenance__item ui-src--verified">3 sources</span>
|
|
87
|
+
<span class="ui-provenance__item ui-src--reviewed">Human-reviewed</span>
|
|
88
|
+
</p>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Recipes
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
import { ui } from '@ponchia/ui/classes';
|
|
95
|
+
|
|
96
|
+
ui.citation({ chip: true, state: 'verified' });
|
|
97
|
+
// "ui-citation ui-citation--chip ui-src--verified"
|
|
98
|
+
ui.source({ state: 'generated' }); // "ui-source-card ui-src--generated"
|
|
99
|
+
ui.provenance({ state: 'reviewed' }); // "ui-provenance ui-src--reviewed"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Accessibility & print
|
|
103
|
+
|
|
104
|
+
- A citation must be a real link or button with a stable accessible name; the
|
|
105
|
+
bracketed index alone is not enough.
|
|
106
|
+
- The trust state must be readable as text — the tone dot/border is decorative
|
|
107
|
+
reinforcement. Under `forced-colors`, dots and borders fall back to
|
|
108
|
+
`CanvasText`, so the label remains the channel.
|
|
109
|
+
- Tone dots and the card's tone border carry `print-color-adjust: exact`, so
|
|
110
|
+
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).
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Public API Stability
|
|
2
|
+
|
|
3
|
+
`@ponchia/ui` is pre-1.0. Breaking changes ship in the minor (`0.x.0`), and
|
|
4
|
+
patches are non-breaking. This matrix defines what counts as public API.
|
|
5
|
+
|
|
6
|
+
| Surface | Stability | Contract |
|
|
7
|
+
| --- | --- | --- |
|
|
8
|
+
| CSS package root (`@ponchia/ui`) | Stable | CSS-only entrypoint. CSS side-effect imports are supported in CSS-aware bundlers; Node/runtime JS root imports are not. |
|
|
9
|
+
| JS module format | Stable | JS subpaths are ESM-only. CommonJS consumers use dynamic `import()`. |
|
|
10
|
+
| CSS class names (`.ui-*`) | Stable | Names and documented modifier semantics are public. Internal selector structure and leaf-file boundaries may change. |
|
|
11
|
+
| Class recipes (`@ponchia/ui/classes`) | Stable | Exported `cls`, `ui`, `cx`, recipe names, and option unions are public. |
|
|
12
|
+
| 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
|
+
| `--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. |
|
|
14
|
+
| 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.) |
|
|
15
|
+
| Behavior attributes (`data-bronto-*`) | Stable | Attribute names and documented markup relationships are public. Behavior internals are not. |
|
|
16
|
+
| Behavior functions (`@ponchia/ui/behaviors`) | Stable | Exported function names, option names, custom events, SSR no-op behavior, idempotency, and cleanup-returning contract are public. |
|
|
17
|
+
| 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
|
+
| `.ui-icon` mask renderer | Stable | Class name, `--icon-size`, currentColor inheritance, and `--icon-mask` contract are public. The internal data URL encoding is not. |
|
|
19
|
+
| 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. |
|
|
20
|
+
| Skins (`@ponchia/ui/skins`, `css/skins.css`) | Stable additive | Existing skin names stay valid. New skins are additive. Skins are root-level choices. |
|
|
21
|
+
| 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. |
|
|
22
|
+
| Reports (`css/report.css`, `.ui-report*`, `.ui-chart*`, print utilities) | Stable additive | Report class names, BEM part names, chart helper class 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`. |
|
|
23
|
+
| 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. |
|
|
24
|
+
| 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. |
|
|
25
|
+
| 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. |
|
|
26
|
+
| 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. |
|
|
27
|
+
| 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. |
|
|
28
|
+
| 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. |
|
|
29
|
+
| 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. |
|
|
30
|
+
| 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. |
|
|
31
|
+
| 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. |
|
|
32
|
+
| 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. |
|
|
33
|
+
| 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. |
|
|
34
|
+
| 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. |
|
|
35
|
+
| 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. |
|
|
36
|
+
| 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). |
|
|
37
|
+
| 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. |
|
|
38
|
+
| Demo, examples, tests, scripts | Internal | Useful for learning and verification, but not shipped runtime API unless a path is explicitly exported in `package.json`. |
|
|
39
|
+
|
|
40
|
+
## Trust Boundary
|
|
41
|
+
|
|
42
|
+
Behaviors assume trusted application markup. If a delegated root includes
|
|
43
|
+
untrusted CMS or user HTML, sanitize it first or do not initialize behaviors on
|
|
44
|
+
that root. The behavior layer intentionally lets authored `data-bronto-*`,
|
|
45
|
+
`aria-controls`, and `id` relationships control elements inside the root.
|
|
46
|
+
Dialog, disclosure, and popover targets resolve root-first and then
|
|
47
|
+
document-wide for body/portal-mounted overlays; scoped roots are not a sandbox
|
|
48
|
+
for untrusted markup.
|
|
49
|
+
|
|
50
|
+
The one-node glyph mask renderer emits inline style/custom-property data. Apps
|
|
51
|
+
with a strict CSP should either allow the required `data:` mask/image source and
|
|
52
|
+
inline custom-property style path, or use the DOM dot/solid renderers.
|