@ponchia/ui 0.3.5 → 0.4.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 +945 -0
- package/README.md +31 -7
- package/behaviors/index.d.ts +11 -0
- package/behaviors/index.js +109 -0
- package/classes/index.d.ts +3 -0
- package/classes/index.js +3 -0
- package/classes/vscode.css-custom-data.json +4 -12
- package/css/dataviz.css +96 -0
- package/css/dots.css +70 -4
- package/css/skins.css +54 -0
- package/css/tokens.css +4 -10
- package/dist/bronto.css +1 -1
- package/dist/css/dataviz.css +1 -0
- package/dist/css/dots.css +1 -1
- package/dist/css/skins.css +1 -0
- package/dist/css/tokens.css +1 -1
- package/docs/adr/0001-color-system.md +272 -0
- package/docs/contrast.md +170 -51
- package/docs/reference.md +13 -9
- package/docs/theming.md +66 -1
- package/docs/usage.md +99 -0
- package/glyphs/glyphs.d.ts +115 -0
- package/glyphs/glyphs.js +1063 -0
- package/llms.txt +54 -4
- package/package.json +63 -5
- package/react/index.d.ts +36 -0
- package/react/index.js +67 -0
- package/solid/index.d.ts +36 -0
- package/solid/index.js +67 -0
- package/tokens/charts.d.ts +37 -0
- package/tokens/charts.js +96 -0
- package/tokens/charts.json +61 -0
- package/tokens/index.d.ts +3 -3
- package/tokens/index.js +4 -8
- package/tokens/index.json +8 -16
- package/tokens/resolved.json +9 -13
- package/tokens/skins.d.ts +27 -0
- package/tokens/skins.js +62 -0
- package/tokens/tokens.dtcg.json +4 -24
package/docs/usage.md
CHANGED
|
@@ -146,6 +146,105 @@ carousel crops (`cover`); the lightbox shows the whole image (`contain`).
|
|
|
146
146
|
This is deliberately *not* an auto-playing marketing slider (no timers, no
|
|
147
147
|
infinite-clone track). It's a gallery: the user drives it.
|
|
148
148
|
|
|
149
|
+
## Display glyphs: when (and when not)
|
|
150
|
+
|
|
151
|
+
`@ponchia/ui/glyphs` is a 43-glyph dot-matrix icon set — navigation
|
|
152
|
+
(`arrow-*`, `chevron-*`), actions (`check`, `close`, `plus`, `minus`,
|
|
153
|
+
`search`, `menu`, `gear`), status (`info`, `warning`, `bell`, `lock`) and
|
|
154
|
+
common marks (`home`, `user`, `heart`, `star`, `spark`) — rendered on the
|
|
155
|
+
`.ui-dotmatrix` primitive, so they re-skin with the same `--field-dot*`
|
|
156
|
+
tokens as every other dot surface (no SVG, no icon font).
|
|
157
|
+
|
|
158
|
+
**Two rendering modes — pick by size.** The dots need physical room to
|
|
159
|
+
read, so the default _dot_ look is for **display** sizes (~40px up: hero
|
|
160
|
+
marks, empty states, status bursts, section headers, large buttons). For
|
|
161
|
+
small/inline use pass **`solid: true`** (or `data-bronto-glyph-solid`):
|
|
162
|
+
that fuses the cells into a square, gapless pixel glyph that stays crisp and
|
|
163
|
+
legible down to **~16px** — so the same set doubles as real inline UI icons,
|
|
164
|
+
not just decoration. (Below the dot fragments into dot-soup; solid does not.)
|
|
165
|
+
|
|
166
|
+
`renderGlyph(name, { label })` returns an SSR-safe string: decorative
|
|
167
|
+
(`aria-hidden`) by default, or `role="img"` + `aria-label` when you pass a
|
|
168
|
+
`label` — which is how it conveys meaning to assistive tech. Prefer the
|
|
169
|
+
`data-bronto-glyph` placeholder + `initDotGlyph()` when the markup is
|
|
170
|
+
easier dropped than inlined. Size with `--dotmatrix-dot` (and a tight
|
|
171
|
+
`--dotmatrix-gap`) for an intrinsic dot, or let it stretch to its container.
|
|
172
|
+
It is still a pixel-grid aesthetic, not a hairline vector set — but it now
|
|
173
|
+
spans both inline-icon and display use from one source.
|
|
174
|
+
|
|
175
|
+
**Animation** is opt-in via `anim` (`renderGlyph(name, { anim: 'reveal' })`)
|
|
176
|
+
or `data-bronto-glyph-anim`: `reveal` powers the cells on in a scan (a
|
|
177
|
+
dot-matrix booting up), `pulse` makes the glyph breathe for a live/attention
|
|
178
|
+
state. It's **decorative only** — disabled under `prefers-reduced-motion`,
|
|
179
|
+
and the meaning still lives in the static frame + `label`, never in the
|
|
180
|
+
motion. Don't animate to convey information a reduced-motion user would miss.
|
|
181
|
+
Tune the scan speed with `--dotmatrix-reveal-step` (delay per cell, default
|
|
182
|
+
`3ms`). Use `pulse` sparingly — one attention target per view: it loops
|
|
183
|
+
indefinitely, and animation that runs in parallel with other content is the
|
|
184
|
+
consumer's WCAG 2.2.2 (Pause/Stop/Hide) responsibility (reduced-motion is not
|
|
185
|
+
a substitute).
|
|
186
|
+
|
|
187
|
+
A few sharp edges to know:
|
|
188
|
+
|
|
189
|
+
- **Inline icon recipe.** `renderGlyph` returns a `<span>`, so it's valid
|
|
190
|
+
inline and inside a `<button>`. For an inline UI icon, render `solid` and
|
|
191
|
+
size the dot, e.g. inside a button:
|
|
192
|
+
`` `<button class="ui-button">${renderGlyph('search', { solid: true, dot: '1.2px', label: 'Search' })}<span>Search</span></button>` `` —
|
|
193
|
+
the button's `display: inline-flex; gap` aligns icon + text. For icon-in-prose,
|
|
194
|
+
set `--dotmatrix-dot` to ~`0.08em` and `vertical-align: -0.15em` on the span.
|
|
195
|
+
- **`solid` wins.** `solid: true` implies glyph-only and forces
|
|
196
|
+
`--dotmatrix-gap: 0` / square cells, so a `grid: true` or `gap` passed
|
|
197
|
+
alongside it is ignored.
|
|
198
|
+
- **Directional glyphs are physical, not logical.** `arrow-left/right`,
|
|
199
|
+
`chevron-left/right` are fixed bitmaps; in an RTL context flip them yourself
|
|
200
|
+
(e.g. swap the name, or `transform: scaleX(-1)`), the framework won't.
|
|
201
|
+
- **Cost / icon-at-scale.** The default (cell) render is a 16×16 grid = 256
|
|
202
|
+
cells (DOM nodes), regardless of `solid`/`grid`; `anim: 'reveal'` adds a
|
|
203
|
+
per-cell `--i`. That's the dot-matrix display look — but for **many** icons
|
|
204
|
+
(one in every row of a long table) use **`renderGlyph(name, { render: 'mask' })`**:
|
|
205
|
+
it returns a **single** `.ui-icon` element masked by the bitmap (one node, not
|
|
206
|
+
256), sizes to `size` / `--icon-size` (default `1em`) and inherits
|
|
207
|
+
`currentColor` — a normal inline icon. Pick `render: 'mask'` for icons,
|
|
208
|
+
the cell render for display marks/animation.
|
|
209
|
+
|
|
210
|
+
## Colorways: when to reach for a skin
|
|
211
|
+
|
|
212
|
+
`@ponchia/ui/css/skins.css` adds `data-bronto-skin="amber-crt |
|
|
213
|
+
phosphor-green | e-ink"` — a **root-level** colorway (apply on `<html>`, like
|
|
214
|
+
`data-theme`) that re-points the one accent to a different single hue.
|
|
215
|
+
|
|
216
|
+
- **Use a skin** when you want a distinct, on-brand _look_ (a phosphor/CRT or
|
|
217
|
+
e-ink feel) for the whole page or app — it's the supported, contrast-gated
|
|
218
|
+
way to recolour without leaving the design system.
|
|
219
|
+
- **Use a raw `--accent` override** when you just need _your_ brand hue: it's
|
|
220
|
+
one declaration (see "Re-brand obligations" below) — but then contrast is
|
|
221
|
+
yours, whereas the shipped skins are pre-gated.
|
|
222
|
+
- **Don't** put `data-bronto-skin` on a subtree — it's root-level by design
|
|
223
|
+
(the derived accent family only recomputes at `:root`); a subtree skin
|
|
224
|
+
no-ops. For a one-section recolour, scope a raw `--accent` override instead.
|
|
225
|
+
- It's **opt-in**: a separate stylesheet, never in `dist/bronto.css`. No skin
|
|
226
|
+
imported → zero cost. Full detail in [theming.md](theming.md) → "Display
|
|
227
|
+
colorways".
|
|
228
|
+
|
|
229
|
+
## Data-viz colours: charts, not chrome
|
|
230
|
+
|
|
231
|
+
`@ponchia/ui/css/dataviz.css` (opt-in) adds a Tier-4 chart palette for
|
|
232
|
+
dashboards: `--chart-1..8` (categorical), `--chart-seq-*` (sequential),
|
|
233
|
+
`--chart-div-*` (diverging), and `--chart-pattern-1..8` (dot-matrix fills).
|
|
234
|
+
|
|
235
|
+
- **Use it for charts only.** These are not UI tokens — a build gate fails if
|
|
236
|
+
`var(--chart-*)` appears in component CSS. Style buttons/badges with the
|
|
237
|
+
accent/status tiers, not chart colours.
|
|
238
|
+
- **Series 1 is the accent**, so your brand leads the palette; series 2–8 are a
|
|
239
|
+
colourblind-safe set (gated for distinctness under protan/deutan/tritan).
|
|
240
|
+
- **Always pair colour with pattern** (`--chart-pattern-N`) and/or a direct
|
|
241
|
+
label — never colour alone (WCAG 1.4.1):
|
|
242
|
+
`background: var(--chart-3); background-image: var(--chart-pattern-3); background-size: var(--chart-pattern-size);`
|
|
243
|
+
- **In JS** (Chart.js, canvas, SVG): import resolved hex from
|
|
244
|
+
`@ponchia/ui/charts.json` (`{ light, dark }`, series 1 = the resolved accent).
|
|
245
|
+
Cap a chart at ~8 series. Full detail in [theming.md](theming.md) →
|
|
246
|
+
"Data-viz palette".
|
|
247
|
+
|
|
149
248
|
## When to add a behavior
|
|
150
249
|
|
|
151
250
|
The CSS is the framework; `@ponchia/ui/behaviors` is the *sanctioned*
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/** @ponchia/ui — GENERATED from glyphs/glyphs.js by scripts/gen-glyphs.mjs.
|
|
2
|
+
* Do not edit by hand; run `npm run glyphs:build`. Drift-checked in CI. */
|
|
3
|
+
|
|
4
|
+
/** Every display-glyph name @ponchia/ui ships (literal union). Use this as a
|
|
5
|
+
* type annotation to reject typos (`const n: GlyphName = 'arow'` is an error). */
|
|
6
|
+
export type GlyphName =
|
|
7
|
+
| 'arrow-down'
|
|
8
|
+
| 'arrow-left'
|
|
9
|
+
| 'arrow-right'
|
|
10
|
+
| 'arrow-up'
|
|
11
|
+
| 'bell'
|
|
12
|
+
| 'check'
|
|
13
|
+
| 'check-circle'
|
|
14
|
+
| 'chevron-down'
|
|
15
|
+
| 'chevron-left'
|
|
16
|
+
| 'chevron-right'
|
|
17
|
+
| 'chevron-up'
|
|
18
|
+
| 'circle'
|
|
19
|
+
| 'clock'
|
|
20
|
+
| 'close'
|
|
21
|
+
| 'download'
|
|
22
|
+
| 'edit'
|
|
23
|
+
| 'eye'
|
|
24
|
+
| 'eye-off'
|
|
25
|
+
| 'file'
|
|
26
|
+
| 'folder'
|
|
27
|
+
| 'gear'
|
|
28
|
+
| 'grid'
|
|
29
|
+
| 'heart'
|
|
30
|
+
| 'home'
|
|
31
|
+
| 'info'
|
|
32
|
+
| 'link'
|
|
33
|
+
| 'lock'
|
|
34
|
+
| 'mail'
|
|
35
|
+
| 'menu'
|
|
36
|
+
| 'minus'
|
|
37
|
+
| 'minus-circle'
|
|
38
|
+
| 'moon'
|
|
39
|
+
| 'more-horizontal'
|
|
40
|
+
| 'more-vertical'
|
|
41
|
+
| 'pause'
|
|
42
|
+
| 'play'
|
|
43
|
+
| 'plus'
|
|
44
|
+
| 'plus-circle'
|
|
45
|
+
| 'refresh'
|
|
46
|
+
| 'search'
|
|
47
|
+
| 'spark'
|
|
48
|
+
| 'star'
|
|
49
|
+
| 'sun'
|
|
50
|
+
| 'trash'
|
|
51
|
+
| 'upload'
|
|
52
|
+
| 'user'
|
|
53
|
+
| 'warning'
|
|
54
|
+
| 'x-circle';
|
|
55
|
+
|
|
56
|
+
/** A glyph name, or any string — for dynamic dispatch (a CMS/config value). The
|
|
57
|
+
* known names still autocomplete; an unknown name hits the runtime fallback
|
|
58
|
+
* (`glyph`→`undefined`, `glyphCells`→`[]`, `renderGlyph`→`''`). */
|
|
59
|
+
export type GlyphNameInput = GlyphName | (string & {});
|
|
60
|
+
|
|
61
|
+
/** A glyph is 16 rows of 16 chars: `.` off, `#` lit, `*` accent. */
|
|
62
|
+
export type Glyph = readonly string[];
|
|
63
|
+
|
|
64
|
+
/** One rendered dot. `on:false` is an unlit panel dot; tone picks the lit color. */
|
|
65
|
+
export interface GlyphCell {
|
|
66
|
+
on: boolean;
|
|
67
|
+
tone?: 'hot' | 'accent';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface RenderGlyphOptions {
|
|
71
|
+
/** Show the unlit panel dots (default true). `false` → glyph-only look. */
|
|
72
|
+
grid?: boolean;
|
|
73
|
+
/** Render lit cells as square, gapless pixels (a filled silhouette) instead
|
|
74
|
+
* of separated dots — the legible mode at small/inline sizes (~16–24px).
|
|
75
|
+
* Implies glyph-only. Default false (the dot-matrix display look). */
|
|
76
|
+
solid?: boolean;
|
|
77
|
+
/** Opt into a decorative animation (disabled under `prefers-reduced-motion`;
|
|
78
|
+
* meaning stays in the static frame + `label`). `'reveal'` powers the cells
|
|
79
|
+
* on in a scan; `'pulse'` makes the glyph breathe. */
|
|
80
|
+
anim?: 'reveal' | 'pulse';
|
|
81
|
+
/** Expose as `role="img"` with this label; omit for decorative (aria-hidden). */
|
|
82
|
+
label?: string;
|
|
83
|
+
/** CSS length for one dot (sets `--dotmatrix-dot`; sanitized — a value that
|
|
84
|
+
* is not a plain length/calc expression is dropped). */
|
|
85
|
+
dot?: string;
|
|
86
|
+
/** CSS length for the gap between dots (sets `--dotmatrix-gap`; sanitized
|
|
87
|
+
* the same way as `dot`). */
|
|
88
|
+
gap?: string;
|
|
89
|
+
/** `'mask'` returns a single `.ui-icon` element masked by the glyph bitmap
|
|
90
|
+
* (one DOM node, not GLYPH_SIZE²) — the icon-at-scale path. Inherits
|
|
91
|
+
* `currentColor`; the cell-mode options above don't apply. Needs the
|
|
92
|
+
* `.ui-icon` rule from `@ponchia/ui/css`. */
|
|
93
|
+
render?: 'mask';
|
|
94
|
+
/** With `render: 'mask'`, the icon size (sets `--icon-size`; defaults to
|
|
95
|
+
* `1em`; sanitized to a length/calc allowlist). */
|
|
96
|
+
size?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The grid edge length (rows = cols = 16). */
|
|
100
|
+
export declare const GLYPH_SIZE: 16;
|
|
101
|
+
|
|
102
|
+
/** The frozen name→bitmap registry. */
|
|
103
|
+
export declare const GLYPHS: Readonly<Record<GlyphName, Glyph>>;
|
|
104
|
+
|
|
105
|
+
/** Every glyph name, frozen and sorted. */
|
|
106
|
+
export declare const GLYPH_NAMES: readonly GlyphName[];
|
|
107
|
+
|
|
108
|
+
/** The raw bitmap rows for a glyph, or `undefined` if the name is unknown. */
|
|
109
|
+
export declare function glyph(name: GlyphNameInput): Glyph | undefined;
|
|
110
|
+
|
|
111
|
+
/** 256 cell descriptors (row-major), or `[]` if unknown. */
|
|
112
|
+
export declare function glyphCells(name: GlyphNameInput): GlyphCell[];
|
|
113
|
+
|
|
114
|
+
/** A full `.ui-dotmatrix` HTML string for a glyph (`''` if unknown). */
|
|
115
|
+
export declare function renderGlyph(name: GlyphNameInput, options?: RenderGlyphOptions): string;
|