@skiddph/prui 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/app/resource.d.ts +44 -1
  2. package/dist/app.js +1 -1
  3. package/dist/chunks/auth-shell-DQJ4UmUv.js +1208 -0
  4. package/dist/chunks/data-table-toolbar-B-5J2Ozl.js +736 -0
  5. package/dist/core/accordion.d.ts +16 -0
  6. package/dist/core/accordion.js +108 -0
  7. package/dist/core/alert.d.ts +20 -0
  8. package/dist/core/alert.js +63 -0
  9. package/dist/core/anchor.d.ts +35 -0
  10. package/dist/core/anchor.js +39 -0
  11. package/dist/core/breadcrumb.d.ts +30 -0
  12. package/dist/core/breadcrumb.js +67 -0
  13. package/dist/core/button.d.ts +8 -1
  14. package/dist/core/button.js +23 -18
  15. package/dist/core/calendar.d.ts +29 -0
  16. package/dist/core/calendar.js +180 -0
  17. package/dist/core/card.d.ts +5 -1
  18. package/dist/core/card.js +33 -29
  19. package/dist/core/checkbox.d.ts +19 -0
  20. package/dist/core/checkbox.js +55 -0
  21. package/dist/core/combobox.d.ts +32 -0
  22. package/dist/core/combobox.js +193 -0
  23. package/dist/core/date-picker.d.ts +62 -0
  24. package/dist/core/date-picker.js +314 -0
  25. package/dist/core/dialog.d.ts +15 -0
  26. package/dist/core/dialog.js +77 -60
  27. package/dist/core/drawer.d.ts +34 -0
  28. package/dist/core/drawer.js +129 -0
  29. package/dist/core/dropdown.d.ts +8 -4
  30. package/dist/core/dropdown.js +136 -51
  31. package/dist/core/file-upload.d.ts +28 -0
  32. package/dist/core/file-upload.js +111 -0
  33. package/dist/core/index.d.ts +23 -1
  34. package/dist/core/list-nav.d.ts +27 -0
  35. package/dist/core/list-nav.js +51 -0
  36. package/dist/core/modal.d.ts +14 -5
  37. package/dist/core/modal.js +163 -156
  38. package/dist/core/overlay.d.ts +93 -0
  39. package/dist/core/overlay.js +189 -0
  40. package/dist/core/popover.d.ts +29 -0
  41. package/dist/core/popover.js +124 -0
  42. package/dist/core/progress.d.ts +21 -0
  43. package/dist/core/progress.js +59 -0
  44. package/dist/core/radio.d.ts +20 -0
  45. package/dist/core/radio.js +115 -0
  46. package/dist/core/select.d.ts +6 -0
  47. package/dist/core/select.js +187 -98
  48. package/dist/core/skeleton.d.ts +20 -0
  49. package/dist/core/skeleton.js +41 -0
  50. package/dist/core/spinner.d.ts +15 -0
  51. package/dist/core/spinner.js +41 -0
  52. package/dist/core/tabs.js +82 -53
  53. package/dist/core/time-picker.d.ts +68 -0
  54. package/dist/core/time-picker.js +305 -0
  55. package/dist/core/timeline.d.ts +22 -0
  56. package/dist/core/timeline.js +57 -0
  57. package/dist/core/toast.d.ts +36 -0
  58. package/dist/core/toast.js +123 -0
  59. package/dist/core/tooltip.d.ts +23 -0
  60. package/dist/core/tooltip.js +96 -0
  61. package/dist/core/tree-view.d.ts +34 -0
  62. package/dist/core/tree-view.js +133 -0
  63. package/dist/core.js +160 -62
  64. package/dist/data-table/data-table.d.ts +22 -1
  65. package/dist/data-table.js +1 -1
  66. package/dist/forms/form.d.ts +8 -0
  67. package/dist/forms.js +213 -200
  68. package/dist/i18n/index.d.ts +89 -0
  69. package/dist/i18n.js +105 -0
  70. package/dist/index.d.ts +1 -0
  71. package/dist/index.js +263 -155
  72. package/dist/prui-utilities.css +1 -1
  73. package/dist/prui.css +111 -4
  74. package/dist/theme/base.css +110 -3
  75. package/dist/theme/index.d.ts +27 -0
  76. package/dist/theme.js +86 -58
  77. package/package.json +9 -2
  78. package/dist/chunks/auth-shell-BG5vx9eG.js +0 -1054
  79. package/dist/chunks/data-table-toolbar-BUy2EWPy.js +0 -581
