@skiddph/prui 0.7.0 → 0.8.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 (77) 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 +183 -0
  23. package/dist/core/date-picker.d.ts +41 -0
  24. package/dist/core/date-picker.js +202 -0
  25. package/dist/core/dialog.d.ts +8 -0
  26. package/dist/core/dialog.js +59 -61
  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 +21 -0
  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 +178 -97
  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/timeline.d.ts +22 -0
  54. package/dist/core/timeline.js +57 -0
  55. package/dist/core/toast.d.ts +36 -0
  56. package/dist/core/toast.js +123 -0
  57. package/dist/core/tooltip.d.ts +23 -0
  58. package/dist/core/tooltip.js +96 -0
  59. package/dist/core/tree-view.d.ts +34 -0
  60. package/dist/core/tree-view.js +133 -0
  61. package/dist/core.js +152 -62
  62. package/dist/data-table/data-table.d.ts +22 -1
  63. package/dist/data-table.js +1 -1
  64. package/dist/forms/form.d.ts +8 -0
  65. package/dist/forms.js +213 -200
  66. package/dist/i18n/index.d.ts +83 -0
  67. package/dist/i18n.js +99 -0
  68. package/dist/index.d.ts +1 -0
  69. package/dist/index.js +256 -156
  70. package/dist/prui-utilities.css +1 -1
  71. package/dist/prui.css +111 -4
  72. package/dist/theme/base.css +110 -3
  73. package/dist/theme/index.d.ts +27 -0
  74. package/dist/theme.js +86 -58
  75. package/package.json +9 -2
  76. package/dist/chunks/auth-shell-BG5vx9eG.js +0 -1054
  77. package/dist/chunks/data-table-toolbar-BUy2EWPy.js +0 -581
