@ponchia/ui 0.3.6 → 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/docs/usage.md CHANGED
@@ -198,11 +198,52 @@ A few sharp edges to know:
198
198
  - **Directional glyphs are physical, not logical.** `arrow-left/right`,
199
199
  `chevron-left/right` are fixed bitmaps; in an RTL context flip them yourself
200
200
  (e.g. swap the name, or `transform: scaleX(-1)`), the framework won't.
201
- - **Cost.** Each glyph is a 16×16 grid = 256 cells (DOM nodes / spans),
202
- regardless of mode; `anim: 'reveal'` adds a per-cell `--i` (≈doubles the
203
- string size). Fine for display marks and the odd inline icon — but don't
204
- render hundreds at once (e.g. one in every row of a long table) without
205
- measuring.
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".
206
247
 
207
248
  ## When to add a behavior
208
249
 
@@ -10,10 +10,12 @@ export type GlyphName =
10
10
  | 'arrow-up'
11
11
  | 'bell'
12
12
  | 'check'
13
+ | 'check-circle'
13
14
  | 'chevron-down'
14
15
  | 'chevron-left'
15
16
  | 'chevron-right'
16
17
  | 'chevron-up'
18
+ | 'circle'
17
19
  | 'clock'
18
20
  | 'close'
19
21
  | 'download'
@@ -32,12 +34,14 @@ export type GlyphName =
32
34
  | 'mail'
33
35
  | 'menu'
34
36
  | 'minus'
37
+ | 'minus-circle'
35
38
  | 'moon'
36
39
  | 'more-horizontal'
37
40
  | 'more-vertical'
38
41
  | 'pause'
39
42
  | 'play'
40
43
  | 'plus'
44
+ | 'plus-circle'
41
45
  | 'refresh'
42
46
  | 'search'
43
47
  | 'spark'
@@ -46,7 +50,8 @@ export type GlyphName =
46
50
  | 'trash'
47
51
  | 'upload'
48
52
  | 'user'
49
- | 'warning';
53
+ | 'warning'
54
+ | 'x-circle';
50
55
 
51
56
  /** A glyph name, or any string — for dynamic dispatch (a CMS/config value). The
52
57
  * known names still autocomplete; an unknown name hits the runtime fallback
@@ -81,6 +86,14 @@ export interface RenderGlyphOptions {
81
86
  /** CSS length for the gap between dots (sets `--dotmatrix-gap`; sanitized
82
87
  * the same way as `dot`). */
83
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;
84
97
  }
85
98
 
86
99
  /** The grid edge length (rows = cols = 16). */
package/glyphs/glyphs.js CHANGED
@@ -25,6 +25,96 @@ export const GLYPH_SIZE = 16;
25
25
  // `.` off · `#` hot · `*` accent. Only `spark` uses accent dots — it is the
26
26
  // canonical two-tone demo; the gate in check-glyphs.mjs enforces the shape.
