@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.
Files changed (123) hide show
  1. package/CHANGELOG.md +352 -12
  2. package/MIGRATIONS.json +92 -0
  3. package/README.md +27 -17
  4. package/annotations/index.d.ts +280 -0
  5. package/annotations/index.js +522 -0
  6. package/behaviors/carousel.js +197 -0
  7. package/behaviors/combobox.js +195 -0
  8. package/behaviors/command.js +187 -0
  9. package/behaviors/connectors.js +96 -0
  10. package/behaviors/crosshair.js +58 -0
  11. package/behaviors/dialog.js +73 -0
  12. package/behaviors/disclosure.js +25 -0
  13. package/behaviors/dismissible.js +24 -0
  14. package/behaviors/forms.js +158 -0
  15. package/behaviors/glyph.js +109 -0
  16. package/behaviors/index.d.ts +82 -1
  17. package/behaviors/index.js +18 -1336
  18. package/behaviors/internal.js +50 -0
  19. package/behaviors/legend.js +46 -0
  20. package/behaviors/menu.js +46 -0
  21. package/behaviors/popover.js +108 -0
  22. package/behaviors/spotlight.js +53 -0
  23. package/behaviors/table.js +109 -0
  24. package/behaviors/tabs.js +103 -0
  25. package/behaviors/theme.js +82 -0
  26. package/behaviors/toast.js +152 -0
  27. package/classes/index.d.ts +318 -0
  28. package/classes/index.js +352 -0
  29. package/classes/vscode.css-custom-data.json +18 -14
  30. package/connectors/index.d.ts +71 -0
  31. package/connectors/index.js +179 -0
  32. package/css/analytical.css +21 -0
  33. package/css/annotations.css +292 -0
  34. package/css/command.css +97 -0
  35. package/css/connectors.css +93 -0
  36. package/css/crosshair.css +100 -0
  37. package/css/disclosure.css +29 -0
  38. package/css/dots.css +2 -0
  39. package/css/feedback.css +104 -0
  40. package/css/fonts.css +11 -7
  41. package/css/generated.css +117 -0
  42. package/css/legend.css +268 -0
  43. package/css/marks.css +144 -0
  44. package/css/motion.css +88 -0
  45. package/css/overlay.css +52 -1
  46. package/css/primitives.css +18 -0
  47. package/css/report.css +363 -0
  48. package/css/selection.css +46 -0
  49. package/css/sources.css +179 -0
  50. package/css/spotlight.css +104 -0
  51. package/css/state.css +121 -0
  52. package/css/tokens.css +78 -60
  53. package/css/workbench.css +83 -0
  54. package/dist/bronto.css +1 -1
  55. package/dist/css/analytical.css +1 -0
  56. package/dist/css/annotations.css +1 -0
  57. package/dist/css/command.css +1 -0
  58. package/dist/css/connectors.css +1 -0
  59. package/dist/css/crosshair.css +1 -0
  60. package/dist/css/disclosure.css +1 -1
  61. package/dist/css/dots.css +1 -1
  62. package/dist/css/feedback.css +1 -1
  63. package/dist/css/fonts.css +1 -1
  64. package/dist/css/generated.css +1 -0
  65. package/dist/css/legend.css +1 -0
  66. package/dist/css/marks.css +1 -0
  67. package/dist/css/motion.css +1 -1
  68. package/dist/css/overlay.css +1 -1
  69. package/dist/css/primitives.css +1 -1
  70. package/dist/css/report.css +1 -0
  71. package/dist/css/selection.css +1 -0
  72. package/dist/css/sources.css +1 -0
  73. package/dist/css/spotlight.css +1 -0
  74. package/dist/css/state.css +1 -0
  75. package/dist/css/tokens.css +1 -1
  76. package/dist/css/workbench.css +1 -0
  77. package/docs/adr/0001-color-system.md +26 -27
  78. package/docs/adr/0002-scope-and-2026-baseline.md +104 -0
  79. package/docs/adr/0003-theme-model.md +97 -0
  80. package/docs/annotations.md +345 -0
  81. package/docs/architecture.md +202 -0
  82. package/docs/command.md +95 -0
  83. package/docs/connectors.md +91 -0
  84. package/docs/contrast.md +42 -42
  85. package/docs/crosshair.md +63 -0
  86. package/docs/generated.md +91 -0
  87. package/docs/legends.md +168 -0
  88. package/docs/marks.md +86 -0
  89. package/docs/reference.md +418 -15
  90. package/docs/reporting.md +305 -0
  91. package/docs/selection.md +40 -0
  92. package/docs/sources.md +110 -0
  93. package/docs/spotlight.md +78 -0
  94. package/docs/stability.md +52 -0
  95. package/docs/state.md +85 -0
  96. package/docs/theming.md +18 -6
  97. package/docs/usage.md +43 -3
  98. package/docs/workbench.md +72 -0
  99. package/fonts/doto-400.woff2 +0 -0
  100. package/fonts/doto-500.woff2 +0 -0
  101. package/fonts/doto-600.woff2 +0 -0
  102. package/fonts/doto-700.woff2 +0 -0
  103. package/fonts/doto-800.woff2 +0 -0
  104. package/fonts/doto-900.woff2 +0 -0
  105. package/llms.txt +288 -8
  106. package/package.json +95 -5
  107. package/qwik/index.d.ts +60 -0
  108. package/qwik/index.js +149 -0
  109. package/react/index.d.ts +40 -14
  110. package/react/index.js +32 -5
  111. package/solid/index.d.ts +40 -14
  112. package/solid/index.js +31 -3
  113. package/tokens/index.d.ts +3 -3
  114. package/tokens/index.js +25 -19
  115. package/tokens/index.json +32 -28
  116. package/tokens/resolved.json +34 -32
  117. package/tokens/tokens.dtcg.json +22 -14
  118. package/fonts/doto-400.ttf +0 -0
  119. package/fonts/doto-500.ttf +0 -0
  120. package/fonts/doto-600.ttf +0 -0
  121. package/fonts/doto-700.ttf +0 -0
  122. package/fonts/doto-800.ttf +0 -0
  123. package/fonts/doto-900.ttf +0 -0
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@ponchia/ui",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
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.",
5
+ "description": "CSS-first design system for interfaces that explain themselves works in HTML, every framework, and PDF, no component runtime. A standard component set plus an opt-in analytical & report layer (annotations, legends, connectors, data-viz, report grammar). Monochrome with one rationed accent, re-skinnable from one --accent knob. Zero runtime dependencies.",
6
6
  "keywords": [
7
7
  "css",
8
8
  "ui",
@@ -46,16 +46,37 @@
46
46
  "classes",
47
47
  "behaviors",
48
48
  "glyphs",
49
+ "annotations",
50
+ "connectors",
49
51
  "react",
50
52
  "solid",
53
+ "qwik",
51
54
  "shiki",
52
55
  "llms.txt",
53
56
  "CHANGELOG.md",
57
+ "MIGRATIONS.json",
58
+ "docs/architecture.md",
54
59
  "docs/reference.md",
55
60
  "docs/theming.md",
56
61
  "docs/contrast.md",
62
+ "docs/stability.md",
57
63
  "docs/usage.md",
58
- "docs/adr/0001-color-system.md"
64
+ "docs/reporting.md",
65
+ "docs/annotations.md",
66
+ "docs/legends.md",
67
+ "docs/marks.md",
68
+ "docs/connectors.md",
69
+ "docs/spotlight.md",
70
+ "docs/crosshair.md",
71
+ "docs/selection.md",
72
+ "docs/sources.md",
73
+ "docs/state.md",
74
+ "docs/generated.md",
75
+ "docs/workbench.md",
76
+ "docs/command.md",
77
+ "docs/adr/0001-color-system.md",
78
+ "docs/adr/0002-scope-and-2026-baseline.md",
79
+ "docs/adr/0003-theme-model.md"
59
80
  ],
