@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
@@ -1,89 +1,174 @@
1
- import { jsxs as p, jsx as a } from "react/jsx-runtime";
2
- import * as l from "react";
3
- import { cn as i } from "./cn.js";
4
- const k = ({
5
- items: f,
1
+ import { jsxs as I, jsx as p } from "react/jsx-runtime";
2
+ import * as o from "react";
3
+ import { cn as x } from "./cn.js";
4
+ import { useOverlayStack as P, useEscapeKey as _ } from "./overlay.js";
5
+ import { typeaheadIndex as $, endIndex as q, homeIndex as B, moveIndex as R } from "./list-nav.js";
6
+ const F = "[role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio']", H = o.forwardRef(function({
7
+ items: N,
6
8
  trigger: m,
7
- children: v,
8
- open: u,
9
- defaultOpen: b = !1,
10
- onOpenChange: d,
11
- align: y = "start",
12
- className: w
13
- }) => {
14
- const [x, g] = l.useState(b), c = u !== void 0, n = c ? u : x, s = l.useRef(null), o = (e) => {
15
- c || g(e), d == null || d(e);
16
- };
17
- return l.useEffect(() => {
18
- if (!n) return;
19
- const e = (r) => {
20
- s.current && !s.current.contains(r.target) && o(!1);
21
- }, t = (r) => {
22
- r.key === "Escape" && o(!1);
9
+ children: A,
10
+ open: h,
11
+ defaultOpen: K = !1,
12
+ onOpenChange: b,
13
+ align: C = "start",
14
+ className: S
15
+ }, i) {
16
+ const [j, M] = o.useState(K), D = h !== void 0, r = D ? h : j, v = o.useRef(null), c = o.useRef(null), y = o.useRef(null), [d, w] = o.useState(-1), E = o.useRef({ buffer: "", at: 0 }), s = (e) => {
17
+ var n, t;
18
+ if (D || M(e), b == null || b(e), !e) {
19
+ w(-1), E.current = { buffer: "", at: 0 };
20
+ const a = document.activeElement;
21
+ a && ((n = c.current) != null && n.contains(a)) && ((t = y.current) == null || t.focus());
22
+ }
23
+ }, { setElement: T, isTop: L } = P(r);
24
+ _(r, L, () => {
25
+ s(!1);
26
+ }), o.useEffect(() => {
27
+ if (!r) return;
28
+ const e = (n) => {
29
+ v.current && !v.current.contains(n.target) && s(!1);
23
30
  };
24
- return document.addEventListener("mousedown", e), document.addEventListener("keydown", t), () => {
25
- document.removeEventListener("mousedown", e), document.removeEventListener("keydown", t);
31
+ return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
32
+ });
33
+ const f = o.useCallback(() => {
34
+ const e = c.current;
35
+ return e ? Array.from(e.querySelectorAll(F)) : [];
36
+ }, []), u = (e) => {
37
+ var t;
38
+ w(e), (t = f()[e]) == null || t.focus();
39
+ };
40
+ o.useEffect(() => {
41
+ var t;
42
+ if (!r) return;
43
+ const e = f(), n = e.findIndex((a) => !a.disabled);
44
+ n >= 0 ? (w(n), (t = e[n]) == null || t.focus()) : c.current && c.current.focus();
45
+ }, [r, f]);
46
+ const U = (e) => {
47
+ const n = f(), t = (a) => {
48
+ var l;
49
+ return !((l = n[a]) != null && l.disabled);
26
50
  };
27
- }), /* @__PURE__ */ p("div", { ref: s, className: i("prui-dropdown relative inline-block", w), "data-state": n ? "open" : "closed", children: [
28
- /* @__PURE__ */ a(
29
- "div",
51
+ switch (e.key) {
52
+ case "ArrowDown":
53
+ e.preventDefault(), u(R(d, 1, n.length, { enabled: t }));
54
+ break;
55
+ case "ArrowUp":
56
+ e.preventDefault(), u(R(d, -1, n.length, { enabled: t }));
57
+ break;
58
+ case "Home":
59
+ e.preventDefault(), u(B(n.length, t));
60
+ break;
61
+ case "End":
62
+ e.preventDefault(), u(q(n.length, t));
63
+ break;
64
+ case "Tab":
65
+ s(!1);
66
+ break;
67
+ case "Enter":
68
+ case " ":
69
+ break;
70
+ default:
71
+ if (e.key.length === 1) {
72
+ const a = () => n.map((z) => z.textContent ?? ""), { index: l } = $(a, E.current, e.key, d);
73
+ l >= 0 && l !== d && (e.preventDefault(), u(l));
74
+ }
75
+ }
76
+ }, g = () => {
77
+ s(!0);
78
+ };
79
+ let k;
80
+ if (o.isValidElement(m)) {
81
+ const e = m;
82
+ k = o.cloneElement(e, {
83
+ ref: (n) => {
84
+ y.current = n;
85
+ const t = e.props.ref;
86
+ typeof t == "function" ? t(n) : t && typeof t == "object" && (t.current = n);
87
+ },
88
+ "aria-haspopup": "menu",
89
+ "aria-expanded": r,
90
+ onClick: (n) => {
91
+ const t = e.props.onClick;
92
+ t == null || t(n), n.defaultPrevented || s(!r);
93
+ },
94
+ onKeyDown: (n) => {
95
+ const t = e.props.onKeyDown;
96
+ t == null || t(n), !n.defaultPrevented && (n.key === "ArrowDown" || n.key === "Enter" || n.key === " ") && (r || (n.preventDefault(), g()));
97
+ }
98
+ });
99
+ } else
100
+ k = /* @__PURE__ */ p(
101
+ "button",
30
102
  {
31
- role: "button",
32
- tabIndex: 0,
103
+ type: "button",
104
+ ref: (e) => {
105
+ y.current = e;
106
+ },
33
107
  "aria-haspopup": "menu",
34
- "aria-expanded": n,
35
- onClick: () => o(!n),
108
+ "aria-expanded": r,
109
+ onClick: () => s(!r),
36
110
  onKeyDown: (e) => {
37
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), o(!n));
111
+ (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && !r && (e.preventDefault(), g());
38
112
  },
39
113
  children: m
40
114
  }
41
- ),
42
- n ? /* @__PURE__ */ a(
115
+ );
116
+ return /* @__PURE__ */ I("div", { ref: (e) => {
117
+ v.current = e, typeof i == "function" ? i(e) : i && (i.current = e);
118
+ }, className: x("prui-dropdown relative inline-block", S), "data-state": r ? "open" : "closed", children: [
119
+ k,
120
+ r ? /* @__PURE__ */ p(
43
121
  "div",
44
122
  {
123
+ ref: (e) => {
124
+ c.current = e, T((e == null ? void 0 : e.parentElement) ?? null);
125
+ },
45
126
  role: "menu",
46
- className: i(
47
- "prui-dropdown-menu absolute z-50 mt-1 min-w-40 rounded-[var(--prui-radius)] border border-[var(--prui-line)]",
48
- "bg-[var(--prui-surface)] p-1 shadow-lg",
49
- y === "end" ? "right-0" : "left-0"
127
+ tabIndex: -1,
128
+ onKeyDown: U,
129
+ className: x(
130
+ "prui-dropdown-menu absolute z-[var(--prui-z-overlay)] mt-1 min-w-40 rounded-[var(--prui-radius)] border border-[var(--prui-line)]",
131
+ "bg-[var(--prui-surface)] p-1 shadow-[var(--prui-shadow-md)] outline-none",
132
+ C === "end" ? "right-0" : "left-0"
50
133
  ),
51
- children: v ?? (f ?? []).map((e, t) => /* @__PURE__ */ p(l.Fragment, { children: [
52
- e.separatorBefore ? /* @__PURE__ */ a("div", { className: "my-1 h-px bg-[var(--prui-line)]" }) : null,
53
- /* @__PURE__ */ a(
134
+ children: A ?? (N ?? []).map((e, n) => /* @__PURE__ */ I(o.Fragment, { children: [
135
+ e.separatorBefore ? /* @__PURE__ */ p("div", { className: "my-1 h-px bg-[var(--prui-line)]" }) : null,
136
+ /* @__PURE__ */ p(
54
137
  "button",
55
138
  {
56
139
  type: "button",
57
140
  role: "menuitem",
141
+ tabIndex: -1,
58
142
  disabled: e.disabled,
59
143
  onClick: () => {
60
- var r;
61
- e.disabled || (o(!1), (r = e.onSelect) == null || r.call(e));
144
+ var t;
145
+ e.disabled || (s(!1), (t = e.onSelect) == null || t.call(e));
62
146
  },
63
- className: i(
147
+ className: x(
64
148
  "flex w-full items-center rounded-[calc(var(--prui-radius)-1px)] px-2.5 py-1.5 text-left text-sm",
65
- "hover:bg-[var(--prui-raise)] cursor-pointer disabled:opacity-50 disabled:pointer-events-none",
149
+ "hover:bg-[var(--prui-raise)] focus-visible:bg-[var(--prui-raise)] outline-none cursor-pointer disabled:opacity-50 disabled:pointer-events-none",
66
150
  e.danger ? "text-[var(--prui-danger)]" : "text-[var(--prui-fg)]"
67
151
  ),
68
152
  children: e.label
69
153
  }
70
154
  )
71
- ] }, `${e.label}-${t}`))
155
+ ] }, `${e.label}-${n}`))
72
156
  }
73
157
  ) : null
74
158
  ] });
75
- };
76
- k.displayName = "Dropdown";
77
- const E = {
159
+ });
160
+ H.displayName = "Dropdown";
161
+ const Q = {
78
162
  name: "Dropdown",
79
163
  props: [
80
164
  { name: "items", type: "DropdownItem[]", default: "[]", control: "object" },
81
165
  { name: "trigger", type: "ReactNode", default: null, control: "none" },
82
166
  { name: "align", type: "'start' | 'end'", default: "'start'", control: "select", options: ["start", "end"] },
83
- { name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" }
167
+ { name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" },
168
+ { name: "open", type: "boolean", default: "undefined", control: "boolean" }
84
169
  ]
85
170
  };
86
171
  export {
87
- k as Dropdown,
88
- E as dropdownPropsMeta
172
+ H as Dropdown,
173
+ Q as dropdownPropsMeta
89
174
  };
@@ -0,0 +1,28 @@
1
+ import { PropsMeta } from './props-meta';
2
+ import * as React from "react";
3
+ /**
4
+ * FileUpload: an accessible dropzone + file picker. The dropzone is a real
5
+ * button wrapping a visually-hidden input (keyboard + screen reader
6
+ * native); drag events highlight the zone. Files render as a removable
7
+ * list. Accept/multiple mirror the native input attributes.
8
+ */
9
+ export interface FileUploadProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onError"> {
10
+ /** Accepted file types (native input accept syntax). */
11
+ accept?: string;
12
+ /** Allow multiple files. Default true. */
13
+ multiple?: boolean;
14
+ /** Validate/reject files; return an error message string or null. */
15
+ validate?: (file: File) => string | null;
16
+ onFiles?: (files: File[]) => void;
17
+ /** Control the visible file list externally. */
18
+ files?: File[];
19
+ /** Max file size in bytes per file. */
20
+ maxSize?: number;
21
+ /** Primary dropzone copy. */
22
+ hint?: React.ReactNode;
23
+ disabled?: boolean;
24
+ /** Hide the selected-files list (caller renders their own). */
25
+ hideList?: boolean;
26
+ }
27
+ export declare const FileUpload: React.ForwardRefExoticComponent<FileUploadProps & React.RefAttributes<HTMLInputElement>>;
28
+ export declare const fileUploadPropsMeta: PropsMeta;
@@ -0,0 +1,111 @@
1
+ import { jsxs as h, jsx as t } from "react/jsx-runtime";
2
+ import * as i from "react";
3
+ import { UploadCloud as M, File as S, X as T } from "lucide-react";
4
+ import { cn as k } from "./cn.js";
5
+ import { usePruiI18n as z } from "../i18n.js";
6
+ function C(n) {
7
+ return n < 1024 ? `${n} B` : n < 1024 * 1024 ? `${(n / 1024).toFixed(1)} KB` : `${(n / 1024 / 1024).toFixed(1)} MB`;
8
+ }
9
+ const K = i.forwardRef(function({ accept: F, multiple: v = !0, validate: p, onFiles: o, files: b, maxSize: f, hint: R, disabled: l, hideList: B, className: j, ...A }, s) {
10
+ const { t: y } = z(), [E, N] = i.useState([]), [$, m] = i.useState(!1), [g, I] = i.useState([]), x = b !== void 0, u = x ? b : E, w = i.useRef(null), D = (e) => {
11
+ if (l) return;
12
+ const r = [], a = [];
13
+ for (const d of Array.from(e)) {
14
+ const U = f != null && d.size > f ? `${d.name} is larger than ${C(f)}.` : (p == null ? void 0 : p(d)) ?? null;
15
+ U ? r.push(U) : a.push(d);
16
+ }
17
+ I(r);
18
+ const c = v ? [...u, ...a] : a.slice(-1);
19
+ x || N(c), o == null || o(c);
20
+ }, L = (e) => {
21
+ const r = u.filter((a, c) => c !== e);
22
+ x || N(r), o == null || o(r);
23
+ };
24
+ return /* @__PURE__ */ h("div", { className: k("prui-file-upload flex flex-col gap-2", j), ...A, children: [
25
+ /* @__PURE__ */ h(
26
+ "button",
27
+ {
28
+ type: "button",
29
+ disabled: l,
30
+ "aria-describedby": g.length ? "prui-file-upload-errors" : void 0,
31
+ onClick: () => {
32
+ var e;
33
+ return (e = w.current) == null ? void 0 : e.click();
34
+ },
35
+ onDragOver: (e) => {
36
+ e.preventDefault(), l || m(!0);
37
+ },
38
+ onDragLeave: () => m(!1),
39
+ onDrop: (e) => {
40
+ var r, a;
41
+ e.preventDefault(), m(!1), (a = (r = e.dataTransfer) == null ? void 0 : r.files) != null && a.length && D(e.dataTransfer.files);
42
+ },
43
+ "data-dragging": $ || void 0,
44
+ "data-disabled": l || void 0,
45
+ className: k(
46
+ "flex cursor-pointer flex-col items-center justify-center gap-2 rounded-[var(--prui-radius)] border border-dashed p-8 text-sm",
47
+ "transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[var(--prui-brand)]",
48
+ $ ? "border-[var(--prui-brand)] bg-[var(--prui-brand)]/10 text-[var(--prui-brand)]" : "border-[var(--prui-line)] bg-[var(--prui-background)] text-[var(--prui-dim)] hover:border-[var(--prui-dim)]",
49
+ l && "opacity-50 cursor-not-allowed"
50
+ ),
51
+ children: [
52
+ /* @__PURE__ */ t(M, { className: "h-6 w-6", "aria-hidden": !0 }),
53
+ /* @__PURE__ */ t("span", { children: R ?? y.dropFiles })
54
+ ]
55
+ }
56
+ ),
57
+ /* @__PURE__ */ t(
58
+ "input",
59
+ {
60
+ ref: (e) => {
61
+ w.current = e, typeof s == "function" ? s(e) : s && (s.current = e);
62
+ },
63
+ type: "file",
64
+ accept: F,
65
+ multiple: v,
66
+ disabled: l,
67
+ className: "sr-only",
68
+ tabIndex: -1,
69
+ "aria-hidden": !0,
70
+ onChange: (e) => {
71
+ var r;
72
+ (r = e.target.files) != null && r.length && D(e.target.files), e.target.value = "";
73
+ }
74
+ }
75
+ ),
76
+ g.length > 0 ? /* @__PURE__ */ t("div", { id: "prui-file-upload-errors", role: "alert", className: "flex flex-col gap-1 text-xs text-[var(--prui-danger)]", children: g.map((e, r) => /* @__PURE__ */ t("span", { children: e }, r)) }) : null,
77
+ !B && u.length > 0 ? /* @__PURE__ */ t("ul", { className: "flex flex-col gap-1", "data-testid": "file-upload-list", children: u.map((e, r) => /* @__PURE__ */ h("li", { className: "flex items-center gap-2 rounded-[var(--prui-radius-1)] bg-[var(--prui-raise)] px-3 py-2 text-sm text-[var(--prui-fg)]", children: [
78
+ /* @__PURE__ */ t(S, { className: "h-4 w-4 shrink-0 text-[var(--prui-dim)]", "aria-hidden": !0 }),
79
+ /* @__PURE__ */ t("span", { className: "min-w-0 flex-1 truncate", children: e.name }),
80
+ /* @__PURE__ */ t("span", { className: "text-xs text-[var(--prui-dim)]", children: C(e.size) }),
81
+ /* @__PURE__ */ t(
82
+ "button",
83
+ {
84
+ type: "button",
85
+ "aria-label": `${y.removeFile}: ${e.name}`,
86
+ onClick: () => L(r),
87
+ className: "rounded-[var(--prui-radius-1)] p-1 text-[var(--prui-dim)] transition-colors hover:text-[var(--prui-danger)] cursor-pointer",
88
+ children: /* @__PURE__ */ t(T, { className: "h-3.5 w-3.5", "aria-hidden": !0 })
89
+ }
90
+ )
91
+ ] }, `${e.name}-${r}`)) }) : null
92
+ ] });
93
+ });
94
+ K.displayName = "FileUpload";
95
+ const q = {
96
+ name: "FileUpload",
97
+ props: [
98
+ { name: "accept", type: "string (input accept)", default: "undefined", control: "text" },
99
+ { name: "multiple", type: "boolean", default: "true", control: "boolean" },
100
+ { name: "onFiles", type: "(files: File[]) => void", default: null, control: "none" },
101
+ { name: "files", type: "File[]", default: "internal state", control: "none" },
102
+ { name: "maxSize", type: "number (bytes)", default: "undefined", control: "number" },
103
+ { name: "validate", type: "(file: File) => string | null", default: null, control: "none" },
104
+ { name: "hint", type: "ReactNode", default: "'Drag files here or click to browse'", control: "text" },
105
+ { name: "hideList", type: "boolean", default: "false", control: "boolean" }
106
+ ]
107
+ };
108
+ export {
109
+ K as FileUpload,
110
+ q as fileUploadPropsMeta
111
+ };
@@ -2,6 +2,8 @@
2
2
  export { cn } from './cn';
3
3
  export { resolveSurface, withSurface, type SurfaceProps, type SurfaceRadius, type SurfaceTexture, type SurfaceElevation } from './surface';
4
4
  export type { PropsMeta, PropMeta, PropControl } from './props-meta';
5
+ export { Portal, useReducedMotion, useFocusTrap, useEscapeKey, useScrollLock, useInertBackground, useOverlay, useOverlayStack, pushOverlay, removeOverlay, isTopOverlay, overlayCount, getFocusable, overlayPropsMeta, } from './overlay';
6
+ export { moveIndex, homeIndex, endIndex, typeaheadIndex } from './list-nav';
5
7
  export { Button, buttonPropsMeta, type ButtonProps, type ButtonVariant, type ButtonSize, } from './button';
6
8
  export { Input, inputPropsMeta, Textarea, textareaPropsMeta, type InputProps, type TextareaProps, } from './input';
7
9
  export { Label, labelPropsMeta, Separator, separatorPropsMeta, type LabelProps, type SeparatorProps } from './label';
@@ -13,3 +15,22 @@ export { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Di
13
15
  export { Dropdown, dropdownPropsMeta, type DropdownProps, type DropdownItem, } from './dropdown';
14
16
  export { ScrollArea, scrollAreaPropsMeta, type ScrollAreaProps } from './scroll-area';
15
17
  export { Modal, confirmModal, modalPropsMeta, confirmModalPropsMeta, type ModalProps, type ModalSize, type ConfirmModalOptions, type ConfirmModalType, } from './modal';
18
+ export { computePosition, useAnchoredPosition, type AnchorSide, type AnchorAlign, type AnchoredPosition } from './anchor';
19
+ export { Spinner, spinnerPropsMeta, type SpinnerProps, type SpinnerSize } from './spinner';
20
+ export { Skeleton, skeletonPropsMeta, type SkeletonProps } from './skeleton';
21
+ export { Alert, alertPropsMeta, type AlertProps, type AlertVariant } from './alert';
22
+ export { Progress, progressPropsMeta, type ProgressProps } from './progress';
23
+ export { Toaster, toast, dismissAllToasts, toasterPropsMeta, toastPropsMeta, type ToasterProps, type ToastOptions, type ToastVariant, type ToastHandle } from './toast';
24
+ export { Tooltip, tooltipPropsMeta, type TooltipProps } from './tooltip';
25
+ export { Popover, popoverPropsMeta, type PopoverProps } from './popover';
26
+ export { Drawer, Sheet, drawerPropsMeta, sheetPropsMeta, type DrawerProps, type DrawerSide } from './drawer';
27
+ export { Checkbox, checkboxPropsMeta, type CheckboxProps } from './checkbox';
28
+ export { RadioGroup, Radio, radioGroupPropsMeta, type RadioGroupProps, type RadioProps } from './radio';
29
+ export { Combobox, comboboxPropsMeta, type ComboboxProps, type ComboboxOption } from './combobox';
30
+ export { Accordion, AccordionItem, accordionPropsMeta, type AccordionProps, type AccordionItemProps } from './accordion';
31
+ export { Breadcrumb, BreadcrumbItem, BreadcrumbEllipsis, breadcrumbPropsMeta, type BreadcrumbProps, type BreadcrumbItemProps } from './breadcrumb';
32
+ export { TreeView, treeViewPropsMeta, type TreeViewProps, type TreeViewItem } from './tree-view';
33
+ export { Timeline, timelinePropsMeta, type TimelineProps, type TimelineItemData, type TimelineVariant } from './timeline';
34
+ export { Calendar, calendarPropsMeta, toDateKey, fromDateKey, type CalendarProps } from './calendar';
35
+ export { DatePicker, DateRangePicker, datePickerPropsMeta, dateRangePickerPropsMeta, type DatePickerProps, type DateRangePickerProps, type DateRange } from './date-picker';
36
+ export { FileUpload, fileUploadPropsMeta, type FileUploadProps } from './file-upload';
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared list/menus keyboard navigation helpers.
3
+ *
4
+ * Pure index math plus a typeahead buffer, reused by Dropdown, Select,
5
+ * CommandPalette, the nav rail flyout, Combobox and any roving-tabIndex
6
+ * list. No DOM assumptions: callers own focus and rendering.
7
+ */
8
+ /** Next index for ArrowUp/ArrowDown (and Left/Right in horizontal lists). */
9
+ export declare function moveIndex(current: number, delta: 1 | -1, length: number, opts?: {
10
+ loop?: boolean;
11
+ enabled?: (index: number) => boolean;
12
+ }): number;
13
+ /** Home / End clamps. */
14
+ export declare function homeIndex(length: number, enabled?: (i: number) => boolean): number;
15
+ export declare function endIndex(length: number, enabled?: (i: number) => boolean): number;
16
+ /**
17
+ * Typeahead: given the item labels, find the next item whose label starts
18
+ * with the accumulated prefix (searching forward from the active item,
19
+ * wrapping). Case-insensitive; resets after `resetMs` of inactivity.
20
+ */
21
+ export declare function typeaheadIndex(labels: () => string[], state: {
22
+ buffer: string;
23
+ at: number;
24
+ }, key: string, activeIndex: number, resetMs?: number): {
25
+ index: number;
26
+ buffer: string;
27
+ };
@@ -0,0 +1,51 @@
1
+ function m(n, r, t, f = {}) {
2
+ if (t <= 0) return -1;
3
+ const { loop: o = !0, enabled: u } = f;
4
+ if (n < 0)
5
+ return r > 0 ? h(0, 1, t, u) : h(t - 1, -1, t, u);
6
+ let i = n;
7
+ for (let e = 0; e < t; e++) {
8
+ if (i = i + r, i >= t || i < 0) {
9
+ if (!o) return n;
10
+ i = i < 0 ? t - 1 : 0;
11
+ }
12
+ if (!u || u(i)) return i;
13
+ }
14
+ return n;
15
+ }
16
+ function h(n, r, t, f) {
17
+ for (let o = n; o >= 0 && o < t; o += r)
18
+ if (!f || f(o)) return o;
19
+ return -1;
20
+ }
21
+ function p(n, r) {
22
+ return h(0, 1, n, r);
23
+ }
24
+ function w(n, r) {
25
+ return h(n - 1, -1, n, r);
26
+ }
27
+ function a(n, r, t, f, o = 500) {
28
+ var x, b;
29
+ if (t.length !== 1) return { index: f, buffer: r.buffer };
30
+ const u = Date.now(), e = u - r.at < o ? r.buffer + t.toLowerCase() : t.toLowerCase();
31
+ r.buffer = e, r.at = u;
32
+ const c = n().map((s) => s.trim().toLowerCase());
33
+ for (let s = 1; s <= c.length; s++) {
34
+ const d = (f + s) % c.length;
35
+ if ((x = c[d]) != null && x.startsWith(e)) return { index: d, buffer: e };
36
+ }
37
+ if (e.length > 1) {
38
+ const s = e[e.length - 1];
39
+ for (let d = 1; d <= c.length; d++) {
40
+ const l = (f + d) % c.length;
41
+ if ((b = c[l]) != null && b.startsWith(s)) return { index: l, buffer: e };
42
+ }
43
+ }
44
+ return { index: f, buffer: e };
45
+ }
46
+ export {
47
+ w as endIndex,
48
+ p as homeIndex,
49
+ m as moveIndex,
50
+ a as typeaheadIndex
51
+ };
@@ -7,6 +7,12 @@ import * as React from "react";
7
7
  * false = shake feedback, and an imperative confirmModal() that renders a
8
8
  * typed confirmation dialog imperatively and resolves a Promise<boolean>.
9
9
  * Restyled onto PRUI tokens instead of hardcoded hex.
10
+ *
11
+ * Built on the shared overlay infrastructure (core/overlay): portaled to the
12
+ * body, focus-trapped with initial focus and focus restoration, Escape is
13
+ * answered only by the topmost overlay, and the background is aria-hidden +
14
+ * inert where supported while open. prefers-reduced-motion disables the
15
+ * shake/scale/fade choreography.
10
16
  */
11
17
  export type ModalSize = "xs" | "sm" | "md" | "lg" | "xl";
12
18
  export interface ModalProps {
@@ -32,11 +38,12 @@ export interface ModalProps {
32
38
  /** Accessible label. */
33
39
  ariaLabel?: string;
34
40
  className?: string;
41
+ /** Inline style applied to the modal content element. */
42
+ style?: React.CSSProperties;
43
+ /** Initial focus target: the first focusable, the dialog itself, a specific element, or none. */
44
+ initialFocus?: React.RefObject<HTMLElement | null> | "first" | "container" | false;
35
45
  }
36
- export declare function Modal({ open, onClose, children, disableDefaultClose, closeOnOverlayClick, size, xs, sm, md, lg, xl, maxWidth, padding, noPadding, showCloseButton, ariaLabel, className, }: ModalProps): React.JSX.Element | null;
37
- export declare namespace Modal {
38
- var displayName: string;
39
- }
46
+ export declare const Modal: React.ForwardRefExoticComponent<ModalProps & React.RefAttributes<HTMLDivElement>>;
40
47
  export type ConfirmModalType = "success" | "warning" | "danger" | "error" | "info";
41
48
  export interface ConfirmModalOptions {
42
49
  title: string;
@@ -49,7 +56,9 @@ export interface ConfirmModalOptions {
49
56
  /**
50
57
  * confirmModal({ title, message, type }) => Promise<boolean>
51
58
  * Renders the confirmation modal imperatively; resolves true on confirm,
52
- * false on cancel/Escape/overlay-shake close. Focus-trapped like the original.
59
+ * false on cancel/Escape/overlay-shake close. Focus-trapped via the shared
60
+ * overlay infrastructure: initial focus lands on the confirm action and
61
+ * focus returns to the invoker on close.
53
62
  */
54
63
  export declare function confirmModal(options: ConfirmModalOptions): Promise<boolean>;
55
64
  export declare const modalPropsMeta: PropsMeta;