@@ -0,0 +1,202 @@
1
+ import { jsxs as x, Fragment as $, jsx as a } from "react/jsx-runtime";
2
+ import * as s from "react";
3
+ import { CalendarDays as z } from "lucide-react";
4
+ import { cn as j } from "./cn.js";
5
+ import { useOverlayStack as E, useEscapeKey as F, Portal as T } from "./overlay.js";
6
+ import { useAnchoredPosition as H } from "./anchor.js";
7
+ import { Calendar as U } from "./calendar.js";
8
+ import { usePruiI18n as I } from "../i18n.js";
9
+ const K = s.forwardRef(function({ value: v, defaultValue: D, onChange: t, min: h, max: M, placeholder: R = "YYYY-MM-DD", disabled: b, className: k, ariaLabel: w }, l) {
10
+ const [g, N] = s.useState(D ?? ""), m = v !== void 0, f = m ? v : g, [r, o] = s.useState(!1), i = s.useRef(null), [u, y] = s.useState(""), { setElement: P, isTop: S } = E(r);
11
+ F(r, S, () => {
12
+ var e;
13
+ o(!1), (e = i.current) == null || e.focus();
14
+ });
15
+ const { ref: d, position: c } = H({ active: r, anchorRef: i, side: "bottom", align: "start", offsetHeight: 360 }), Y = (e) => {
16
+ var n;
17
+ m || N(e), t == null || t(e), o(!1), (n = i.current) == null || n.focus();
18
+ };
19
+ return /* @__PURE__ */ x($, { children: [
20
+ /* @__PURE__ */ a(
21
+ "input",
22
+ {
23
+ ref: (e) => {
24
+ i.current = e, typeof l == "function" ? l(e) : l && (l.current = e);
25
+ },
26
+ type: "text",
27
+ readOnly: !0,
28
+ role: "combobox",
29
+ "aria-expanded": r,
30
+ "aria-haspopup": "dialog",
31
+ "aria-label": w,
32
+ placeholder: R,
33
+ disabled: b,
34
+ value: u !== "" ? u : f,
35
+ onFocus: () => {
36
+ !b && !r && o(!0);
37
+ },
38
+ onClick: () => o(!0),
39
+ onChange: (e) => {
40
+ const n = e.target.value;
41
+ y(n), /^\d{4}-\d{2}-\d{2}$/.test(n) && (y(""), Y(n));
42
+ },
43
+ className: j(
44
+ "prui-date-picker flex h-9 w-full cursor-pointer items-center gap-2 border border-[var(--prui-line)]",
45
+ "bg-[var(--prui-background)] rounded-[var(--prui-radius)] px-3 text-sm text-[var(--prui-fg)] placeholder:text-[var(--prui-dim)]",
46
+ "outline-none transition-colors focus:border-[var(--prui-brand)] focus:ring-2 focus:ring-[var(--prui-brand)]/30",
47
+ "disabled:opacity-50 disabled:cursor-not-allowed",
48
+ k
49
+ )
50
+ }
51
+ ),
52
+ /* @__PURE__ */ a(z, { className: "pointer-events-none -ml-7 h-4 w-4 text-[var(--prui-dim)]", "aria-hidden": !0 }),
53
+ r ? /* @__PURE__ */ a(T, { children: /* @__PURE__ */ a(
54
+ "div",
55
+ {
56
+ ref: (e) => {
57
+ d(e), P(e);
58
+ },
59
+ role: "dialog",
60
+ "aria-label": "Choose date",
61
+ className: "fixed z-[var(--prui-z-overlay)]",
62
+ style: { top: (c == null ? void 0 : c.top) ?? -9999, left: (c == null ? void 0 : c.left) ?? -9999 },
63
+ children: /* @__PURE__ */ a(U, { value: f, onSelect: Y, min: h, max: M, className: "shadow-[var(--prui-shadow-lg)]" })
64
+ }
65
+ ) }) : null
66
+ ] });
67
+ });
68
+ K.displayName = "DatePicker";
69
+ const q = s.forwardRef(function({ value: v, defaultValue: D, onChange: t, min: h, max: M, placeholder: R = "YYYY-MM-DD – YYYY-MM-DD", disabled: b, className: k, ariaLabel: w }, l) {
70
+ const { t: g } = I(), [N, m] = s.useState(D ?? {}), f = v !== void 0, r = f ? v : N, [o, i] = s.useState(!1), u = s.useRef(null), { setElement: y, isTop: P } = E(o);
71
+ F(o, P, () => {
72
+ var e;
73
+ i(!1), (e = u.current) == null || e.focus();
74
+ });
75
+ const { ref: S, position: d } = H({ active: o, anchorRef: u, side: "bottom", align: "start", offsetHeight: 360 }), c = (e) => {
76
+ var O;
77
+ const { from: n, to: A } = r;
78
+ let p;
79
+ if (!n || n && A)
80
+ p = { from: e };
81
+ else if (e < n)
82
+ p = { from: e };
83
+ else {
84
+ p = { from: n, to: e }, t == null || t(p), f || m(p), i(!1), (O = u.current) == null || O.focus();
85
+ return;
86
+ }
87
+ f || m(p), t == null || t(p);
88
+ }, Y = r.from ? r.to ? `${r.from} – ${r.to}` : `${r.from} – …` : "";
89
+ return /* @__PURE__ */ x($, { children: [
90
+ /* @__PURE__ */ a(
91
+ "input",
92
+ {
93
+ ref: (e) => {
94
+ u.current = e, typeof l == "function" ? l(e) : l && (l.current = e);
95
+ },
96
+ type: "text",
97
+ readOnly: !0,
98
+ role: "combobox",
99
+ "aria-expanded": o,
100
+ "aria-haspopup": "dialog",
101
+ "aria-label": w,
102
+ placeholder: R,
103
+ disabled: b,
104
+ value: Y,
105
+ onClick: () => i(!0),
106
+ onFocus: () => {
107
+ !b && !o && i(!0);
108
+ },
109
+ className: j(
110
+ "prui-date-range-picker flex h-9 w-full cursor-pointer items-center border border-[var(--prui-line)]",
111
+ "bg-[var(--prui-background)] rounded-[var(--prui-radius)] px-3 text-sm text-[var(--prui-fg)] placeholder:text-[var(--prui-dim)]",
112
+ "outline-none transition-colors focus:border-[var(--prui-brand)] focus:ring-2 focus:ring-[var(--prui-brand)]/30",
113
+ "disabled:opacity-50 disabled:cursor-not-allowed",
114
+ k
115
+ )
116
+ }
117
+ ),
118
+ /* @__PURE__ */ a(z, { className: "pointer-events-none -ml-7 h-4 w-4 text-[var(--prui-dim)]", "aria-hidden": !0 }),
119
+ o ? /* @__PURE__ */ a(T, { children: /* @__PURE__ */ a(
120
+ "div",
121
+ {
122
+ ref: (e) => {
123
+ S(e), y(e);
124
+ },
125
+ role: "dialog",
126
+ "aria-label": "Choose date range",
127
+ className: "fixed z-[var(--prui-z-overlay)]",
128
+ style: { top: (d == null ? void 0 : d.top) ?? -9999, left: (d == null ? void 0 : d.left) ?? -9999 },
129
+ children: /* @__PURE__ */ x("div", { className: "shadow-[var(--prui-shadow-lg)]", children: [
130
+ /* @__PURE__ */ a(
131
+ U,
132
+ {
133
+ value: r.to ?? r.from,
134
+ month: r.from ? `${r.from.slice(0, 7)}` : void 0,
135
+ onSelect: c,
136
+ min: h,
137
+ max: M,
138
+ showToday: !1,
139
+ className: "border-0 shadow-none",
140
+ "data-range-from": r.from ?? "",
141
+ "data-range-to": r.to ?? ""
142
+ }
143
+ ),
144
+ /* @__PURE__ */ x("div", { className: "flex items-center justify-between gap-2 border-t border-[var(--prui-line)] px-3 py-2 text-xs text-[var(--prui-dim)]", children: [
145
+ /* @__PURE__ */ a("span", { "data-testid": "range-label", children: Y || g.today }),
146
+ /* @__PURE__ */ x("div", { className: "flex gap-2", children: [
147
+ /* @__PURE__ */ a(
148
+ "button",
149
+ {
150
+ type: "button",
151
+ onClick: () => {
152
+ f || m({}), t == null || t({});
153
+ },
154
+ className: "cursor-pointer rounded-[var(--prui-radius-1)] px-2 py-1 transition-colors hover:bg-[var(--prui-raise)]",
155
+ children: g.clear
156
+ }
157
+ ),
158
+ /* @__PURE__ */ a(
159
+ "button",
160
+ {
161
+ type: "button",
162
+ onClick: () => {
163
+ var e;
164
+ i(!1), (e = u.current) == null || e.focus();
165
+ },
166
+ className: "cursor-pointer rounded-[var(--prui-radius-1)] bg-[var(--prui-brand)]/15 px-2 py-1 text-[var(--prui-brand)] transition-colors hover:bg-[var(--prui-brand)]/25",
167
+ children: g.apply
168
+ }
169
+ )
170
+ ] })
171
+ ] })
172
+ ] })
173
+ }
174
+ ) }) : null
175
+ ] });
176
+ });
177
+ q.displayName = "DateRangePicker";
178
+ const Z = {
179
+ name: "DatePicker",
180
+ props: [
181
+ { name: "value", type: "string 'YYYY-MM-DD'", default: "undefined", control: "date" },
182
+ { name: "defaultValue", type: "string 'YYYY-MM-DD'", default: "undefined", control: "date" },
183
+ { name: "onChange", type: "(date: string) => void", default: null, control: "none" },
184
+ { name: "min", type: "string 'YYYY-MM-DD'", default: "undefined", control: "date" },
185
+ { name: "max", type: "string 'YYYY-MM-DD'", default: "undefined", control: "date" }
186
+ ]
187
+ }, _ = {
188
+ name: "DateRangePicker",
189
+ props: [
190
+ { name: "value", type: "{ from?: string, to?: string }", default: "{}", control: "daterange" },
191
+ { name: "defaultValue", type: "{ from?: string, to?: string }", default: "{}", control: "daterange" },
192
+ { name: "onChange", type: "(range: DateRange) => void", default: null, control: "none" },
193
+ { name: "min", type: "string 'YYYY-MM-DD'", default: "undefined", control: "date" },
194
+ { name: "max", type: "string 'YYYY-MM-DD'", default: "undefined", control: "date" }
195
+ ]
196
+ };
197
+ export {
198
+ K as DatePicker,
199
+ q as DateRangePicker,
200
+ Z as datePickerPropsMeta,
201
+ _ as dateRangePickerPropsMeta
202
+ };
@@ -1,5 +1,11 @@
1
1
  import { PropsMeta } from './props-meta';