60
81
  "style": "./dist/bronto.css",
61
82
  "scripts": {
@@ -63,7 +84,9 @@
63
84
  "lint:fix": "stylelint \"css/**/*.css\" --fix",
64
85
  "format": "prettier --write .",
65
86
  "check:format": "prettier --check .",
87
+ "size:report": "node scripts/size-report.mjs",
66
88
  "tokens:build": "node scripts/gen-tokens-json.mjs",
89
+ "tokens:css:build": "node scripts/gen-tokens-css.mjs",
67
90
  "dtcg:build": "node scripts/gen-dtcg.mjs",
68
91
  "resolved:build": "node scripts/gen-resolved.mjs",
69
92
  "dts:build": "node scripts/gen-dts.mjs",
@@ -80,10 +103,13 @@
80
103
  "check:dts": "node scripts/check-dts.mjs",
81
104
  "check:behaviors": "node scripts/check-behaviors.mjs",
82
105
  "check:bindings": "node scripts/check-bindings.mjs",
106
+ "check:helpers-dts": "node scripts/check-helpers-dts.mjs",
83
107
  "check:glyphs": "node scripts/check-glyphs.mjs",
84
108
  "check:color-policy": "node scripts/check-color-policy.mjs",
85
109
  "check:skins": "node scripts/check-skins.mjs",
86
110
  "check:charts": "node scripts/check-charts.mjs",
111
+ "check:report": "node scripts/check-report.mjs",
112
+ "check:legend": "node scripts/check-legend.mjs",
87
113
  "check:types": "tsc -p tsconfig.json",
88
114
  "check:dtcg": "node scripts/check-dtcg.mjs",
89
115
  "check:resolved": "node scripts/check-resolved.mjs",
@@ -94,26 +120,34 @@
94
120
  "check:reference": "node scripts/check-reference.mjs",
95
121
  "check:contrast": "node scripts/check-contrast.mjs",
96
122
  "check:vscode": "node scripts/check-vscode-data.mjs",
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",
123
+ "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:helpers-dts && npm run check:glyphs && npm run check:color-policy && npm run check:skins && npm run check:charts && npm run check:report && npm run check:legend",
98
124
  "test": "node --test \"test/*.test.mjs\"",
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",
125
+ "prepack": "npm run tokens:css:build && 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",
100
126
  "prepublishOnly": "npm run check && npm test"
101
127
  },