@@ -1,144 +1,233 @@
1
- import { jsxs as b, jsx as s, Fragment as P } from "react/jsx-runtime";
2
- import * as o from "react";
3
- import { ChevronDown as z, Check as D } from "lucide-react";
4
- import { cn as m } from "./cn.js";
5
- const S = o.createContext(null);
6
- function g() {
7
- const r = o.useContext(S);
8
- if (!r) throw new Error("Select parts must be used inside <Select>");
9
- return r;
1
+ import { jsxs as D, jsx as y, Fragment as W } from "react/jsx-runtime";
2
+ import * as a from "react";
3
+ import { ChevronDown as q, Check as H } from "lucide-react";
4
+ import { cn as A } from "./cn.js";
5
+ import { useOverlayStack as B, useEscapeKey as G, Portal as J } from "./overlay.js";
6
+ import { useAnchoredPosition as Q } from "./anchor.js";
7
+ import { typeaheadIndex as X, endIndex as Y, homeIndex as Z, moveIndex as F } from "./list-nav.js";
8
+ const L = a.createContext(null);
9
+ function E() {
10
+ const i = a.useContext(L);
11
+ if (!i) throw new Error("Select parts must be used inside <Select>");
12
+ return i;
10
13
  }
11
- const F = ({
12
- options: r,
13
- value: a,
14
- defaultValue: t,
15
- placeholder: i = "Select...",
16
- disabled: e,
17
- name: d,
18
- id: u,
19
- onChange: l,
14
+ const _ = ({
15
+ options: i,
16
+ value: u,
17
+ defaultValue: b,
18
+ placeholder: d = "Select...",
19
+ disabled: f,
20
+ name: l,
21
+ id: v,
22
+ onChange: n,
20
23
  onOpenChange: p,
21
- children: f,
22
- ...c
24
+ children: w,
25
+ ...g
23
26
  }) => {
24
- const [v, I] = o.useState(t ?? ""), [R, T] = o.useState(!1), [V, j] = o.useState(), x = a !== void 0 ? a : v, O = (n) => {
25
- a === void 0 && I(n), l == null || l(n);
26
- }, E = (n) => {
27
- T(n), p == null || p(n);
28
- };
29
- return /* @__PURE__ */ b(
30
- S.Provider,
27
+ var o;
28
+ const [m, h] = a.useState(b ?? ""), [x, S] = a.useState(!1), [e, V] = a.useState(null), [O, P] = a.useState({}), T = u !== void 0 ? u : m, I = a.useCallback((r, c) => {
29
+ P((s) => {
30
+ if (c === null) {
31
+ if (!(r in s)) return s;
32
+ const R = { ...s };
33
+ return delete R[r], R;
34
+ }
35
+ return s[r] === c ? s : { ...s, [r]: c };
36
+ });
37
+ }, []), N = (r) => {
38
+ u === void 0 && h(r), n == null || n(r);
39
+ }, k = (r) => {
40
+ S(r), p == null || p(r);
41
+ }, j = () => e == null ? void 0 : e.focus(), t = O[T] ?? ((o = i == null ? void 0 : i.find((r) => r.value === T)) == null ? void 0 : o.label);
42
+ return /* @__PURE__ */ D(
43
+ L.Provider,
31
44
  {
32
- value: { value: x, open: R, triggerId: V, setValue: O, setOpen: E, registerTrigger: j },
45
+ value: { value: T, displayValue: t, open: x, triggerEl: e, triggerId: (e == null ? void 0 : e.id) || void 0, setValue: N, setOpen: k, registerTrigger: V, returnFocusToTrigger: j, registerLabel: I },
33
46
  children: [
34
- d ? /* @__PURE__ */ s("input", { type: "hidden", name: d, value: x }) : null,
35
- f ?? /* @__PURE__ */ b(P, { children: [
36
- /* @__PURE__ */ s(h, { disabled: e, id: u, ...c, children: /* @__PURE__ */ s(y, { placeholder: i }) }),
37
- /* @__PURE__ */ s(w, { children: (r ?? []).map((n) => /* @__PURE__ */ s(N, { value: n.value, disabled: n.disabled, children: n.label }, n.value)) })
47
+ l ? /* @__PURE__ */ y("input", { type: "hidden", name: l, value: T }) : null,
48
+ w ?? /* @__PURE__ */ D(W, { children: [
49
+ /* @__PURE__ */ y(U, { disabled: f, id: v, ...g, children: /* @__PURE__ */ y($, { placeholder: d }) }),
50
+ /* @__PURE__ */ y(z, { children: (i ?? []).map((r) => /* @__PURE__ */ y(M, { value: r.value, disabled: r.disabled, children: r.label }, r.value)) })
38
51
  ] })
39
52
  ]
40
53
  }
41
54
  );
42
55
  };
43
- F.displayName = "Select";
44
- const h = o.forwardRef(
45
- ({ className: r, children: a, onClick: t, disabled: i, id: e, ...d }, u) => {
46
- const { open: l, setOpen: p, registerTrigger: f } = g();
47
- return o.useEffect(() => {
48
- e && f(e);
49
- }, [e, f]), /* @__PURE__ */ b(
56
+ _.displayName = "Select";
57
+ const U = a.forwardRef(
58
+ ({ className: i, children: u, onClick: b, onKeyDown: d, disabled: f, id: l, ...v }, n) => {
59
+ const { open: p, setOpen: w, registerTrigger: g } = E(), m = a.useRef(null), h = a.useId(), x = l ?? `prui-select-${h}`;
60
+ a.useEffect(() => (g(m.current), () => g(null)), [g]);
61
+ const S = `${x}-listbox`;
62
+ return /* @__PURE__ */ D(
50
63
  "button",
51
64
  {
52
- ref: u,
53
- id: e,
65
+ ref: (e) => {
66
+ m.current = e, typeof n == "function" ? n(e) : n && (n.current = e);
67
+ },
68
+ id: x,
54
69
  type: "button",
55
70
  role: "combobox",
56
- "aria-expanded": l,
71
+ "aria-expanded": p,
57
72
  "aria-haspopup": "listbox",
58
- disabled: i,
59
- "data-state": l ? "open" : "closed",
60
- className: m(
73
+ "aria-controls": p ? S : void 0,
74
+ disabled: f,
75
+ "data-state": p ? "open" : "closed",
76
+ className: A(
61
77
  "prui-select-trigger flex h-9 w-full items-center justify-between gap-2 border border-[var(--prui-line)]",
62
78
  "bg-[var(--prui-background)] rounded-[var(--prui-radius)] px-3 text-sm text-[var(--prui-fg)]",
63
79
  "outline-none transition-colors focus:border-[var(--prui-brand)] focus:ring-2 focus:ring-[var(--prui-brand)]/30",
64
80
  "disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer",
65
- r
81
+ i
66
82
  ),
67
- onClick: (c) => {
68
- t == null || t(c), c.defaultPrevented || p(!l);
83
+ onClick: (e) => {
84
+ b == null || b(e), e.defaultPrevented || w(!p);
69
85
  },
70
- ...d,
86
+ onKeyDown: (e) => {
87
+ d == null || d(e), !e.defaultPrevented && !p && (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Enter" || e.key === " ") && (e.preventDefault(), w(!0));
88
+ },
89
+ ...v,
71
90
  children: [
72
- a,
73
- /* @__PURE__ */ s(z, { className: m("h-4 w-4 shrink-0 text-[var(--prui-dim)] transition-transform", l && "rotate-180"), "aria-hidden": !0 })
91
+ u,
92
+ /* @__PURE__ */ y(q, { className: A("h-4 w-4 shrink-0 text-[var(--prui-dim)] transition-transform", p && "rotate-180"), "aria-hidden": !0 })
74
93
  ]
75
94
  }
76
95
  );
77
96
  }
78
97
  );
79
- h.displayName = "SelectTrigger";
80
- const y = o.forwardRef(
81
- ({ className: r, placeholder: a, children: t, ...i }, e) => {
82
- const { value: d } = g();
83
- return /* @__PURE__ */ s("span", { ref: e, className: m("truncate", r), ...i, children: t ?? (d || /* @__PURE__ */ s("span", { className: "text-[var(--prui-dim)]", children: a })) });
98
+ U.displayName = "SelectTrigger";
99
+ const $ = a.forwardRef(
100
+ ({ className: i, placeholder: u, children: b, ...d }, f) => {
101
+ const { value: l, displayValue: v } = E();
102
+ return /* @__PURE__ */ y("span", { ref: f, className: A("truncate", i), ...d, children: b ?? v ?? (l || /* @__PURE__ */ y("span", { className: "text-[var(--prui-dim)]", children: u })) });
84
103
  }
85
104
  );
86
- y.displayName = "SelectValue";
87
- const w = o.forwardRef(
88
- ({ className: r, children: a, ...t }, i) => {
89
- const { open: e, setOpen: d, triggerId: u } = g();
90
- return e ? /* @__PURE__ */ s(
105
+ $.displayName = "SelectValue";
106
+ const z = a.forwardRef(
107
+ ({ className: i, children: u, id: b, ...d }, f) => {
108
+ const { open: l, setOpen: v, triggerEl: n, setValue: p, returnFocusToTrigger: w } = E(), g = a.useRef(null), [m, h] = a.useState(-1), x = a.useRef({ buffer: "", at: 0 }), S = a.useRef(null);
109
+ S.current = n;
110
+ const [e, V] = a.useState(null), { setElement: O, isTop: P } = B(l);
111
+ G(l, P, () => {
112
+ v(!1), w();
113
+ });
114
+ const { ref: T, position: I } = Q({ active: l, anchorRef: S, side: "bottom", align: "start" }), N = a.useCallback(() => {
115
+ const t = g.current;
116
+ return t ? Array.from(t.querySelectorAll("[role='option']")) : [];
117
+ }, []), k = (t) => {
118
+ var o;
119
+ h(t), (o = N()[t]) == null || o.focus();
120
+ };
121
+ if (a.useEffect(() => {
122
+ var s;
123
+ if (!l || !e) return;
124
+ h(-1);
125
+ const t = N(), o = t.findIndex((R) => R.getAttribute("aria-selected") === "true"), r = t.findIndex((R) => R.getAttribute("aria-disabled") !== "true"), c = o >= 0 ? o : r;
126
+ c >= 0 && (h(c), (s = t[c]) == null || s.focus());
127
+ }, [l, e, N]), !l) return null;
128
+ const j = (t) => {
129
+ const o = N(), r = (c) => {
130
+ var s;
131
+ return ((s = o[c]) == null ? void 0 : s.getAttribute("aria-disabled")) !== "true";
132
+ };
133
+ switch (t.key) {
134
+ case "ArrowDown":
135
+ t.preventDefault(), k(F(m, 1, o.length, { enabled: r }));
136
+ break;
137
+ case "ArrowUp":
138
+ t.preventDefault(), k(F(m, -1, o.length, { enabled: r }));
139
+ break;
140
+ case "Home":
141
+ t.preventDefault(), k(Z(o.length, r));
142
+ break;
143
+ case "End":
144
+ t.preventDefault(), k(Y(o.length, r));
145
+ break;
146
+ case "Enter":
147
+ case " ": {
148
+ t.preventDefault();
149
+ const c = o[m];
150
+ if (c && r(m)) {
151
+ const s = c.dataset.value;
152
+ s !== void 0 ? (p(s), v(!1), w()) : c.click();
153
+ }
154
+ break;
155
+ }
156
+ case "Tab":
157
+ v(!1);
158
+ break;
159
+ default:
160
+ if (t.key.length === 1) {
161
+ const c = () => o.map((R) => R.textContent ?? ""), { index: s } = X(c, x.current, t.key, m);
162
+ s >= 0 && s !== m && (t.preventDefault(), k(s));
163
+ }
164
+ }
165
+ };
166
+ return /* @__PURE__ */ y(J, { children: /* @__PURE__ */ y(
91
167
  "div",
92
168
  {
93
- ref: i,
169
+ ref: (t) => {
170
+ g.current = t, V(t), T(t), O(t), typeof f == "function" ? f(t) : f && (f.current = t);
171
+ },
172
+ id: b ?? (n != null && n.id ? `${n.id}-listbox` : void 0),
94
173
  role: "listbox",
95
- "aria-labelledby": u,
174
+ "aria-labelledby": (n == null ? void 0 : n.id) || void 0,
96
175
  tabIndex: -1,
97
- "data-state": e ? "open" : "closed",
98
- className: m(
99
- "prui-select-content absolute z-50 mt-1 min-w-40 max-h-60 overflow-auto p-1",
100
- "bg-[var(--prui-surface)] border border-[var(--prui-line)] rounded-[var(--prui-radius)] shadow-lg",
101
- r
176
+ "data-state": l ? "open" : "closed",
177
+ onKeyDown: j,
178
+ className: A(
179
+ "prui-select-content fixed z-[var(--prui-z-overlay)] max-h-60 overflow-auto p-1",
180
+ "bg-[var(--prui-surface)] border border-[var(--prui-line)] rounded-[var(--prui-radius)] shadow-[var(--prui-shadow-md)] outline-none",
181
+ i
102
182
  ),
103
- ...t,
104
- children: a
183
+ style: {
184
+ top: (I == null ? void 0 : I.top) ?? -9999,
185
+ left: (I == null ? void 0 : I.left) ?? -9999,
186
+ minWidth: n ? Math.max(n.offsetWidth, 160) : 160
187
+ },
188
+ ...d,
189
+ children: u
105
190
  }
106
- ) : null;
191
+ ) });
107
192
  }
108
193
  );
109
- w.displayName = "SelectContent";
110
- const N = o.forwardRef(
111
- ({ className: r, value: a, disabled: t, children: i, onClick: e, ...d }, u) => {
112
- const { value: l, setValue: p, setOpen: f } = g(), c = l === a;
113
- return /* @__PURE__ */ b(
194
+ z.displayName = "SelectContent";
195
+ const M = a.forwardRef(
196
+ ({ className: i, value: u, disabled: b, children: d, onClick: f, tabIndex: l = -1, ...v }, n) => {
197
+ const { value: p, setValue: w, setOpen: g, returnFocusToTrigger: m, registerLabel: h } = E(), x = p === u, S = typeof d == "string" || typeof d == "number" ? String(d) : void 0;
198
+ return a.useEffect(() => {
199
+ S !== void 0 && h(u, S);
200
+ }, [u, S, h]), /* @__PURE__ */ D(
114
201
  "div",
115
202
  {
116
- ref: u,
203
+ ref: n,
117
204
  role: "option",
118
- "aria-selected": c,
119
- "aria-disabled": t,
120
- "data-selected": c || void 0,
121
- className: m(
205
+ "aria-selected": x,
206
+ "aria-disabled": b,
207
+ "data-selected": x || void 0,
208
+ "data-value": u,
209
+ tabIndex: l,
210
+ className: A(
122
211
  "prui-select-item relative flex cursor-pointer items-center gap-2 rounded-[calc(var(--prui-radius)-1px)]",
123
- "py-1.5 pl-3 pr-8 text-sm text-[var(--prui-fg)] hover:bg-[var(--prui-raise)]",
124
- c && "font-medium",
125
- t && "opacity-50 pointer-events-none",
126
- r
212
+ "py-1.5 pl-3 pr-8 text-sm text-[var(--prui-fg)] hover:bg-[var(--prui-raise)] focus-visible:bg-[var(--prui-raise)] outline-none",
213
+ x && "font-medium",
214
+ b && "opacity-50 pointer-events-none",
215
+ i
127
216
  ),
128
- onClick: (v) => {
129
- e == null || e(v), !(v.defaultPrevented || t) && (p(a), f(!1));
217
+ onClick: (e) => {
218
+ f == null || f(e), !(e.defaultPrevented || b) && (w(u), g(!1), m());
130
219
  },
131
- ...d,
220
+ ...v,
132
221
  children: [
133
- i,
134
- c ? /* @__PURE__ */ s(D, { className: "absolute right-2 h-4 w-4 text-[var(--prui-brand)]", "aria-hidden": !0 }) : null
222
+ d,
223
+ x ? /* @__PURE__ */ y(H, { className: "absolute right-2 h-4 w-4 text-[var(--prui-brand)]", "aria-hidden": !0 }) : null
135
224
  ]
136
225
  }
137
226
  );
138
227
  }
139
228
  );
140
- N.displayName = "SelectItem";
141
- const A = {
229
+ M.displayName = "SelectItem";
230
+ const ne = {
142
231
  name: "Select",
143
232
  props: [
144
233
  { name: "options", type: "SelectOption[]", default: "[]", control: "object" },
@@ -150,10 +239,10 @@ const A = {
150
239
  ]
151
240
  };
152
241
  export {
153
- F as Select,
154
- w as SelectContent,
155
- N as SelectItem,
156
- h as SelectTrigger,
157
- y as SelectValue,
158
- A as selectPropsMeta
242
+ _ as Select,
243
+ z as SelectContent,
244
+ M as SelectItem,
245
+ U as SelectTrigger,
246
+ $ as SelectValue,
247
+ ne as selectPropsMeta
159
248
  };
@@ -0,0 +1,20 @@
1
+ import { PropsMeta } from './props-meta';
2
+ import * as React from "react";
3
+ /**
4
+ * Skeleton: a placeholder shimmer for loading layouts. Purely decorative
5
+ * (aria-hidden); pair with a live region or <Spinner> for the accessible
6
+ * loading announcement.
7
+ */
8
+ export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement>, SurfacePropsLike {
9
+ /** Shape preset. */
10
+ variant?: "text" | "rect" | "circle";
11
+ /** Text variant line height in rem units (e.g. 1 for a text line). */
12
+ lines?: number;
13
+ }
14
+ interface SurfacePropsLike {
15
+ /** Any CSS background value overriding the shimmer base. */
16
+ bg?: string;
17
+ }
18
+ export declare const Skeleton: React.ForwardRefExoticComponent<SkeletonProps & React.RefAttributes<HTMLDivElement>>;
19
+ export declare const skeletonPropsMeta: PropsMeta;
20
+ export {};
@@ -0,0 +1,41 @@
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import * as c from "react";
3
+ import { cn as o } from "./cn.js";
4
+ const s = {
5
+ text: "rounded-[var(--prui-radius-1)] h-4",
6
+ rect: "rounded-[var(--prui-radius)]",
7
+ circle: "rounded-[var(--prui-radius-full)] aspect-square"
8
+ }, p = c.forwardRef(
9
+ ({ className: a, variant: n = "text", lines: e = 1, bg: i, style: l, ...u }, d) => n === "text" && e > 1 ? /* @__PURE__ */ t("div", { className: o("prui-skeleton-group flex flex-col gap-2", a), role: "presentation", children: Array.from({ length: e }).map((m, r) => /* @__PURE__ */ t(
10
+ "div",
11
+ {
12
+ ref: r === 0 ? d : void 0,
13
+ "aria-hidden": !0,
14
+ className: o("prui-skeleton prui-anim-fade", s.text, r === e - 1 && "w-2/3"),
15
+ style: { backgroundColor: i ?? void 0, ...l }
16
+ },
17
+ r
18
+ )) }) : /* @__PURE__ */ t(
19
+ "div",
20
+ {
21
+ ref: d,
22
+ "aria-hidden": !0,
23
+ className: o("prui-skeleton prui-anim-fade", s[n], a),
24
+ style: { backgroundColor: i ?? void 0, ...l },
25
+ ...u
26
+ }
27
+ )
28
+ );
29
+ p.displayName = "Skeleton";
30
+ const k = {
31
+ name: "Skeleton",
32
+ props: [
33
+ { name: "variant", type: "'text' | 'rect' | 'circle'", default: "'text'", control: "select", options: ["text", "rect", "circle"] },
34
+ { name: "lines", type: "number (text variant)", default: "1", control: "number" },
35
+ { name: "bg", type: "string (CSS background)", default: "shimmer token", control: "text" }
36
+ ]
37
+ };
38
+ export {
39
+ p as Skeleton,
40
+ k as skeletonPropsMeta
41
+ };
@@ -0,0 +1,15 @@
1
+ import { PropsMeta } from './props-meta';
2
+ import * as React from "react";
3
+ /**
4
+ * Spinner: an inline loading indicator with an accessible label. Announces
5
+ * through role="status" so screen readers hear loading state without
6
+ * stealing focus.
7
+ */
8
+ export type SpinnerSize = "xs" | "sm" | "md" | "lg";
9
+ export interface SpinnerProps extends React.HTMLAttributes<HTMLSpanElement> {
10
+ /** Accessible label announced to screen readers. */
11
+ label?: string;
12
+ size?: SpinnerSize;
13
+ }
14
+ export declare const Spinner: React.ForwardRefExoticComponent<SpinnerProps & React.RefAttributes<HTMLSpanElement>>;
15
+ export declare const spinnerPropsMeta: PropsMeta;
@@ -0,0 +1,41 @@
1
+ import { jsxs as m, jsx as s } from "react/jsx-runtime";
2
+ import * as p from "react";
3
+ import { Loader2 as l } from "lucide-react";
4
+ import { cn as n } from "./cn.js";
5
+ import { usePruiI18n as c } from "../i18n.js";
6
+ const d = {
7
+ xs: "h-3 w-3",
8
+ sm: "h-4 w-4",
9
+ md: "h-6 w-6",
10
+ lg: "h-8 w-8"
11
+ }, f = p.forwardRef(
12
+ ({ className: r, label: e, size: i = "md", ...t }, a) => {
13
+ const { t: o } = c();
14
+ return /* @__PURE__ */ m(
15
+ "span",
16
+ {
17
+ ref: a,
18
+ role: "status",
19
+ "aria-label": e ?? o.loading,
20
+ className: n("prui-spinner inline-flex items-center justify-center text-[var(--prui-dim)]", r),
21
+ ...t,
22
+ children: [
23
+ /* @__PURE__ */ s(l, { className: n("animate-spin", d[i]), "aria-hidden": !0 }),
24
+ e ? /* @__PURE__ */ s("span", { className: "sr-only", children: e }) : null
25
+ ]
26
+ }
27
+ );
28
+ }
29
+ );
30
+ f.displayName = "Spinner";
31
+ const w = {
32
+ name: "Spinner",
33
+ props: [
34
+ { name: "label", type: "string", default: "'Loading...'", control: "text", description: "Accessible label." },
35
+ { name: "size", type: "'xs' | 'sm' | 'md' | 'lg'", default: "'md'", control: "select", options: ["xs", "sm", "md", "lg"] }
36
+ ]
37
+ };
38
+ export {
39
+ f as Spinner,
40
+ w as spinnerPropsMeta
41
+ };
package/dist/core/tabs.js CHANGED
@@ -1,82 +1,111 @@
1
- import { jsx as l } from "react/jsx-runtime";
2
- import * as r from "react";
3
- import { cn as c } from "./cn.js";
4
- const f = r.createContext(null);
5
- function m() {
6
- const t = r.useContext(f);
7
- if (!t) throw new Error("Tabs parts must be used inside <Tabs>");
8
- return t;
1
+ import { jsx as f } from "react/jsx-runtime";
2
+ import * as l from "react";
3
+ import { cn as m } from "./cn.js";
4
+ const y = l.createContext(null);
5
+ function g() {
6
+ const n = l.useContext(y);
7
+ if (!n) throw new Error("Tabs parts must be used inside <Tabs>");
8
+ return n;
9
9
  }
10
- const x = ({ value: t, defaultValue: e, onChange: a, className: i, children: o, ...s }) => {
11
- const [b, u] = r.useState(e ?? ""), n = t !== void 0 ? t : b, d = r.useId(), v = (p) => {
12
- t === void 0 && u(p), a == null || a(p);
10
+ const x = ({ value: n, defaultValue: a, onChange: s, className: i, children: o, ...u }) => {
11
+ const [b, t] = l.useState(a ?? ""), e = n !== void 0 ? n : b, c = l.useId(), p = (d) => {
12
+ n === void 0 && t(d), s == null || s(d);
13
13
  };
14
- return /* @__PURE__ */ l(f.Provider, { value: { value: n, setValue: v, baseId: d }, children: /* @__PURE__ */ l("div", { className: c("prui-tabs", i), ...s, children: o }) });
14
+ return /* @__PURE__ */ f(y.Provider, { value: { value: e, setValue: p, baseId: c }, children: /* @__PURE__ */ f("div", { className: m("prui-tabs", i), ...u, children: o }) });
15
15
  };
16
16
  x.displayName = "Tabs";
17
- const g = r.forwardRef(
18
- ({ className: t, ...e }, a) => /* @__PURE__ */ l(
19
- "div",
20
- {
21
- ref: a,
22
- role: "tablist",
23
- className: c(
24
- "prui-tabs-list inline-flex h-9 items-center gap-1 rounded-[var(--prui-radius)] bg-[var(--prui-raise)] p-1",
25
- t
26
- ),
27
- ...e
28
- }
29
- )
17
+ const T = l.forwardRef(
18
+ ({ className: n, onKeyDown: a, ...s }, i) => {
19
+ const o = l.useRef(null), u = () => {
20
+ const t = o.current;
21
+ return t ? Array.from(t.querySelectorAll("[role='tab']")) : [];
22
+ };
23
+ return /* @__PURE__ */ f(
24
+ "div",
25
+ {
26
+ ref: (t) => {
27
+ o.current = t, typeof i == "function" ? i(t) : i && (i.current = t);
28
+ },
29
+ role: "tablist",
30
+ "aria-orientation": "horizontal",
31
+ onKeyDown: (t) => {
32
+ var d, v;
33
+ if (a == null || a(t), t.defaultPrevented) return;
34
+ const e = u(), c = e.findIndex((r) => r.tabIndex === 0), p = t.key === "ArrowRight" || t.key === "ArrowDown" ? 1 : t.key === "ArrowLeft" || t.key === "ArrowUp" ? -1 : 0;
35
+ if (p !== 0) {
36
+ t.preventDefault();
37
+ const r = e[(c + p + e.length) % e.length];
38
+ r == null || r.focus(), r == null || r.click();
39
+ return;
40
+ }
41
+ if (t.key === "Home") {
42
+ t.preventDefault(), (d = e[0]) == null || d.focus(), (v = e[0]) == null || v.click();
43
+ return;
44
+ }
45
+ if (t.key === "End") {
46
+ t.preventDefault();
47
+ const r = e[e.length - 1];
48
+ r == null || r.focus(), r == null || r.click();
49
+ }
50
+ },
51
+ className: m(
52
+ "prui-tabs-list inline-flex h-9 items-center gap-1 rounded-[var(--prui-radius)] bg-[var(--prui-raise)] p-1",
53
+ n
54
+ ),
55
+ ...s
56
+ }
57
+ );
58
+ }
30
59
  );
31
- g.displayName = "TabsList";
32
- const T = r.forwardRef(
33
- ({ className: t, value: e, onClick: a, ...i }, o) => {
34
- const { value: s, setValue: b, baseId: u } = m(), n = s === e;
35
- return /* @__PURE__ */ l(
60
+ T.displayName = "TabsList";
61
+ const w = l.forwardRef(
62
+ ({ className: n, value: a, onClick: s, ...i }, o) => {
63
+ const { value: u, setValue: b, baseId: t } = g(), e = u === a;
64
+ return /* @__PURE__ */ f(
36
65
  "button",
37
66
  {
38
67
  ref: o,
39
68
  type: "button",
40
69
  role: "tab",
41
- id: `${u}-tab-${e}`,
42
- "aria-selected": n,
43
- "aria-controls": `${u}-panel-${e}`,
44
- "data-state": n ? "active" : "inactive",
45
- tabIndex: n ? 0 : -1,
46
- className: c(
70
+ id: `${t}-tab-${a}`,
71
+ "aria-selected": e,
72
+ "aria-controls": e ? `${t}-panel-${a}` : void 0,
73
+ "data-state": e ? "active" : "inactive",
74
+ tabIndex: e ? 0 : -1,
75
+ className: m(
47
76
  "prui-tabs-trigger inline-flex items-center justify-center whitespace-nowrap rounded-[calc(var(--prui-radius)-1px)]",
48
77
  "px-3 py-1 text-sm font-medium transition-colors cursor-pointer outline-none",
49
78
  "focus-visible:ring-2 focus-visible:ring-[var(--prui-brand)]",
50
- n ? "bg-[var(--prui-background)] text-[var(--prui-fg)] shadow" : "text-[var(--prui-dim)] hover:text-[var(--prui-fg)]",
51
- t
79
+ e ? "bg-[var(--prui-background)] text-[var(--prui-fg)] shadow" : "text-[var(--prui-dim)] hover:text-[var(--prui-fg)]",
80
+ n
52
81
  ),
53
- onClick: (d) => {
54
- a == null || a(d), d.defaultPrevented || b(e);
82
+ onClick: (c) => {
83
+ s == null || s(c), c.defaultPrevented || b(a);
55
84
  },
56
85
  ...i
57
86
  }
58
87
  );
59
88
  }
60
89
  );
61
- T.displayName = "TabsTrigger";
62
- const y = r.forwardRef(
63
- ({ className: t, value: e, ...a }, i) => {
64
- const { value: o, baseId: s } = m();
65
- return o !== e ? null : /* @__PURE__ */ l(
90
+ w.displayName = "TabsTrigger";
91
+ const h = l.forwardRef(
92
+ ({ className: n, value: a, ...s }, i) => {
93
+ const { value: o, baseId: u } = g();
94
+ return o !== a ? null : /* @__PURE__ */ f(
66
95
  "div",
67
96
  {
68
97
  ref: i,
69
98
  role: "tabpanel",
70
- id: `${s}-panel-${e}`,
71
- "aria-labelledby": `${s}-tab-${e}`,
99
+ id: `${u}-panel-${a}`,
100
+ "aria-labelledby": `${u}-tab-${a}`,
72
101
  tabIndex: 0,
73
- className: c("prui-tabs-content mt-2 outline-none", t),
74
- ...a
102
+ className: m("prui-tabs-content mt-2 outline-none", n),
103
+ ...s
75
104
  }
76
105
  );
77
106
  }
78
107
  );
79
- y.displayName = "TabsContent";
108
+ h.displayName = "TabsContent";
80
109
  const $ = {
81
110
  name: "Tabs",
82
111
  props: [
@@ -87,8 +116,8 @@ const $ = {
87
116
  };
88
117
  export {
89
118
  x as Tabs,
90
- y as TabsContent,
91
- g as TabsList,
92
- T as TabsTrigger,
119
+ h as TabsContent,
120
+ T as TabsList,
121
+ w as TabsTrigger,
93
122
  $ as tabsPropsMeta
94
123
  };