2
2
  import * as React from "react";
3
+ /**
4
+ * Dialog: the compound, declarative modal surface (<Dialog> + <DialogContent/
5
+ * Header/Title/Description/Footer>). Built on the shared overlay
6
+ * infrastructure: portaled, focus-trapped with focus restoration, topmost
7
+ * Escape, scroll-locked, background aria-hidden/inert while open.
8
+ */
3
9
  export interface DialogProps {
4
10
  open?: boolean;
5
11
  defaultOpen?: boolean;
@@ -16,6 +22,8 @@ export interface DialogContentProps extends React.HTMLAttributes<HTMLDivElement>
16
22
  /** Accessibility label when no DialogTitle is rendered. */
17
23
  ariaLabel?: string;
18
24
  hideClose?: boolean;
25
+ /** Initial focus target: first focusable (default), the dialog itself, a specific element, or none. */
26
+ initialFocus?: React.RefObject<HTMLElement | null> | "first" | "container" | false;
19
27
  }
20
28
  export declare const DialogContent: React.ForwardRefExoticComponent<DialogContentProps & React.RefAttributes<HTMLDivElement>>;
21
29
  export declare const DialogHeader: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
@@ -1,102 +1,100 @@
1
- import { jsx as a, jsxs as y } from "react/jsx-runtime";
2
- import * as l from "react";
3
- import { X as x } from "lucide-react";
4
- import { cn as d } from "./cn.js";
5
- const m = l.createContext(null);
6
- function v() {
7
- const e = l.useContext(m);
1
+ import { jsx as t, jsxs as y } from "react/jsx-runtime";
2
+ import * as a from "react";
3
+ import { X as D } from "lucide-react";
4
+ import { cn as n } from "./cn.js";
5
+ import { useOverlay as h, Portal as w } from "./overlay.js";
6
+ import { usePruiI18n as N } from "../i18n.js";
7
+ const v = a.createContext(null);
8
+ function g() {
9
+ const e = a.useContext(v);
8
10
  if (!e) throw new Error("Dialog parts must be used inside <Dialog>");
9
11
  return e;
10
12
  }
11
- const w = ({ open: e, defaultOpen: o = !1, onOpenChange: t, children: n }) => {
12
- const [c, p] = l.useState(o), u = e !== void 0, s = u ? e : c, i = l.useId(), f = (r) => {
13
- u || p(r), t == null || t(r);
13
+ const I = ({ open: e, defaultOpen: o = !1, onOpenChange: r, children: i }) => {
14
+ const [c, p] = a.useState(o), s = e !== void 0, f = s ? e : c, d = a.useId(), l = (u) => {
15
+ s || p(u), r == null || r(u);
14
16
  };
15
- return /* @__PURE__ */ a(m.Provider, { value: { open: s, setOpen: f, labelId: i }, children: n });
17
+ return /* @__PURE__ */ t(v.Provider, { value: { open: f, setOpen: l, labelId: d }, children: i });
16
18
  };
17
- w.displayName = "Dialog";
18
- const D = l.forwardRef(
19
- ({ className: e, children: o, ariaLabel: t, hideClose: n, onClick: c, ...p }, u) => {
20
- const { open: s, setOpen: i, labelId: f } = v();
21
- return l.useEffect(() => {
22
- if (!s) return;
23
- const r = (b) => {
24
- b.key === "Escape" && i(!1);
25
- };
26
- document.addEventListener("keydown", r);
27
- const g = document.body.style.overflow;
28
- return document.body.style.overflow = "hidden", () => {
29
- document.removeEventListener("keydown", r), document.body.style.overflow = g;
30
- };
31
- }, [s, i]), s ? /* @__PURE__ */ a(
19
+ I.displayName = "Dialog";
20
+ const C = a.forwardRef(
21
+ ({ className: e, children: o, ariaLabel: r, hideClose: i, initialFocus: c = "first", onClick: p, ...s }, f) => {
22
+ const { open: d, setOpen: l, labelId: u } = g(), { t: b } = N(), { ref: x } = h({
23
+ open: d,
24
+ onEscape: () => l(!1),
25
+ initialFocus: c
26
+ });
27
+ return d ? /* @__PURE__ */ t(w, { children: /* @__PURE__ */ t("div", { ref: x, children: /* @__PURE__ */ t(
32
28
  "div",
33
29
  {
34
- className: "prui-dialog-overlay fixed inset-0 z-50 flex items-center justify-center p-4",
35
- style: { backgroundColor: "rgba(0,0,0,0.55)" },
36
- onMouseDown: (r) => {
37
- r.target === r.currentTarget && i(!1);
30
+ className: "prui-dialog-overlay fixed inset-0 z-[var(--prui-z-overlay)] flex items-center justify-center p-4",
31
+ style: { backgroundColor: "var(--prui-scrim)" },
32
+ onMouseDown: (m) => {
33
+ m.target === m.currentTarget && l(!1);
38
34
  },
39
35
  children: /* @__PURE__ */ y(
40
36
  "div",
41
37
  {
42
- ref: u,
38
+ ref: f,
43
39
  role: "dialog",
44
40
  "aria-modal": "true",
45
- "aria-label": t,
46
- "aria-labelledby": t ? void 0 : f,
47
- className: d(
48
- "prui-dialog-content relative z-10 w-full max-w-lg rounded-[var(--prui-radius)]",
49
- "border border-[var(--prui-line)] bg-[var(--prui-surface)] shadow-xl",
41
+ "aria-label": r,
42
+ "aria-labelledby": r ? void 0 : u,
43
+ tabIndex: -1,
44
+ className: n(
45
+ "prui-dialog-content relative z-[var(--prui-z-content)] w-full max-w-lg rounded-[var(--prui-radius)]",
46
+ "border border-[var(--prui-line)] bg-[var(--prui-surface)] shadow-[var(--prui-shadow-lg)]",
50
47
  "max-h-[85vh] overflow-auto outline-none",
51
48
  e
52
49
  ),
53
- onClick: c,
54
- ...p,
50
+ onClick: p,
51
+ ...s,
55
52
  children: [
56
53
  o,
57
- n ? null : /* @__PURE__ */ a(
54
+ i ? null : /* @__PURE__ */ t(
58
55
  "button",
59
56
  {
60
57
  type: "button",
61
- "aria-label": "Close",
62
- onClick: () => i(!1),
58
+ "aria-label": b.close,
59
+ onClick: () => l(!1),
63
60
  className: "absolute right-3 top-3 rounded-[var(--prui-radius-1)] p-1 text-[var(--prui-dim)] hover:text-[var(--prui-fg)] hover:bg-[var(--prui-raise)] cursor-pointer",
64
- children: /* @__PURE__ */ a(x, { className: "h-4 w-4", "aria-hidden": !0 })
61
+ children: /* @__PURE__ */ t(D, { className: "h-4 w-4", "aria-hidden": !0 })
65
62
  }
66
63
  )
67
64
  ]
68
65
  }
69
66
  )
70
67
  }
71
- ) : null;
68
+ ) }) }) : null;
72
69
  }
73
70
  );
74
- D.displayName = "DialogContent";
75
- const j = ({ className: e, ...o }) => /* @__PURE__ */ a("div", { className: d("prui-dialog-header flex flex-col gap-1 p-4 pb-2", e), ...o }), h = l.forwardRef(
76
- ({ className: e, ...o }, t) => {
77
- const { labelId: n } = v();
78
- return /* @__PURE__ */ a("h2", { ref: t, id: n, className: d("prui-dialog-title text-base font-semibold text-[var(--prui-fg)]", e), ...o });
71
+ C.displayName = "DialogContent";
72
+ const F = ({ className: e, ...o }) => /* @__PURE__ */ t("div", { className: n("prui-dialog-header flex flex-col gap-1 p-4 pb-2", e), ...o }), R = a.forwardRef(
73
+ ({ className: e, ...o }, r) => {
74
+ const { labelId: i } = g();
75
+ return /* @__PURE__ */ t("h2", { ref: r, id: i, className: n("prui-dialog-title text-base font-semibold text-[var(--prui-fg)]", e), ...o });
79
76
  }
80
77
  );
81
- h.displayName = "DialogTitle";
82
- const N = l.forwardRef(
83
- ({ className: e, ...o }, t) => /* @__PURE__ */ a("p", { ref: t, className: d("prui-dialog-description text-sm text-[var(--prui-dim)]", e), ...o })
78
+ R.displayName = "DialogTitle";
79
+ const j = a.forwardRef(
80
+ ({ className: e, ...o }, r) => /* @__PURE__ */ t("p", { ref: r, className: n("prui-dialog-description text-sm text-[var(--prui-dim)]", e), ...o })
84
81
  );
85
- N.displayName = "DialogDescription";
86
- const I = ({ className: e, ...o }) => /* @__PURE__ */ a("div", { className: d("prui-dialog-footer flex items-center justify-end gap-2 p-4 pt-2", e), ...o }), R = {
82
+ j.displayName = "DialogDescription";
83
+ const M = ({ className: e, ...o }) => /* @__PURE__ */ t("div", { className: n("prui-dialog-footer flex items-center justify-end gap-2 p-4 pt-2", e), ...o }), H = {
87
84
  name: "Dialog",
88
85
  props: [
89
86
  { name: "open", type: "boolean", default: "undefined", control: "boolean" },
90
87
  { name: "defaultOpen", type: "boolean", default: "false", control: "boolean" },
91
- { name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" }
88
+ { name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" },
89
+ { name: "initialFocus", type: 'ref | "first" | "container" | false', default: '"first"', control: "none" }
92
90
  ]
93
91
  };
94
92
  export {
95
- w as Dialog,
96
- D as DialogContent,
97
- N as DialogDescription,
98
- I as DialogFooter,
99
- j as DialogHeader,
100
- h as DialogTitle,
101
- R as dialogPropsMeta
93
+ I as Dialog,
94
+ C as DialogContent,
95
+ j as DialogDescription,
96
+ M as DialogFooter,
97
+ F as DialogHeader,
98
+ R as DialogTitle,
99
+ H as dialogPropsMeta
102
100
  };
@@ -0,0 +1,34 @@
1
+ import { PropsMeta } from './props-meta';
2
+ import * as React from "react";
3
+ /**
4
+ * Drawer: a side-anchored modal panel (left/right/top/bottom) built on the
5
+ * shared overlay infrastructure: portaled, focus-trapped, scroll-locked,
6
+ * background inert, topmost Escape, focus restoration, reduced motion.
7
+ * Sheet is the same surface preset to bottom (mobile-first) with a drag
8
+ * handle. Controlled and uncontrolled open.
9
+ */
10
+ export type DrawerSide = "left" | "right" | "top" | "bottom";
11
+ export interface DrawerProps {
12
+ open?: boolean;
13
+ defaultOpen?: boolean;
14
+ onOpenChange?: (open: boolean) => void;
15
+ /** Anchor edge. Default right. */
16
+ side?: DrawerSide;
17
+ /** Panel width for left/right (any CSS length). Default 400px. */
18
+ size?: number | string;
19
+ children?: React.ReactNode;
20
+ /** Accessible label. */
21
+ ariaLabel?: string;
22
+ /** Hide the close button. */
23
+ hideClose?: boolean;
24
+ className?: string;
25
+ style?: React.CSSProperties;
26
+ }
27
+ export declare const Drawer: React.ForwardRefExoticComponent<DrawerProps & React.RefAttributes<HTMLDivElement>>;
28
+ /**
29
+ * Sheet: the bottom-anchored Drawer preset (mobile-first detail surface).
30
+ * Same overlay guarantees; size sets max height.
31
+ */
32
+ export declare const Sheet: React.ForwardRefExoticComponent<Omit<DrawerProps, "side"> & React.RefAttributes<HTMLDivElement>>;
33
+ export declare const drawerPropsMeta: PropsMeta;
34
+ export declare const sheetPropsMeta: PropsMeta;
@@ -0,0 +1,129 @@
1
+ import { jsx as t, jsxs as Y } from "react/jsx-runtime";
2
+ import * as a from "react";
3
+ import { X as k } from "lucide-react";
4
+ import { cn as P } from "./cn.js";
5
+ import { useReducedMotion as j, useOverlay as A, Portal as E } from "./overlay.js";
6
+ import { usePruiI18n as F } from "../i18n.js";
7
+ const L = {
8
+ left: "left-0 top-0 h-full prui-drawer-panel",
9
+ right: "right-0 top-0 h-full prui-drawer-panel",
10
+ top: "left-0 top-0 w-full prui-drawer-panel",
11
+ bottom: "left-0 bottom-0 w-full prui-drawer-panel"
12
+ }, $ = {
13
+ left: "translateX(0)",
14
+ right: "translateX(0)",
15
+ top: "translateY(0)",
16
+ bottom: "translateY(0)"
17
+ }, q = {
18
+ left: "translateX(-100%)",
19
+ right: "translateX(100%)",
20
+ top: "translateY(-100%)",
21
+ bottom: "translateY(100%)"
22
+ }, h = a.forwardRef(function({ open: n, defaultOpen: i = !1, onOpenChange: s, side: r = "right", size: o, children: v, ariaLabel: w, hideClose: y, className: g, style: x }, S) {
23
+ const [N, D] = a.useState(i), m = n !== void 0, l = m ? n : N, [M, u] = a.useState(l), [p, d] = a.useState(!1), f = j(), { t: R } = F(), c = (e) => {
24
+ m || D(e), s == null || s(e);
25
+ };
26
+ a.useEffect(() => {
27
+ if (l) {
28
+ if (u(!0), f) {
29
+ d(!0);
30
+ return;
31
+ }
32
+ const C = requestAnimationFrame(() => d(!0));
33
+ return () => cancelAnimationFrame(C);
34
+ }
35
+ if (d(!1), f) {
36
+ u(!1);
37
+ return;
38
+ }
39
+ const e = setTimeout(() => u(!1), 300);
40
+ return () => clearTimeout(e);
41
+ }, [l, f]);
42
+ const { ref: T } = A({
43
+ open: l,
44
+ onEscape: () => c(!1)
45
+ });
46
+ if (!M) return null;
47
+ const X = {
48
+ transform: p ? $[r] : q[r],
49
+ transition: "transform var(--prui-duration-slow) var(--prui-ease-out)",
50
+ ...r === "left" || r === "right" ? { width: typeof o == "number" ? `${o}px` : o ?? "400px" } : { maxHeight: typeof o == "number" ? `${o}px` : o ?? "80vh" },
51
+ ...x
52
+ };
53
+ return /* @__PURE__ */ t(E, { children: /* @__PURE__ */ t("div", { ref: T, children: /* @__PURE__ */ t(
54
+ "div",
55
+ {
56
+ className: "prui-drawer-overlay fixed inset-0 z-[var(--prui-z-modal)]",
57
+ style: {
58
+ backgroundColor: "var(--prui-scrim)",
59
+ opacity: p ? 1 : 0,
60
+ transition: "opacity var(--prui-duration-slow) var(--prui-ease-out)"
61
+ },
62
+ onMouseDown: (e) => {
63
+ e.target === e.currentTarget && c(!1);
64
+ },
65
+ children: /* @__PURE__ */ Y(
66
+ "div",
67
+ {
68
+ ref: S,
69
+ role: "dialog",
70
+ "aria-modal": "true",
71
+ "aria-label": w,
72
+ "data-state": p ? "open" : "closed",
73
+ className: P(
74
+ "absolute flex flex-col overflow-y-auto border border-[var(--prui-line)] bg-[var(--prui-surface)]",
75
+ "text-[var(--prui-fg)] shadow-[var(--prui-shadow-modal)] outline-none",
76
+ L[r],
77
+ g
78
+ ),
79
+ style: X,
80
+ children: [
81
+ r === "bottom" ? /* @__PURE__ */ t("div", { "aria-hidden": !0, className: "mx-auto mt-2 mb-1 h-1 w-10 shrink-0 rounded-[var(--prui-radius-full)] bg-[var(--prui-line)]" }) : null,
82
+ v,
83
+ y ? null : /* @__PURE__ */ t(
84
+ "button",
85
+ {
86
+ type: "button",
87
+ "aria-label": R.close,
88
+ onClick: () => c(!1),
89
+ className: "absolute right-3 top-3 rounded-[var(--prui-radius-1)] p-1 text-[var(--prui-dim)] transition-colors hover:bg-[var(--prui-raise)] hover:text-[var(--prui-fg)] cursor-pointer",
90
+ children: /* @__PURE__ */ t(k, { className: "h-4 w-4", "aria-hidden": !0 })
91
+ }
92
+ )
93
+ ]
94
+ }
95
+ )
96
+ }
97
+ ) }) });
98
+ });
99
+ h.displayName = "Drawer";
100
+ const H = a.forwardRef(function(n, i) {
101
+ return /* @__PURE__ */ t(h, { ref: i, side: "bottom", ...n });
102
+ });
103
+ H.displayName = "Sheet";
104
+ const J = {
105
+ name: "Drawer",
106
+ props: [
107
+ { name: "open", type: "boolean", default: "undefined", control: "boolean" },
108
+ { name: "defaultOpen", type: "boolean", default: "false", control: "boolean" },
109
+ { name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" },
110
+ { name: "side", type: "'left' | 'right' | 'top' | 'bottom'", default: "'right'", control: "select", options: ["left", "right", "top", "bottom"] },
111
+ { name: "size", type: "number | string (CSS length)", default: "400px / 80vh", control: "text" },
112
+ { name: "ariaLabel", type: "string", default: null, control: "text" },
113
+ { name: "hideClose", type: "boolean", default: "false", control: "boolean" }
114
+ ]
115
+ }, K = {
116
+ name: "Sheet",
117
+ props: [
118
+ { name: "open", type: "boolean", default: "undefined", control: "boolean" },
119
+ { name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" },
120
+ { name: "size", type: "number | string (max height)", default: "80vh", control: "text" },
121
+ { name: "ariaLabel", type: "string", default: null, control: "text" }
122
+ ]
123
+ };
124
+ export {
125
+ h as Drawer,
126
+ H as Sheet,
127
+ J as drawerPropsMeta,
128
+ K as sheetPropsMeta
129
+ };
@@ -1,5 +1,12 @@
1
1
  import { PropsMeta } from './props-meta';
2
2
  import * as React from "react";
3
+ /**
4
+ * Dropdown: an anchored menu over a trigger. Full WAI-ARIA menu keyboard
5
+ * support: Enter/Space/ArrowDown open, ArrowUp/Down + Home/End move,
6
+ * printable-character typeahead selects, Escape (topmost overlay only)
7
+ * closes and restores focus to the trigger, Tab closes. Non-modal: no scroll
8
+ * lock and no background inertness.
9
+ */
3
10
  export interface DropdownItem {
4
11
  label: string;
5
12
  onSelect?: () => void;
@@ -17,8 +24,5 @@ export interface DropdownProps {
17
24
  align?: "start" | "end";
18
25
  className?: string;
19
26
  }
20
- export declare const Dropdown: {
21
- ({ items, trigger, children, open: openProp, defaultOpen, onOpenChange, align, className, }: DropdownProps): React.JSX.Element;
22
- displayName: string;
23
- };
27
+ export declare const Dropdown: React.ForwardRefExoticComponent<DropdownProps & React.RefAttributes<HTMLDivElement>>;
24
28
  export declare const dropdownPropsMeta: PropsMeta;