102
128
  "devDependencies": {
103
129
  "@axe-core/playwright": "^4.11.3",
130
+ "@builder.io/qwik": "^1.20.0",
104
131
  "@playwright/test": "^1.60.0",
105
132
  "jsdom": "^29.1.1",
106
133
  "prettier": "^3.8.3",
134
+ "react": "^19.2.6",
135
+ "react-dom": "^19.2.6",
136
+ "solid-js": "^1.9.13",
107
137
  "stylelint": "^17.11.1",
108
138
  "stylelint-config-standard": "^40.0.0",
109
139
  "stylelint-use-logical": "^2.1.3",
110
140
  "typescript": "^6.0.3"
111
141
  },
112
142
  "peerDependencies": {
143
+ "@builder.io/qwik": ">=1.5",
113
144
  "react": ">=18",
114
145
  "solid-js": ">=1.6"
115
146
  },
116
147
  "peerDependenciesMeta": {
148
+ "@builder.io/qwik": {
149
+ "optional": true
150
+ },
117
151
  "react": {
118
152
  "optional": true
119
153
  },
@@ -146,6 +180,20 @@
146
180
  "./css/app.css": "./dist/css/app.css",
147
181
  "./css/skins.css": "./dist/css/skins.css",
148
182
  "./css/dataviz.css": "./dist/css/dataviz.css",
183
+ "./css/report.css": "./dist/css/report.css",
184
+ "./css/annotations.css": "./dist/css/annotations.css",
185
+ "./css/legend.css": "./dist/css/legend.css",
186
+ "./css/marks.css": "./dist/css/marks.css",
187
+ "./css/connectors.css": "./dist/css/connectors.css",
188
+ "./css/spotlight.css": "./dist/css/spotlight.css",
189
+ "./css/crosshair.css": "./dist/css/crosshair.css",
190
+ "./css/selection.css": "./dist/css/selection.css",
191
+ "./css/sources.css": "./dist/css/sources.css",
192
+ "./css/state.css": "./dist/css/state.css",
193
+ "./css/generated.css": "./dist/css/generated.css",
194
+ "./css/workbench.css": "./dist/css/workbench.css",
195
+ "./css/command.css": "./dist/css/command.css",
196
+ "./css/analytical.css": "./dist/css/analytical.css",
149
197
  "./css/unlayered/tokens.css": "./css/tokens.css",
150
198
  "./css/unlayered/fonts.css": "./css/fonts.css",
151
199
  "./css/unlayered/base.css": "./css/base.css",
@@ -163,6 +211,19 @@
163
211
  "./css/unlayered/app.css": "./css/app.css",
164
212
  "./css/unlayered/skins.css": "./css/skins.css",
165
213
  "./css/unlayered/dataviz.css": "./css/dataviz.css",
214
+ "./css/unlayered/report.css": "./css/report.css",
215
+ "./css/unlayered/annotations.css": "./css/annotations.css",
216
+ "./css/unlayered/legend.css": "./css/legend.css",
217
+ "./css/unlayered/marks.css": "./css/marks.css",
218
+ "./css/unlayered/connectors.css": "./css/connectors.css",
219
+ "./css/unlayered/spotlight.css": "./css/spotlight.css",
220
+ "./css/unlayered/crosshair.css": "./css/crosshair.css",
221
+ "./css/unlayered/selection.css": "./css/selection.css",
222
+ "./css/unlayered/sources.css": "./css/sources.css",
223
+ "./css/unlayered/state.css": "./css/state.css",
224
+ "./css/unlayered/generated.css": "./css/generated.css",
225
+ "./css/unlayered/workbench.css": "./css/workbench.css",
226
+ "./css/unlayered/command.css": "./css/command.css",
166
227
  "./tokens": {
167
228
  "types": "./tokens/index.d.ts",
168
229
  "default": "./tokens/index.js"
@@ -173,11 +234,28 @@
173
234
  "./tokens/resolved.json": "./tokens/resolved.json",
174
235
  "./shiki/nothing.json": "./shiki/nothing.json",
175
236
  "./llms.txt": "./llms.txt",
237
+ "./docs/architecture.md": "./docs/architecture.md",
176
238
  "./docs/reference.md": "./docs/reference.md",
177
239
  "./docs/theming.md": "./docs/theming.md",
178
240
  "./docs/contrast.md": "./docs/contrast.md",
241
+ "./docs/stability.md": "./docs/stability.md",
179
242
  "./docs/usage.md": "./docs/usage.md",
243
+ "./docs/reporting.md": "./docs/reporting.md",
244
+ "./docs/annotations.md": "./docs/annotations.md",
245
+ "./docs/legends.md": "./docs/legends.md",
246
+ "./docs/marks.md": "./docs/marks.md",
247
+ "./docs/connectors.md": "./docs/connectors.md",
248
+ "./docs/spotlight.md": "./docs/spotlight.md",
249
+ "./docs/crosshair.md": "./docs/crosshair.md",
250
+ "./docs/selection.md": "./docs/selection.md",
251
+ "./docs/sources.md": "./docs/sources.md",
252
+ "./docs/state.md": "./docs/state.md",
253
+ "./docs/generated.md": "./docs/generated.md",
254
+ "./docs/workbench.md": "./docs/workbench.md",
255
+ "./docs/command.md": "./docs/command.md",
180
256
  "./docs/adr/0001-color-system.md": "./docs/adr/0001-color-system.md",
257
+ "./docs/adr/0002-scope-and-2026-baseline.md": "./docs/adr/0002-scope-and-2026-baseline.md",
258
+ "./docs/adr/0003-theme-model.md": "./docs/adr/0003-theme-model.md",
181
259
  "./classes": {
182
260
  "types": "./classes/index.d.ts",
183
261
  "default": "./classes/index.js"
@@ -190,6 +268,14 @@
190
268
  "types": "./glyphs/glyphs.d.ts",
191
269
  "default": "./glyphs/glyphs.js"
192
270
  },
271
+ "./annotations": {
272
+ "types": "./annotations/index.d.ts",
273
+ "default": "./annotations/index.js"
274
+ },
275
+ "./connectors": {
276
+ "types": "./connectors/index.d.ts",
277
+ "default": "./connectors/index.js"
278
+ },
193
279
  "./react": {
194
280
  "types": "./react/index.d.ts",
195
281
  "default": "./react/index.js"
@@ -198,6 +284,10 @@
198
284
  "types": "./solid/index.d.ts",
199
285
  "default": "./solid/index.js"
200
286
  },
287
+ "./qwik": {
288
+ "types": "./qwik/index.d.ts",
289
+ "default": "./qwik/index.js"
290
+ },
201
291
  "./skins": {
202
292
  "types": "./tokens/skins.d.ts",
203
293
  "default": "./tokens/skins.js"
@@ -0,0 +1,60 @@
1
+ /** @ponchia/ui/qwik — thin Qwik bindings over the SSR-safe behaviors.
2
+ * Optional peer dep `@builder.io/qwik`. Hooks run a delegated behavior on
3
+ * visible and register cleanup on dispose (via `useVisibleTask$`); they take
4
+ * the same options as the behavior and return void. See behaviors/index.d.ts. */
5
+ import type { Cleanup, DelegateOpts, ThemeStorageOpts, ToastOpts } from '../behaviors/index.js';
6
+
7
+ export type BrontoBindingRoot =
8
+ | Document
9
+ | Element
10
+ // Qwik `useSignal()` (and any { value } / { current } ref shape).
11
+ | { value: Document | Element | null | undefined }
12
+ | { current: Document | Element | null | undefined }
13
+ | (() => Document | Element | null | undefined)
14
+ | null
15
+ | undefined;
16
+
17
+ export type BrontoBindingOpts<T extends DelegateOpts = DelegateOpts> = Omit<T, 'root'> & {
18
+ root?: BrontoBindingRoot;
19
+ };
20
+
21
+ export type BrontoBindingOptsResolver<T extends DelegateOpts = DelegateOpts> =
22
+ | BrontoBindingOpts<T>
23
+ | (() => BrontoBindingOpts<T> | null | undefined)
24
+ | null
25
+ | undefined;
26
+
27
+ /** Run any delegated behavior for the component's lifetime (init on visible,
28
+ * its returned cleanup on dispose). Prefer the specific `use*` hooks in Qwik
29
+ * so the optimizer can serialize the task; this generic form is safe only with
30
+ * an optimizer-visible (module-imported) behavior. */
31
+ export declare function useBrontoBehavior(
32
+ init: (opts?: DelegateOpts) => Cleanup | void,
33
+ opts?: BrontoBindingOptsResolver,
34
+ ): void;
35
+
36
+ export declare function useThemeToggle(
37
+ opts?: BrontoBindingOptsResolver<ThemeStorageOpts & DelegateOpts>,
38
+ ): void;
39
+ export declare function useDismissible(opts?: BrontoBindingOptsResolver): void;
40
+ export declare function useDisclosure(opts?: BrontoBindingOptsResolver): void;
41
+ export declare function useMenu(opts?: BrontoBindingOptsResolver): void;
42
+ export declare function useFormValidation(opts?: BrontoBindingOptsResolver): void;
43
+ export declare function useCombobox(opts?: BrontoBindingOptsResolver): void;
44
+ export declare function usePopover(opts?: BrontoBindingOptsResolver): void;
45
+ export declare function useTableSort(opts?: BrontoBindingOptsResolver): void;
46
+ export declare function useTabs(opts?: BrontoBindingOptsResolver): void;
47
+ export declare function useDialog(opts?: BrontoBindingOptsResolver): void;
48
+ export declare function useCarousel(opts?: BrontoBindingOptsResolver): void;
49
+ export declare function useDotGlyph(opts?: BrontoBindingOptsResolver): void;
50
+ export declare function useLegend(opts?: BrontoBindingOptsResolver): void;
51
+ export declare function useConnectors(opts?: BrontoBindingOptsResolver): void;
52
+ export declare function useSpotlight(opts?: BrontoBindingOptsResolver): void;
53
+ export declare function useCrosshair(opts?: BrontoBindingOptsResolver): void;
54
+ export declare function useCommand(opts?: BrontoBindingOptsResolver): void;
55
+
56
+ /** The `toast()` imperative (no lifecycle of its own). */
57
+ export declare function useToast(): (message: string, opts?: ToastOpts) => Cleanup;
58
+
59
+ export { applyStoredTheme } from '../behaviors/index.js';
60
+ export { cls, ui, cx } from '../classes/index.js';
package/qwik/index.js ADDED
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @ponchia/ui/qwik — thin Qwik 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 Qwik's client lifecycle. Thin adapters, not a
6
+ * component library (architecture ADR). `@builder.io/qwik` is an optional peer
7
+ * dependency.
8
+ *
9
+ * Qwik is resumable: nothing runs until needed, and our behaviors are exactly
10
+ * the kind of "enhance on the client" glue that fits — they `useVisibleTask$`
11
+ * (run when the owning component first becomes visible) and register cleanup,
12
+ * so a server-rendered page stays zero-JS until interaction. Each hook inlines
13
+ * its specific behavior so the Qwik optimizer can resolve the import inside the
14
+ * extracted task segment.
15
+ *
16
+ * import { component$ } from '@builder.io/qwik';
17
+ * import { useDialog, useToast } from '@ponchia/ui/qwik';
18
+ * export default component$(() => {
19
+ * useDialog(); // wires every .ui-modal under document
20
+ * const toast = useToast();
21
+ * return <button onClick$={() => toast('Saved', { tone: 'success' })}>Save</button>;
22
+ * });
23
+ *
24
+ * Scope a behavior to a subtree by passing a Qwik signal:
25
+ * const root = useSignal();
26
+ * useDialog({ root }); // <section ref={root}> … </section>
27
+ */
28
+ import { useVisibleTask$ } from '@builder.io/qwik';
29
+ import {
30
+ applyStoredTheme,
31
+ initThemeToggle,
32
+ dismissible,
33
+ initDisclosure,
34
+ initMenu,
35
+ initFormValidation,
36
+ initCombobox,
37
+ initPopover,
38
+ initTableSort,
39
+ initTabs,
40
+ initDialog,
41
+ initCarousel,
42
+ initDotGlyph,
43
+ initLegend,
44
+ initConnectors,
45
+ initSpotlight,
46
+ initCrosshair,
47
+ initCommand,
48
+ toast,
49
+ } from '../behaviors/index.js';
50
+
51
+ function resolveMaybe(v) {
52
+ return typeof v === 'function' ? v() : v;
53
+ }
54
+
55
+ function resolveRoot(root) {
56
+ const value = resolveMaybe(root);
57
+ if (value && typeof value === 'object') {
58
+ if ('value' in value) return value.value; // Qwik signal (useSignal)
59
+ if ('current' in value) return value.current; // generic ref shape
60
+ }
61
+ return value;
62
+ }
63
+
64
+ function resolveOpts(opts) {
65
+ const value = resolveMaybe(opts);
66
+ if (!value || typeof value !== 'object') return undefined;
67
+ const root = resolveRoot(value.root);
68
+ return root ? { ...value, root } : { ...value, root: undefined };
69
+ }
70
+
71
+ /** Run a delegated behavior on visible and register its cleanup on dispose.
72
+ * `init` and `opts` are resolved inside the visible task, so a Qwik-signal
73
+ * root is read after the element is assigned. Shared, non-QRL, so the
74
+ * optimizer keeps the captured behavior import inside the task segment. */
75
+ function start(init, opts, ctx) {
76
+ const cleanup = init(resolveOpts(opts));
77
+ if (typeof cleanup === 'function') ctx.cleanup(cleanup);
78
+ }
79
+
80
+ /** Generic escape hatch. NOTE for Qwik: prefer the specific `use*` hooks
81
+ * below — they inline a statically-imported behavior so the optimizer can
82
+ * serialize the task. Passing a runtime function here is only safe when it
83
+ * is itself optimizer-visible (a module import). */
84
+ export function useBrontoBehavior(init, opts) {
85
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
86
+ useVisibleTask$((ctx) => start(init, opts, ctx));
87
+ }
88
+
89
+ export const useThemeToggle = (opts) =>
90
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
91
+ useVisibleTask$((ctx) => start(initThemeToggle, opts, ctx));
92
+ export const useDismissible = (opts) =>
93
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
94
+ useVisibleTask$((ctx) => start(dismissible, opts, ctx));
95
+ export const useDisclosure = (opts) =>
96
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
97
+ useVisibleTask$((ctx) => start(initDisclosure, opts, ctx));
98
+ export const useMenu = (opts) =>
99
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
100
+ useVisibleTask$((ctx) => start(initMenu, opts, ctx));
101
+ export const useFormValidation = (opts) =>
102
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
103
+ useVisibleTask$((ctx) => start(initFormValidation, opts, ctx));
104
+ export const useCombobox = (opts) =>
105
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
106
+ useVisibleTask$((ctx) => start(initCombobox, opts, ctx));
107
+ export const usePopover = (opts) =>
108
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
109
+ useVisibleTask$((ctx) => start(initPopover, opts, ctx));
110
+ export const useTableSort = (opts) =>
111
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
112
+ useVisibleTask$((ctx) => start(initTableSort, opts, ctx));
113
+ export const useTabs = (opts) =>
114
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
115
+ useVisibleTask$((ctx) => start(initTabs, opts, ctx));
116
+ export const useDialog = (opts) =>
117
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
118
+ useVisibleTask$((ctx) => start(initDialog, opts, ctx));
119
+ export const useCarousel = (opts) =>
120
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
121
+ useVisibleTask$((ctx) => start(initCarousel, opts, ctx));
122
+ export const useDotGlyph = (opts) =>
123
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
124
+ useVisibleTask$((ctx) => start(initDotGlyph, opts, ctx));
125
+ export const useLegend = (opts) =>
126
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
127
+ useVisibleTask$((ctx) => start(initLegend, opts, ctx));
128
+ export const useConnectors = (opts) =>
129
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
130
+ useVisibleTask$((ctx) => start(initConnectors, opts, ctx));
131
+ export const useSpotlight = (opts) =>
132
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
133
+ useVisibleTask$((ctx) => start(initSpotlight, opts, ctx));
134
+ export const useCrosshair = (opts) =>
135
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
136
+ useVisibleTask$((ctx) => start(initCrosshair, opts, ctx));
137
+ export const useCommand = (opts) =>
138
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
139
+ useVisibleTask$((ctx) => start(initCommand, opts, ctx));
140
+
141
+ /** The `toast()` imperative (no lifecycle of its own). */
142
+ export const useToast = () => toast;
143
+
144
+ // No-flash theme application must run before paint — do it in an inline head
145
+ // script, not on visible. Re-exported for manual/SSR-bootstrap use.
146
+ export { applyStoredTheme };
147
+
148
+ // Convenience: the framework-agnostic class contract, re-exported.
149
+ export { cls, ui, cx } from '../classes/index.js';
package/react/index.d.ts CHANGED
@@ -9,25 +9,51 @@ import type {
9
9
  ToastOpts,
10
10
  } from '../behaviors/index.js';
11
11
 
12
+ export type BrontoBindingRoot =
13
+ | Document
14
+ | Element
15
+ | { current: Document | Element | null | undefined }
16
+ | (() => Document | Element | null | undefined)
17
+ | null
18
+ | undefined;
19
+
20
+ export type BrontoBindingOpts<T extends DelegateOpts = DelegateOpts> = Omit<T, 'root'> & {
21
+ root?: BrontoBindingRoot;
22
+ };
23
+
24
+ export type BrontoBindingOptsResolver<T extends DelegateOpts = DelegateOpts> =
25
+ | BrontoBindingOpts<T>
26
+ | (() => BrontoBindingOpts<T> | null | undefined)
27
+ | null
28
+ | undefined;
29
+
12
30
  /** Run any delegated behavior for the component's lifetime (init on mount,
13
- * its returned cleanup on unmount). The behavior is run once. */
31
+ * its returned cleanup on unmount). The behavior is run once. Options resolve
32
+ * on mount, so scoped roots may be React refs or resolver callbacks. */
14
33
  export declare function useBrontoBehavior(
15
34
  init: (opts?: DelegateOpts) => Cleanup | void,
16
- opts?: DelegateOpts,
35
+ opts?: BrontoBindingOptsResolver,
17
36
  ): void;
18
37
 
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;
38
+ export declare function useThemeToggle(
39
+ opts?: BrontoBindingOptsResolver<ThemeStorageOpts & DelegateOpts>,
40
+ ): void;
41
+ export declare function useDismissible(opts?: BrontoBindingOptsResolver): void;
42
+ export declare function useDisclosure(opts?: BrontoBindingOptsResolver): void;
43
+ export declare function useMenu(opts?: BrontoBindingOptsResolver): void;
44
+ export declare function useFormValidation(opts?: BrontoBindingOptsResolver): void;
45
+ export declare function useCombobox(opts?: BrontoBindingOptsResolver): void;
46
+ export declare function usePopover(opts?: BrontoBindingOptsResolver): void;
47
+ export declare function useTableSort(opts?: BrontoBindingOptsResolver): void;
48
+ export declare function useTabs(opts?: BrontoBindingOptsResolver): void;
49
+ export declare function useDialog(opts?: BrontoBindingOptsResolver): void;
50
+ export declare function useCarousel(opts?: BrontoBindingOptsResolver): void;
51
+ export declare function useDotGlyph(opts?: BrontoBindingOptsResolver): void;
52
+ export declare function useLegend(opts?: BrontoBindingOptsResolver): void;
53
+ export declare function useConnectors(opts?: BrontoBindingOptsResolver): void;
54
+ export declare function useSpotlight(opts?: BrontoBindingOptsResolver): void;
55
+ export declare function useCrosshair(opts?: BrontoBindingOptsResolver): void;
56
+ export declare function useCommand(opts?: BrontoBindingOptsResolver): void;
31
57
 
32
58
  /** The `toast()` imperative (no lifecycle of its own). */
33
59
  export declare function useToast(): (message: string, opts?: ToastOpts) => Cleanup;
package/react/index.js CHANGED
@@ -7,8 +7,8 @@
7
7
  * the architecture ADR. `react` is an optional peer dependency.
8
8
  *
9
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.
10
+ * near the relevant subtree; pass `{ root: ref }` or a resolver callback to
11
+ * scope it. The options resolve on mount, after refs have been assigned.
12
12
  *
13
13
  * import { useDialog, useToast } from '@ponchia/ui/react';
14
14
  * function App() {
@@ -32,14 +32,36 @@ import {
32
32
  initDialog,
33
33
  initCarousel,
34
34
  initDotGlyph,
35
+ initLegend,
36
+ initConnectors,
37
+ initSpotlight,
38
+ initCrosshair,
39
+ initCommand,
35
40
  toast,
36
41
  } from '../behaviors/index.js';
37
42
 
43
+ function resolveMaybe(v) {
44
+ return typeof v === 'function' ? v() : v;
45
+ }
46
+
47
+ function resolveRoot(root) {
48
+ const value = resolveMaybe(root);
49
+ if (value && typeof value === 'object' && 'current' in value) return value.current;
50
+ return value;
51
+ }
52
+
53
+ function resolveOpts(opts) {
54
+ const value = resolveMaybe(opts);
55
+ if (!value || typeof value !== 'object') return undefined;
56
+ const root = resolveRoot(value.root);
57
+ return root ? { ...value, root } : { ...value, root: undefined };
58
+ }
59
+
38
60
  /** 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. */
61
+ * returned cleanup on unmount). The behavior is run once; `opts` resolves
62
+ * on mount so refs are usable for scoped roots. */
41
63
  export function useBrontoBehavior(init, opts) {
42
- useEffect(() => init(opts), []); // eslint-disable-line react-hooks/exhaustive-deps -- delegated once on mount
64
+ useEffect(() => init(resolveOpts(opts)), []); // eslint-disable-line react-hooks/exhaustive-deps -- delegated once on mount
43
65
  }
44
66
 
45
67
  export const useThemeToggle = (opts) => useBrontoBehavior(initThemeToggle, opts);
@@ -54,6 +76,11 @@ export const useTabs = (opts) => useBrontoBehavior(initTabs, opts);
54
76
  export const useDialog = (opts) => useBrontoBehavior(initDialog, opts);
55
77
  export const useCarousel = (opts) => useBrontoBehavior(initCarousel, opts);
56
78
  export const useDotGlyph = (opts) => useBrontoBehavior(initDotGlyph, opts);
79
+ export const useLegend = (opts) => useBrontoBehavior(initLegend, opts);
80
+ export const useConnectors = (opts) => useBrontoBehavior(initConnectors, opts);
81
+ export const useSpotlight = (opts) => useBrontoBehavior(initSpotlight, opts);
82
+ export const useCrosshair = (opts) => useBrontoBehavior(initCrosshair, opts);
83
+ export const useCommand = (opts) => useBrontoBehavior(initCommand, opts);
57
84
 
58
85
  /** The `toast()` imperative (no lifecycle of its own). */
59
86
  export const useToast = () => toast;
package/solid/index.d.ts CHANGED
@@ -9,25 +9,51 @@ import type {
9
9
  ToastOpts,
10
10
  } from '../behaviors/index.js';
11
11
 
12
+ export type BrontoBindingRoot =
13
+ | Document
14
+ | Element
15
+ | { current: Document | Element | null | undefined }
16
+ | (() => Document | Element | null | undefined)
17
+ | null
18
+ | undefined;
19
+
20
+ export type BrontoBindingOpts<T extends DelegateOpts = DelegateOpts> = Omit<T, 'root'> & {
21
+ root?: BrontoBindingRoot;
22
+ };
23
+
24
+ export type BrontoBindingOptsResolver<T extends DelegateOpts = DelegateOpts> =
25
+ | BrontoBindingOpts<T>
26
+ | (() => BrontoBindingOpts<T> | null | undefined)
27
+ | null
28
+ | undefined;
29
+
12
30
  /** Run any delegated behavior for the component's lifetime (init on mount,
13
- * its returned cleanup on dispose). */
31
+ * its returned cleanup on dispose). The behavior is run once. Options resolve
32
+ * on mount, so scoped roots may be refs or resolver callbacks. */
14
33
  export declare function useBrontoBehavior(
15
34
  init: (opts?: DelegateOpts) => Cleanup | void,
16
- opts?: DelegateOpts,
35
+ opts?: BrontoBindingOptsResolver,
17
36
  ): void;
18
37
 
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;
38
+ export declare function useThemeToggle(
39
+ opts?: BrontoBindingOptsResolver<ThemeStorageOpts & DelegateOpts>,
40
+ ): void;
41
+ export declare function useDismissible(opts?: BrontoBindingOptsResolver): void;
42
+ export declare function useDisclosure(opts?: BrontoBindingOptsResolver): void;
43
+ export declare function useMenu(opts?: BrontoBindingOptsResolver): void;
44
+ export declare function useFormValidation(opts?: BrontoBindingOptsResolver): void;
45
+ export declare function useCombobox(opts?: BrontoBindingOptsResolver): void;
46
+ export declare function usePopover(opts?: BrontoBindingOptsResolver): void;
47
+ export declare function useTableSort(opts?: BrontoBindingOptsResolver): void;
48
+ export declare function useTabs(opts?: BrontoBindingOptsResolver): void;
49
+ export declare function useDialog(opts?: BrontoBindingOptsResolver): void;
50
+ export declare function useCarousel(opts?: BrontoBindingOptsResolver): void;
51
+ export declare function useDotGlyph(opts?: BrontoBindingOptsResolver): void;
52
+ export declare function useLegend(opts?: BrontoBindingOptsResolver): void;
53
+ export declare function useConnectors(opts?: BrontoBindingOptsResolver): void;
54
+ export declare function useSpotlight(opts?: BrontoBindingOptsResolver): void;
55
+ export declare function useCrosshair(opts?: BrontoBindingOptsResolver): void;
56
+ export declare function useCommand(opts?: BrontoBindingOptsResolver): void;
31
57
 
32
58
  /** The `toast()` imperative (no lifecycle of its own). */
33
59
  export declare function useToast(): (message: string, opts?: ToastOpts) => Cleanup;