@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.
- package/dist/app/resource.d.ts +44 -1
- package/dist/app.js +1 -1
- package/dist/chunks/auth-shell-DQJ4UmUv.js +1208 -0
- package/dist/chunks/data-table-toolbar-B-5J2Ozl.js +736 -0
- package/dist/core/accordion.d.ts +16 -0
- package/dist/core/accordion.js +108 -0
- package/dist/core/alert.d.ts +20 -0
- package/dist/core/alert.js +63 -0
- package/dist/core/anchor.d.ts +35 -0
- package/dist/core/anchor.js +39 -0
- package/dist/core/breadcrumb.d.ts +30 -0
- package/dist/core/breadcrumb.js +67 -0
- package/dist/core/button.d.ts +8 -1
- package/dist/core/button.js +23 -18
- package/dist/core/calendar.d.ts +29 -0
- package/dist/core/calendar.js +180 -0
- package/dist/core/card.d.ts +5 -1
- package/dist/core/card.js +33 -29
- package/dist/core/checkbox.d.ts +19 -0
- package/dist/core/checkbox.js +55 -0
- package/dist/core/combobox.d.ts +32 -0
- package/dist/core/combobox.js +193 -0
- package/dist/core/date-picker.d.ts +62 -0
- package/dist/core/date-picker.js +314 -0
- package/dist/core/dialog.d.ts +15 -0
- package/dist/core/dialog.js +77 -60
- package/dist/core/drawer.d.ts +34 -0
- package/dist/core/drawer.js +129 -0
- package/dist/core/dropdown.d.ts +8 -4
- package/dist/core/dropdown.js +136 -51
- package/dist/core/file-upload.d.ts +28 -0
- package/dist/core/file-upload.js +111 -0
- package/dist/core/index.d.ts +23 -1
- package/dist/core/list-nav.d.ts +27 -0
- package/dist/core/list-nav.js +51 -0
- package/dist/core/modal.d.ts +14 -5
- package/dist/core/modal.js +163 -156
- package/dist/core/overlay.d.ts +93 -0
- package/dist/core/overlay.js +189 -0
- package/dist/core/popover.d.ts +29 -0
- package/dist/core/popover.js +124 -0
- package/dist/core/progress.d.ts +21 -0
- package/dist/core/progress.js +59 -0
- package/dist/core/radio.d.ts +20 -0
- package/dist/core/radio.js +115 -0
- package/dist/core/select.d.ts +6 -0
- package/dist/core/select.js +187 -98
- package/dist/core/skeleton.d.ts +20 -0
- package/dist/core/skeleton.js +41 -0
- package/dist/core/spinner.d.ts +15 -0
- package/dist/core/spinner.js +41 -0
- package/dist/core/tabs.js +82 -53
- package/dist/core/time-picker.d.ts +68 -0
- package/dist/core/time-picker.js +305 -0
- package/dist/core/timeline.d.ts +22 -0
- package/dist/core/timeline.js +57 -0
- package/dist/core/toast.d.ts +36 -0
- package/dist/core/toast.js +123 -0
- package/dist/core/tooltip.d.ts +23 -0
- package/dist/core/tooltip.js +96 -0
- package/dist/core/tree-view.d.ts +34 -0
- package/dist/core/tree-view.js +133 -0
- package/dist/core.js +160 -62
- package/dist/data-table/data-table.d.ts +22 -1
- package/dist/data-table.js +1 -1
- package/dist/forms/form.d.ts +8 -0
- package/dist/forms.js +213 -200
- package/dist/i18n/index.d.ts +89 -0
- package/dist/i18n.js +105 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +263 -155
- package/dist/prui-utilities.css +1 -1
- package/dist/prui.css +111 -4
- package/dist/theme/base.css +110 -3
- package/dist/theme/index.d.ts +27 -0
- package/dist/theme.js +86 -58
- package/package.json +9 -2
- package/dist/chunks/auth-shell-BG5vx9eG.js +0 -1054
- package/dist/chunks/data-table-toolbar-BUy2EWPy.js +0 -581
package/dist/core/modal.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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;
|
package/dist/core/modal.js
CHANGED
|
@@ -1,155 +1,170 @@
|
|
|
1
|
-
import { jsx as e, jsxs as
|
|
2
|
-
import * as
|
|
3
|
-
import { createRoot as
|
|
4
|
-
import { X as
|
|
5
|
-
import { cn as
|
|
6
|
-
|
|
1
|
+
import { jsx as e, jsxs as a } from "react/jsx-runtime";
|
|
2
|
+
import * as o from "react";
|
|
3
|
+
import { createRoot as X } from "react-dom/client";
|
|
4
|
+
import { X as q } from "lucide-react";
|
|
5
|
+
import { cn as G } from "./cn.js";
|
|
6
|
+
import { useReducedMotion as B, useOverlay as F, Portal as H } from "./overlay.js";
|
|
7
|
+
import { getPruiDictionary as J } from "../i18n.js";
|
|
8
|
+
const O = {
|
|
7
9
|
xs: { width: "320px", minWidth: "280px" },
|
|
8
10
|
sm: { width: "448px", minWidth: "320px" },
|
|
9
11
|
md: { width: "640px", minWidth: "384px" },
|
|
10
12
|
lg: { width: "896px", minWidth: "512px" },
|
|
11
13
|
xl: { width: "1152px", minWidth: "640px" }
|
|
12
|
-
},
|
|
14
|
+
}, K = {
|
|
13
15
|
xs: "24px 32px",
|
|
14
16
|
sm: "24px 32px",
|
|
15
17
|
md: "32px 40px",
|
|
16
18
|
lg: "32px 40px",
|
|
17
19
|
xl: "40px 48px"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
onClose: o,
|
|
20
|
+
}, Q = o.forwardRef(function({
|
|
21
|
+
open: r,
|
|
22
|
+
onClose: n,
|
|
22
23
|
children: W,
|
|
23
|
-
disableDefaultClose:
|
|
24
|
-
closeOnOverlayClick:
|
|
24
|
+
disableDefaultClose: p = !1,
|
|
25
|
+
closeOnOverlayClick: M = !0,
|
|
25
26
|
size: y,
|
|
26
|
-
xs:
|
|
27
|
-
sm:
|
|
28
|
-
md:
|
|
29
|
-
lg:
|
|
30
|
-
xl:
|
|
31
|
-
maxWidth:
|
|
32
|
-
padding:
|
|
33
|
-
noPadding:
|
|
34
|
-
showCloseButton:
|
|
35
|
-
ariaLabel:
|
|
36
|
-
className:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
27
|
+
xs: S,
|
|
28
|
+
sm: T,
|
|
29
|
+
md: N,
|
|
30
|
+
lg: m,
|
|
31
|
+
xl: b,
|
|
32
|
+
maxWidth: R,
|
|
33
|
+
padding: z,
|
|
34
|
+
noPadding: w = !1,
|
|
35
|
+
showCloseButton: k = !0,
|
|
36
|
+
ariaLabel: f,
|
|
37
|
+
className: h,
|
|
38
|
+
style: s,
|
|
39
|
+
initialFocus: P = "first"
|
|
40
|
+
}, l) {
|
|
41
|
+
const v = y ?? (S ? "xs" : T ? "sm" : m ? "lg" : b ? "xl" : "md"), [x, i] = o.useState(r), [d, u] = o.useState(!1), [g, L] = o.useState(!1), A = o.useRef(null), C = B(), E = () => {
|
|
42
|
+
C || (L(!0), setTimeout(() => L(!1), 500));
|
|
43
|
+
};
|
|
44
|
+
o.useEffect(() => {
|
|
45
|
+
if (r) {
|
|
46
|
+
if (i(!0), C) {
|
|
47
|
+
u(!0);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
42
50
|
const t = setTimeout(() => {
|
|
43
|
-
|
|
51
|
+
u(!0);
|
|
44
52
|
}, 10);
|
|
45
53
|
return () => clearTimeout(t);
|
|
46
54
|
}
|
|
47
|
-
|
|
48
|
-
}, [
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
u(!1), C && i(!1);
|
|
56
|
+
}, [r, C]);
|
|
57
|
+
const { ref: V } = F({
|
|
58
|
+
open: r,
|
|
59
|
+
onEscape: () => {
|
|
60
|
+
if (p)
|
|
61
|
+
return E(), !1;
|
|
62
|
+
n();
|
|
63
|
+
},
|
|
64
|
+
initialFocus: P
|
|
65
|
+
});
|
|
66
|
+
if (!x && !d) return null;
|
|
67
|
+
const I = (t) => {
|
|
56
68
|
if (t.target === t.currentTarget) {
|
|
57
|
-
if (
|
|
58
|
-
|
|
69
|
+
if (p || !M) {
|
|
70
|
+
E();
|
|
59
71
|
return;
|
|
60
72
|
}
|
|
61
|
-
|
|
73
|
+
n();
|
|
62
74
|
}
|
|
63
|
-
},
|
|
64
|
-
return /* @__PURE__ */ e(
|
|
75
|
+
}, j = O[v], D = w ? "0" : z ?? K[v];
|
|
76
|
+
return /* @__PURE__ */ e(H, { children: /* @__PURE__ */ e("div", { ref: V, children: /* @__PURE__ */ e(
|
|
65
77
|
"div",
|
|
66
78
|
{
|
|
67
|
-
className: "prui-modal-overlay fixed inset-0 z-[
|
|
79
|
+
className: "prui-modal-overlay fixed inset-0 z-[var(--prui-z-modal)] flex justify-center overflow-y-auto p-4",
|
|
68
80
|
style: {
|
|
69
81
|
alignItems: "flex-start",
|
|
70
82
|
paddingTop: "10vh",
|
|
71
|
-
backgroundColor: "
|
|
83
|
+
backgroundColor: "var(--prui-scrim)",
|
|
72
84
|
backdropFilter: "blur(4px)",
|
|
73
|
-
opacity:
|
|
74
|
-
transition: "opacity
|
|
85
|
+
opacity: d ? 1 : 0,
|
|
86
|
+
transition: "opacity var(--prui-duration-slow) var(--prui-ease-out)"
|
|
75
87
|
},
|
|
76
|
-
onClick:
|
|
88
|
+
onClick: I,
|
|
77
89
|
onMouseDown: (t) => {
|
|
78
|
-
t.target === t.currentTarget &&
|
|
90
|
+
t.target === t.currentTarget && I(t);
|
|
79
91
|
},
|
|
80
|
-
children: /* @__PURE__ */
|
|
92
|
+
children: /* @__PURE__ */ a(
|
|
81
93
|
"div",
|
|
82
94
|
{
|
|
83
|
-
ref:
|
|
95
|
+
ref: (t) => {
|
|
96
|
+
A.current = t, typeof l == "function" ? l(t) : l && (l.current = t);
|
|
97
|
+
},
|
|
84
98
|
role: "dialog",
|
|
85
99
|
"aria-modal": "true",
|
|
86
|
-
"aria-label":
|
|
87
|
-
className:
|
|
100
|
+
"aria-label": f,
|
|
101
|
+
className: G(
|
|
88
102
|
"prui-modal-content relative h-fit m-auto w-full",
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
g && "prui-modal-shake",
|
|
104
|
+
h
|
|
91
105
|
),
|
|
92
106
|
style: {
|
|
93
|
-
width:
|
|
94
|
-
minWidth:
|
|
95
|
-
maxWidth:
|
|
96
|
-
padding:
|
|
107
|
+
width: j.width,
|
|
108
|
+
minWidth: j.minWidth,
|
|
109
|
+
maxWidth: R ?? j.width,
|
|
110
|
+
padding: D,
|
|
97
111
|
backgroundColor: "var(--prui-surface)",
|
|
98
112
|
border: "1px solid var(--prui-line)",
|
|
99
113
|
borderRadius: "var(--prui-radius-3)",
|
|
100
|
-
boxShadow: "
|
|
114
|
+
boxShadow: "var(--prui-shadow-modal)",
|
|
101
115
|
color: "var(--prui-fg)",
|
|
102
|
-
transform:
|
|
103
|
-
opacity:
|
|
104
|
-
transition: "transform
|
|
116
|
+
transform: d ? "scale(1) translateY(0)" : "scale(0.95) translateY(8px)",
|
|
117
|
+
opacity: d ? 1 : 0,
|
|
118
|
+
transition: "transform var(--prui-duration-slow) var(--prui-ease-out), opacity var(--prui-duration-slow) var(--prui-ease-out)",
|
|
119
|
+
...s
|
|
105
120
|
},
|
|
106
121
|
onTransitionEnd: () => {
|
|
107
|
-
|
|
122
|
+
r || i(!1);
|
|
108
123
|
},
|
|
109
124
|
children: [
|
|
110
|
-
|
|
125
|
+
W,
|
|
126
|
+
k && !p ? /* @__PURE__ */ e(
|
|
111
127
|
"button",
|
|
112
128
|
{
|
|
113
129
|
type: "button",
|
|
114
|
-
onClick:
|
|
130
|
+
onClick: n,
|
|
115
131
|
"aria-label": "Close modal",
|
|
116
132
|
className: "absolute right-4 top-4 flex h-10 w-10 cursor-pointer items-center justify-center rounded-[var(--prui-radius)] text-[var(--prui-dim)] transition-all hover:bg-[var(--prui-raise)] hover:text-[var(--prui-fg)]",
|
|
117
|
-
children: /* @__PURE__ */ e(
|
|
133
|
+
children: /* @__PURE__ */ e(q, { className: "h-4 w-4", "aria-hidden": !0 })
|
|
118
134
|
}
|
|
119
|
-
) : null
|
|
120
|
-
W
|
|
135
|
+
) : null
|
|
121
136
|
]
|
|
122
137
|
}
|
|
123
138
|
)
|
|
124
139
|
}
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const
|
|
140
|
+
) }) });
|
|
141
|
+
});
|
|
142
|
+
Q.displayName = "Modal";
|
|
143
|
+
const Y = {
|
|
129
144
|
success: "var(--prui-ok)",
|
|
130
145
|
warning: "var(--prui-warn)",
|
|
131
146
|
danger: "var(--prui-danger)",
|
|
132
147
|
error: "var(--prui-danger)",
|
|
133
148
|
info: "var(--prui-brand)",
|
|
134
149
|
default: "var(--prui-brand)"
|
|
135
|
-
},
|
|
136
|
-
const
|
|
137
|
-
switch (
|
|
150
|
+
}, U = ({ type: c }) => {
|
|
151
|
+
const r = Y[c ?? "default"];
|
|
152
|
+
switch (c) {
|
|
138
153
|
case "success":
|
|
139
|
-
return /* @__PURE__ */
|
|
154
|
+
return /* @__PURE__ */ a("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", style: { color: r }, "aria-hidden": !0, children: [
|
|
140
155
|
/* @__PURE__ */ e("path", { d: "M9 12l2 2 4-4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
141
156
|
/* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" })
|
|
142
157
|
] });
|
|
143
158
|
case "warning":
|
|
144
|
-
return /* @__PURE__ */ e("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", style: { color:
|
|
159
|
+
return /* @__PURE__ */ e("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", style: { color: r }, "aria-hidden": !0, children: /* @__PURE__ */ e("path", { d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.694-.833-2.464 0L4.34 16.5c-.77.833.192 2.5 1.732 2.5z", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
145
160
|
case "danger":
|
|
146
161
|
case "error":
|
|
147
|
-
return /* @__PURE__ */
|
|
162
|
+
return /* @__PURE__ */ a("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", style: { color: r }, "aria-hidden": !0, children: [
|
|
148
163
|
/* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" }),
|
|
149
|
-
/* @__PURE__ */ e("path", { d: "M15 9l-6 6m0-6l6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round"
|
|
164
|
+
/* @__PURE__ */ e("path", { d: "M15 9l-6 6m0-6l6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
150
165
|
] });
|
|
151
166
|
case "info":
|
|
152
|
-
return /* @__PURE__ */
|
|
167
|
+
return /* @__PURE__ */ a("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", style: { color: r }, "aria-hidden": !0, children: [
|
|
153
168
|
/* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" }),
|
|
154
169
|
/* @__PURE__ */ e("path", { d: "M12 8v4m0 4h.01", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
155
170
|
] });
|
|
@@ -157,109 +172,100 @@ const B = {
|
|
|
157
172
|
return null;
|
|
158
173
|
}
|
|
159
174
|
};
|
|
160
|
-
function
|
|
161
|
-
const { title:
|
|
162
|
-
return new Promise((
|
|
163
|
-
const
|
|
164
|
-
document.body.appendChild(
|
|
165
|
-
const
|
|
175
|
+
function oe(c) {
|
|
176
|
+
const r = J(), { title: n, message: W, confirmText: p = r.confirm, cancelText: M = r.cancel, type: y, size: S = "sm" } = c, T = Y[y ?? "default"];
|
|
177
|
+
return new Promise((N) => {
|
|
178
|
+
const m = document.createElement("div");
|
|
179
|
+
document.body.appendChild(m);
|
|
180
|
+
const b = X(m), R = () => {
|
|
166
181
|
setTimeout(() => {
|
|
167
|
-
|
|
182
|
+
b.unmount(), m.remove();
|
|
168
183
|
}, 320);
|
|
169
|
-
},
|
|
170
|
-
const [
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
184
|
+
}, z = () => {
|
|
185
|
+
const [w, k] = o.useState(!1), [f, h] = o.useState(!1), [s, P] = o.useState(!1), l = o.useRef(null), v = o.useRef(null), x = B();
|
|
186
|
+
o.useEffect(() => {
|
|
187
|
+
if (x) {
|
|
188
|
+
k(!0), h(!0);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const g = setTimeout(() => {
|
|
192
|
+
k(!0), h(!0);
|
|
174
193
|
}, 10);
|
|
175
|
-
return () => clearTimeout(
|
|
176
|
-
}, []);
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}, 300);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
a.preventDefault(), m(!1);
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (a.key !== "Tab") return;
|
|
193
|
-
const s = [g.current, c.current].filter((j) => !!j);
|
|
194
|
-
if (!s.length) return;
|
|
195
|
-
const b = s[0], t = s[s.length - 1], p = document.activeElement;
|
|
196
|
-
!p || !s.some((j) => j === p) ? (a.preventDefault(), b.focus()) : a.shiftKey && p === b ? (a.preventDefault(), t.focus()) : !a.shiftKey && p === t && (a.preventDefault(), b.focus());
|
|
197
|
-
};
|
|
198
|
-
return document.addEventListener("keydown", i), () => document.removeEventListener("keydown", i);
|
|
199
|
-
}, [h, l]), !h) return null;
|
|
200
|
-
const w = P[T];
|
|
201
|
-
return /* @__PURE__ */ e(
|
|
194
|
+
return () => clearTimeout(g);
|
|
195
|
+
}, [x]);
|
|
196
|
+
const i = (g) => {
|
|
197
|
+
P(!0), h(!1), setTimeout(() => {
|
|
198
|
+
R(), N(g);
|
|
199
|
+
}, x ? 0 : 300);
|
|
200
|
+
}, { ref: d } = F({
|
|
201
|
+
open: w && !s,
|
|
202
|
+
onEscape: () => (s || i(!1), !1),
|
|
203
|
+
initialFocus: v
|
|
204
|
+
});
|
|
205
|
+
if (!w) return null;
|
|
206
|
+
const u = O[S];
|
|
207
|
+
return /* @__PURE__ */ e("div", { ref: d, children: /* @__PURE__ */ e(
|
|
202
208
|
"div",
|
|
203
209
|
{
|
|
204
|
-
className: "prui-modal-overlay fixed inset-0 z-[
|
|
210
|
+
className: "prui-modal-overlay fixed inset-0 z-[var(--prui-z-confirm)] flex justify-center overflow-y-auto p-4",
|
|
205
211
|
style: {
|
|
206
212
|
alignItems: "flex-start",
|
|
207
213
|
paddingTop: "12vh",
|
|
208
|
-
backgroundColor: "
|
|
214
|
+
backgroundColor: "var(--prui-scrim)",
|
|
209
215
|
backdropFilter: "blur(4px)",
|
|
210
|
-
opacity:
|
|
211
|
-
transition: "opacity
|
|
216
|
+
opacity: f ? 1 : 0,
|
|
217
|
+
transition: "opacity var(--prui-duration-slow) var(--prui-ease-out)"
|
|
212
218
|
},
|
|
213
|
-
children: /* @__PURE__ */
|
|
219
|
+
children: /* @__PURE__ */ a(
|
|
214
220
|
"div",
|
|
215
221
|
{
|
|
216
222
|
role: "alertdialog",
|
|
217
223
|
"aria-modal": "true",
|
|
218
|
-
"aria-label":
|
|
224
|
+
"aria-label": n,
|
|
219
225
|
className: "prui-modal-content relative m-auto w-full",
|
|
220
226
|
style: {
|
|
221
|
-
width:
|
|
222
|
-
minWidth:
|
|
227
|
+
width: u.width,
|
|
228
|
+
minWidth: u.minWidth,
|
|
223
229
|
backgroundColor: "var(--prui-surface)",
|
|
224
230
|
border: "1px solid var(--prui-line)",
|
|
225
231
|
borderRadius: "var(--prui-radius-3)",
|
|
226
|
-
boxShadow: "
|
|
232
|
+
boxShadow: "var(--prui-shadow-modal)",
|
|
227
233
|
color: "var(--prui-fg)",
|
|
228
|
-
transform:
|
|
229
|
-
opacity:
|
|
230
|
-
transition: "transform
|
|
234
|
+
transform: f ? "scale(1) translateY(0)" : "scale(0.95) translateY(8px)",
|
|
235
|
+
opacity: f ? 1 : 0,
|
|
236
|
+
transition: "transform var(--prui-duration-slow) var(--prui-ease-out), opacity var(--prui-duration-slow) var(--prui-ease-out)"
|
|
231
237
|
},
|
|
232
238
|
children: [
|
|
233
|
-
/* @__PURE__ */
|
|
234
|
-
/* @__PURE__ */ e(
|
|
235
|
-
/* @__PURE__ */
|
|
236
|
-
/* @__PURE__ */ e("h2", { className: "m-0 text-lg font-semibold leading-normal", style: { color: "var(--prui-fg)" }, children:
|
|
239
|
+
/* @__PURE__ */ a("div", { className: "flex items-start gap-3 p-4 pb-2", children: [
|
|
240
|
+
/* @__PURE__ */ e(U, { type: y }),
|
|
241
|
+
/* @__PURE__ */ a("div", { className: "min-w-0", children: [
|
|
242
|
+
/* @__PURE__ */ e("h2", { className: "m-0 text-lg font-semibold leading-normal", style: { color: "var(--prui-fg)" }, children: n }),
|
|
237
243
|
/* @__PURE__ */ e("p", { className: "mt-2 text-sm leading-normal", style: { color: "var(--prui-dim)" }, children: W })
|
|
238
244
|
] })
|
|
239
245
|
] }),
|
|
240
|
-
/* @__PURE__ */
|
|
246
|
+
/* @__PURE__ */ a("div", { className: "flex items-center justify-end gap-3 px-4 pb-4", children: [
|
|
241
247
|
/* @__PURE__ */ e(
|
|
242
248
|
"button",
|
|
243
249
|
{
|
|
244
250
|
type: "button",
|
|
245
|
-
ref:
|
|
246
|
-
disabled:
|
|
247
|
-
onClick: () =>
|
|
251
|
+
ref: l,
|
|
252
|
+
disabled: s,
|
|
253
|
+
onClick: () => i(!1),
|
|
248
254
|
className: "cursor-pointer rounded-[var(--prui-radius)] border px-4 py-2 text-sm font-medium transition-all disabled:opacity-60",
|
|
249
255
|
style: { background: "transparent", borderColor: "var(--prui-line)", color: "var(--prui-fg)" },
|
|
250
|
-
children:
|
|
256
|
+
children: M
|
|
251
257
|
}
|
|
252
258
|
),
|
|
253
259
|
/* @__PURE__ */ e(
|
|
254
260
|
"button",
|
|
255
261
|
{
|
|
256
262
|
type: "button",
|
|
257
|
-
ref:
|
|
258
|
-
disabled:
|
|
259
|
-
onClick: () =>
|
|
263
|
+
ref: v,
|
|
264
|
+
disabled: s,
|
|
265
|
+
onClick: () => i(!0),
|
|
260
266
|
className: "cursor-pointer rounded-[var(--prui-radius)] border border-transparent px-4 py-2 text-sm font-medium text-white transition-all disabled:opacity-60",
|
|
261
|
-
style: { backgroundColor:
|
|
262
|
-
children:
|
|
267
|
+
style: { backgroundColor: T },
|
|
268
|
+
children: p
|
|
263
269
|
}
|
|
264
270
|
)
|
|
265
271
|
] })
|
|
@@ -267,12 +273,12 @@ function G(n) {
|
|
|
267
273
|
}
|
|
268
274
|
)
|
|
269
275
|
}
|
|
270
|
-
);
|
|
276
|
+
) });
|
|
271
277
|
};
|
|
272
|
-
|
|
278
|
+
b.render(/* @__PURE__ */ e(z, {}));
|
|
273
279
|
});
|
|
274
280
|
}
|
|
275
|
-
const
|
|
281
|
+
const ae = {
|
|
276
282
|
name: "Modal",
|
|
277
283
|
props: [
|
|
278
284
|
{ name: "open", type: "boolean", default: null, control: "boolean" },
|
|
@@ -283,9 +289,10 @@ const H = {
|
|
|
283
289
|
{ name: "noPadding", type: "boolean", default: "false", control: "boolean" },
|
|
284
290
|
{ name: "showCloseButton", type: "boolean", default: "true", control: "boolean" },
|
|
285
291
|
{ name: "padding", type: "string (CSS)", default: "per-size", control: "text" },
|
|
286
|
-
{ name: "maxWidth", type: "string (CSS)", default: "per-size", control: "text" }
|
|
292
|
+
{ name: "maxWidth", type: "string (CSS)", default: "per-size", control: "text" },
|
|
293
|
+
{ name: "initialFocus", type: 'ref | "first" | "container" | false', default: '"first"', control: "none" }
|
|
287
294
|
]
|
|
288
|
-
},
|
|
295
|
+
}, ie = {
|
|
289
296
|
name: "confirmModal",
|
|
290
297
|
props: [
|
|
291
298
|
{ name: "title", type: "string", default: null, control: "text" },
|
|
@@ -296,8 +303,8 @@ const H = {
|
|
|
296
303
|
]
|
|
297
304
|
};
|
|
298
305
|
export {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
306
|
+
Q as Modal,
|
|
307
|
+
oe as confirmModal,
|
|
308
|
+
ie as confirmModalPropsMeta,
|
|
309
|
+
ae as modalPropsMeta
|
|
303
310
|
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { PropsMeta } from './props-meta';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Shared overlay infrastructure.
|
|
5
|
+
*
|
|
6
|
+
* Every floating surface in PRUI (Modal, Dialog, Drawer, Sheet, Command
|
|
7
|
+
* Palette, Dropdown, Tooltip, Popover, Toast, confirmModal) builds on the
|
|
8
|
+
* primitives in this file instead of duplicating focus/escape/scroll logic:
|
|
9
|
+
*
|
|
10
|
+
* - <Portal> renders into document.body (or a custom container).
|
|
11
|
+
* - useReducedMotion() mirrors prefers-reduced-motion.
|
|
12
|
+
* - useOverlayStack() registers the overlay so only the TOPMOST one answers
|
|
13
|
+
* Escape, and nested dialogs stack correctly.
|
|
14
|
+
* - useFocusTrap() cycles Tab/Shift+Tab inside the overlay, moves initial
|
|
15
|
+
* focus in, and restores focus to the invoker on close.
|
|
16
|
+
* - useScrollLock() is counter-based so nested overlays cannot unlock each
|
|
17
|
+
* other's body lock.
|
|
18
|
+
* - useInertBackground() hides the rest of the page from assistive tech
|
|
19
|
+
* (aria-hidden + the native inert attribute where supported).
|
|
20
|
+
* - useOverlay() composes all of the above for modal surfaces.
|
|
21
|
+
*/
|
|
22
|
+
export declare function Portal({ children, container, }: {
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
container?: HTMLElement | null;
|
|
25
|
+
}): React.ReactPortal | null;
|
|
26
|
+
/** True when the user asked the OS for reduced motion. */
|
|
27
|
+
export declare function useReducedMotion(): boolean;
|
|
28
|
+
/** All focusable elements inside root, in DOM order. */
|
|
29
|
+
export declare function getFocusable(root: HTMLElement | null): HTMLElement[];
|
|
30
|
+
/** Register an overlay; returns its stack id. */
|
|
31
|
+
export declare function pushOverlay(element: HTMLElement | null): symbol;
|
|
32
|
+
/** Unregister an overlay by id. */
|
|
33
|
+
export declare function removeOverlay(id: symbol): void;
|
|
34
|
+
/** True when `id` is the topmost registered overlay. */
|
|
35
|
+
export declare function isTopOverlay(id: symbol): boolean;
|
|
36
|
+
/** Number of currently open overlays (for nesting decisions). */
|
|
37
|
+
export declare function overlayCount(): number;
|
|
38
|
+
/**
|
|
39
|
+
* Registers/unregisters an overlay in the stack while `active`.
|
|
40
|
+
* Registration happens in effect order (= mount order = nesting order), so
|
|
41
|
+
* the last-registered open overlay is the topmost. Returns
|
|
42
|
+
* [setElement, isTop] — setElement keeps the stack entry's DOM node current
|
|
43
|
+
* for inert-background exemption.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useOverlayStack(active: boolean): {
|
|
46
|
+
setElement: (el: HTMLElement | null) => void;
|
|
47
|
+
isTop: () => boolean;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Calls onEscape for Escape keydowns while active AND topmost in the overlay
|
|
51
|
+
* stack. Returning false from onEscape marks the key handled-but-blocked
|
|
52
|
+
* (e.g. the Modal shake) and stops the event from leaking to lower overlays.
|
|
53
|
+
*/
|
|
54
|
+
export declare function useEscapeKey(active: boolean, isTop: () => boolean, onEscape: () => boolean | void): void;
|
|
55
|
+
/** Locks body scroll while active. Nest-safe: the last overlay to unlock wins. */
|
|
56
|
+
export declare function useScrollLock(active: boolean): void;
|
|
57
|
+
/**
|
|
58
|
+
* Hides everything outside the overlay element from assistive technology
|
|
59
|
+
* while active. Elements registered as open overlay portals (this overlay
|
|
60
|
+
* and any nested ones) stay reachable. SSR-safe no-op.
|
|
61
|
+
*/
|
|
62
|
+
export declare function useInertBackground(active: boolean, element: HTMLElement | null): void;
|
|
63
|
+
export interface FocusTrapOptions {
|
|
64
|
+
active: boolean;
|
|
65
|
+
/** Container to trap inside. */
|
|
66
|
+
container: HTMLElement | null;
|
|
67
|
+
/** Focus target on activation: a ref, "first" focusable, or the container. */
|
|
68
|
+
initialFocus?: React.RefObject<HTMLElement | null> | "first" | "container" | false;
|
|
69
|
+
/** Return focus to the pre-open active element on deactivate. */
|
|
70
|
+
restoreFocus?: boolean;
|
|
71
|
+
}
|
|
72
|
+
export declare function useFocusTrap({ active, container, initialFocus, restoreFocus }: FocusTrapOptions): void;
|
|
73
|
+
export interface UseOverlayOptions {
|
|
74
|
+
open: boolean;
|
|
75
|
+
/** Escape behavior; return false to block (e.g. shake). Default closes via onEscape. */
|
|
76
|
+
onEscape?: () => boolean | void;
|
|
77
|
+
/** Modal: trap focus, lock scroll, inert the background. Default true. */
|
|
78
|
+
modal?: boolean;
|
|
79
|
+
initialFocus?: React.RefObject<HTMLElement | null> | "first" | "container" | false;
|
|
80
|
+
restoreFocus?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The composite hook for modal overlays: stack registration, topmost-only
|
|
84
|
+
* Escape, scroll locking, background inertness, focus trapping, initial
|
|
85
|
+
* focus and focus restoration. Returns props to spread on the portaled
|
|
86
|
+
* wrapper element.
|
|
87
|
+
*/
|
|
88
|
+
export declare function useOverlay({ open, onEscape, modal, initialFocus, restoreFocus, }: UseOverlayOptions): {
|
|
89
|
+
ref: (el: HTMLElement | null) => void;
|
|
90
|
+
element: HTMLElement | null;
|
|
91
|
+
top: () => boolean;
|
|
92
|
+
};
|
|
93
|
+
export declare const overlayPropsMeta: PropsMeta;
|