@ponchia/ui 0.3.6 → 0.4.1

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 (55) hide show
  1. package/CHANGELOG.md +1063 -0
  2. package/README.md +31 -14
  3. package/behaviors/index.d.ts +3 -1
  4. package/behaviors/index.js +179 -106
  5. package/classes/index.d.ts +41 -0
  6. package/classes/index.js +42 -0
  7. package/classes/vscode.css-custom-data.json +18 -22
  8. package/css/dataviz.css +96 -0
  9. package/css/disclosure.css +29 -0
  10. package/css/dots.css +32 -2
  11. package/css/feedback.css +53 -0
  12. package/css/motion.css +88 -0
  13. package/css/overlay.css +52 -1
  14. package/css/report.css +382 -0
  15. package/css/skins.css +54 -0
  16. package/css/tokens.css +56 -32
  17. package/dist/bronto.css +1 -1
  18. package/dist/css/dataviz.css +1 -0
  19. package/dist/css/disclosure.css +1 -1
  20. package/dist/css/dots.css +1 -1
  21. package/dist/css/feedback.css +1 -1
  22. package/dist/css/motion.css +1 -1
  23. package/dist/css/overlay.css +1 -1
  24. package/dist/css/report.css +1 -0
  25. package/dist/css/skins.css +1 -0
  26. package/dist/css/tokens.css +1 -1
  27. package/docs/adr/0001-color-system.md +271 -0
  28. package/docs/adr/0002-scope-and-2026-baseline.md +104 -0
  29. package/docs/adr/0003-theme-model.md +94 -0
  30. package/docs/contrast.md +170 -51
  31. package/docs/reference.md +118 -19
  32. package/docs/reporting.md +270 -0
  33. package/docs/stability.md +37 -0
  34. package/docs/theming.md +84 -7
  35. package/docs/usage.md +67 -8
  36. package/glyphs/glyphs.d.ts +14 -1
  37. package/glyphs/glyphs.js +143 -2
  38. package/llms.txt +101 -5
  39. package/package.json +79 -5
  40. package/qwik/index.d.ts +55 -0
  41. package/qwik/index.js +129 -0
  42. package/react/index.d.ts +57 -0
  43. package/react/index.js +84 -0
  44. package/solid/index.d.ts +57 -0
  45. package/solid/index.js +85 -0
  46. package/tokens/charts.d.ts +37 -0
  47. package/tokens/charts.js +96 -0
  48. package/tokens/charts.json +61 -0
  49. package/tokens/index.d.ts +3 -3
  50. package/tokens/index.js +16 -18
  51. package/tokens/index.json +32 -36
  52. package/tokens/resolved.json +39 -41
  53. package/tokens/skins.d.ts +27 -0
  54. package/tokens/skins.js +62 -0
  55. package/tokens/tokens.dtcg.json +22 -34
