@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
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { PropsMeta } from './props-meta';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* DatePicker / DateRangePicker: a text trigger opening a Calendar popover.
|
|
5
|
+
* Values stay plain strings — "YYYY-MM-DD" by default, or
|
|
6
|
+
* "YYYY-MM-DD HH:mm(:ss)" with timepicker on — so they remain
|
|
7
|
+
* native-input compatible with no date library. The trigger is
|
|
8
|
+
* keyboard-operable (Enter/ArrowDown opens, Escape topmost closes and
|
|
9
|
+
* refocuses, typing a full value commits); clicking outside dismisses.
|
|
10
|
+
* The range picker anchors on the start date, supports a maxRange cap
|
|
11
|
+
* ("90d", "12w", "3m", "1y", or a plain number of days), and restarts
|
|
12
|
+
* when the picked end precedes the start.
|
|
13
|
+
*/
|
|
14
|
+
export interface DatePickerProps {
|
|
15
|
+
value?: string;
|
|
16
|
+
defaultValue?: string;
|
|
17
|
+
onChange?: (date: string) => void;
|
|
18
|
+
min?: string;
|
|
19
|
+
max?: string;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
className?: string;
|
|
23
|
+
/** Accessible label for the trigger input. */
|
|
24
|
+
ariaLabel?: string;
|
|
25
|
+
/** Include a time panel; values become "YYYY-MM-DD HH:mm(:ss)". Default false. */
|
|
26
|
+
timepicker?: boolean;
|
|
27
|
+
/** Seconds column for the time panel (requires timepicker). */
|
|
28
|
+
seconds?: boolean;
|
|
29
|
+
/** Minute step for the time panel (requires timepicker). */
|
|
30
|
+
minuteStep?: number;
|
|
31
|
+
}
|
|
32
|
+
export declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLInputElement>>;
|
|
33
|
+
export interface DateRange {
|
|
34
|
+
from?: string;
|
|
35
|
+
to?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* maxRange caps the span between from and to. Accept a plain number of
|
|
39
|
+
* days, or a string with a unit: "90d" days, "12w" weeks, "3m" months
|
|
40
|
+
* (calendar-aware), "1y" years.
|
|
41
|
+
*/
|
|
42
|
+
export type MaxRange = number | `${number}d` | `${number}w` | `${number}m` | `${number}y` | (string & {});
|
|
43
|
+
export interface DateRangePickerProps {
|
|
44
|
+
value?: DateRange;
|
|
45
|
+
defaultValue?: DateRange;
|
|
46
|
+
onChange?: (range: DateRange) => void;
|
|
47
|
+
min?: string;
|
|
48
|
+
max?: string;
|
|
49
|
+
/** Cap the selectable span, e.g. 90, "90d", "12w", "3m", "1y". */
|
|
50
|
+
maxRange?: MaxRange;
|
|
51
|
+
placeholder?: string;
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
className?: string;
|
|
54
|
+
ariaLabel?: string;
|
|
55
|
+
/** Include time panels; values become "YYYY-MM-DD HH:mm(:ss)". Default false. */
|
|
56
|
+
timepicker?: boolean;
|
|
57
|
+
seconds?: boolean;
|
|
58
|
+
minuteStep?: number;
|
|
59
|
+
}
|
|
60
|
+
export declare const DateRangePicker: React.ForwardRefExoticComponent<DateRangePickerProps & React.RefAttributes<HTMLInputElement>>;
|
|
61
|
+
export declare const datePickerPropsMeta: PropsMeta;
|
|
62
|
+
export declare const dateRangePickerPropsMeta: PropsMeta;
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { jsxs as h, Fragment as G, jsx as r } from "react/jsx-runtime";
|
|
2
|
+
import * as b from "react";
|
|
3
|
+
import { Clock as J, CalendarDays as Q } from "lucide-react";
|
|
4
|
+
import { cn as V } from "./cn.js";
|
|
5
|
+
import { Portal as W, useOverlayStack as te, useEscapeKey as re } from "./overlay.js";
|
|
6
|
+
import { useAnchoredPosition as ae } from "./anchor.js";
|
|
7
|
+
import { Calendar as X, fromDateKey as ne } from "./calendar.js";
|
|
8
|
+
import { TimePanel as U } from "./time-picker.js";
|
|
9
|
+
import { usePruiI18n as oe } from "../i18n.js";
|
|
10
|
+
const ie = /^\d{4}-\d{2}-\d{2}$/, le = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?$/;
|
|
11
|
+
function _(c, o) {
|
|
12
|
+
if (!c) return { date: "", time: o ? "00:00" : "" };
|
|
13
|
+
const [s, i] = c.split(" ");
|
|
14
|
+
return { date: s ?? "", time: o ? i ?? "00:00" : i ?? "" };
|
|
15
|
+
}
|
|
16
|
+
function Z(c, o, s) {
|
|
17
|
+
const { setElement: i, isTop: f } = te(o);
|
|
18
|
+
re(o, f, s);
|
|
19
|
+
const { ref: l, position: g } = ae({ active: o, anchorRef: c, side: "bottom", align: "start", offsetHeight: 380 });
|
|
20
|
+
return b.useEffect(() => {
|
|
21
|
+
if (!o) return;
|
|
22
|
+
const M = (R) => {
|
|
23
|
+
var u;
|
|
24
|
+
const D = R.target;
|
|
25
|
+
(u = c.current) != null && u.contains(D) || (!(D instanceof Element) || !D.closest("[data-prui-picker-panel]")) && s();
|
|
26
|
+
};
|
|
27
|
+
return document.addEventListener("mousedown", M), () => document.removeEventListener("mousedown", M);
|
|
28
|
+
}), { setElement: i, floatingRef: l, position: g };
|
|
29
|
+
}
|
|
30
|
+
const de = b.forwardRef(function({
|
|
31
|
+
value: o,
|
|
32
|
+
defaultValue: s,
|
|
33
|
+
onChange: i,
|
|
34
|
+
min: f,
|
|
35
|
+
max: l,
|
|
36
|
+
placeholder: g,
|
|
37
|
+
disabled: M,
|
|
38
|
+
className: R,
|
|
39
|
+
ariaLabel: D,
|
|
40
|
+
timepicker: u = !1,
|
|
41
|
+
seconds: m = !1,
|
|
42
|
+
minuteStep: H
|
|
43
|
+
}, N) {
|
|
44
|
+
const E = g ?? (u ? "YYYY-MM-DD HH:mm" : "YYYY-MM-DD"), [y, j] = b.useState(s ?? ""), C = o !== void 0, T = C ? o : y, [$, d] = b.useState(!1), x = b.useRef(null), [Y, w] = b.useState(""), { date: k, time: F } = _(T, u), O = x, { setElement: I, floatingRef: K, position: v } = Z(O, $, () => {
|
|
45
|
+
var n;
|
|
46
|
+
d(!1), (n = x.current) == null || n.focus();
|
|
47
|
+
}), a = (n) => {
|
|
48
|
+
var p;
|
|
49
|
+
C || j(n), i == null || i(n), u || (d(!1), (p = x.current) == null || p.focus());
|
|
50
|
+
}, t = (n) => {
|
|
51
|
+
a(u ? `${n} ${F || "00:00"}` : n);
|
|
52
|
+
}, P = (n) => {
|
|
53
|
+
k && a(`${k} ${n}`);
|
|
54
|
+
};
|
|
55
|
+
return /* @__PURE__ */ h(G, { children: [
|
|
56
|
+
/* @__PURE__ */ r(
|
|
57
|
+
"input",
|
|
58
|
+
{
|
|
59
|
+
ref: (n) => {
|
|
60
|
+
x.current = n, typeof N == "function" ? N(n) : N && (N.current = n);
|
|
61
|
+
},
|
|
62
|
+
type: "text",
|
|
63
|
+
readOnly: !0,
|
|
64
|
+
role: "combobox",
|
|
65
|
+
"aria-expanded": $,
|
|
66
|
+
"aria-haspopup": "dialog",
|
|
67
|
+
"aria-label": D,
|
|
68
|
+
placeholder: E,
|
|
69
|
+
disabled: M,
|
|
70
|
+
value: Y !== "" ? Y : T,
|
|
71
|
+
onClick: () => d(!0),
|
|
72
|
+
onFocus: () => {
|
|
73
|
+
!M && !$ && d(!0);
|
|
74
|
+
},
|
|
75
|
+
onChange: (n) => {
|
|
76
|
+
const p = n.target.value;
|
|
77
|
+
w(p), (u ? le.test(p) : ie.test(p)) && (w(""), a(p));
|
|
78
|
+
},
|
|
79
|
+
className: V(
|
|
80
|
+
"prui-date-picker h-9 w-full cursor-pointer rounded-[var(--prui-radius)] border border-[var(--prui-line)]",
|
|
81
|
+
"bg-[var(--prui-background)] px-3 pr-8 text-sm text-[var(--prui-fg)] placeholder:text-[var(--prui-dim)]",
|
|
82
|
+
"outline-none transition-colors focus:border-[var(--prui-brand)] focus:ring-2 focus:ring-[var(--prui-brand)]/30",
|
|
83
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
84
|
+
R
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
u ? /* @__PURE__ */ r(J, { className: "pointer-events-none -ml-7 h-4 w-4 text-[var(--prui-dim)]", "aria-hidden": !0 }) : /* @__PURE__ */ r(Q, { className: "pointer-events-none -ml-7 h-4 w-4 text-[var(--prui-dim)]", "aria-hidden": !0 }),
|
|
89
|
+
$ ? /* @__PURE__ */ r(W, { children: /* @__PURE__ */ r(
|
|
90
|
+
"div",
|
|
91
|
+
{
|
|
92
|
+
ref: (n) => {
|
|
93
|
+
K(n), I(n);
|
|
94
|
+
},
|
|
95
|
+
role: "dialog",
|
|
96
|
+
"aria-label": D ?? "Choose date",
|
|
97
|
+
"data-prui-picker-panel": !0,
|
|
98
|
+
className: "fixed z-[var(--prui-z-overlay)] rounded-[var(--prui-radius)] border border-[var(--prui-line)] bg-[var(--prui-surface)] p-1 shadow-[var(--prui-shadow-lg)]",
|
|
99
|
+
style: { top: (v == null ? void 0 : v.top) ?? -9999, left: (v == null ? void 0 : v.left) ?? -9999 },
|
|
100
|
+
children: /* @__PURE__ */ h("div", { className: V("flex gap-2", u && "p-1"), children: [
|
|
101
|
+
/* @__PURE__ */ r(
|
|
102
|
+
X,
|
|
103
|
+
{
|
|
104
|
+
value: k || void 0,
|
|
105
|
+
onSelect: t,
|
|
106
|
+
min: f ? f.slice(0, 10) : void 0,
|
|
107
|
+
max: l ? l.slice(0, 10) : void 0,
|
|
108
|
+
showToday: !1,
|
|
109
|
+
className: "border-0 shadow-none"
|
|
110
|
+
}
|
|
111
|
+
),
|
|
112
|
+
u ? /* @__PURE__ */ r("div", { className: "flex flex-col gap-1 border-l border-[var(--prui-line)] pl-2", children: /* @__PURE__ */ r(U, { value: F, onSelect: P, seconds: m, minuteStep: H }) }) : null
|
|
113
|
+
] })
|
|
114
|
+
}
|
|
115
|
+
) }) : null
|
|
116
|
+
] });
|
|
117
|
+
});
|
|
118
|
+
de.displayName = "DatePicker";
|
|
119
|
+
function se(c, o) {
|
|
120
|
+
const s = typeof o == "string" ? /^(\d+)([dwmy])$/i.exec(o.trim()) : null, i = Number(s ? s[1] : o), f = s ? s[2].toLowerCase() : "d", l = new Date(c);
|
|
121
|
+
return f === "d" ? l.setDate(l.getDate() + i) : f === "w" ? l.setDate(l.getDate() + i * 7) : f === "m" ? l.setMonth(l.getMonth() + i) : l.setFullYear(l.getFullYear() + i), l;
|
|
122
|
+
}
|
|
123
|
+
function A(c, o) {
|
|
124
|
+
const s = se(ne(c), o), i = s.getFullYear(), f = String(s.getMonth() + 1).padStart(2, "0"), l = String(s.getDate()).padStart(2, "0");
|
|
125
|
+
return `${i}-${f}-${l}`;
|
|
126
|
+
}
|
|
127
|
+
function B(c) {
|
|
128
|
+
return c ? c.slice(0, 10) : void 0;
|
|
129
|
+
}
|
|
130
|
+
const ce = b.forwardRef(function({
|
|
131
|
+
value: o,
|
|
132
|
+
defaultValue: s,
|
|
133
|
+
onChange: i,
|
|
134
|
+
min: f,
|
|
135
|
+
max: l,
|
|
136
|
+
maxRange: g,
|
|
137
|
+
placeholder: M,
|
|
138
|
+
disabled: R,
|
|
139
|
+
className: D,
|
|
140
|
+
ariaLabel: u,
|
|
141
|
+
timepicker: m = !1,
|
|
142
|
+
seconds: H = !1,
|
|
143
|
+
minuteStep: N
|
|
144
|
+
}, E) {
|
|
145
|
+
const { t: y } = oe(), j = M ?? (m ? "YYYY-MM-DD HH:mm – YYYY-MM-DD HH:mm" : "YYYY-MM-DD – YYYY-MM-DD"), [C, T] = b.useState(s ?? {}), $ = o !== void 0, d = $ ? o : C, [x, Y] = b.useState(!1), w = b.useRef(null), k = w, [F, O] = b.useState(void 0), { setElement: I, floatingRef: K, position: v } = Z(k, x, () => {
|
|
146
|
+
var e;
|
|
147
|
+
Y(!1), (e = w.current) == null || e.focus();
|
|
148
|
+
});
|
|
149
|
+
b.useEffect(() => {
|
|
150
|
+
x && O(d.from ? d.from.slice(0, 7) : void 0);
|
|
151
|
+
}, [x, d.from === void 0]);
|
|
152
|
+
const a = d.from ? _(d.from, m) : void 0, t = d.to ? _(d.to, m) : void 0, P = (a == null ? void 0 : a.date) ?? "", n = b.useCallback(
|
|
153
|
+
(e) => !g || !P || t != null && t.date ? !1 : e > A(P, g),
|
|
154
|
+
[g, P, t == null ? void 0 : t.date]
|
|
155
|
+
), p = (e) => {
|
|
156
|
+
$ || T(e), i == null || i(e);
|
|
157
|
+
}, ee = (e) => {
|
|
158
|
+
var z;
|
|
159
|
+
if (!a || a.date && (t != null && t.date)) {
|
|
160
|
+
p({ from: m ? `${e} 00:00` : e });
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (e < a.date) {
|
|
164
|
+
p({ from: m ? `${e} 00:00` : e });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (g && e > A(a.date, g)) {
|
|
168
|
+
const S = A(a.date, g);
|
|
169
|
+
p({ from: d.from, to: m ? `${S} ${(t == null ? void 0 : t.time) ?? "23:59"}` : S });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
p({ from: d.from, to: m ? `${e} ${(t == null ? void 0 : t.time) ?? "23:59"}` : e }), m || (Y(!1), (z = w.current) == null || z.focus());
|
|
173
|
+
}, L = (e, z) => {
|
|
174
|
+
const S = e === "from" ? a : t;
|
|
175
|
+
S != null && S.date && p({ ...d, [e]: `${S.date} ${z}` });
|
|
176
|
+
}, q = a ? t ? `${d.from} – ${d.to}` : `${d.from} – …` : "";
|
|
177
|
+
return /* @__PURE__ */ h(G, { children: [
|
|
178
|
+
/* @__PURE__ */ r(
|
|
179
|
+
"input",
|
|
180
|
+
{
|
|
181
|
+
ref: (e) => {
|
|
182
|
+
w.current = e, typeof E == "function" ? E(e) : E && (E.current = e);
|
|
183
|
+
},
|
|
184
|
+
type: "text",
|
|
185
|
+
readOnly: !0,
|
|
186
|
+
role: "combobox",
|
|
187
|
+
"aria-expanded": x,
|
|
188
|
+
"aria-haspopup": "dialog",
|
|
189
|
+
"aria-label": u,
|
|
190
|
+
placeholder: j,
|
|
191
|
+
disabled: R,
|
|
192
|
+
value: q,
|
|
193
|
+
onClick: () => Y(!0),
|
|
194
|
+
onFocus: () => {
|
|
195
|
+
!R && !x && Y(!0);
|
|
196
|
+
},
|
|
197
|
+
className: V(
|
|
198
|
+
"prui-date-range-picker h-9 w-full cursor-pointer rounded-[var(--prui-radius)] border border-[var(--prui-line)]",
|
|
199
|
+
"bg-[var(--prui-background)] px-3 pr-8 text-sm text-[var(--prui-fg)] placeholder:text-[var(--prui-dim)]",
|
|
200
|
+
"outline-none transition-colors focus:border-[var(--prui-brand)] focus:ring-2 focus:ring-[var(--prui-brand)]/30",
|
|
201
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
202
|
+
D
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
),
|
|
206
|
+
m ? /* @__PURE__ */ r(J, { className: "pointer-events-none -ml-7 h-4 w-4 text-[var(--prui-dim)]", "aria-hidden": !0 }) : /* @__PURE__ */ r(Q, { className: "pointer-events-none -ml-7 h-4 w-4 text-[var(--prui-dim)]", "aria-hidden": !0 }),
|
|
207
|
+
x ? /* @__PURE__ */ r(W, { children: /* @__PURE__ */ r(
|
|
208
|
+
"div",
|
|
209
|
+
{
|
|
210
|
+
ref: (e) => {
|
|
211
|
+
K(e), I(e);
|
|
212
|
+
},
|
|
213
|
+
role: "dialog",
|
|
214
|
+
"aria-label": u ?? "Choose date range",
|
|
215
|
+
"data-prui-picker-panel": !0,
|
|
216
|
+
className: "fixed z-[var(--prui-z-overlay)] rounded-[var(--prui-radius)] border border-[var(--prui-line)] bg-[var(--prui-surface)] shadow-[var(--prui-shadow-lg)]",
|
|
217
|
+
style: { top: (v == null ? void 0 : v.top) ?? -9999, left: (v == null ? void 0 : v.left) ?? -9999 },
|
|
218
|
+
children: /* @__PURE__ */ h("div", { className: V("flex gap-2 p-1", m && "p-2"), children: [
|
|
219
|
+
/* @__PURE__ */ h("div", { children: [
|
|
220
|
+
/* @__PURE__ */ r("div", { className: "px-1 pb-1 pt-1 text-[10px] font-semibold uppercase tracking-wide text-[var(--prui-dim)]", children: y.from }),
|
|
221
|
+
/* @__PURE__ */ r(
|
|
222
|
+
X,
|
|
223
|
+
{
|
|
224
|
+
value: a == null ? void 0 : a.date,
|
|
225
|
+
month: F,
|
|
226
|
+
onMonthChange: O,
|
|
227
|
+
onSelect: ee,
|
|
228
|
+
min: f ? B(f) : void 0,
|
|
229
|
+
max: l ? B(l) : g && P && !(t != null && t.date) ? A(P, g) : void 0,
|
|
230
|
+
disabled: n,
|
|
231
|
+
showToday: !1,
|
|
232
|
+
className: "border-0 shadow-none"
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
] }),
|
|
236
|
+
/* @__PURE__ */ h("div", { className: "flex flex-col gap-1 border-l border-[var(--prui-line)] pl-2", children: [
|
|
237
|
+
m ? /* @__PURE__ */ h("div", { children: [
|
|
238
|
+
/* @__PURE__ */ r("div", { className: "mb-1 px-1 text-[10px] font-semibold uppercase tracking-wide text-[var(--prui-dim)]", children: y.time }),
|
|
239
|
+
/* @__PURE__ */ h("div", { className: "flex gap-2", children: [
|
|
240
|
+
/* @__PURE__ */ h("div", { children: [
|
|
241
|
+
/* @__PURE__ */ r("div", { className: "mb-1 px-1 text-[10px] font-semibold uppercase tracking-wide text-[var(--prui-dim)]", children: y.from }),
|
|
242
|
+
/* @__PURE__ */ r(U, { compact: !0, value: a == null ? void 0 : a.time, onSelect: (e) => L("from", e), seconds: H, minuteStep: N })
|
|
243
|
+
] }),
|
|
244
|
+
/* @__PURE__ */ h("div", { children: [
|
|
245
|
+
/* @__PURE__ */ r("div", { className: "mb-1 px-1 text-[10px] font-semibold uppercase tracking-wide text-[var(--prui-dim)]", children: y.to }),
|
|
246
|
+
/* @__PURE__ */ r(U, { compact: !0, value: t == null ? void 0 : t.time, onSelect: (e) => L("to", e), seconds: H, minuteStep: N })
|
|
247
|
+
] })
|
|
248
|
+
] })
|
|
249
|
+
] }) : null,
|
|
250
|
+
/* @__PURE__ */ h("div", { className: "mt-auto flex items-center justify-between gap-2 border-t border-[var(--prui-line)] px-1 pb-1 pt-2 text-xs text-[var(--prui-dim)]", children: [
|
|
251
|
+
/* @__PURE__ */ r("span", { "data-testid": "range-label", children: q || y.today }),
|
|
252
|
+
/* @__PURE__ */ h("div", { className: "flex gap-1", children: [
|
|
253
|
+
/* @__PURE__ */ r(
|
|
254
|
+
"button",
|
|
255
|
+
{
|
|
256
|
+
type: "button",
|
|
257
|
+
onClick: () => p({}),
|
|
258
|
+
className: "cursor-pointer rounded-[var(--prui-radius-1)] px-2 py-1 transition-colors hover:bg-[var(--prui-raise)]",
|
|
259
|
+
children: y.clear
|
|
260
|
+
}
|
|
261
|
+
),
|
|
262
|
+
/* @__PURE__ */ r(
|
|
263
|
+
"button",
|
|
264
|
+
{
|
|
265
|
+
type: "button",
|
|
266
|
+
onClick: () => {
|
|
267
|
+
var e;
|
|
268
|
+
Y(!1), (e = w.current) == null || e.focus();
|
|
269
|
+
},
|
|
270
|
+
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",
|
|
271
|
+
children: y.apply
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
] })
|
|
275
|
+
] })
|
|
276
|
+
] })
|
|
277
|
+
] })
|
|
278
|
+
}
|
|
279
|
+
) }) : null
|
|
280
|
+
] });
|
|
281
|
+
});
|
|
282
|
+
ce.displayName = "DateRangePicker";
|
|
283
|
+
const xe = {
|
|
284
|
+
name: "DatePicker",
|
|
285
|
+
props: [
|
|
286
|
+
{ name: "value", type: "string 'YYYY-MM-DD' | 'YYYY-MM-DD HH:mm'", default: "undefined", control: "date" },
|
|
287
|
+
{ name: "defaultValue", type: "string", default: "undefined", control: "date" },
|
|
288
|
+
{ name: "onChange", type: "(date: string) => void", default: null, control: "none" },
|
|
289
|
+
{ name: "min", type: "string", default: "undefined", control: "date" },
|
|
290
|
+
{ name: "max", type: "string", default: "undefined", control: "date" },
|
|
291
|
+
{ name: "timepicker", type: "boolean", default: "false", control: "boolean", description: "Adds a time panel; values become 'YYYY-MM-DD HH:mm(:ss)'." },
|
|
292
|
+
{ name: "seconds", type: "boolean", default: "false", control: "boolean", description: "Seconds column (needs timepicker)." },
|
|
293
|
+
{ name: "minuteStep", type: "number", default: "1", control: "number", description: "Minute step (needs timepicker)." }
|
|
294
|
+
]
|
|
295
|
+
}, ye = {
|
|
296
|
+
name: "DateRangePicker",
|
|
297
|
+
props: [
|
|
298
|
+
{ name: "value", type: "{ from?: string, to?: string }", default: "{}", control: "daterange" },
|
|
299
|
+
{ name: "defaultValue", type: "{ from?: string, to?: string }", default: "{}", control: "daterange" },
|
|
300
|
+
{ name: "onChange", type: "(range: DateRange) => void", default: null, control: "none" },
|
|
301
|
+
{ name: "min", type: "string", default: "undefined", control: "date" },
|
|
302
|
+
{ name: "max", type: "string", default: "undefined", control: "date" },
|
|
303
|
+
{ name: "maxRange", type: "number | '90d' | '12w' | '3m' | '1y'", default: "undefined", control: "text", description: "Caps the selectable span; days beyond from+maxRange are disabled." },
|
|
304
|
+
{ name: "timepicker", type: "boolean", default: "false", control: "boolean" },
|
|
305
|
+
{ name: "seconds", type: "boolean", default: "false", control: "boolean" },
|
|
306
|
+
{ name: "minuteStep", type: "number", default: "1", control: "number" }
|
|
307
|
+
]
|
|
308
|
+
};
|
|
309
|
+
export {
|
|
310
|
+
de as DatePicker,
|
|
311
|
+
ce as DateRangePicker,
|
|
312
|
+
xe as datePickerPropsMeta,
|
|
313
|
+
ye as dateRangePickerPropsMeta
|
|
314
|
+
};
|
package/dist/core/dialog.d.ts
CHANGED
|
@@ -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,10 +22,19 @@ 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;
|
|
22
30
|
export declare const DialogTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLHeadingElement>>;
|
|
31
|
+
export interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
32
|
+
/** Remove the default vertical padding (keeps horizontal). */
|
|
33
|
+
flush?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** Padded content area for DialogContent: consistent x/y gutters. */
|
|
36
|
+
export declare const DialogBody: React.ForwardRefExoticComponent<DialogBodyProps & React.RefAttributes<HTMLDivElement>>;
|
|
23
37
|
export declare const DialogDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
24
38
|
export declare const DialogFooter: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
|
|
25
39
|
export declare const dialogPropsMeta: PropsMeta;
|
|
40
|
+
export declare const dialogBodyPropsMeta: PropsMeta;
|
package/dist/core/dialog.js
CHANGED
|
@@ -1,102 +1,119 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import * as
|
|
3
|
-
import { X as
|
|
4
|
-
import { cn as
|
|
5
|
-
|
|
1
|
+
import { jsx as r, jsxs as x } from "react/jsx-runtime";
|
|
2
|
+
import * as t from "react";
|
|
3
|
+
import { X as D } from "lucide-react";
|
|
4
|
+
import { cn as i } from "./cn.js";
|
|
5
|
+
import { useOverlay as h, Portal as N } from "./overlay.js";
|
|
6
|
+
import { usePruiI18n as w } from "../i18n.js";
|
|
7
|
+
const g = t.createContext(null);
|
|
6
8
|
function v() {
|
|
7
|
-
const e =
|
|
9
|
+
const e = t.useContext(g);
|
|
8
10
|
if (!e) throw new Error("Dialog parts must be used inside <Dialog>");
|
|
9
11
|
return e;
|
|
10
12
|
}
|
|
11
|
-
const
|
|
12
|
-
const [
|
|
13
|
-
|
|
13
|
+
const R = ({ open: e, defaultOpen: o = !1, onOpenChange: a, children: l }) => {
|
|
14
|
+
const [u, c] = t.useState(o), s = e !== void 0, f = s ? e : u, d = t.useId(), n = (p) => {
|
|
15
|
+
s || c(p), a == null || a(p);
|
|
14
16
|
};
|
|
15
|
-
return /* @__PURE__ */
|
|
17
|
+
return /* @__PURE__ */ r(g.Provider, { value: { open: f, setOpen: n, labelId: d }, children: l });
|
|
16
18
|
};
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
({ className: e, children: o, ariaLabel:
|
|
20
|
-
const { open:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
R.displayName = "Dialog";
|
|
20
|
+
const I = t.forwardRef(
|
|
21
|
+
({ className: e, children: o, ariaLabel: a, hideClose: l, initialFocus: u = "first", onClick: c, ...s }, f) => {
|
|
22
|
+
const { open: d, setOpen: n, labelId: p } = v(), { t: b } = w(), { ref: y } = h({
|
|
23
|
+
open: d,
|
|
24
|
+
onEscape: () => n(!1),
|
|
25
|
+
initialFocus: u
|
|
26
|
+
});
|
|
27
|
+
return d ? /* @__PURE__ */ r(N, { children: /* @__PURE__ */ r("div", { ref: y, children: /* @__PURE__ */ r(
|
|
32
28
|
"div",
|
|
33
29
|
{
|
|
34
|
-
className: "prui-dialog-overlay fixed inset-0 z-
|
|
35
|
-
style: { backgroundColor: "
|
|
36
|
-
onMouseDown: (
|
|
37
|
-
|
|
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 && n(!1);
|
|
38
34
|
},
|
|
39
|
-
children: /* @__PURE__ */
|
|
35
|
+
children: /* @__PURE__ */ x(
|
|
40
36
|
"div",
|
|
41
37
|
{
|
|
42
|
-
ref:
|
|
38
|
+
ref: f,
|
|
43
39
|
role: "dialog",
|
|
44
40
|
"aria-modal": "true",
|
|
45
|
-
"aria-label":
|
|
46
|
-
"aria-labelledby":
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
41
|
+
"aria-label": a,
|
|
42
|
+
"aria-labelledby": a ? void 0 : p,
|
|
43
|
+
tabIndex: -1,
|
|
44
|
+
className: i(
|
|
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
50
|
onClick: c,
|
|
54
|
-
...
|
|
51
|
+
...s,
|
|
55
52
|
children: [
|
|
56
53
|
o,
|
|
57
|
-
|
|
54
|
+
l ? null : /* @__PURE__ */ r(
|
|
58
55
|
"button",
|
|
59
56
|
{
|
|
60
57
|
type: "button",
|
|
61
|
-
"aria-label":
|
|
62
|
-
onClick: () =>
|
|
58
|
+
"aria-label": b.close,
|
|
59
|
+
onClick: () => n(!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__ */
|
|
61
|
+
children: /* @__PURE__ */ r(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
|
-
|
|
75
|
-
const
|
|
76
|
-
({ className: e, ...o },
|
|
77
|
-
const { labelId:
|
|
78
|
-
return /* @__PURE__ */
|
|
71
|
+
I.displayName = "DialogContent";
|
|
72
|
+
const E = ({ className: e, ...o }) => /* @__PURE__ */ r("div", { className: i("prui-dialog-header flex flex-col gap-1 p-4 pb-2", e), ...o }), C = t.forwardRef(
|
|
73
|
+
({ className: e, ...o }, a) => {
|
|
74
|
+
const { labelId: l } = v();
|
|
75
|
+
return /* @__PURE__ */ r("h2", { ref: a, id: l, className: i("prui-dialog-title text-base font-semibold text-[var(--prui-fg)]", e), ...o });
|
|
79
76
|
}
|
|
80
77
|
);
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
({ className: e,
|
|
78
|
+
C.displayName = "DialogTitle";
|
|
79
|
+
const j = t.forwardRef(
|
|
80
|
+
({ className: e, flush: o, ...a }, l) => /* @__PURE__ */ r(
|
|
81
|
+
"div",
|
|
82
|
+
{
|
|
83
|
+
ref: l,
|
|
84
|
+
className: i("prui-dialog-body px-4", o ? "pt-0 pb-0" : "pt-1 pb-4", e),
|
|
85
|
+
...a
|
|
86
|
+
}
|
|
87
|
+
)
|
|
84
88
|
);
|
|
85
|
-
|
|
86
|
-
const
|
|
89
|
+
j.displayName = "DialogBody";
|
|
90
|
+
const z = t.forwardRef(
|
|
91
|
+
({ className: e, ...o }, a) => /* @__PURE__ */ r("p", { ref: a, className: i("prui-dialog-description text-sm text-[var(--prui-dim)]", e), ...o })
|
|
92
|
+
);
|
|
93
|
+
z.displayName = "DialogDescription";
|
|
94
|
+
const F = ({ className: e, ...o }) => /* @__PURE__ */ r("div", { className: i("prui-dialog-footer flex items-center justify-end gap-2 p-4 pt-2", e), ...o }), H = {
|
|
87
95
|
name: "Dialog",
|
|
88
96
|
props: [
|
|
89
97
|
{ name: "open", type: "boolean", default: "undefined", control: "boolean" },
|
|
90
98
|
{ name: "defaultOpen", type: "boolean", default: "false", control: "boolean" },
|
|
91
|
-
{ name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" }
|
|
99
|
+
{ name: "onOpenChange", type: "(open: boolean) => void", default: null, control: "none" },
|
|
100
|
+
{ name: "initialFocus", type: 'ref | "first" | "container" | false', default: '"first"', control: "none" }
|
|
101
|
+
]
|
|
102
|
+
}, O = {
|
|
103
|
+
name: "DialogBody",
|
|
104
|
+
props: [
|
|
105
|
+
{ name: "flush", type: "boolean", default: "false", control: "boolean", description: "Remove vertical padding." },
|
|
106
|
+
{ name: "className", type: "string", default: "undefined", control: "text" }
|
|
92
107
|
]
|
|
93
108
|
};
|
|
94
109
|
export {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
110
|
+
R as Dialog,
|
|
111
|
+
j as DialogBody,
|
|
112
|
+
I as DialogContent,
|
|
113
|
+
z as DialogDescription,
|
|
114
|
+
F as DialogFooter,
|
|
115
|
+
E as DialogHeader,
|
|
116
|
+
C as DialogTitle,
|
|
117
|
+
O as dialogBodyPropsMeta,
|
|
118
|
+
H as dialogPropsMeta
|
|
102
119
|
};
|
|
@@ -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;
|