27
27
  const RAW = {
28
+ circle: [
29
+ '................',
30
+ '.....######.....',
31
+ '....########....',
32
+ '...###....###...',
33
+ '..##........##..',
34
+ '.###........###.',
35
+ '.##..........##.',
36
+ '.##..........##.',
37
+ '.##..........##.',
38
+ '.##..........##.',
39
+ '.###........###.',
40
+ '..##........##..',
41
+ '...###....###...',
42
+ '....########....',
43
+ '.....######.....',
44
+ '................',
45
+ ],
46
+ 'check-circle': [
47
+ '................',
48
+ '.....######.....',
49
+ '....########....',
50
+ '...###....###...',
51
+ '..##........##..',
52
+ '.###........###.',
53
+ '.##........####.',
54
+ '.##..##...##.##.',
55
+ '.##...##.##..##.',
56
+ '.##....###...##.',
57
+ '.###...##...###.',
58
+ '..##........##..',
59
+ '...###....###...',
60
+ '....########....',
61
+ '.....######.....',
62
+ '................',
63
+ ],
64
+ 'x-circle': [
65
+ '................',
66
+ '.....######.....',
67
+ '....########....',
68
+ '...###....###...',
69
+ '..##........##..',
70
+ '.###.##..##.###.',
71
+ '.##...####...##.',
72
+ '.##....##....##.',
73
+ '.##...####...##.',
74
+ '.##..##..##..##.',
75
+ '.#####....#####.',
76
+ '..##........##..',
77
+ '...###....###...',
78
+ '....########....',
79
+ '.....######.....',
80
+ '................',
81
+ ],
82
+ 'plus-circle': [
83
+ '................',
84
+ '.....######.....',
85
+ '....########....',
86
+ '...###....###...',
87
+ '..##........##..',
88
+ '.###...##...###.',
89
+ '.##....##....##.',
90
+ '.##..######..##.',
91
+ '.##..######..##.',
92
+ '.##....##....##.',
93
+ '.###...##...###.',
94
+ '..##........##..',
95
+ '...###....###...',
96
+ '....########....',
97
+ '.....######.....',
98
+ '................',
99
+ ],
100
+ 'minus-circle': [
101
+ '................',
102
+ '.....######.....',
103
+ '....########....',
104
+ '...###....###...',
105
+ '..##........##..',
106
+ '.###........###.',
107
+ '.##..........##.',
108
+ '.##..######..##.',
109
+ '.##..######..##.',
110
+ '.##..........##.',
111
+ '.###........###.',
112
+ '..##........##..',
113
+ '...###....###...',
114
+ '....########....',
115
+ '.....######.....',
116
+ '................',
117
+ ],
28
118
  'arrow-down': [
29
119
  '................',
30
120
  '......####......',
@@ -860,6 +950,40 @@ function cssLen(v) {
860
950
  return /^[\w.%+\-*/()\s,]+$/.test(v) ? v : '';
861
951
  }
862
952
 
953
+ /**
954
+ * Build a CSS `mask-image` `url()` of an inline SVG for a glyph's lit cells —
955
+ * the basis of the one-node `render: 'mask'` path. Horizontal runs are merged
956
+ * into single `<rect>`s (fewer nodes, no seams). The SVG is alpha-masked, so
957
+ * the element's `currentColor` background shows through only the lit cells —
958
+ * one DOM node instead of GLYPH_SIZE² (256), for an icon at any size/colour.
959
+ */
960
+ function maskUrl(rows) {
961
+ let rects = '';
962
+ rows.forEach((row, y) => {
963
+ let run = 0;
964
+ for (let x = 0; x <= GLYPH_SIZE; x++) {
965
+ const on = x < GLYPH_SIZE && row[x] !== '.';
966
+ if (on) run++;
967
+ else if (run) {
968
+ rects += `<rect x='${x - run}' y='${y}' width='${run}' height='1'/>`;
969
+ run = 0;
970
+ }
971
+ }
972
+ });
973
+ // The url() lands unquoted inside an HTML `style="…"` attribute, so it must
974
+ // carry no spaces or quotes of its own — encode them (and `<>#`) so it stays
975
+ // a single CSS url-token and can't break out of the attribute.
976
+ const svg = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${GLYPH_SIZE} ${GLYPH_SIZE}'>${rects}</svg>`;
977
+ const enc = svg
978
+ .replace(/%/g, '%25')
979
+ .replace(/</g, '%3C')
980
+ .replace(/>/g, '%3E')
981
+ .replace(/#/g, '%23')
982
+ .replace(/'/g, '%27')
983
+ .replace(/ /g, '%20');
984
+ return `url(data:image/svg+xml,${enc})`;
985
+ }
986
+
863
987
  /**
864
988
  * A full `.ui-dotmatrix` HTML string for a glyph (`''` if the name is
865
989
  * unknown). Decorative by default (`aria-hidden`); pass `label` to expose it
@@ -875,11 +999,28 @@ function cssLen(v) {
875
999
  * `anim` opts into a decorative animation (disabled under reduced-motion;
876
1000
  * the static frame + `label` still carry the meaning): `'reveal'` powers the
877
1001
  * cells on in a scan, `'pulse'` makes the glyph breathe.
1002
+ *
1003
+ * `render: 'mask'` returns a single `.ui-icon` element masked by the glyph
1004
+ * bitmap (one DOM node, not GLYPH_SIZE²) — the icon-at-scale path: it sizes to
1005
+ * `size` (or `--icon-size` / `1em`) and inherits `currentColor`. The
1006
+ * cell-mode options (grid/solid/anim/dot/gap) don't apply; `label` does.
1007
+ * Needs `@ponchia/ui/css` (the `.ui-icon` rule).
878
1008
  */
879
1009
  export function renderGlyph(name, options = {}) {
1010
+ const rows = GLYPHS[name];
1011
+ if (!rows) return '';
1012
+ const { grid = true, solid = false, anim, label, dot, gap, render, size } = options;
1013
+
1014
+ // One-node icon: a single `.ui-icon` span masked by the glyph's bitmap, so
1015
+ // it scales to any font-size and inherits `currentColor` — for icon-at-scale
1016
+ // (e.g. one in every table row) where the GLYPH_SIZE²-cell path is too heavy.
1017
+ if (render === 'mask') {
1018
+ const a11yM = label ? `role="img" aria-label="${esc(label)}"` : 'aria-hidden="true"';
1019
+ const sz = size && cssLen(size) ? `--icon-size:${cssLen(size)};` : '';
1020
+ return `<span class="ui-icon" style="${sz}--icon-mask:${maskUrl(rows)}" ${a11yM}></span>`;
1021
+ }
1022
+
880
1023
  const cells = glyphCells(name);
881
- if (!cells.length) return '';
882
- const { grid = true, solid = false, anim, label, dot, gap } = options;
883
1024
 
884
1025
  const style = [`--dotmatrix-cols:${GLYPH_SIZE}`];
885
1026
  const dotLen = dot && cssLen(dot);
package/llms.txt CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  > CSS-first, framework-agnostic UI framework. Zero runtime dependencies.
4
4
  > One `@layer bronto` cascade, a typed class vocabulary, design tokens as
5
- > data, and optional SSR-safe vanilla behaviors. Nothing-inspired:
6
- > monochrome surfaces, a single rationed accent, dot-matrix display type.
5
+ > data, and optional SSR-safe vanilla behaviors. Token-driven restraint:
6
+ > monochrome by default, one rationed accent, dot-matrix display type, with
7
+ > opt-in colorways + a colourblind-safe data-viz palette layered on top.
7
8
  >
8
9
  > This file orients an LLM/agent. The authoritative, always-correct API
9
10
  > is the TypeScript declarations shipped in this package (paths below):
@@ -45,6 +46,13 @@ Optional vanilla behaviors (theme toggle, etc. — SSR-safe, tree-shakeable):
45
46
  import { applyStoredTheme } from '@ponchia/ui/behaviors';
46
47
  ```
47
48
 
49
+ For React/Solid, optional thin hook bindings over those behaviors (peer deps
50
+ `react` / `solid-js`, optional — core stays zero-dep):
51
+
52
+ ```js
53
+ import { useDialog, useToast } from '@ponchia/ui/react'; // or '@ponchia/ui/solid'
54
+ ```
55
+
48
56
  Optional display glyphs — dot-matrix bitmaps on the `.ui-dotmatrix` primitive
49
57
  (decorative by default; `renderGlyph` is SSR-safe, `initDotGlyph` is the DOM form):
50
58
 
@@ -53,6 +61,34 @@ import { renderGlyph, GLYPH_NAMES } from '@ponchia/ui/glyphs';
53
61
  el.innerHTML = renderGlyph('check', { label: 'Done' });
54
62
  ```
55
63
 
64
+ Optional display colorways — opt-in, never in the default bundle. Root-level,
65
+ like `data-theme` (the derived accent family only recomputes at `:root`):
66
+
67
+ ```html
68
+ <link rel="stylesheet" href="@ponchia/ui/css/skins.css" />
69
+ <html data-bronto-skin="amber-crt | phosphor-green | e-ink">
70
+ ```
71
+
72
+ Each re-points the one `--accent` (OKLCH, per-theme, contrast-gated); status
73
+ colours and the neutral canvas are untouched. Details in `docs/theming.md`.
74
+
75
+ Optional data-viz palette for dashboards — opt-in, charts-only (never UI
76
+ chrome), never in the default bundle:
77
+
78
+ ```html
79
+ <link rel="stylesheet" href="@ponchia/ui/css/dataviz.css" />
80
+ ```
81
+
82
+ ```js
83
+ import charts from '@ponchia/ui/charts.json' with { type: 'json' };
84
+ // charts.dark.categorical → ['#ff3b41', …] (series 0 = the resolved accent)
85
+ ```
86
+
87
+ `--chart-1..8` (categorical; series 1 = accent; colourblind-safe, gated under
88
+ simulated protan/deutan/tritan), `--chart-seq-*` (sequential), `--chart-div-*`
89
+ (diverging), and `--chart-pattern-1..8` (dot-matrix fills — pair colour N with
90
+ pattern N; colour is never the sole signal). Details in `docs/theming.md`.
91
+
56
92
  ## Authoritative offline references (shipped in this package)
57
93
 
58
94
  Read these from `node_modules/@ponchia/ui/` — no network needed:
@@ -97,6 +133,9 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
97
133
  - Prefer the `ui.*()` recipes over hand-concatenating modifier strings.
98
134
  - Override framework styles by writing your own rules outside
99
135
  `@layer bronto` — not with higher specificity or `!important`.
100
- - The accent color is deliberately rationed (monochrome + one accent).
101
- Do not introduce new hues; theme via the documented tokens only.
136
+ - Color is tiered (ADR-0001): neutral canvas · one rationed accent · locked
137
+ status · display expression · opt-in data-viz. Theme via the documented
138
+ tokens — re-point `--accent` (or a `data-bronto-skin` colorway), use status
139
+ tokens for status, and `--chart-*` (from `css/dataviz.css`) for charts only.
140
+ Don't add raw hues to components; `check:color-policy` enforces this.
102
141
  - Pre-1.0 SemVer: breaking changes ship in the *minor*. Pin `~0.x`.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@ponchia/ui",
3
- "version": "0.3.6",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
- "description": "Nothing-inspired, CSS-first UI framework — monochrome design tokens, one rationed accent, dot-matrix motifs, zero runtime dependencies, framework-agnostic.",
5
+ "description": "CSS-first, framework-agnostic UI framework — token-driven restraint (monochrome by default, one rationed accent), OKLCH colorways, a dot-matrix icon set, a colourblind-safe data-viz palette, dot-matrix motifs, zero runtime dependencies.",
6
6
  "keywords": [
7
7
  "css",
8
8
  "ui",
@@ -13,6 +13,11 @@
13
13
  "css-layers",
14
14
  "nothing",
15
15
  "monochrome",
16
+ "oklch",
17
+ "colorways",
18
+ "icons",
19
+ "data-visualization",
20
+ "wcag",
16
21
  "framework-agnostic",
17
22
  "zero-dependencies",
18
23
  "dark-mode",
@@ -41,12 +46,16 @@
41
46
  "classes",
42
47
  "behaviors",
43
48
  "glyphs",
49
+ "react",
50
+ "solid",
44
51
  "shiki",
45
52
  "llms.txt",
53
+ "CHANGELOG.md",
46
54
  "docs/reference.md",
47
55
  "docs/theming.md",
48
56
  "docs/contrast.md",
49
- "docs/usage.md"
57
+ "docs/usage.md",
58
+ "docs/adr/0001-color-system.md"
50
59
  ],
51
60
  "style": "./dist/bronto.css",
52
61
  "scripts": {
@@ -59,6 +68,8 @@
59
68
  "resolved:build": "node scripts/gen-resolved.mjs",
60
69
  "dts:build": "node scripts/gen-dts.mjs",
61
70
  "glyphs:build": "node scripts/gen-glyphs.mjs",
71
+ "skins:build": "node scripts/gen-skins.mjs",
72
+ "charts:build": "node scripts/gen-charts.mjs",
62
73
  "reference:build": "node scripts/gen-reference.mjs",
63
74
  "contrast:build": "node scripts/gen-contrast.mjs",
64
75
  "vscode:build": "node scripts/gen-vscode-data.mjs",
@@ -68,7 +79,11 @@
68
79
  "check:classes": "node scripts/check-classes.mjs",
69
80
  "check:dts": "node scripts/check-dts.mjs",
70
81
  "check:behaviors": "node scripts/check-behaviors.mjs",
82
+ "check:bindings": "node scripts/check-bindings.mjs",
71
83
  "check:glyphs": "node scripts/check-glyphs.mjs",
84
+ "check:color-policy": "node scripts/check-color-policy.mjs",
85
+ "check:skins": "node scripts/check-skins.mjs",
86
+ "check:charts": "node scripts/check-charts.mjs",
72
87
  "check:types": "tsc -p tsconfig.json",
73
88
  "check:dtcg": "node scripts/check-dtcg.mjs",
74
89
  "check:resolved": "node scripts/check-resolved.mjs",
@@ -79,9 +94,9 @@
79
94
  "check:reference": "node scripts/check-reference.mjs",
80
95
  "check:contrast": "node scripts/check-contrast.mjs",
81
96
  "check:vscode": "node scripts/check-vscode-data.mjs",
82
- "check": "npm run lint && npm run check:format && npm run check:exports && npm run check:tokens && npm run check:classes && npm run check:dts && npm run check:types && npm run check:dtcg && npm run check:resolved && npm run check:shiki && npm run check:dist && npm run check:pack && npm run check:release && npm run check:reference && npm run check:contrast && npm run check:vscode && npm run check:behaviors && npm run check:glyphs",
97
+ "check": "npm run lint && npm run check:format && npm run check:exports && npm run check:tokens && npm run check:classes && npm run check:dts && npm run check:types && npm run check:dtcg && npm run check:resolved && npm run check:shiki && npm run check:dist && npm run check:pack && npm run check:release && npm run check:reference && npm run check:contrast && npm run check:vscode && npm run check:behaviors && npm run check:bindings && npm run check:glyphs && npm run check:color-policy && npm run check:skins && npm run check:charts",
83
98
  "test": "node --test \"test/*.test.mjs\"",
84
- "prepack": "npm run tokens:build && npm run dtcg:build && npm run resolved:build && npm run dts:build && npm run reference:build && npm run contrast:build && npm run vscode:build && npm run dist:build && npm run glyphs:build",
99
+ "prepack": "npm run tokens:build && npm run dtcg:build && npm run resolved:build && npm run dts:build && npm run reference:build && npm run contrast:build && npm run vscode:build && npm run skins:build && npm run charts:build && npm run dist:build && npm run glyphs:build",
85
100
  "prepublishOnly": "npm run check && npm test"
86
101
  },
87
102
  "devDependencies": {
@@ -94,6 +109,18 @@
94
109
  "stylelint-use-logical": "^2.1.3",
95
110
  "typescript": "^6.0.3"
96
111
  },
112
+ "peerDependencies": {
113
+ "react": ">=18",
114
+ "solid-js": ">=1.6"
115
+ },
116
+ "peerDependenciesMeta": {
117
+ "react": {
118
+ "optional": true
119
+ },
120
+ "solid-js": {
121
+ "optional": true
122
+ }
123
+ },
97
124
  "exports": {
98
125
  ".": {
99
126
  "style": "./dist/bronto.css",
@@ -117,6 +144,8 @@
117
144
  "./css/disclosure.css": "./dist/css/disclosure.css",
118
145
  "./css/table.css": "./dist/css/table.css",
119
146
  "./css/app.css": "./dist/css/app.css",
147
+ "./css/skins.css": "./dist/css/skins.css",
148
+ "./css/dataviz.css": "./dist/css/dataviz.css",
120
149
  "./css/unlayered/tokens.css": "./css/tokens.css",
121
150
  "./css/unlayered/fonts.css": "./css/fonts.css",
122
151
  "./css/unlayered/base.css": "./css/base.css",
@@ -132,6 +161,8 @@
132
161
  "./css/unlayered/disclosure.css": "./css/disclosure.css",
133
162
  "./css/unlayered/table.css": "./css/table.css",
134
163
  "./css/unlayered/app.css": "./css/app.css",
164
+ "./css/unlayered/skins.css": "./css/skins.css",
165
+ "./css/unlayered/dataviz.css": "./css/dataviz.css",
135
166
  "./tokens": {
136
167
  "types": "./tokens/index.d.ts",
137
168
  "default": "./tokens/index.js"
@@ -146,6 +177,7 @@
146
177
  "./docs/theming.md": "./docs/theming.md",
147
178
  "./docs/contrast.md": "./docs/contrast.md",
148
179
  "./docs/usage.md": "./docs/usage.md",
180
+ "./docs/adr/0001-color-system.md": "./docs/adr/0001-color-system.md",
149
181
  "./classes": {
150
182
  "types": "./classes/index.d.ts",
151
183
  "default": "./classes/index.js"
@@ -158,6 +190,23 @@
158
190
  "types": "./glyphs/glyphs.d.ts",
159
191
  "default": "./glyphs/glyphs.js"
160
192
  },
193
+ "./react": {
194
+ "types": "./react/index.d.ts",
195
+ "default": "./react/index.js"
196
+ },
197
+ "./solid": {
198
+ "types": "./solid/index.d.ts",
199
+ "default": "./solid/index.js"
200
+ },
201
+ "./skins": {
202
+ "types": "./tokens/skins.d.ts",
203
+ "default": "./tokens/skins.js"
204
+ },
205
+ "./charts": {
206
+ "types": "./tokens/charts.d.ts",
207
+ "default": "./tokens/charts.js"
208
+ },
209
+ "./charts.json": "./tokens/charts.json",
161
210
  "./fonts/*": "./fonts/*"
162
211
  }
163
212
  }
@@ -0,0 +1,36 @@
1
+ /** @ponchia/ui/react — thin React bindings over the SSR-safe behaviors.
2
+ * Optional peer dep `react`. Hooks run a delegated behavior for the
3
+ * component's lifetime; they take the same options as the behavior and
4
+ * return void (the cleanup is wired to unmount). See behaviors/index.d.ts. */
5
+ import type {
6
+ Cleanup,
7
+ DelegateOpts,
8
+ ThemeStorageOpts,
9
+ ToastOpts,
10
+ } from '../behaviors/index.js';
11
+
12
+ /** Run any delegated behavior for the component's lifetime (init on mount,
13
+ * its returned cleanup on unmount). The behavior is run once. */
14
+ export declare function useBrontoBehavior(
15
+ init: (opts?: DelegateOpts) => Cleanup | void,
16
+ opts?: DelegateOpts,
17
+ ): void;
18
+
19
+ export declare function useThemeToggle(opts?: ThemeStorageOpts & DelegateOpts): void;
20
+ export declare function useDismissible(opts?: DelegateOpts): void;
21
+ export declare function useDisclosure(opts?: DelegateOpts): void;
22
+ export declare function useMenu(opts?: DelegateOpts): void;
23
+ export declare function useFormValidation(opts?: DelegateOpts): void;
24
+ export declare function useCombobox(opts?: DelegateOpts): void;
25
+ export declare function usePopover(opts?: DelegateOpts): void;
26
+ export declare function useTableSort(opts?: DelegateOpts): void;
27
+ export declare function useTabs(opts?: DelegateOpts): void;
28
+ export declare function useDialog(opts?: DelegateOpts): void;
29
+ export declare function useCarousel(opts?: DelegateOpts): void;
30
+ export declare function useDotGlyph(opts?: DelegateOpts): void;
31
+
32
+ /** The `toast()` imperative (no lifecycle of its own). */
33
+ export declare function useToast(): (message: string, opts?: ToastOpts) => Cleanup;
34
+
35
+ export { applyStoredTheme } from '../behaviors/index.js';
36
+ export { cls, ui, cx } from '../classes/index.js';
package/react/index.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @ponchia/ui/react — thin React bindings over @ponchia/ui/behaviors.
3
+ *
4
+ * The CSS is the framework; these are *optional* hooks that wrap the SSR-safe
5
+ * vanilla `init*` behaviors in a component lifecycle (run on mount, clean up on
6
+ * unmount). They are deliberately thin adapters — not a component library — per
7
+ * the architecture ADR. `react` is an optional peer dependency.
8
+ *
9
+ * The behaviors delegate from a root (default `document`), so call a hook once
10
+ * near the relevant subtree; pass `{ root: ref.current }` to scope it. The root
11
+ * is captured on mount — keep it stable (a ref), like any effect dependency.
12
+ *
13
+ * import { useDialog, useToast } from '@ponchia/ui/react';
14
+ * function App() {
15
+ * useDialog(); // wires every .ui-modal under document
16
+ * const toast = useToast();
17
+ * return <button onClick={() => toast('Saved', { tone: 'success' })}>Save</button>;
18
+ * }
19
+ */
20
+ import { useEffect } from 'react';
21
+ import {
22
+ applyStoredTheme,
23
+ initThemeToggle,
24
+ dismissible,
25
+ initDisclosure,
26
+ initMenu,
27
+ initFormValidation,
28
+ initCombobox,
29
+ initPopover,
30
+ initTableSort,
31
+ initTabs,
32
+ initDialog,
33
+ initCarousel,
34
+ initDotGlyph,
35
+ toast,
36
+ } from '../behaviors/index.js';
37
+
38
+ /** Run a delegated behavior for the component's lifetime (init on mount, its
39
+ * returned cleanup on unmount). The behavior is run once; `opts` is captured
40
+ * on mount — pass a stable root (a ref) if you scope it. */
41
+ export function useBrontoBehavior(init, opts) {
42
+ useEffect(() => init(opts), []); // eslint-disable-line react-hooks/exhaustive-deps -- delegated once on mount
43
+ }
44
+
45
+ export const useThemeToggle = (opts) => useBrontoBehavior(initThemeToggle, opts);
46
+ export const useDismissible = (opts) => useBrontoBehavior(dismissible, opts);
47
+ export const useDisclosure = (opts) => useBrontoBehavior(initDisclosure, opts);
48
+ export const useMenu = (opts) => useBrontoBehavior(initMenu, opts);
49
+ export const useFormValidation = (opts) => useBrontoBehavior(initFormValidation, opts);
50
+ export const useCombobox = (opts) => useBrontoBehavior(initCombobox, opts);
51
+ export const usePopover = (opts) => useBrontoBehavior(initPopover, opts);
52
+ export const useTableSort = (opts) => useBrontoBehavior(initTableSort, opts);
53
+ export const useTabs = (opts) => useBrontoBehavior(initTabs, opts);
54
+ export const useDialog = (opts) => useBrontoBehavior(initDialog, opts);
55
+ export const useCarousel = (opts) => useBrontoBehavior(initCarousel, opts);
56
+ export const useDotGlyph = (opts) => useBrontoBehavior(initDotGlyph, opts);
57
+
58
+ /** The `toast()` imperative (no lifecycle of its own). */
59
+ export const useToast = () => toast;
60
+
61
+ // No-flash theme application has to run before paint; do it in an inline head
62
+ // script, not an effect. Re-exported for manual/SSR-bootstrap use.
63
+ export { applyStoredTheme };
64
+
65
+ // Convenience: the framework-agnostic class contract, re-exported so a React
66
+ // consumer needs one import.
67
+ export { cls, ui, cx } from '../classes/index.js';
@@ -0,0 +1,36 @@
1
+ /** @ponchia/ui/solid — thin Solid bindings over the SSR-safe behaviors.
2
+ * Optional peer dep `solid-js`. Primitives run a delegated behavior for the
3
+ * component's lifetime; they take the same options as the behavior and return
4
+ * void (the cleanup is wired to dispose). See behaviors/index.d.ts. */
5
+ import type {
6
+ Cleanup,
7
+ DelegateOpts,
8
+ ThemeStorageOpts,
9
+ ToastOpts,
10
+ } from '../behaviors/index.js';
11
+
12
+ /** Run any delegated behavior for the component's lifetime (init on mount,
13
+ * its returned cleanup on dispose). */
14
+ export declare function useBrontoBehavior(
15
+ init: (opts?: DelegateOpts) => Cleanup | void,
16
+ opts?: DelegateOpts,
17
+ ): void;
18
+
19
+ export declare function useThemeToggle(opts?: ThemeStorageOpts & DelegateOpts): void;
20
+ export declare function useDismissible(opts?: DelegateOpts): void;
21
+ export declare function useDisclosure(opts?: DelegateOpts): void;
22
+ export declare function useMenu(opts?: DelegateOpts): void;
23
+ export declare function useFormValidation(opts?: DelegateOpts): void;
24
+ export declare function useCombobox(opts?: DelegateOpts): void;
25
+ export declare function usePopover(opts?: DelegateOpts): void;
26
+ export declare function useTableSort(opts?: DelegateOpts): void;
27
+ export declare function useTabs(opts?: DelegateOpts): void;
28
+ export declare function useDialog(opts?: DelegateOpts): void;
29
+ export declare function useCarousel(opts?: DelegateOpts): void;
30
+ export declare function useDotGlyph(opts?: DelegateOpts): void;
31
+
32
+ /** The `toast()` imperative (no lifecycle of its own). */
33
+ export declare function useToast(): (message: string, opts?: ToastOpts) => Cleanup;
34
+
35
+ export { applyStoredTheme } from '../behaviors/index.js';
36
+ export { cls, ui, cx } from '../classes/index.js';