package/qwik/index.js ADDED
@@ -0,0 +1,129 @@
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
+ toast,
44
+ } from '../behaviors/index.js';
45
+
46
+ function resolveMaybe(v) {
47
+ return typeof v === 'function' ? v() : v;
48
+ }
49
+
50
+ function resolveRoot(root) {
51
+ const value = resolveMaybe(root);
52
+ if (value && typeof value === 'object') {
53
+ if ('value' in value) return value.value; // Qwik signal (useSignal)
54
+ if ('current' in value) return value.current; // generic ref shape
55
+ }
56
+ return value;
57
+ }
58
+
59
+ function resolveOpts(opts) {
60
+ const value = resolveMaybe(opts);
61
+ if (!value || typeof value !== 'object') return undefined;
62
+ const root = resolveRoot(value.root);
63
+ return root ? { ...value, root } : { ...value, root: undefined };
64
+ }
65
+
66
+ /** Run a delegated behavior on visible and register its cleanup on dispose.
67
+ * `init` and `opts` are resolved inside the visible task, so a Qwik-signal
68
+ * root is read after the element is assigned. Shared, non-QRL, so the
69
+ * optimizer keeps the captured behavior import inside the task segment. */
70
+ function start(init, opts, ctx) {
71
+ const cleanup = init(resolveOpts(opts));
72
+ if (typeof cleanup === 'function') ctx.cleanup(cleanup);
73
+ }
74
+
75
+ /** Generic escape hatch. NOTE for Qwik: prefer the specific `use*` hooks
76
+ * below — they inline a statically-imported behavior so the optimizer can
77
+ * serialize the task. Passing a runtime function here is only safe when it
78
+ * is itself optimizer-visible (a module import). */
79
+ export function useBrontoBehavior(init, opts) {
80
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
81
+ useVisibleTask$((ctx) => start(init, opts, ctx));
82
+ }
83
+
84
+ export const useThemeToggle = (opts) =>
85
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
86
+ useVisibleTask$((ctx) => start(initThemeToggle, opts, ctx));
87
+ export const useDismissible = (opts) =>
88
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
89
+ useVisibleTask$((ctx) => start(dismissible, opts, ctx));
90
+ export const useDisclosure = (opts) =>
91
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
92
+ useVisibleTask$((ctx) => start(initDisclosure, opts, ctx));
93
+ export const useMenu = (opts) =>
94
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
95
+ useVisibleTask$((ctx) => start(initMenu, opts, ctx));
96
+ export const useFormValidation = (opts) =>
97
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
98
+ useVisibleTask$((ctx) => start(initFormValidation, opts, ctx));
99
+ export const useCombobox = (opts) =>
100
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
101
+ useVisibleTask$((ctx) => start(initCombobox, opts, ctx));
102
+ export const usePopover = (opts) =>
103
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
104
+ useVisibleTask$((ctx) => start(initPopover, opts, ctx));
105
+ export const useTableSort = (opts) =>
106
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
107
+ useVisibleTask$((ctx) => start(initTableSort, opts, ctx));
108
+ export const useTabs = (opts) =>
109
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
110
+ useVisibleTask$((ctx) => start(initTabs, opts, ctx));
111
+ export const useDialog = (opts) =>
112
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
113
+ useVisibleTask$((ctx) => start(initDialog, opts, ctx));
114
+ export const useCarousel = (opts) =>
115
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
116
+ useVisibleTask$((ctx) => start(initCarousel, opts, ctx));
117
+ export const useDotGlyph = (opts) =>
118
+ // eslint-disable-next-line qwik/no-use-visible-task -- delegated DOM glue + cleanup
119
+ useVisibleTask$((ctx) => start(initDotGlyph, opts, ctx));
120
+
121
+ /** The `toast()` imperative (no lifecycle of its own). */
122
+ export const useToast = () => toast;
123
+
124
+ // No-flash theme application must run before paint — do it in an inline head
125
+ // script, not on visible. Re-exported for manual/SSR-bootstrap use.
126
+ export { applyStoredTheme };
127
+
128
+ // Convenience: the framework-agnostic class contract, re-exported.
129
+ export { cls, ui, cx } from '../classes/index.js';
@@ -0,0 +1,57 @@
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
+ 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
+
30
+ /** Run any delegated behavior for the component's lifetime (init on mount,
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. */
33
+ export declare function useBrontoBehavior(
34
+ init: (opts?: DelegateOpts) => Cleanup | void,
35
+ opts?: BrontoBindingOptsResolver,
36
+ ): void;
37
+
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
+
53
+ /** The `toast()` imperative (no lifecycle of its own). */
54
+ export declare function useToast(): (message: string, opts?: ToastOpts) => Cleanup;
55
+
56
+ export { applyStoredTheme } from '../behaviors/index.js';
57
+ export { cls, ui, cx } from '../classes/index.js';
package/react/index.js ADDED
@@ -0,0 +1,84 @@
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 }` or a resolver callback to
11
+ * scope it. The options resolve on mount, after refs have been assigned.
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
+ function resolveMaybe(v) {
39
+ return typeof v === 'function' ? v() : v;
40
+ }
41
+
42
+ function resolveRoot(root) {
43
+ const value = resolveMaybe(root);
44
+ if (value && typeof value === 'object' && 'current' in value) return value.current;
45
+ return value;
46
+ }
47
+
48
+ function resolveOpts(opts) {
49
+ const value = resolveMaybe(opts);
50
+ if (!value || typeof value !== 'object') return undefined;
51
+ const root = resolveRoot(value.root);
52
+ return root ? { ...value, root } : { ...value, root: undefined };
53
+ }
54
+
55
+ /** Run a delegated behavior for the component's lifetime (init on mount, its
56
+ * returned cleanup on unmount). The behavior is run once; `opts` resolves
57
+ * on mount so refs are usable for scoped roots. */
58
+ export function useBrontoBehavior(init, opts) {
59
+ useEffect(() => init(resolveOpts(opts)), []); // eslint-disable-line react-hooks/exhaustive-deps -- delegated once on mount
60
+ }
61
+
62
+ export const useThemeToggle = (opts) => useBrontoBehavior(initThemeToggle, opts);
63
+ export const useDismissible = (opts) => useBrontoBehavior(dismissible, opts);
64
+ export const useDisclosure = (opts) => useBrontoBehavior(initDisclosure, opts);
65
+ export const useMenu = (opts) => useBrontoBehavior(initMenu, opts);
66
+ export const useFormValidation = (opts) => useBrontoBehavior(initFormValidation, opts);
67
+ export const useCombobox = (opts) => useBrontoBehavior(initCombobox, opts);
68
+ export const usePopover = (opts) => useBrontoBehavior(initPopover, opts);
69
+ export const useTableSort = (opts) => useBrontoBehavior(initTableSort, opts);
70
+ export const useTabs = (opts) => useBrontoBehavior(initTabs, opts);
71
+ export const useDialog = (opts) => useBrontoBehavior(initDialog, opts);
72
+ export const useCarousel = (opts) => useBrontoBehavior(initCarousel, opts);
73
+ export const useDotGlyph = (opts) => useBrontoBehavior(initDotGlyph, opts);
74
+
75
+ /** The `toast()` imperative (no lifecycle of its own). */
76
+ export const useToast = () => toast;
77
+
78
+ // No-flash theme application has to run before paint; do it in an inline head
79
+ // script, not an effect. Re-exported for manual/SSR-bootstrap use.
80
+ export { applyStoredTheme };
81
+
82
+ // Convenience: the framework-agnostic class contract, re-exported so a React
83
+ // consumer needs one import.
84
+ export { cls, ui, cx } from '../classes/index.js';
@@ -0,0 +1,57 @@
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
+ 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
+
30
+ /** Run any delegated behavior for the component's lifetime (init on mount,
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. */
33
+ export declare function useBrontoBehavior(
34
+ init: (opts?: DelegateOpts) => Cleanup | void,
35
+ opts?: BrontoBindingOptsResolver,
36
+ ): void;
37
+
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
+
53
+ /** The `toast()` imperative (no lifecycle of its own). */
54
+ export declare function useToast(): (message: string, opts?: ToastOpts) => Cleanup;
55
+
56
+ export { applyStoredTheme } from '../behaviors/index.js';
57
+ export { cls, ui, cx } from '../classes/index.js';
package/solid/index.js ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @ponchia/ui/solid — thin Solid bindings over @ponchia/ui/behaviors.
3
+ *
4
+ * The CSS is the framework; these are *optional* primitives that wrap the
5
+ * SSR-safe vanilla `init*` behaviors in Solid's lifecycle (run on mount, clean
6
+ * up on dispose). Thin adapters, not a component library (architecture ADR).
7
+ * `solid-js` is an optional peer dependency.
8
+ *
9
+ * Behaviors delegate from a root (default `document`); call a primitive once in
10
+ * a component that owns the relevant subtree, and pass a root resolver to scope
11
+ * it when the element is assigned by Solid's ref lifecycle.
12
+ *
13
+ * import { useDialog, useToast } from '@ponchia/ui/solid';
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 { onMount, onCleanup } from 'solid-js';
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
+ function resolveMaybe(v) {
39
+ return typeof v === 'function' ? v() : v;
40
+ }
41
+
42
+ function resolveRoot(root) {
43
+ const value = resolveMaybe(root);
44
+ if (value && typeof value === 'object' && 'current' in value) return value.current;
45
+ return value;
46
+ }
47
+
48
+ function resolveOpts(opts) {
49
+ const value = resolveMaybe(opts);
50
+ if (!value || typeof value !== 'object') return undefined;
51
+ const root = resolveRoot(value.root);
52
+ return root ? { ...value, root } : { ...value, root: undefined };
53
+ }
54
+
55
+ /** Run a delegated behavior for the component's lifetime (init on mount, its
56
+ * returned cleanup on dispose). Options resolve on mount, after refs exist. */
57
+ export function useBrontoBehavior(init, opts) {
58
+ onMount(() => {
59
+ const cleanup = init(resolveOpts(opts));
60
+ if (typeof cleanup === 'function') onCleanup(cleanup);
61
+ });
62
+ }
63
+
64
+ export const useThemeToggle = (opts) => useBrontoBehavior(initThemeToggle, opts);
65
+ export const useDismissible = (opts) => useBrontoBehavior(dismissible, opts);
66
+ export const useDisclosure = (opts) => useBrontoBehavior(initDisclosure, opts);
67
+ export const useMenu = (opts) => useBrontoBehavior(initMenu, opts);
68
+ export const useFormValidation = (opts) => useBrontoBehavior(initFormValidation, opts);
69
+ export const useCombobox = (opts) => useBrontoBehavior(initCombobox, opts);
70
+ export const usePopover = (opts) => useBrontoBehavior(initPopover, opts);
71
+ export const useTableSort = (opts) => useBrontoBehavior(initTableSort, opts);
72
+ export const useTabs = (opts) => useBrontoBehavior(initTabs, opts);
73
+ export const useDialog = (opts) => useBrontoBehavior(initDialog, opts);
74
+ export const useCarousel = (opts) => useBrontoBehavior(initCarousel, opts);
75
+ export const useDotGlyph = (opts) => useBrontoBehavior(initDotGlyph, opts);
76
+
77
+ /** The `toast()` imperative (no lifecycle of its own). */
78
+ export const useToast = () => toast;
79
+
80
+ // No-flash theme application must run before paint — do it in an inline head
81
+ // script, not on mount. Re-exported for manual/SSR-bootstrap use.
82
+ export { applyStoredTheme };
83
+
84
+ // Convenience: the framework-agnostic class contract, re-exported.
85
+ export { cls, ui, cx } from '../classes/index.js';
@@ -0,0 +1,37 @@
1
+ /** @ponchia/ui — GENERATED from tokens/charts.js by scripts/gen-charts.mjs.
2
+ * Do not edit by hand; run `npm run charts:build`. Drift-checked in CI. */
3
+
4
+ /** A theme's data-viz palette. Values are CSS colour strings (OKLCH for the
5
+ * authored series; `var(--accent)` for series 1). For resolved sRGB **hex**
6
+ * (canvas/SVG/charting libs), import `@ponchia/ui/charts.json` instead. */
7
+ export interface ChartTheme {
8
+ /** 8 distinct series colours (index 0 = `var(--accent)`, the brand). */
9
+ categorical: string[];
10
+ /** Single-hue sequential ramp (light→dark), for heatmaps/intensity. */
11
+ sequential: string[];
12
+ /** Diverging ramp (− … neutral … +), for gains/losses. */
13
+ diverging: string[];
14
+ }
15
+
16
+ /** The categorical CSS custom-property names (1-based; `--chart-1` = the accent). */
17
+ export type ChartTokenName =
18
+ | '--chart-1'
19
+ | '--chart-2'
20
+ | '--chart-3'
21
+ | '--chart-4'
22
+ | '--chart-5'
23
+ | '--chart-6'
24
+ | '--chart-7'
25
+ | '--chart-8';
26
+
27
+ /** The opt-in data-viz palette source, per theme (CSS colour strings). */
28
+ export declare const charts: { light: ChartTheme; dark: ChartTheme };
29
+
30
+ /** Series 1 sentinel — the live brand accent. */
31
+ export declare const ACCENT: 'var(--accent)';
32
+
33
+ export declare const CHART_CATEGORICAL: 8;
34
+ export declare const CHART_PATTERN_COUNT: 8;
35
+
36
+ declare const _default: { light: ChartTheme; dark: ChartTheme };
37
+ export default _default;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @ponchia/ui — Tier-4 data-viz colour module (ADR-0001 step 7).
3
+ *
4
+ * The single source for the opt-in chart palette (`@ponchia/ui/css/dataviz.css`
5
+ * + `tokens/charts.json`). **Charts only, never UI chrome** — `check-color-policy`
6
+ * forbids `var(--chart-*)` in core component CSS. Opt-in: a separate entrypoint,
7
+ * never in the default bundle.
8
+ *
9
+ * Hybrid accent-led: **series 1 is the live `var(--accent)`** (the brand stays
10
+ * series 1, so it re-themes/-skins for free); series 2–8 are an Okabe-Ito-derived
11
+ * colourblind-safe set, authored in OKLCH per-theme (darker in light, brighter
12
+ * in dark) and **gated for pairwise distinguishability under normal + simulated
13
+ * protan/deutan/tritan vision** (scripts/check-charts.mjs). Series 8 is a neutral
14
+ * grey (on-brand, and a useful "other"/baseline series).
15
+ *
16
+ * Colour is never the sole signal: `--chart-pattern-1..8` ship a matching
17
+ * dot-matrix pattern per series (WCAG 1.4.1). Use colour N WITH pattern N.
18
+ *
19
+ * Generated → drift-checked: css/dataviz.css, tokens/charts.json (resolved hex
20
+ * for JS/canvas/SVG/charting libs), tokens/charts.d.ts.
21
+ */
22
+
23
+ /** Series 1 is the live accent (a CSS var, not a fixed hue). Resolved to the
24
+ * theme accent for the JSON/gate. */
25
+ export const ACCENT = 'var(--accent)';
26
+
27
+ /** Series 2–8 — the Okabe-Ito colourblind-safe set, used **verbatim** (the same
28
+ * hues both themes). Authored as sRGB hex on purpose: Okabe-Ito is a published,
29
+ * CVD-proven *set*, and round-tripping through OKLCH (or re-spacing per theme)
30
+ * breaks the careful lightness relationships that make it colourblind-safe —
31
+ * which the CVD gate caught. Series 1 (the accent, per-theme) replaces
32
+ * Okabe-Ito's vermillion; a dark slate-grey is the 8th (a CVD-distinct "other"
33
+ * / baseline, far enough in lightness from the reddish-purple to clear deutan).
34
+ * The sequential/diverging ramps below ARE authored in OKLCH (new work). */
35
+ const FILLS = [
36
+ '#e69f00', // 2 orange
37
+ '#56b4e9', // 3 sky blue
38
+ '#009e73', // 4 bluish green
39
+ '#f0e442', // 5 yellow
40
+ '#0072b2', // 6 blue
41
+ '#cc79a7', // 7 reddish purple
42
+ '#4d5358', // 8 dark slate (CVD-distinct neutral)
43
+ ];
44
+
45
+ export const charts = {
46
+ light: {
47
+ categorical: [ACCENT, ...FILLS],
48
+ sequential: [
49
+ 'oklch(94% 0.03 25deg)',
50
+ 'oklch(85% 0.07 25deg)',
51
+ 'oklch(74% 0.12 25deg)',
52
+ 'oklch(62% 0.16 25deg)',
53
+ 'oklch(50% 0.16 25deg)',
54
+ 'oklch(38% 0.13 25deg)',
55
+ ],
56
+ diverging: [
57
+ 'oklch(45% 0.14 255deg)', // − strong blue
58
+ 'oklch(62% 0.1 250deg)',
59
+ 'oklch(82% 0.05 245deg)',
60
+ 'oklch(90% 0.01 250deg)', // mid neutral
61
+ 'oklch(80% 0.07 60deg)',
62
+ 'oklch(66% 0.13 55deg)',
63
+ 'oklch(56% 0.15 45deg)', // + strong orange
64
+ ],
65
+ },
66
+ dark: {
67
+ categorical: [ACCENT, ...FILLS],
68
+ sequential: [
69
+ 'oklch(30% 0.1 25deg)',
70
+ 'oklch(42% 0.15 25deg)',
71
+ 'oklch(55% 0.17 25deg)',
72
+ 'oklch(68% 0.15 25deg)',
73
+ 'oklch(80% 0.1 25deg)',
74
+ 'oklch(90% 0.05 25deg)',
75
+ ],
76
+ diverging: [
77
+ 'oklch(70% 0.13 250deg)', // − blue
78
+ 'oklch(60% 0.12 252deg)',
79
+ 'oklch(48% 0.08 255deg)',
80
+ 'oklch(40% 0.01 250deg)', // mid neutral
81
+ 'oklch(58% 0.1 60deg)',
82
+ 'oklch(72% 0.13 58deg)',
83
+ 'oklch(80% 0.12 55deg)', // + orange
84
+ ],
85
+ },
86
+ };
87
+
88
+ /** Pattern fills — dot-matrix CSS background-images, the second (non-colour)
89
+ * channel per series. Each uses `--chart-pattern-ink` (set it to the series
90
+ * colour). Index matches the categorical series. */
91
+ export const CHART_PATTERN_COUNT = 8;
92
+
93
+ /** Number of categorical series. */
94
+ export const CHART_CATEGORICAL = 8;
95
+
96
+ export default charts;
@@ -0,0 +1,61 @@
1
+ {
2
+ "$comment": "@ponchia/ui data-viz palette resolved to static hex per theme, for non-CSS render targets (canvas/SVG/charting libs). Series 1 = the resolved brand accent. Generated from tokens/charts.js — do not edit by hand; run `npm run charts:build`. Drift-checked in CI.",
3
+ "light": {
4
+ "categorical": [
5
+ "#d71921",
6
+ "#e69f00",
7
+ "#56b4e9",
8
+ "#009e73",
9
+ "#f0e442",
10
+ "#0072b2",
11
+ "#cc79a7",
12
+ "#4d5358"
13
+ ],
14
+ "sequential": [
15
+ "#ffe4e1",
16
+ "#f9bdb7",
17
+ "#ed8c84",
18
+ "#d55753",
19
+ "#ac3031",
20
+ "#79191b"
21
+ ],
22
+ "diverging": [
23
+ "#0c54a0",
24
+ "#558ac0",
25
+ "#aac8e3",
26
+ "#d9dfe5",
27
+ "#e0b491",
28
+ "#ce7a3b",
29
+ "#b95115"
30
+ ]
31
+ },
32
+ "dark": {
33
+ "categorical": [
34
+ "#ff3b41",
35
+ "#e69f00",
36
+ "#56b4e9",
37
+ "#009e73",
38
+ "#f0e442",
39
+ "#0072b2",
40
+ "#cc79a7",
41
+ "#4d5358"
42
+ ],
43
+ "sequential": [
44
+ "#551112",
45
+ "#8d1a1e",
46
+ "#c13c3b",
47
+ "#e66e68",
48
+ "#f8a49d",
49
+ "#fed2cd"
50
+ ],
51
+ "diverging": [
52
+ "#5aa3ec",
53
+ "#4683c5",
54
+ "#3e5f8a",
55
+ "#44484d",
56
+ "#a56b38",
57
+ "#e18e4b",
58
+ "#f9a870"
59
+ ]
60
+ }
61
+ }
package/tokens/index.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  export type ThemeName = 'light' | 'dark';
5
5
 
6
6
  export type GlobalTokenName = '--radius-xl' | '--radius-lg' | '--radius-md' | '--radius-sm' | '--radius-pill' | '--space-2xs' | '--space-xs' | '--space-sm' | '--space-md' | '--space-lg' | '--space-xl' | '--space-2xl' | '--mono' | '--sans' | '--dot-font' | '--display' | '--text-2xs' | '--text-xs' | '--text-sm' | '--text-base' | '--text-lg' | '--text-xl' | '--tracking-wide' | '--tracking-wider' | '--ease-standard' | '--ease-spring' | '--ease-out' | '--duration-fast' | '--duration-base' | '--duration-slow' | '--dot-size' | '--dot-gap' | '--z-base' | '--z-raised' | '--z-sticky' | '--z-overlay' | '--z-popover' | '--z-toast' | '--accent-1' | '--accent-2' | '--accent-3' | '--accent-4' | '--accent-5' | '--accent-6' | '--surface-1' | '--surface-2' | '--surface-3' | '--surface-4' | '--surface-5' | '--surface-6' | '--bronto-color-bg' | '--bronto-color-surface' | '--bronto-color-surface-raised' | '--bronto-color-border' | '--bronto-color-border-strong' | '--bronto-color-text' | '--bronto-color-text-muted' | '--bronto-color-action' | '--bronto-color-on-action' | '--bronto-color-focus' | '--bronto-color-success' | '--bronto-color-warning' | '--bronto-color-danger' | '--bronto-color-info' | '--surface' | '--surface-raised' | '--surface-muted' | '--border' | '--border-strong';
7
- export type LightTokenName = '--bg' | '--bg-elevated' | '--bg-accent' | '--panel' | '--panel-strong' | '--panel-soft' | '--line' | '--line-strong' | '--text' | '--text-soft' | '--text-dim' | '--accent' | '--accent-strong' | '--accent-text' | '--accent-soft' | '--success' | '--success-soft' | '--warning' | '--warning-soft' | '--orange' | '--orange-soft' | '--danger' | '--danger-soft' | '--info' | '--info-soft' | '--code-bg' | '--button-text' | '--field-dot' | '--field-dot-hot' | '--field-dot-accent' | '--focus-ring' | '--shadow' | '--shadow-raised';
8
- export type DarkTokenName = '--bg' | '--bg-elevated' | '--bg-accent' | '--panel' | '--panel-strong' | '--panel-soft' | '--line' | '--line-strong' | '--text' | '--text-soft' | '--text-dim' | '--accent' | '--accent-strong' | '--accent-text' | '--accent-soft' | '--success' | '--success-soft' | '--warning' | '--warning-soft' | '--orange' | '--orange-soft' | '--danger' | '--danger-soft' | '--info' | '--info-soft' | '--code-bg' | '--button-text' | '--field-dot' | '--field-dot-hot' | '--field-dot-accent' | '--focus-ring' | '--shadow' | '--shadow-raised';
7
+ export type LightTokenName = '--bg' | '--bg-elevated' | '--bg-accent' | '--panel' | '--panel-strong' | '--panel-soft' | '--line' | '--line-strong' | '--text' | '--text-soft' | '--text-dim' | '--accent' | '--accent-ramp-end' | '--accent-strong' | '--accent-text' | '--accent-soft' | '--success' | '--success-soft' | '--warning' | '--warning-soft' | '--danger' | '--danger-soft' | '--info' | '--info-soft' | '--code-bg' | '--button-text' | '--field-dot' | '--field-dot-hot' | '--field-dot-accent' | '--focus-ring' | '--shadow' | '--shadow-raised';
8
+ export type DarkTokenName = '--bg' | '--bg-elevated' | '--bg-accent' | '--panel' | '--panel-strong' | '--panel-soft' | '--line' | '--line-strong' | '--text' | '--text-soft' | '--text-dim' | '--accent' | '--accent-ramp-end' | '--accent-strong' | '--accent-text' | '--accent-soft' | '--success' | '--success-soft' | '--warning' | '--warning-soft' | '--danger' | '--danger-soft' | '--info' | '--info-soft' | '--code-bg' | '--button-text' | '--field-dot' | '--field-dot-hot' | '--field-dot-accent' | '--focus-ring' | '--shadow' | '--shadow-raised';
9
9
 
10
10
  /** Exact mirror of the :root blocks in css/tokens.css (literal keys). */
11
11
  export declare const cssVars: {
@@ -15,7 +15,7 @@ export declare const cssVars: {
15
15
  };
16
16
 
17
17
  export type ScaleKey = 'radius-xl' | 'radius-lg' | 'radius-md' | 'radius-sm' | 'radius-pill' | 'space-2xs' | 'space-xs' | 'space-sm' | 'space-md' | 'space-lg' | 'space-xl' | 'space-2xl' | 'mono' | 'sans' | 'dot-font' | 'display' | 'text-2xs' | 'text-xs' | 'text-sm' | 'text-base' | 'text-lg' | 'text-xl' | 'tracking-wide' | 'tracking-wider' | 'ease-standard' | 'ease-spring' | 'ease-out' | 'duration-fast' | 'duration-base' | 'duration-slow' | 'dot-size' | 'dot-gap' | 'z-base' | 'z-raised' | 'z-sticky' | 'z-overlay' | 'z-popover' | 'z-toast' | 'accent-1' | 'accent-2' | 'accent-3' | 'accent-4' | 'accent-5' | 'accent-6' | 'surface-1' | 'surface-2' | 'surface-3' | 'surface-4' | 'surface-5' | 'surface-6' | 'bronto-color-bg' | 'bronto-color-surface' | 'bronto-color-surface-raised' | 'bronto-color-border' | 'bronto-color-border-strong' | 'bronto-color-text' | 'bronto-color-text-muted' | 'bronto-color-action' | 'bronto-color-on-action' | 'bronto-color-focus' | 'bronto-color-success' | 'bronto-color-warning' | 'bronto-color-danger' | 'bronto-color-info' | 'surface' | 'surface-raised' | 'surface-muted' | 'border' | 'border-strong';
18
- export type ColorKey = 'bg' | 'bg-elevated' | 'bg-accent' | 'panel' | 'panel-strong' | 'panel-soft' | 'line' | 'line-strong' | 'text' | 'text-soft' | 'text-dim' | 'accent' | 'accent-strong' | 'accent-text' | 'accent-soft' | 'success' | 'success-soft' | 'warning' | 'warning-soft' | 'orange' | 'orange-soft' | 'danger' | 'danger-soft' | 'info' | 'info-soft' | 'code-bg' | 'button-text' | 'field-dot' | 'field-dot-hot' | 'field-dot-accent' | 'focus-ring' | 'shadow' | 'shadow-raised';
18
+ export type ColorKey = 'bg' | 'bg-elevated' | 'bg-accent' | 'panel' | 'panel-strong' | 'panel-soft' | 'line' | 'line-strong' | 'text' | 'text-soft' | 'text-dim' | 'accent' | 'accent-ramp-end' | 'accent-strong' | 'accent-text' | 'accent-soft' | 'success' | 'success-soft' | 'warning' | 'warning-soft' | 'danger' | 'danger-soft' | 'info' | 'info-soft' | 'code-bg' | 'button-text' | 'field-dot' | 'field-dot-hot' | 'field-dot-accent' | 'focus-ring' | 'shadow' | 'shadow-raised';
19
19
 
20
20
  /** Ergonomic view derived from {@link cssVars} (`--` prefix stripped). */
21
21
  export declare const tokens: {