@cascivo/react 0.4.3 → 0.5.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.
@@ -1,63 +1,63 @@
1
1
  "use client";
2
2
 
3
3
  import e from "./alert-dialog.module.js";
4
- import { useSignal as t, useSignalEffect as n } from "@cascivo/core";
5
- import { builtin as r, t as i } from "@cascivo/i18n";
6
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
- import { useRef as s } from "react";
4
+ import { useId as t, useSignal as n, useSignalEffect as r } from "@cascivo/core";
5
+ import { builtin as i, t as a } from "@cascivo/i18n";
6
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ import { useRef as c } from "react";
8
8
  //#region ../components/src/alert-dialog/alert-dialog.tsx
9
- function c({ open: c, title: l, description: u, onConfirm: d, onCancel: f, labels: p, variant: m = "default" }) {
10
- let h = s(null), g = t(c);
11
- g.value = c;
12
- let _ = s(null), v = s(f);
13
- v.current = f;
14
- let y = s(d);
15
- return y.current = d, n(() => {
16
- let e = h.current;
17
- if (e) if (g.value) {
9
+ function l({ open: l, title: u, description: d, onConfirm: f, onCancel: p, labels: m, variant: h = "default" }) {
10
+ let g = c(null), _ = t("cascivo-alert-dialog-title"), v = t("cascivo-alert-dialog-desc"), y = n(l);
11
+ y.value = l;
12
+ let b = c(null), x = c(p);
13
+ x.current = p;
14
+ let S = c(f);
15
+ return S.current = f, r(() => {
16
+ let e = g.current;
17
+ if (e) if (y.value) {
18
18
  try {
19
19
  e.showPopover();
20
20
  } catch {}
21
- requestAnimationFrame(() => _.current?.focus());
21
+ requestAnimationFrame(() => b.current?.focus());
22
22
  } else try {
23
23
  e.hidePopover();
24
24
  } catch {}
25
- }), /* @__PURE__ */ a("div", {
26
- ref: h,
25
+ }), /* @__PURE__ */ o("div", {
26
+ ref: g,
27
27
  popover: "manual",
28
28
  role: "alertdialog",
29
29
  "aria-modal": "true",
30
- "aria-labelledby": "cascade-alert-dialog-title",
31
- "aria-describedby": "cascade-alert-dialog-desc",
32
- "data-state": c ? "open" : "closed",
33
- "data-variant": m,
30
+ "aria-labelledby": _,
31
+ "aria-describedby": v,
32
+ "data-state": l ? "open" : "closed",
33
+ "data-variant": h,
34
34
  className: e.dialog,
35
- children: /* @__PURE__ */ o("div", {
35
+ children: /* @__PURE__ */ s("div", {
36
36
  className: e.content,
37
37
  children: [
38
- /* @__PURE__ */ a("p", {
39
- id: "cascade-alert-dialog-title",
38
+ /* @__PURE__ */ o("p", {
39
+ id: _,
40
40
  className: e.title,
41
- children: l
41
+ children: u
42
42
  }),
43
- /* @__PURE__ */ a("p", {
44
- id: "cascade-alert-dialog-desc",
43
+ /* @__PURE__ */ o("p", {
44
+ id: v,
45
45
  className: e.description,
46
- children: u
46
+ children: d
47
47
  }),
48
- /* @__PURE__ */ o("div", {
48
+ /* @__PURE__ */ s("div", {
49
49
  className: e.actions,
50
- children: [/* @__PURE__ */ a("button", {
51
- ref: _,
50
+ children: [/* @__PURE__ */ o("button", {
51
+ ref: b,
52
52
  type: "button",
53
53
  className: e.cancel,
54
- onClick: () => v.current(),
55
- children: p?.cancel ?? i(r.alertDialog.cancel)
56
- }), /* @__PURE__ */ a("button", {
54
+ onClick: () => x.current(),
55
+ children: m?.cancel ?? a(i.alertDialog.cancel)
56
+ }), /* @__PURE__ */ o("button", {
57
57
  type: "button",
58
58
  className: e.confirm,
59
- onClick: () => y.current(),
60
- children: p?.confirm ?? i(r.alertDialog.confirm)
59
+ onClick: () => S.current(),
60
+ children: m?.confirm ?? a(i.alertDialog.confirm)
61
61
  })]
62
62
  })
63
63
  ]
@@ -65,4 +65,4 @@ function c({ open: c, title: l, description: u, onConfirm: d, onCancel: f, label
65
65
  });
66
66
  }
67
67
  //#endregion
68
- export { c as AlertDialog };
68
+ export { l as AlertDialog };
@@ -7,13 +7,36 @@ import { useRef as o } from "react";
7
7
  //#region ../components/src/context-menu/context-menu.tsx
8
8
  function s({ children: s }) {
9
9
  r();
10
- let c = o(null), l = o(null), u = t(!1);
10
+ let c = o(null), l = o(null), u = t(!1), d = () => {
11
+ let e = c.current;
12
+ return e ? Array.from(e.querySelectorAll("[role=\"menuitem\"]:not([aria-disabled=\"true\"])")) : [];
13
+ }, f = (e) => {
14
+ let t = d();
15
+ t.length !== 0 && t[e(t, t.indexOf(document.activeElement))]?.focus();
16
+ }, p = (e) => {
17
+ switch (e.key) {
18
+ case "ArrowDown":
19
+ e.preventDefault(), f((e, t) => t < 0 ? 0 : (t + 1) % e.length);
20
+ break;
21
+ case "ArrowUp":
22
+ e.preventDefault(), f((e, t) => t < 0 ? e.length - 1 : (t - 1 + e.length) % e.length);
23
+ break;
24
+ case "Home":
25
+ e.preventDefault(), f(() => 0);
26
+ break;
27
+ case "End":
28
+ e.preventDefault(), f((e) => e.length - 1);
29
+ break;
30
+ }
31
+ };
11
32
  n(() => {
12
33
  let e = c.current;
13
- if (e) if (u.value) try {
14
- e.showPopover();
15
- } catch {}
16
- else try {
34
+ if (e) if (u.value) {
35
+ try {
36
+ e.showPopover();
37
+ } catch {}
38
+ d()[0]?.focus();
39
+ } else try {
17
40
  e.hidePopover();
18
41
  } catch {}
19
42
  }), n(() => {
@@ -24,34 +47,40 @@ function s({ children: s }) {
24
47
  };
25
48
  return e.addEventListener("toggle", t), () => e.removeEventListener("toggle", t);
26
49
  });
27
- function d(e) {
50
+ function m(e) {
28
51
  e.preventDefault();
29
52
  let t = l.current;
30
53
  t && (t.style.setProperty("--cascivo-context-x", `${e.clientX}px`), t.style.setProperty("--cascivo-context-y", `${e.clientY}px`), u.value = !0);
31
54
  }
32
- let [f, ...p] = Array.isArray(s) ? s : [s];
55
+ let [h, ...g] = Array.isArray(s) ? s : [s];
33
56
  return /* @__PURE__ */ a("div", {
34
57
  ref: l,
35
- onContextMenu: d,
58
+ onContextMenu: m,
36
59
  className: e.wrapper,
37
- children: [f, /* @__PURE__ */ i("div", {
60
+ children: [h, /* @__PURE__ */ i("div", {
38
61
  ref: c,
39
62
  popover: "auto",
40
63
  role: "menu",
41
64
  "data-state": u.value ? "open" : "closed",
42
65
  className: e.menu,
43
- children: p
66
+ onKeyDown: p,
67
+ children: g
44
68
  })]
45
69
  });
46
70
  }
47
71
  function c({ children: t, onSelect: n, disabled: r }) {
72
+ function a() {
73
+ r || n();
74
+ }
75
+ function o(e) {
76
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), a());
77
+ }
48
78
  return /* @__PURE__ */ i("div", {
49
79
  role: "menuitem",
50
80
  tabIndex: r ? -1 : 0,
51
81
  "aria-disabled": r,
52
- onClick: () => {
53
- r || n();
54
- },
82
+ onClick: a,
83
+ onKeyDown: o,
55
84
  className: e.item,
56
85
  children: t
57
86
  });
package/dist/index.d.ts CHANGED
@@ -1866,12 +1866,14 @@ declare function CopyButton({
1866
1866
  className,
1867
1867
  ...props
1868
1868
  }: CopyButtonProps): import("react").JSX.Element;
1869
- interface StatProps extends HTMLAttributes<HTMLDivElement> {
1869
+ interface StatProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
1870
1870
  label: string;
1871
1871
  value: string | number;
1872
1872
  delta?: string;
1873
1873
  trend?: 'up' | 'down' | 'flat';
1874
1874
  helpText?: string;
1875
+ /** Trailing visual, e.g. a `Sparkline` from `@cascivo/charts`. Purely decorative — mark it `aria-hidden` yourself if it duplicates the value/delta already announced. */
1876
+ visual?: ReactNode;
1875
1877
  }
1876
1878
  declare function Stat({
1877
1879
  label,
@@ -1879,6 +1881,7 @@ declare function Stat({
1879
1881
  delta,
1880
1882
  trend,
1881
1883
  helpText,
1884
+ visual,
1882
1885
  className,
1883
1886
  ...props
1884
1887
  }: StatProps): import("react").JSX.Element;
package/dist/menu/menu.js CHANGED
@@ -2,80 +2,105 @@
2
2
 
3
3
  import { usePopover as e } from "../popover/use-popover.js";
4
4
  import t from "./menu.module.js";
5
- import { useSignalEffect as n, useSignals as r } from "@cascivo/core";
6
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
7
- import { createContext as o } from "react";
5
+ import { useSignalEffect as n, useSignals as r, useTypeahead as i } from "@cascivo/core";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ import { createContext as s } from "react";
8
8
  //#region ../components/src/menu/menu.tsx
9
- var s = o(null);
10
- function c({ ctx: e, children: a }) {
9
+ var c = s(null);
10
+ function l({ ctx: e, children: o }) {
11
11
  r();
12
- let { popoverRef: o, anchorName: s, isOpen: c } = e;
12
+ let { popoverRef: s, anchorName: c, isOpen: l } = e, u = () => {
13
+ let e = s.current;
14
+ return e ? Array.from(e.querySelectorAll("[role=\"menuitem\"]:not([aria-disabled=\"true\"])")) : [];
15
+ }, d = (e) => {
16
+ let t = u();
17
+ t.length !== 0 && t[e(t, t.indexOf(document.activeElement))]?.focus();
18
+ }, f = i({ onMatch: (e) => {
19
+ u().find((t) => (t.textContent ?? "").trim().toLowerCase().startsWith(e))?.focus();
20
+ } });
13
21
  return n(() => {
14
- if (!c.value) return;
15
- let e = o.current;
22
+ if (!l.value) return;
23
+ let e = s.current;
16
24
  e && e.querySelector("[role=\"menuitem\"]:not([aria-disabled=\"true\"])")?.focus();
17
- }), /* @__PURE__ */ i("div", {
18
- ref: o,
25
+ }), /* @__PURE__ */ a("div", {
26
+ ref: s,
19
27
  popover: "auto",
20
28
  role: "menu",
21
- "data-state": c.value ? "open" : "closed",
22
- style: { positionAnchor: s },
29
+ "data-state": l.value ? "open" : "closed",
30
+ style: { positionAnchor: c },
23
31
  className: t.panel,
24
- children: a
32
+ onKeyDown: (e) => {
33
+ switch (e.key) {
34
+ case "ArrowDown":
35
+ e.preventDefault(), d((e, t) => t < 0 ? 0 : (t + 1) % e.length);
36
+ break;
37
+ case "ArrowUp":
38
+ e.preventDefault(), d((e, t) => t < 0 ? e.length - 1 : (t - 1 + e.length) % e.length);
39
+ break;
40
+ case "Home":
41
+ e.preventDefault(), d(() => 0);
42
+ break;
43
+ case "End":
44
+ e.preventDefault(), d((e) => e.length - 1);
45
+ break;
46
+ default: f.onKeyDown(e);
47
+ }
48
+ },
49
+ children: o
25
50
  });
26
51
  }
27
- function l({ children: e }) {
28
- return /* @__PURE__ */ i(s.Consumer, { children: (t) => {
52
+ function u({ children: e }) {
53
+ return /* @__PURE__ */ a(c.Consumer, { children: (t) => {
29
54
  if (!t) throw Error("MenuPanel must be inside <Menu>");
30
- return /* @__PURE__ */ i(c, {
55
+ return /* @__PURE__ */ a(l, {
31
56
  ctx: t,
32
57
  children: e
33
58
  });
34
59
  } });
35
60
  }
36
- function u({ children: t }) {
37
- let n = e(), [r, ...o] = Array.isArray(t) ? t : [t];
38
- return /* @__PURE__ */ a(s.Provider, {
61
+ function d({ children: t }) {
62
+ let n = e(), [r, ...i] = Array.isArray(t) ? t : [t];
63
+ return /* @__PURE__ */ o(c.Provider, {
39
64
  value: n,
40
- children: [r, /* @__PURE__ */ i(l, { children: o })]
65
+ children: [r, /* @__PURE__ */ a(u, { children: i })]
41
66
  });
42
67
  }
43
- function d({ ctx: e, children: n, "aria-label": a }) {
68
+ function f({ ctx: e, children: n, "aria-label": i }) {
44
69
  r();
45
70
  let { triggerRef: o, toggle: s, anchorName: c, isOpen: l } = e;
46
- return /* @__PURE__ */ i("button", {
71
+ return /* @__PURE__ */ a("button", {
47
72
  ref: o,
48
73
  type: "button",
49
74
  "aria-haspopup": "menu",
50
75
  "aria-expanded": l.value,
51
- "aria-label": a,
76
+ "aria-label": i,
52
77
  style: { anchorName: c },
53
78
  onClick: s,
54
79
  className: t.trigger,
55
80
  children: n
56
81
  });
57
82
  }
58
- function f({ children: e, "aria-label": t }) {
59
- return /* @__PURE__ */ i(s.Consumer, { children: (n) => {
83
+ function p({ children: e, "aria-label": t }) {
84
+ return /* @__PURE__ */ a(c.Consumer, { children: (n) => {
60
85
  if (!n) throw Error("MenuTrigger must be inside <Menu>");
61
- return /* @__PURE__ */ i(d, {
86
+ return /* @__PURE__ */ a(f, {
62
87
  ctx: n,
63
88
  ...t !== void 0 && { "aria-label": t },
64
89
  children: e
65
90
  });
66
91
  } });
67
92
  }
68
- function p({ children: e, onSelect: n, disabled: r }) {
69
- return /* @__PURE__ */ i(s.Consumer, { children: (a) => {
70
- if (!a) throw Error("MenuItem must be inside <Menu>");
71
- let { close: o } = a;
93
+ function m({ children: e, onSelect: n, disabled: r }) {
94
+ return /* @__PURE__ */ a(c.Consumer, { children: (i) => {
95
+ if (!i) throw Error("MenuItem must be inside <Menu>");
96
+ let { close: o } = i;
72
97
  function s() {
73
98
  r || (n(), o());
74
99
  }
75
100
  function c(e) {
76
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), s()), e.key === "ArrowDown" && (e.preventDefault(), e.currentTarget.nextElementSibling?.focus()), e.key === "ArrowUp" && (e.preventDefault(), e.currentTarget.previousElementSibling?.focus());
101
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.stopPropagation(), s());
77
102
  }
78
- return /* @__PURE__ */ i("div", {
103
+ return /* @__PURE__ */ a("div", {
79
104
  role: "menuitem",
80
105
  tabIndex: r ? -1 : 0,
81
106
  "aria-disabled": r,
@@ -86,11 +111,11 @@ function p({ children: e, onSelect: n, disabled: r }) {
86
111
  });
87
112
  } });
88
113
  }
89
- function m() {
90
- return /* @__PURE__ */ i("div", {
114
+ function h() {
115
+ return /* @__PURE__ */ a("div", {
91
116
  role: "separator",
92
117
  className: t.separator
93
118
  });
94
119
  }
95
120
  //#endregion
96
- export { u as Menu, p as MenuItem, m as MenuSeparator, f as MenuTrigger };
121
+ export { d as Menu, m as MenuItem, h as MenuSeparator, p as MenuTrigger };
@@ -1,73 +1,70 @@
1
1
  "use client";
2
2
 
3
3
  import e from "./modal.module.js";
4
- import { cn as t, useDraggable as n, useSignal as r, useSignalEffect as i, useSignals as a } from "@cascivo/core";
5
- import { builtin as o, t as s } from "@cascivo/i18n";
6
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
- import { useRef as u } from "react";
4
+ import { cn as t, useDraggable as n, useId as r, useSignal as i, useSignalEffect as a, useSignals as o } from "@cascivo/core";
5
+ import { builtin as s, t as c } from "@cascivo/i18n";
6
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
7
+ import { useRef as d } from "react";
8
8
  //#region ../components/src/modal/modal.tsx
9
- function d({ open: d = !1, onClose: f, title: p, description: m, children: h, className: g, size: _ = "md", draggable: v = !1 }) {
10
- a();
11
- let y = u(null), b = u(f);
12
- b.current = f;
13
- let { handleRef: x, offset: S } = n({ isDisabled: !v }), C = v ? {
14
- "--modal-x": `${S.value.x}px`,
15
- "--modal-y": `${S.value.y}px`
16
- } : void 0, w = r(d);
17
- return w.value = d, i(() => {
18
- let e = y.current;
19
- e && (w.value ? e.open || e.showModal() : e.open && e.close());
20
- }), i(() => {
21
- let e = y.current;
9
+ function f({ open: f = !1, onClose: p, title: m, description: h, children: g, className: _, size: v = "md", draggable: y = !1 }) {
10
+ o();
11
+ let b = d(null), x = d(p);
12
+ x.current = p;
13
+ let S = r("cascivo-modal-title"), C = r("cascivo-modal-desc"), { handleRef: w, offset: T } = n({ isDisabled: !y }), E = y ? {
14
+ "--modal-x": `${T.value.x}px`,
15
+ "--modal-y": `${T.value.y}px`
16
+ } : void 0, D = i(f);
17
+ return D.value = f, a(() => {
18
+ let e = b.current;
19
+ e && (D.value ? e.open || e.showModal() : e.open && e.close());
20
+ }), a(() => {
21
+ let e = b.current;
22
22
  if (!e) return;
23
- let t = () => b.current?.();
23
+ let t = () => x.current?.();
24
24
  return e.addEventListener("close", t), () => e.removeEventListener("close", t);
25
- }), /* @__PURE__ */ c("dialog", {
26
- ref: y,
27
- "data-size": _,
28
- "data-draggable": v || void 0,
29
- className: t(e.dialog, g),
30
- style: C,
25
+ }), /* @__PURE__ */ l("dialog", {
26
+ ref: b,
27
+ "data-size": v,
28
+ "data-draggable": y || void 0,
29
+ className: t(e.dialog, _),
30
+ style: E,
31
31
  onClick: (e) => {
32
- e.target === y.current && y.current?.close();
32
+ e.target === b.current && b.current?.close();
33
33
  },
34
- onKeyDown: (e) => {
35
- e.key === "Escape" && (e.preventDefault(), y.current?.close());
36
- },
37
- "aria-labelledby": p ? "cascade-modal-title" : void 0,
38
- "aria-describedby": m ? "cascade-modal-desc" : void 0,
39
- children: /* @__PURE__ */ l("div", {
34
+ "aria-labelledby": m ? S : void 0,
35
+ "aria-describedby": h ? C : void 0,
36
+ children: /* @__PURE__ */ u("div", {
40
37
  className: e.panel,
41
38
  children: [
42
- (p || f) && /* @__PURE__ */ l("div", {
39
+ (m || p) && /* @__PURE__ */ u("div", {
43
40
  className: e.header,
44
- ref: v ? (e) => {
45
- x.current = e;
41
+ ref: y ? (e) => {
42
+ w.current = e;
46
43
  } : void 0,
47
- children: [p && /* @__PURE__ */ c("h2", {
48
- id: "cascade-modal-title",
44
+ children: [m && /* @__PURE__ */ l("h2", {
45
+ id: S,
49
46
  className: e.title,
50
- children: p
51
- }), f && /* @__PURE__ */ c("button", {
47
+ children: m
48
+ }), p && /* @__PURE__ */ l("button", {
52
49
  type: "button",
53
50
  className: e.close,
54
- onClick: () => y.current?.close(),
55
- "aria-label": s(o.modal.close),
51
+ onClick: () => b.current?.close(),
52
+ "aria-label": c(s.modal.close),
56
53
  children: "✕"
57
54
  })]
58
55
  }),
59
- m && /* @__PURE__ */ c("p", {
60
- id: "cascade-modal-desc",
56
+ h && /* @__PURE__ */ l("p", {
57
+ id: C,
61
58
  className: e.description,
62
- children: m
59
+ children: h
63
60
  }),
64
- /* @__PURE__ */ c("div", {
61
+ /* @__PURE__ */ l("div", {
65
62
  className: e.body,
66
- children: h
63
+ children: g
67
64
  })
68
65
  ]
69
66
  })
70
67
  });
71
68
  }
72
69
  //#endregion
73
- export { d as Modal };
70
+ export { f as Modal };
@@ -1 +1 @@
1
- @layer cascivo.component{._stat_119kx_2{gap:var(--cascivo-space-1);font-family:var(--cascivo-font-sans);flex-direction:column;display:flex}._label_119kx_9{font-size:var(--cascivo-text-sm);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}._value_119kx_15{font-size:var(--cascivo-text-2xl);font-weight:var(--cascivo-font-semibold);color:var(--cascivo-color-text);line-height:var(--cascivo-leading-tight);font-variant-numeric:tabular-nums}._delta_119kx_23{align-items:center;gap:var(--cascivo-space-1);font-size:var(--cascivo-text-sm);font-weight:var(--cascivo-font-medium);font-variant-numeric:tabular-nums;display:inline-flex}._delta_119kx_23[data-trend=up]{color:var(--cascivo-color-success-foreground)}._delta_119kx_23[data-trend=down]{color:var(--cascivo-color-destructive-foreground)}._delta_119kx_23[data-trend=flat]{color:var(--cascivo-color-text-subtle)}._arrow_119kx_44{font-size:var(--cascivo-text-xs);line-height:1}._help_119kx_49{font-size:var(--cascivo-text-xs);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}}
1
+ @layer cascivo.component{._stat_r3v5x_2{gap:var(--cascivo-space-1);font-family:var(--cascivo-font-sans);flex-direction:column;display:flex}._label_r3v5x_9{font-size:var(--cascivo-text-sm);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}._value_r3v5x_15{font-size:var(--cascivo-text-2xl);font-weight:var(--cascivo-font-semibold);color:var(--cascivo-color-text);line-height:var(--cascivo-leading-tight);font-variant-numeric:tabular-nums}._delta_r3v5x_23{align-items:center;gap:var(--cascivo-space-1);font-size:var(--cascivo-text-sm);font-weight:var(--cascivo-font-medium);font-variant-numeric:tabular-nums;display:inline-flex}._delta_r3v5x_23[data-trend=up]{color:var(--cascivo-color-success-foreground)}._delta_r3v5x_23[data-trend=down]{color:var(--cascivo-color-destructive-foreground)}._delta_r3v5x_23[data-trend=flat]{color:var(--cascivo-color-text-subtle)}._arrow_r3v5x_44{font-size:var(--cascivo-text-xs);line-height:1}._help_r3v5x_49{font-size:var(--cascivo-text-xs);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}._visual_r3v5x_55{margin-block-start:var(--cascivo-space-1)}}
package/dist/stat/stat.js CHANGED
@@ -4,10 +4,10 @@ import e from "./stat.module.js";
4
4
  import { cn as t } from "@cascivo/core";
5
5
  import { jsx as n, jsxs as r } from "react/jsx-runtime";
6
6
  //#region ../components/src/stat/stat.tsx
7
- function i({ label: i, value: a, delta: o, trend: s = "flat", helpText: c, className: l, ...u }) {
7
+ function i({ label: i, value: a, delta: o, trend: s = "flat", helpText: c, visual: l, className: u, ...d }) {
8
8
  return /* @__PURE__ */ r("div", {
9
- className: t(e.stat, l),
10
- ...u,
9
+ className: t(e.stat, u),
10
+ ...d,
11
11
  children: [
12
12
  /* @__PURE__ */ n("span", {
13
13
  className: e.label,
@@ -29,6 +29,10 @@ function i({ label: i, value: a, delta: o, trend: s = "flat", helpText: c, class
29
29
  c && /* @__PURE__ */ n("span", {
30
30
  className: e.help,
31
31
  children: c
32
+ }),
33
+ l && /* @__PURE__ */ n("span", {
34
+ className: e.visual,
35
+ children: l
32
36
  })
33
37
  ]
34
38
  });
@@ -2,12 +2,13 @@
2
2
 
3
3
  import './stat.css';
4
4
  var e = {
5
- stat: "_stat_119kx_2",
6
- label: "_label_119kx_9",
7
- value: "_value_119kx_15",
8
- delta: "_delta_119kx_23",
9
- arrow: "_arrow_119kx_44",
10
- help: "_help_119kx_49"
5
+ stat: "_stat_r3v5x_2",
6
+ label: "_label_r3v5x_9",
7
+ value: "_value_r3v5x_15",
8
+ delta: "_delta_r3v5x_23",
9
+ arrow: "_arrow_r3v5x_44",
10
+ help: "_help_r3v5x_49",
11
+ visual: "_visual_r3v5x_55"
11
12
  };
12
13
  //#endregion
13
14
  export { e as default };
package/dist/styles.css CHANGED
@@ -1,3 +1,32 @@
1
+ /* packages/tokens/src/layers.css */
2
+ /* cascivo — canonical @layer order (single source of truth). */
3
+ /*
4
+ * This statement is the ONE authoritative declaration of cascivo's cascade-layer
5
+ * order. Every entry path emits it first (via @import of this file, or — for the
6
+ * @cascivo/react aggregate — by prepending its contents), and identical @layer
7
+ * statements are idempotent, so the order is deterministic no matter which
8
+ * cascivo stylesheet a consumer loads first.
9
+ *
10
+ * Ordered lowest-priority → highest-priority:
11
+ *
12
+ * cascivo.reset consumer reset (box-sizing, margin/padding zeroing) — the floor
13
+ * cascivo.base minimal html font/color reset (@cascivo/themes/base.css)
14
+ * cascivo.tokens primitive design tokens (@cascivo/tokens)
15
+ * cascivo.component component + layout styles
16
+ * cascivo.theme semantic token values per [data-theme] (@cascivo/themes/*)
17
+ * cascivo.override consumer escape hatch — beats tokens, components, and themes
18
+ *
19
+ * theme > component matches the CLI scaffold and every example app: themes own
20
+ * the semantic tier, so a theme always wins over component defaults. cascivo.override
21
+ * sits on top: put brand/one-off overrides in `@layer cascivo.override { … }` and
22
+ * they beat everything cascivo ships — with no `:root:not([data-theme])` specificity
23
+ * fight. App-local sublayers (cascivo.example, cascivo.blocks.*) are not shipped by
24
+ * any package; insert them between cascivo.theme and cascivo.override.
25
+ *
26
+ * Guard: scripts/checks/layer-order.test.ts asserts every shipped/scaffolded
27
+ * @layer statement is an ordered subsequence of this one.
28
+ */
29
+ @layer cascivo.reset, cascivo.base, cascivo.tokens, cascivo.component, cascivo.theme, cascivo.override;
1
30
  @layer cascivo.component{._accordion_9ch4s_2{border:1px solid var(--cascivo-color-border);border-radius:var(--cascivo-radius-surface);flex-direction:column;display:flex;overflow:hidden}._item_9ch4s_10:not(:last-child){border-block-end:1px solid var(--cascivo-color-border)}._heading_9ch4s_16{font-size:inherit;font-weight:inherit;margin:0}._trigger_9ch4s_22{justify-content:space-between;align-items:center;gap:var(--cascivo-space-3);inline-size:100%;padding:var(--cascivo-space-4);font-family:var(--cascivo-font-sans);font-size:var(--cascivo-text-sm);font-weight:var(--cascivo-font-medium);text-align:start;color:var(--cascivo-color-text);cursor:pointer;background:0 0;border:none;display:flex}._trigger_9ch4s_22:hover{background-color:var(--cascivo-color-bg-subtle)}._trigger_9ch4s_22:focus-visible{box-shadow:var(--cascivo-focus-ring);outline:none}._indicator_9ch4s_48{block-size:.75rem;inline-size:.75rem;transition:rotate var(--cascivo-duration-200) var(--cascivo-ease-out);background-color:currentColor;flex-shrink:0;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M4 6l4 4 4-4'/%3E%3C/svg%3E") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M4 6l4 4 4-4'/%3E%3C/svg%3E") 50%/contain no-repeat}._trigger_9ch4s_22[data-state=open] ._indicator_9ch4s_48{rotate:180deg}._content_9ch4s_62{visibility:hidden;color:var(--cascivo-color-text);transition:grid-template-rows var(--cascivo-duration-200) var(--cascivo-ease-out), visibility var(--cascivo-duration-200) var(--cascivo-ease-out);grid-template-rows:0fr;display:grid}._content_9ch4s_62[data-state=open]{visibility:visible;grid-template-rows:1fr}._contentInner_9ch4s_77{font-family:var(--cascivo-font-sans);font-size:var(--cascivo-text-sm);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-relaxed);overflow:hidden}._content_9ch4s_62[data-state=open] ._contentInner_9ch4s_77{padding-inline:var(--cascivo-space-4);padding-block-end:var(--cascivo-space-4)}}@media (forced-colors:active){._accordion_9ch4s_2{border:1px solid buttontext}._trigger_9ch4s_22:focus-visible{outline-offset:2px;outline:2px solid highlight}}
2
31
 
3
32
  @layer cascivo.component{._overlay_17irl_2{z-index:var(--cascivo-z-overlay,50);padding:var(--cascivo-space-3);opacity:1;transition:opacity var(--cascivo-motion-enter);background-color:#0006;flex-direction:column;justify-content:flex-end;align-items:center;padding-block-end:calc(var(--cascivo-space-3) + env(safe-area-inset-bottom,0px));display:flex;position:fixed;inset:0}._overlay_17irl_2[data-state=closed]{opacity:0;transition:opacity var(--cascivo-motion-exit)}@starting-style{._overlay_17irl_2[data-state=open]{opacity:0}}._sheet_17irl_28{gap:var(--cascivo-space-2);inline-size:100%;max-inline-size:32rem;transition:translate var(--cascivo-motion-enter);flex-direction:column;display:flex;translate:0}._overlay_17irl_2[data-state=closed] ._sheet_17irl_28{transition:translate var(--cascivo-motion-exit);translate:0 100%}@starting-style{._overlay_17irl_2[data-state=open] ._sheet_17irl_28{translate:0 100%}}._group_17irl_50{background:var(--cascivo-color-surface);border:1px solid var(--cascivo-color-border);border-radius:var(--cascivo-radius-overlay);box-shadow:var(--cascivo-shadow-overlay);flex-direction:column;display:flex;overflow:hidden}._heading_17irl_60{padding:var(--cascivo-space-4) var(--cascivo-space-6);text-align:center;border-block-end:1px solid var(--cascivo-color-border)}._title_17irl_66{font-size:var(--cascivo-text-sm);font-weight:var(--cascivo-font-semibold);color:var(--cascivo-color-text);margin:0}._description_17irl_73{margin:var(--cascivo-space-1) 0 0;font-size:var(--cascivo-text-sm);color:var(--cascivo-color-text-subtle)}._item_17irl_79{min-block-size:3rem;inline-size:100%;padding:var(--cascivo-space-3) var(--cascivo-space-6);font-size:var(--cascivo-text-base);color:var(--cascivo-color-accent);cursor:pointer;transition:background-color var(--cascivo-duration-150) var(--cascivo-ease-out);background:0 0;border:none;justify-content:center;align-items:center;display:flex}._item_17irl_79+._item_17irl_79{border-block-start:1px solid var(--cascivo-color-border)}._item_17irl_79:hover{background-color:var(--cascivo-color-bg-subtle)}._item_17irl_79:focus-visible{box-shadow:var(--cascivo-focus-ring);z-index:1;outline:none;position:relative}._item_17irl_79[aria-disabled=true]{color:var(--cascivo-color-text-muted);cursor:not-allowed}._item_17irl_79[data-destructive]{color:var(--cascivo-color-destructive)}._cancel_17irl_119{font-weight:var(--cascivo-font-semibold);color:var(--cascivo-color-text)}@media (prefers-reduced-motion:reduce){._sheet_17irl_28{transition:none}}}
@@ -200,7 +229,7 @@
200
229
  /*$vite$:1*/
201
230
  @layer cascivo.component{._stack_2ay4v_2{isolation:isolate;grid-template-areas:"stack";display:grid}._layer_2ay4v_8{transform:translate(calc(var(--cascivo-stack-index,0) * var(--cascivo-stack-offset,4px)), calc(var(--cascivo-stack-index,0) * var(--cascivo-stack-offset,4px)));z-index:calc(10 - var(--cascivo-stack-index,0));grid-area:stack}}
202
231
  /*$vite$:1*/
203
- @layer cascivo.component{._stat_119kx_2{gap:var(--cascivo-space-1);font-family:var(--cascivo-font-sans);flex-direction:column;display:flex}._label_119kx_9{font-size:var(--cascivo-text-sm);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}._value_119kx_15{font-size:var(--cascivo-text-2xl);font-weight:var(--cascivo-font-semibold);color:var(--cascivo-color-text);line-height:var(--cascivo-leading-tight);font-variant-numeric:tabular-nums}._delta_119kx_23{align-items:center;gap:var(--cascivo-space-1);font-size:var(--cascivo-text-sm);font-weight:var(--cascivo-font-medium);font-variant-numeric:tabular-nums;display:inline-flex}._delta_119kx_23[data-trend=up]{color:var(--cascivo-color-success-foreground)}._delta_119kx_23[data-trend=down]{color:var(--cascivo-color-destructive-foreground)}._delta_119kx_23[data-trend=flat]{color:var(--cascivo-color-text-subtle)}._arrow_119kx_44{font-size:var(--cascivo-text-xs);line-height:1}._help_119kx_49{font-size:var(--cascivo-text-xs);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}}
232
+ @layer cascivo.component{._stat_r3v5x_2{gap:var(--cascivo-space-1);font-family:var(--cascivo-font-sans);flex-direction:column;display:flex}._label_r3v5x_9{font-size:var(--cascivo-text-sm);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}._value_r3v5x_15{font-size:var(--cascivo-text-2xl);font-weight:var(--cascivo-font-semibold);color:var(--cascivo-color-text);line-height:var(--cascivo-leading-tight);font-variant-numeric:tabular-nums}._delta_r3v5x_23{align-items:center;gap:var(--cascivo-space-1);font-size:var(--cascivo-text-sm);font-weight:var(--cascivo-font-medium);font-variant-numeric:tabular-nums;display:inline-flex}._delta_r3v5x_23[data-trend=up]{color:var(--cascivo-color-success-foreground)}._delta_r3v5x_23[data-trend=down]{color:var(--cascivo-color-destructive-foreground)}._delta_r3v5x_23[data-trend=flat]{color:var(--cascivo-color-text-subtle)}._arrow_r3v5x_44{font-size:var(--cascivo-text-xs);line-height:1}._help_r3v5x_49{font-size:var(--cascivo-text-xs);color:var(--cascivo-color-text-subtle);line-height:var(--cascivo-leading-tight)}._visual_r3v5x_55{margin-block-start:var(--cascivo-space-1)}}
204
233
  /*$vite$:1*/
205
234
  @layer cascivo.component{._status_u4gep_2{align-items:center;gap:var(--cascivo-space-2);font-family:var(--cascivo-font-sans);font-size:var(--cascivo-text-sm);color:var(--cascivo-color-text);line-height:var(--cascivo-leading-tight);display:inline-flex}._status_u4gep_2[data-status=success] ._dot_u4gep_11{background-color:var(--cascivo-color-success)}._status_u4gep_2[data-status=warning] ._dot_u4gep_11{background-color:var(--cascivo-color-warning)}._status_u4gep_2[data-status=error] ._dot_u4gep_11{background-color:var(--cascivo-color-error)}._status_u4gep_2[data-status=info] ._dot_u4gep_11{background-color:var(--cascivo-color-info)}._status_u4gep_2[data-status=neutral] ._dot_u4gep_11{background-color:var(--cascivo-color-text-muted)}._dot_u4gep_11{border-radius:var(--cascivo-radius-full);flex-shrink:0;block-size:.5rem;inline-size:.5rem}@media (prefers-reduced-motion:no-preference){._status_u4gep_2[data-pulse] ._dot_u4gep_11{animation:_cascade-status-pulse_u4gep_1 2s var(--cascivo-ease-in-out) infinite}}@keyframes _cascade-status-pulse_u4gep_1{0%,to{opacity:1}50%{opacity:.4}}}
206
235
  /*$vite$:1*/
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
 
3
3
  import e from "./tooltip.module.js";
4
- import { createMachine as t, useMachine as n, useSignalEffect as r, useSignals as i } from "@cascivo/core";
5
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
- import { cloneElement as s, useId as c, useRef as l } from "react";
4
+ import { createMachine as t, useId as n, useMachine as r, useSignalEffect as i, useSignals as a } from "@cascivo/core";
5
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
6
+ import { cloneElement as c, useRef as l } from "react";
7
7
  //#region ../components/src/tooltip/tooltip.tsx
8
8
  var u = t({
9
9
  initial: "hidden",
@@ -13,18 +13,18 @@ var u = t({
13
13
  }
14
14
  });
15
15
  function d({ content: t, placement: d = "top", children: f, delay: p = 200 }) {
16
- i();
17
- let [m, h] = n(u), g = c(), _ = l(`t${Math.random().toString(36).slice(2)}`), v = l(void 0), y = l(null), b = m.value === "visible", x = () => {
16
+ a();
17
+ let [m, h] = r(u), g = n("cascivo-tooltip"), _ = n("cascivo-anchor"), v = l(void 0), y = l(null), b = m.value === "visible", x = () => {
18
18
  clearTimeout(v.current), v.current = setTimeout(() => h("SHOW"), p);
19
19
  }, S = () => {
20
20
  clearTimeout(v.current), h("HIDE");
21
21
  };
22
- r(() => () => clearTimeout(v.current)), r(() => {
22
+ i(() => () => clearTimeout(v.current)), i(() => {
23
23
  m.value === "visible" ? y.current?.showPopover() : y.current?.hidePopover();
24
24
  });
25
25
  let C = f, w = C.props, T = {
26
- id: _.current,
27
- style: { anchorName: `--tooltip-${_.current}` },
26
+ id: _,
27
+ style: { anchorName: `--tooltip-${_}` },
28
28
  onMouseEnter: (e) => {
29
29
  w.onMouseEnter?.(e), x();
30
30
  },
@@ -39,16 +39,16 @@ function d({ content: t, placement: d = "top", children: f, delay: p = 200 }) {
39
39
  },
40
40
  "aria-describedby": b ? g : w["aria-describedby"]
41
41
  };
42
- return /* @__PURE__ */ o("span", {
42
+ return /* @__PURE__ */ s("span", {
43
43
  className: e.root,
44
- children: [s(C, T), /* @__PURE__ */ a("span", {
44
+ children: [c(C, T), /* @__PURE__ */ o("span", {
45
45
  ref: y,
46
46
  popover: "manual",
47
47
  role: "tooltip",
48
48
  id: g,
49
49
  "data-placement": d,
50
50
  "data-state": b ? "visible" : "hidden",
51
- "data-anchor": `--tooltip-${_.current}`,
51
+ "data-anchor": `--tooltip-${_}`,
52
52
  className: e.tooltip,
53
53
  children: t
54
54
  })]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cascivo/react",
3
- "version": "0.4.3",
3
+ "version": "0.5.1",
4
4
  "private": false,
5
5
  "description": "Prebuilt cascivo design system components — use without copying source",
6
6
  "keywords": [
@@ -44,8 +44,8 @@
44
44
  "provenance": true
45
45
  },
46
46
  "dependencies": {
47
- "@cascivo/core": "^0.2.6",
48
- "@cascivo/i18n": "^0.2.3"
47
+ "@cascivo/core": "^0.3.1",
48
+ "@cascivo/i18n": "^0.2.5"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@testing-library/jest-dom": "^6.9.1",