@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.
- package/CHANGELOG.md +1063 -0
- package/README.md +31 -14
- package/behaviors/index.d.ts +3 -1
- package/behaviors/index.js +179 -106
- package/classes/index.d.ts +41 -0
- package/classes/index.js +42 -0
- package/classes/vscode.css-custom-data.json +18 -22
- package/css/dataviz.css +96 -0
- package/css/disclosure.css +29 -0
- package/css/dots.css +32 -2
- package/css/feedback.css +53 -0
- package/css/motion.css +88 -0
- package/css/overlay.css +52 -1
- package/css/report.css +382 -0
- package/css/skins.css +54 -0
- package/css/tokens.css +56 -32
- package/dist/bronto.css +1 -1
- package/dist/css/dataviz.css +1 -0
- package/dist/css/disclosure.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/motion.css +1 -1
- package/dist/css/overlay.css +1 -1
- package/dist/css/report.css +1 -0
- package/dist/css/skins.css +1 -0
- package/dist/css/tokens.css +1 -1
- package/docs/adr/0001-color-system.md +271 -0
- package/docs/adr/0002-scope-and-2026-baseline.md +104 -0
- package/docs/adr/0003-theme-model.md +94 -0
- package/docs/contrast.md +170 -51
- package/docs/reference.md +118 -19
- package/docs/reporting.md +270 -0
- package/docs/stability.md +37 -0
- package/docs/theming.md +84 -7
- package/docs/usage.md +67 -8
- package/glyphs/glyphs.d.ts +14 -1
- package/glyphs/glyphs.js +143 -2
- package/llms.txt +101 -5
- package/package.json +79 -5
- package/qwik/index.d.ts +55 -0
- package/qwik/index.js +129 -0
- package/react/index.d.ts +57 -0
- package/react/index.js +84 -0
- package/solid/index.d.ts +57 -0
- package/solid/index.js +85 -0
- package/tokens/charts.d.ts +37 -0
- package/tokens/charts.js +96 -0
- package/tokens/charts.json +61 -0
- package/tokens/index.d.ts +3 -3
- package/tokens/index.js +16 -18
- package/tokens/index.json +32 -36
- package/tokens/resolved.json +39 -41
- package/tokens/skins.d.ts +27 -0
- package/tokens/skins.js +62 -0
- 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';
|
package/react/index.d.ts
ADDED
|
@@ -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';
|
package/solid/index.d.ts
ADDED
|
@@ -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;
|
package/tokens/charts.js
ADDED
|
@@ -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-
|
|
8
|
-
export type DarkTokenName = '--bg' | '--bg-elevated' | '--bg-accent' | '--panel' | '--panel-strong' | '--panel-soft' | '--line' | '--line-strong' | '--text' | '--text-soft' | '--text-dim' | '--accent' | '--accent-
|
|
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' | '
|
|
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: {
|