@diwauhris/ui 1.7.4 → 1.7.7
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/README.md +24 -64
- package/lib/assets/ui.css +189 -7
- package/lib/index.cjs +935 -340
- package/lib/index.mjs +935 -340
- package/lib/types/lib/composeRefs.d.ts +9 -0
- package/lib/types/ui-library/gallery/accordion/Accordion.d.ts +1 -1
- package/lib/types/ui-library/gallery/breadcrumb/Breadcrumb.d.ts +2 -1
- package/lib/types/ui-library/gallery/button/Button.d.ts +7 -1
- package/lib/types/ui-library/gallery/card/Card.d.ts +4 -3
- package/lib/types/ui-library/gallery/checkbox/Checkbox.d.ts +3 -1
- package/lib/types/ui-library/gallery/column-manager/ColumnManager.d.ts +2 -1
- package/lib/types/ui-library/gallery/combobox/Combobox.d.ts +14 -7
- package/lib/types/ui-library/gallery/command-palette/CommandPalette.d.ts +3 -1
- package/lib/types/ui-library/gallery/confirm-action/ConfirmAction.d.ts +3 -1
- package/lib/types/ui-library/gallery/confirm-dialog/ConfirmDialog.d.ts +3 -1
- package/lib/types/ui-library/gallery/date-picker/DatePicker.d.ts +3 -1
- package/lib/types/ui-library/gallery/dialog/Dialog.d.ts +9 -1
- package/lib/types/ui-library/gallery/drawer/Drawer.d.ts +3 -1
- package/lib/types/ui-library/gallery/field/Field.d.ts +2 -1
- package/lib/types/ui-library/gallery/field-input/FieldInput.d.ts +3 -1
- package/lib/types/ui-library/gallery/file-upload/FileUpload.d.ts +7 -1
- package/lib/types/ui-library/gallery/icon-button/IconButton.d.ts +6 -1
- package/lib/types/ui-library/gallery/input/Input.d.ts +3 -1
- package/lib/types/ui-library/gallery/menu/Menu.d.ts +7 -1
- package/lib/types/ui-library/gallery/modal/Modal.d.ts +11 -1
- package/lib/types/ui-library/gallery/pagination/Pagination.d.ts +2 -1
- package/lib/types/ui-library/gallery/popover/Popover.d.ts +3 -2
- package/lib/types/ui-library/gallery/radio-group/RadioGroup.d.ts +2 -1
- package/lib/types/ui-library/gallery/search/Search.d.ts +23 -0
- package/lib/types/ui-library/gallery/select/Select.d.ts +13 -1
- package/lib/types/ui-library/gallery/skeleton/Skeleton.d.ts +19 -9
- package/lib/types/ui-library/gallery/stat-card/Statistic.d.ts +2 -1
- package/lib/types/ui-library/gallery/stepper/Stepper.d.ts +3 -1
- package/lib/types/ui-library/gallery/switch/Switch.d.ts +6 -3
- package/lib/types/ui-library/gallery/textarea/Textarea.d.ts +3 -1
- package/lib/types/ui-library/gallery/timeline/Timeline.d.ts +4 -2
- package/lib/types/ui-library/gallery/tooltip/Tooltip.d.ts +8 -6
- package/lib/types/ui-library/index.d.ts +4 -2
- package/package.json +2 -3
package/lib/index.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { cloneElement, createContext, createElement, isValidElement, use, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
3
1
|
import { clsx } from "clsx";
|
|
4
2
|
import { twMerge } from "tailwind-merge";
|
|
5
|
-
import
|
|
3
|
+
import * as React$1 from "react";
|
|
4
|
+
import React, { cloneElement, createContext, createElement, isValidElement, use, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { createPortal } from "react-dom";
|
|
7
|
+
import { AlertCircle, AlertTriangle, Archive, ArchiveRestore, ArrowDown, Ban, CalendarDays, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, Clock, Command, File, Home, Info, Minus, RotateCcw, Search as Search$1, ShieldCheck, TrendingDown, TrendingUp, UploadCloud, X, ZoomIn, ZoomOut } from "lucide-react";
|
|
6
8
|
import Calendar$1 from "react-calendar";
|
|
7
9
|
import { format, isValid, parse } from "date-fns";
|
|
8
10
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
9
|
-
import { createPortal } from "react-dom";
|
|
10
11
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
11
12
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
12
13
|
import { Link } from "react-router-dom";
|
|
@@ -14,17 +15,169 @@ import * as d3 from "d3";
|
|
|
14
15
|
import { Toaster, toast } from "sonner";
|
|
15
16
|
export * from "lucide-react";
|
|
16
17
|
//#region \0rolldown/runtime.js
|
|
17
|
-
var __defProp = Object.defineProperty;
|
|
18
|
+
var __defProp$2 = Object.defineProperty;
|
|
18
19
|
var __exportAll = (all, no_symbols) => {
|
|
19
20
|
let target = {};
|
|
20
|
-
for (var name in all) __defProp(target, name, {
|
|
21
|
+
for (var name in all) __defProp$2(target, name, {
|
|
21
22
|
get: all[name],
|
|
22
23
|
enumerable: true
|
|
23
24
|
});
|
|
24
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
25
|
+
if (!no_symbols) __defProp$2(target, Symbol.toStringTag, { value: "Module" });
|
|
25
26
|
return target;
|
|
26
27
|
};
|
|
27
28
|
//#endregion
|
|
29
|
+
//#region src/lib/utils.ts
|
|
30
|
+
function cn(...inputs) {
|
|
31
|
+
return twMerge(clsx(inputs));
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region node_modules/@radix-ui/react-compose-refs/dist/index.mjs
|
|
35
|
+
var __defProp$1 = Object.defineProperty;
|
|
36
|
+
var __name$1 = (target, value) => __defProp$1(target, "name", {
|
|
37
|
+
value,
|
|
38
|
+
configurable: true
|
|
39
|
+
});
|
|
40
|
+
function setRef(ref, value) {
|
|
41
|
+
if (typeof ref === "function") return ref(value);
|
|
42
|
+
else if (ref !== null && ref !== void 0) ref.current = value;
|
|
43
|
+
}
|
|
44
|
+
__name$1(setRef, "setRef");
|
|
45
|
+
function composeRefs$1(...refs) {
|
|
46
|
+
return (node) => {
|
|
47
|
+
let hasCleanup = false;
|
|
48
|
+
const cleanups = refs.map((ref) => {
|
|
49
|
+
const cleanup = setRef(ref, node);
|
|
50
|
+
if (!hasCleanup && typeof cleanup == "function") hasCleanup = true;
|
|
51
|
+
return cleanup;
|
|
52
|
+
});
|
|
53
|
+
if (hasCleanup) return () => {
|
|
54
|
+
for (let i = 0; i < cleanups.length; i++) {
|
|
55
|
+
const cleanup = cleanups[i];
|
|
56
|
+
if (typeof cleanup == "function") cleanup();
|
|
57
|
+
else setRef(refs[i], null);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
__name$1(composeRefs$1, "composeRefs");
|
|
63
|
+
function useComposedRefs(...refs) {
|
|
64
|
+
return React$1.useCallback(composeRefs$1(...refs), refs);
|
|
65
|
+
}
|
|
66
|
+
__name$1(useComposedRefs, "useComposedRefs");
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region node_modules/@radix-ui/react-slot/dist/index.mjs
|
|
69
|
+
var __defProp = Object.defineProperty;
|
|
70
|
+
var __name = (target, value) => __defProp(target, "name", {
|
|
71
|
+
value,
|
|
72
|
+
configurable: true
|
|
73
|
+
});
|
|
74
|
+
// @__NO_SIDE_EFFECTS__
|
|
75
|
+
function createSlot(ownerName) {
|
|
76
|
+
const Slot2 = React$1.forwardRef((props, forwardedRef) => {
|
|
77
|
+
let { children, ...slotProps } = props;
|
|
78
|
+
let slottableElement = null;
|
|
79
|
+
let hasSlottable = false;
|
|
80
|
+
const newChildren = [];
|
|
81
|
+
if (isLazyComponent(children) && typeof use$1 === "function") children = use$1(children._payload);
|
|
82
|
+
React$1.Children.forEach(children, (maybeSlottable) => {
|
|
83
|
+
if (isSlottable(maybeSlottable)) {
|
|
84
|
+
hasSlottable = true;
|
|
85
|
+
const slottable = maybeSlottable;
|
|
86
|
+
let child = "child" in slottable.props ? slottable.props.child : slottable.props.children;
|
|
87
|
+
if (isLazyComponent(child) && typeof use$1 === "function") child = use$1(child._payload);
|
|
88
|
+
slottableElement = getSlottableElementFromSlottable(slottable, child);
|
|
89
|
+
newChildren.push(slottableElement?.props?.children);
|
|
90
|
+
} else newChildren.push(maybeSlottable);
|
|
91
|
+
});
|
|
92
|
+
if (slottableElement) slottableElement = React$1.cloneElement(slottableElement, void 0, newChildren);
|
|
93
|
+
else if (!hasSlottable && React$1.Children.count(children) === 1 && React$1.isValidElement(children)) slottableElement = children;
|
|
94
|
+
const slottableElementRef = slottableElement ? getElementRef(slottableElement) : void 0;
|
|
95
|
+
const composedRef = useComposedRefs(forwardedRef, slottableElementRef);
|
|
96
|
+
if (!slottableElement) {
|
|
97
|
+
if (children || children === 0) throw new Error(hasSlottable ? createSlottableError(ownerName) : createSlotError(ownerName));
|
|
98
|
+
return children;
|
|
99
|
+
}
|
|
100
|
+
const mergedProps = mergeProps(slotProps, slottableElement.props ?? {});
|
|
101
|
+
if (slottableElement.type !== React$1.Fragment) mergedProps.ref = forwardedRef ? composedRef : slottableElementRef;
|
|
102
|
+
return React$1.cloneElement(slottableElement, mergedProps);
|
|
103
|
+
});
|
|
104
|
+
Slot2.displayName = `${ownerName}.Slot`;
|
|
105
|
+
return Slot2;
|
|
106
|
+
}
|
|
107
|
+
__name(createSlot, "createSlot");
|
|
108
|
+
var Slot = /* @__PURE__ */ createSlot("Slot");
|
|
109
|
+
var SLOTTABLE_IDENTIFIER = Symbol.for("radix.slottable");
|
|
110
|
+
// @__NO_SIDE_EFFECTS__
|
|
111
|
+
function createSlottable(ownerName) {
|
|
112
|
+
const Slottable2 = /* @__PURE__ */ __name((props) => "child" in props ? props.children(props.child) : props.children, "Slottable");
|
|
113
|
+
Slottable2.displayName = `${ownerName}.Slottable`;
|
|
114
|
+
Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
|
|
115
|
+
return Slottable2;
|
|
116
|
+
}
|
|
117
|
+
__name(createSlottable, "createSlottable");
|
|
118
|
+
var getSlottableElementFromSlottable = /* @__PURE__ */ __name((slottable, child) => {
|
|
119
|
+
if ("child" in slottable.props) {
|
|
120
|
+
const child2 = slottable.props.child;
|
|
121
|
+
if (!React$1.isValidElement(child2)) return null;
|
|
122
|
+
return React$1.cloneElement(child2, void 0, slottable.props.children(child2.props.children));
|
|
123
|
+
}
|
|
124
|
+
return React$1.isValidElement(child) ? child : null;
|
|
125
|
+
}, "getSlottableElementFromSlottable");
|
|
126
|
+
function mergeProps(slotProps, childProps) {
|
|
127
|
+
const overrideProps = { ...childProps };
|
|
128
|
+
for (const propName in childProps) {
|
|
129
|
+
const slotPropValue = slotProps[propName];
|
|
130
|
+
const childPropValue = childProps[propName];
|
|
131
|
+
if (/^on[A-Z]/.test(propName)) {
|
|
132
|
+
if (slotPropValue && childPropValue) overrideProps[propName] = (...args) => {
|
|
133
|
+
const result = childPropValue(...args);
|
|
134
|
+
slotPropValue(...args);
|
|
135
|
+
return result;
|
|
136
|
+
};
|
|
137
|
+
else if (slotPropValue) overrideProps[propName] = slotPropValue;
|
|
138
|
+
} else if (propName === "style") overrideProps[propName] = {
|
|
139
|
+
...slotPropValue,
|
|
140
|
+
...childPropValue
|
|
141
|
+
};
|
|
142
|
+
else if (propName === "className") overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
...slotProps,
|
|
146
|
+
...overrideProps
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
__name(mergeProps, "mergeProps");
|
|
150
|
+
function getElementRef(element) {
|
|
151
|
+
let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
|
|
152
|
+
let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
|
|
153
|
+
if (mayWarn) return element.ref;
|
|
154
|
+
getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
|
|
155
|
+
mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
|
|
156
|
+
if (mayWarn) return element.props.ref;
|
|
157
|
+
return element.props.ref || element.ref;
|
|
158
|
+
}
|
|
159
|
+
__name(getElementRef, "getElementRef");
|
|
160
|
+
function isSlottable(child) {
|
|
161
|
+
return React$1.isValidElement(child) && typeof child.type === "function" && "__radixId" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;
|
|
162
|
+
}
|
|
163
|
+
__name(isSlottable, "isSlottable");
|
|
164
|
+
var REACT_LAZY_TYPE = Symbol.for("react.lazy");
|
|
165
|
+
function isLazyComponent(element) {
|
|
166
|
+
return element != null && typeof element === "object" && "$$typeof" in element && element.$$typeof === REACT_LAZY_TYPE && "_payload" in element && isPromiseLike(element._payload);
|
|
167
|
+
}
|
|
168
|
+
__name(isLazyComponent, "isLazyComponent");
|
|
169
|
+
function isPromiseLike(value) {
|
|
170
|
+
return typeof value === "object" && value !== null && "then" in value;
|
|
171
|
+
}
|
|
172
|
+
__name(isPromiseLike, "isPromiseLike");
|
|
173
|
+
var createSlotError = /* @__PURE__ */ __name((ownerName) => {
|
|
174
|
+
return `${ownerName} failed to slot onto its children. Expected a single React element child or \`Slottable\`.`;
|
|
175
|
+
}, "createSlotError");
|
|
176
|
+
var createSlottableError = /* @__PURE__ */ __name((ownerName) => {
|
|
177
|
+
return `${ownerName} failed to slot onto its \`Slottable\`. Expected \`Slottable\` to receive a single React element child.`;
|
|
178
|
+
}, "createSlottableError");
|
|
179
|
+
var use$1 = React$1[" use ".trim().toString()];
|
|
180
|
+
//#endregion
|
|
28
181
|
//#region src/ui-library/gallery/button/Button.tsx
|
|
29
182
|
var VARIANT_STYLES$1 = {
|
|
30
183
|
primary: "font-bold bg-brand-blue text-white shadow-lg shadow-brand-blue/25 hover:bg-brand-navy hover:shadow-xl hover:shadow-brand-blue/30 active:bg-brand-navy focus-visible:ring-brand-blue/30 disabled:bg-slate-200 disabled:text-slate-400 disabled:shadow-none",
|
|
@@ -39,23 +192,17 @@ var SIZE_STYLES$1 = {
|
|
|
39
192
|
lg: "h-11 gap-2.5 rounded-md px-6 text-base"
|
|
40
193
|
};
|
|
41
194
|
var BASE$1 = "inline-flex items-center justify-center transition-all duration-150 ease-out active:scale-[.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:active:scale-100 select-none";
|
|
42
|
-
function Button({ variant = "primary", size = "md", loading = false, leftIcon, rightIcon, fullWidth = false, children, className = "", disabled, ...props }) {
|
|
43
|
-
return /* @__PURE__ */
|
|
44
|
-
type: "button",
|
|
45
|
-
disabled: disabled || loading,
|
|
46
|
-
className: [
|
|
47
|
-
BASE$1,
|
|
48
|
-
VARIANT_STYLES$1[variant],
|
|
49
|
-
SIZE_STYLES$1[size],
|
|
50
|
-
fullWidth ? "w-full" : "",
|
|
51
|
-
className
|
|
52
|
-
].filter(Boolean).join(" "),
|
|
195
|
+
function Button({ variant = "primary", size = "md", loading = false, leftIcon, rightIcon, fullWidth = false, children, className = "", disabled, asChild = false, ...props }) {
|
|
196
|
+
return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
|
|
197
|
+
type: asChild ? void 0 : "button",
|
|
198
|
+
disabled: asChild ? void 0 : disabled || loading,
|
|
199
|
+
className: cn(BASE$1, VARIANT_STYLES$1[variant], SIZE_STYLES$1[size], fullWidth && "w-full", className),
|
|
53
200
|
...props,
|
|
54
|
-
children: [
|
|
201
|
+
children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
55
202
|
leftIcon && !loading && leftIcon,
|
|
56
203
|
children,
|
|
57
204
|
rightIcon && !loading && rightIcon
|
|
58
|
-
]
|
|
205
|
+
] })
|
|
59
206
|
});
|
|
60
207
|
}
|
|
61
208
|
//#endregion
|
|
@@ -66,14 +213,10 @@ var VARIANT_STYLES = {
|
|
|
66
213
|
edit: "hover:bg-blue-50 hover:text-brand-blue focus-visible:ring-brand-blue/20",
|
|
67
214
|
danger: "hover:bg-rose-50 hover:text-rose-600 focus-visible:ring-rose-100"
|
|
68
215
|
};
|
|
69
|
-
function IconButton({ icon, variant = "default", className = "", ...props }) {
|
|
70
|
-
return /* @__PURE__ */ jsx("button", {
|
|
71
|
-
type: "button",
|
|
72
|
-
className: [
|
|
73
|
-
BASE,
|
|
74
|
-
VARIANT_STYLES[variant],
|
|
75
|
-
className
|
|
76
|
-
].filter(Boolean).join(" "),
|
|
216
|
+
function IconButton({ icon, variant = "default", className = "", asChild = false, ...props }) {
|
|
217
|
+
return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
|
|
218
|
+
type: asChild ? void 0 : "button",
|
|
219
|
+
className: cn(BASE, VARIANT_STYLES[variant], className),
|
|
77
220
|
...props,
|
|
78
221
|
children: icon
|
|
79
222
|
});
|
|
@@ -103,18 +246,28 @@ var SIZE_STYLES = {
|
|
|
103
246
|
};
|
|
104
247
|
function Badge({ tone = "neutral", size = "md", icon, children, className = "" }) {
|
|
105
248
|
return /* @__PURE__ */ jsxs("span", {
|
|
106
|
-
className: [
|
|
107
|
-
"inline-flex items-center border font-semibold uppercase tracking-wide",
|
|
108
|
-
STATUS_TONES.has(tone) ? "rounded" : "rounded-full",
|
|
109
|
-
TONE_STYLES$1[tone],
|
|
110
|
-
SIZE_STYLES[size],
|
|
111
|
-
className
|
|
112
|
-
].filter(Boolean).join(" "),
|
|
249
|
+
className: cn("inline-flex items-center border font-semibold uppercase tracking-wide", STATUS_TONES.has(tone) ? "rounded" : "rounded-full", TONE_STYLES$1[tone], SIZE_STYLES[size], className),
|
|
113
250
|
children: [icon, children]
|
|
114
251
|
});
|
|
115
252
|
}
|
|
116
253
|
//#endregion
|
|
117
254
|
//#region src/ui-library/gallery/spinner/Spinner.tsx
|
|
255
|
+
/**
|
|
256
|
+
* Spinner — Design System Component
|
|
257
|
+
*
|
|
258
|
+
* An indeterminate loading indicator. Purely presentational.
|
|
259
|
+
*
|
|
260
|
+
* Sizes: sm | md | lg
|
|
261
|
+
*
|
|
262
|
+
* Usage:
|
|
263
|
+
* - Inline: inside a button or alongside text
|
|
264
|
+
* - Standalone: centered in a container while content loads
|
|
265
|
+
*
|
|
266
|
+
* Accessibility:
|
|
267
|
+
* - Renders a <span role="status"> that announces label to screen readers
|
|
268
|
+
* - label is required and should describe what is loading
|
|
269
|
+
* - Respects prefers-reduced-motion: animation is suppressed, label stays
|
|
270
|
+
*/
|
|
118
271
|
var SIZE_TRACK = {
|
|
119
272
|
sm: "h-4 w-4 border-2",
|
|
120
273
|
md: "h-6 w-6 border-2",
|
|
@@ -128,7 +281,7 @@ var SIZE_TEXT = {
|
|
|
128
281
|
function Spinner({ size = "md", label = "Loading…", labelHidden = false, className = "" }) {
|
|
129
282
|
return /* @__PURE__ */ jsxs("span", {
|
|
130
283
|
role: "status",
|
|
131
|
-
className:
|
|
284
|
+
className: cn("inline-flex items-center gap-2", className),
|
|
132
285
|
children: [/* @__PURE__ */ jsx("span", {
|
|
133
286
|
"aria-hidden": "true",
|
|
134
287
|
className: ["inline-block animate-spin rounded-full border-slate-200 border-t-brand-blue motion-reduce:animate-none", SIZE_TRACK[size]].join(" ")
|
|
@@ -140,6 +293,25 @@ function Spinner({ size = "md", label = "Loading…", labelHidden = false, class
|
|
|
140
293
|
}
|
|
141
294
|
//#endregion
|
|
142
295
|
//#region src/ui-library/gallery/divider/Divider.tsx
|
|
296
|
+
/**
|
|
297
|
+
* Divider — Design System Component
|
|
298
|
+
*
|
|
299
|
+
* A thin visual separator between content areas.
|
|
300
|
+
*
|
|
301
|
+
* Decorative usage (default, aria-hidden="true"):
|
|
302
|
+
* Used purely for visual grouping. Screen readers skip it.
|
|
303
|
+
* This is the appropriate choice for most cases.
|
|
304
|
+
*
|
|
305
|
+
* Semantic usage (role="separator"):
|
|
306
|
+
* Use when the separation is meaningful to AT users, e.g. between
|
|
307
|
+
* logically distinct regions where the boundary matters.
|
|
308
|
+
* Provide aria-label when context is needed.
|
|
309
|
+
*
|
|
310
|
+
* Orientation:
|
|
311
|
+
* - horizontal (default): full-width horizontal line, displayed as block.
|
|
312
|
+
* - vertical: full-height vertical line, displayed inline. The parent
|
|
313
|
+
* container must give it an explicit height or use flex/grid context.
|
|
314
|
+
*/
|
|
143
315
|
function Divider({ orientation = "horizontal", decorative = true, "aria-label": ariaLabel, className = "" }) {
|
|
144
316
|
const isHorizontal = orientation === "horizontal";
|
|
145
317
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -148,7 +320,7 @@ function Divider({ orientation = "horizontal", decorative = true, "aria-label":
|
|
|
148
320
|
"aria-label": ariaLabel,
|
|
149
321
|
"aria-orientation": orientation
|
|
150
322
|
},
|
|
151
|
-
className:
|
|
323
|
+
className: cn(isHorizontal ? "w-full border-t border-slate-200" : "self-stretch border-l border-slate-200", className)
|
|
152
324
|
});
|
|
153
325
|
}
|
|
154
326
|
//#endregion
|
|
@@ -212,12 +384,7 @@ function Avatar({ name, src, size = "md", color, className = "" }) {
|
|
|
212
384
|
const bg = color ?? deriveColor(name);
|
|
213
385
|
const initials = getInitials(name);
|
|
214
386
|
const label = name || "Unknown";
|
|
215
|
-
const baseClass = [
|
|
216
|
-
"inline-flex items-center justify-center rounded-full shrink-0",
|
|
217
|
-
"font-bold text-white select-none overflow-hidden",
|
|
218
|
-
SIZE_CLASSES[size],
|
|
219
|
-
className
|
|
220
|
-
].filter(Boolean).join(" ");
|
|
387
|
+
const baseClass = cn("inline-flex items-center justify-center rounded-full shrink-0", "font-bold text-white select-none overflow-hidden", SIZE_CLASSES[size], className);
|
|
221
388
|
if (showImage) return /* @__PURE__ */ jsx("img", {
|
|
222
389
|
src,
|
|
223
390
|
alt: label,
|
|
@@ -238,7 +405,7 @@ function Section({ title, description, actions, level = 2, children, className =
|
|
|
238
405
|
const Tag = `h${level}`;
|
|
239
406
|
const headingClass = level === 1 ? "text-2xl font-bold text-slate-900" : level === 2 ? "text-lg font-bold text-slate-900" : "text-base font-bold text-slate-800";
|
|
240
407
|
return /* @__PURE__ */ jsxs("section", {
|
|
241
|
-
className:
|
|
408
|
+
className: cn("space-y-4", className),
|
|
242
409
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
243
410
|
className: "flex items-start justify-between gap-4",
|
|
244
411
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -261,7 +428,7 @@ function Section({ title, description, actions, level = 2, children, className =
|
|
|
261
428
|
//#region src/ui-library/gallery/page-header/PageHeader.tsx
|
|
262
429
|
function PageHeader({ title, subtitle, icon, actions, className = "" }) {
|
|
263
430
|
return /* @__PURE__ */ jsx("div", {
|
|
264
|
-
className,
|
|
431
|
+
className: cn(className),
|
|
265
432
|
children: /* @__PURE__ */ jsxs("div", {
|
|
266
433
|
className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between",
|
|
267
434
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -290,11 +457,7 @@ function PageHeader({ title, subtitle, icon, actions, className = "" }) {
|
|
|
290
457
|
//#region src/ui-library/gallery/toolbar/Toolbar.tsx
|
|
291
458
|
function Toolbar({ left, right, className = "" }) {
|
|
292
459
|
return /* @__PURE__ */ jsxs("div", {
|
|
293
|
-
className:
|
|
294
|
-
"w-full flex flex-wrap items-center justify-between gap-4",
|
|
295
|
-
"bg-white p-2 border border-slate-100 rounded-2xl shadow-sm",
|
|
296
|
-
className
|
|
297
|
-
].filter(Boolean).join(" "),
|
|
460
|
+
className: cn("w-full flex flex-wrap items-center justify-between gap-4", "bg-white p-2 border border-slate-100 rounded-2xl shadow-sm", className),
|
|
298
461
|
children: [left, right]
|
|
299
462
|
});
|
|
300
463
|
}
|
|
@@ -322,7 +485,7 @@ function useFieldContext() {
|
|
|
322
485
|
* FieldInput inside this wrapper automatically receive the correct id,
|
|
323
486
|
* aria-required, aria-invalid, and aria-describedby — with no prop threading.
|
|
324
487
|
*/
|
|
325
|
-
function Field({ label, required = false, error, children, inputId }) {
|
|
488
|
+
function Field({ label, required = false, error, children, inputId, className = "" }) {
|
|
326
489
|
const generatedId = useId();
|
|
327
490
|
const fieldId = inputId ?? generatedId;
|
|
328
491
|
const errorId = `${fieldId}-error`;
|
|
@@ -334,7 +497,7 @@ function Field({ label, required = false, error, children, inputId }) {
|
|
|
334
497
|
invalid: !!error
|
|
335
498
|
},
|
|
336
499
|
children: /* @__PURE__ */ jsxs("div", {
|
|
337
|
-
className:
|
|
500
|
+
className: cn("flex flex-col gap-1.5", error && "shake", className),
|
|
338
501
|
children: [
|
|
339
502
|
/* @__PURE__ */ jsxs("label", {
|
|
340
503
|
htmlFor: fieldId,
|
|
@@ -361,11 +524,6 @@ function Field({ label, required = false, error, children, inputId }) {
|
|
|
361
524
|
});
|
|
362
525
|
}
|
|
363
526
|
//#endregion
|
|
364
|
-
//#region src/lib/utils.ts
|
|
365
|
-
function cn(...inputs) {
|
|
366
|
-
return twMerge(clsx(inputs));
|
|
367
|
-
}
|
|
368
|
-
//#endregion
|
|
369
527
|
//#region src/ui-library/gallery/field-input/FieldInput.tsx
|
|
370
528
|
/**
|
|
371
529
|
* FieldInput — Gallery-native context-aware <input> wrapper.
|
|
@@ -373,13 +531,14 @@ function cn(...inputs) {
|
|
|
373
531
|
* Updated to import FieldContext from gallery-local field directory
|
|
374
532
|
* and to carry full DIWA visual styling.
|
|
375
533
|
*/
|
|
376
|
-
function FieldInput({ id, "aria-required": ariaRequired, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, className = "", disabled, ...rest }) {
|
|
534
|
+
function FieldInput({ id, "aria-required": ariaRequired, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, className = "", disabled, ref, ...rest }) {
|
|
377
535
|
const ctx = useFieldContext();
|
|
378
536
|
const resolvedId = id ?? ctx?.inputId;
|
|
379
537
|
const resolvedRequired = ariaRequired ?? (ctx?.required ? "true" : void 0);
|
|
380
538
|
const resolvedInvalid = ariaInvalid ?? (ctx?.invalid ? "true" : void 0);
|
|
381
539
|
const resolvedDescribedBy = ariaDescribedBy ?? (ctx?.invalid && ctx?.errorId ? ctx.errorId : void 0);
|
|
382
540
|
return /* @__PURE__ */ jsx("input", {
|
|
541
|
+
ref,
|
|
383
542
|
id: resolvedId,
|
|
384
543
|
"aria-required": resolvedRequired,
|
|
385
544
|
"aria-invalid": resolvedInvalid,
|
|
@@ -414,22 +573,18 @@ var FIELD_HELPER_COLOR = {
|
|
|
414
573
|
};
|
|
415
574
|
//#endregion
|
|
416
575
|
//#region src/ui-library/gallery/input/Input.tsx
|
|
417
|
-
function Input({ status = "default", helper, prefix, suffix, disabled, className = "", ...props }) {
|
|
576
|
+
function Input({ status = "default", helper, prefix, suffix, disabled, className = "", ref, ...props }) {
|
|
418
577
|
return /* @__PURE__ */ jsxs("div", {
|
|
419
578
|
className: "w-full",
|
|
420
579
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
421
|
-
className: [
|
|
422
|
-
"flex w-full items-center rounded-md border bg-white transition",
|
|
423
|
-
FIELD_STATUS_RING_WITHIN[status],
|
|
424
|
-
disabled ? "cursor-not-allowed bg-slate-50 opacity-60" : "",
|
|
425
|
-
className
|
|
426
|
-
].filter(Boolean).join(" "),
|
|
580
|
+
className: cn("flex w-full items-center rounded-md border bg-white transition", FIELD_STATUS_RING_WITHIN[status], disabled && "cursor-not-allowed bg-slate-50 opacity-60", className),
|
|
427
581
|
children: [
|
|
428
582
|
prefix && /* @__PURE__ */ jsx("span", {
|
|
429
583
|
className: "flex shrink-0 items-center pl-3.5 text-slate-400",
|
|
430
584
|
children: prefix
|
|
431
585
|
}),
|
|
432
586
|
/* @__PURE__ */ jsx("input", {
|
|
587
|
+
ref,
|
|
433
588
|
disabled,
|
|
434
589
|
className: [
|
|
435
590
|
"w-full bg-transparent py-2.5 text-sm font-medium text-slate-900 outline-none placeholder:text-slate-400",
|
|
@@ -463,7 +618,7 @@ var RESIZE_CLASS = {
|
|
|
463
618
|
vertical: "resize-y",
|
|
464
619
|
both: "resize"
|
|
465
620
|
};
|
|
466
|
-
function Textarea({ status = "default", helper, maxLength, resize = "vertical", disabled, value, defaultValue, onChange, className = "", ...props }) {
|
|
621
|
+
function Textarea({ status = "default", helper, maxLength, resize = "vertical", disabled, value, defaultValue, onChange, className = "", ref, ...props }) {
|
|
467
622
|
const isControlled = value !== void 0;
|
|
468
623
|
const [uncontrolledLength, setUncontrolledLength] = useState(typeof defaultValue === "string" ? defaultValue.length : 0);
|
|
469
624
|
const currentLength = isControlled ? typeof value === "string" ? value.length : 0 : uncontrolledLength;
|
|
@@ -474,18 +629,13 @@ function Textarea({ status = "default", helper, maxLength, resize = "vertical",
|
|
|
474
629
|
return /* @__PURE__ */ jsxs("div", {
|
|
475
630
|
className: "w-full",
|
|
476
631
|
children: [/* @__PURE__ */ jsx("textarea", {
|
|
632
|
+
ref,
|
|
477
633
|
maxLength,
|
|
478
634
|
disabled,
|
|
479
635
|
value,
|
|
480
636
|
defaultValue,
|
|
481
637
|
onChange: handleChange,
|
|
482
|
-
className: [
|
|
483
|
-
"w-full rounded-xl border bg-white px-4 py-3 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400",
|
|
484
|
-
FIELD_STATUS_RING_DIRECT[status],
|
|
485
|
-
RESIZE_CLASS[resize],
|
|
486
|
-
disabled ? "cursor-not-allowed bg-slate-50 opacity-60" : "",
|
|
487
|
-
className
|
|
488
|
-
].filter(Boolean).join(" "),
|
|
638
|
+
className: cn("w-full rounded-xl border bg-white px-4 py-3 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400", FIELD_STATUS_RING_DIRECT[status], RESIZE_CLASS[resize], disabled && "cursor-not-allowed bg-slate-50 opacity-60", className),
|
|
489
639
|
...props
|
|
490
640
|
}), (helper || maxLength !== void 0) && /* @__PURE__ */ jsxs("div", {
|
|
491
641
|
className: "mt-1.5 flex items-start justify-between gap-2",
|
|
@@ -519,23 +669,227 @@ function Textarea({ status = "default", helper, maxLength, resize = "vertical",
|
|
|
519
669
|
* - For searchable/multi-select use cases, use Combobox (Phase 3).
|
|
520
670
|
*
|
|
521
671
|
* The label is NOT included. The consuming feature pairs a <label>.
|
|
672
|
+
*
|
|
673
|
+
* When renderOption is provided, a custom dropdown is rendered instead
|
|
674
|
+
* of the native <select>. Only use this when native option rendering
|
|
675
|
+
* is insufficient (e.g., icons, avatars, multi-line content).
|
|
522
676
|
*/
|
|
523
677
|
function isGroup(item) {
|
|
524
678
|
return "group" in item;
|
|
525
679
|
}
|
|
526
|
-
function
|
|
680
|
+
function CustomDropdown({ items, value, placeholder, status, disabled, renderOption, onChange, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, className = "" }) {
|
|
681
|
+
const [open, setOpen] = useState(false);
|
|
682
|
+
const [highlightIndex, setHighlightIndex] = useState(-1);
|
|
683
|
+
const containerRef = useRef(null);
|
|
684
|
+
const triggerRef = useRef(null);
|
|
685
|
+
const listboxId = useId();
|
|
686
|
+
const triggerId = useId();
|
|
687
|
+
const optionId = (index) => `${listboxId}-opt-${index}`;
|
|
688
|
+
const [panelStyle, setPanelStyle] = useState({});
|
|
689
|
+
const flatItems = [];
|
|
690
|
+
for (const item of items) if (isGroup(item)) {
|
|
691
|
+
flatItems.push({
|
|
692
|
+
type: "group",
|
|
693
|
+
label: item.group
|
|
694
|
+
});
|
|
695
|
+
for (const opt of item.options) flatItems.push({
|
|
696
|
+
type: "option",
|
|
697
|
+
opt
|
|
698
|
+
});
|
|
699
|
+
} else flatItems.push({
|
|
700
|
+
type: "option",
|
|
701
|
+
opt: item
|
|
702
|
+
});
|
|
703
|
+
const flatOptions = flatItems.filter((fi) => fi.type === "option").map((fi) => fi.opt);
|
|
704
|
+
const selectedOption = flatOptions.find((o) => String(o.value) === String(value ?? ""));
|
|
705
|
+
const displayLabel = selectedOption?.label ?? placeholder ?? "";
|
|
706
|
+
const hasValue = Boolean(selectedOption);
|
|
707
|
+
useEffect(() => {
|
|
708
|
+
if (!open) setHighlightIndex(-1);
|
|
709
|
+
}, [open]);
|
|
710
|
+
const listRef = useRef(null);
|
|
711
|
+
useEffect(() => {
|
|
712
|
+
if (highlightIndex >= 0 && listRef.current) listRef.current.querySelector(`[id="${optionId(highlightIndex)}"]`)?.scrollIntoView({ block: "nearest" });
|
|
713
|
+
}, [highlightIndex]);
|
|
714
|
+
useEffect(() => {
|
|
715
|
+
if (!open) return;
|
|
716
|
+
const handlePointerDown = (e) => {
|
|
717
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
|
|
718
|
+
};
|
|
719
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
720
|
+
return () => document.removeEventListener("mousedown", handlePointerDown);
|
|
721
|
+
}, [open]);
|
|
722
|
+
useEffect(() => {
|
|
723
|
+
if (!open || !triggerRef.current) return;
|
|
724
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
725
|
+
setPanelStyle({
|
|
726
|
+
position: "fixed",
|
|
727
|
+
top: rect.bottom + 4,
|
|
728
|
+
left: rect.left,
|
|
729
|
+
zIndex: 9999,
|
|
730
|
+
width: rect.width
|
|
731
|
+
});
|
|
732
|
+
}, [open]);
|
|
733
|
+
const handleSelect = useCallback((opt) => {
|
|
734
|
+
if (opt.disabled) return;
|
|
735
|
+
const syntheticEvent = {
|
|
736
|
+
target: { value: opt.value },
|
|
737
|
+
currentTarget: { value: opt.value }
|
|
738
|
+
};
|
|
739
|
+
onChange?.(syntheticEvent);
|
|
740
|
+
setOpen(false);
|
|
741
|
+
triggerRef.current?.focus();
|
|
742
|
+
}, [onChange]);
|
|
743
|
+
const handleKeyDown = (e) => {
|
|
744
|
+
const nextEnabled = (from, dir) => {
|
|
745
|
+
let idx = from;
|
|
746
|
+
while (idx >= 0 && idx < flatOptions.length) {
|
|
747
|
+
if (!flatOptions[idx]?.disabled) return idx;
|
|
748
|
+
idx += dir;
|
|
749
|
+
}
|
|
750
|
+
return -1;
|
|
751
|
+
};
|
|
752
|
+
switch (e.key) {
|
|
753
|
+
case "ArrowDown":
|
|
754
|
+
e.preventDefault();
|
|
755
|
+
if (!open) {
|
|
756
|
+
setOpen(true);
|
|
757
|
+
const first = nextEnabled(0, 1);
|
|
758
|
+
setHighlightIndex(first);
|
|
759
|
+
} else setHighlightIndex((prev) => {
|
|
760
|
+
const next = nextEnabled(prev + 1, 1);
|
|
761
|
+
return next === -1 ? prev : next;
|
|
762
|
+
});
|
|
763
|
+
break;
|
|
764
|
+
case "ArrowUp":
|
|
765
|
+
e.preventDefault();
|
|
766
|
+
if (open) setHighlightIndex((prev) => {
|
|
767
|
+
const next = nextEnabled(prev - 1, -1);
|
|
768
|
+
return next === -1 ? prev : next;
|
|
769
|
+
});
|
|
770
|
+
break;
|
|
771
|
+
case "Home":
|
|
772
|
+
e.preventDefault();
|
|
773
|
+
if (open) {
|
|
774
|
+
const first = nextEnabled(0, 1);
|
|
775
|
+
setHighlightIndex(first);
|
|
776
|
+
}
|
|
777
|
+
break;
|
|
778
|
+
case "End":
|
|
779
|
+
e.preventDefault();
|
|
780
|
+
if (open) {
|
|
781
|
+
const last = nextEnabled(flatOptions.length - 1, -1);
|
|
782
|
+
setHighlightIndex(last);
|
|
783
|
+
}
|
|
784
|
+
break;
|
|
785
|
+
case "Enter":
|
|
786
|
+
case " ":
|
|
787
|
+
e.preventDefault();
|
|
788
|
+
if (!open) setOpen(true);
|
|
789
|
+
else if (highlightIndex >= 0 && flatOptions[highlightIndex] && !flatOptions[highlightIndex].disabled) handleSelect(flatOptions[highlightIndex]);
|
|
790
|
+
else setOpen(false);
|
|
791
|
+
break;
|
|
792
|
+
case "Escape":
|
|
793
|
+
e.preventDefault();
|
|
794
|
+
setOpen(false);
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
const effectiveTriggerId = id ?? triggerId;
|
|
798
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
799
|
+
className: "relative",
|
|
800
|
+
ref: containerRef,
|
|
801
|
+
children: [
|
|
802
|
+
/* @__PURE__ */ jsx("button", {
|
|
803
|
+
ref: triggerRef,
|
|
804
|
+
id: effectiveTriggerId,
|
|
805
|
+
type: "button",
|
|
806
|
+
role: "combobox",
|
|
807
|
+
"aria-haspopup": "listbox",
|
|
808
|
+
"aria-expanded": open,
|
|
809
|
+
"aria-controls": listboxId,
|
|
810
|
+
"aria-activedescendant": open && highlightIndex >= 0 ? optionId(highlightIndex) : void 0,
|
|
811
|
+
"aria-label": ariaLabel,
|
|
812
|
+
"aria-labelledby": ariaLabelledBy,
|
|
813
|
+
disabled,
|
|
814
|
+
onClick: () => setOpen((v) => !v),
|
|
815
|
+
onKeyDown: handleKeyDown,
|
|
816
|
+
className: cn("w-full appearance-none rounded-md border bg-white py-2.5 pl-4 pr-10 text-left text-sm font-medium outline-none transition", FIELD_STATUS_RING_DIRECT[status], hasValue ? "text-slate-900" : "text-slate-400", disabled ? "cursor-not-allowed bg-slate-50 opacity-60" : "cursor-pointer", className),
|
|
817
|
+
children: displayLabel
|
|
818
|
+
}),
|
|
819
|
+
/* @__PURE__ */ jsx("span", {
|
|
820
|
+
className: "pointer-events-none absolute right-3.5 top-1/2 -translate-y-1/2 text-slate-400",
|
|
821
|
+
"aria-hidden": "true",
|
|
822
|
+
children: /* @__PURE__ */ jsx(ChevronDown, {
|
|
823
|
+
size: 14,
|
|
824
|
+
className: open ? "rotate-180 transition-transform" : "transition-transform"
|
|
825
|
+
})
|
|
826
|
+
}),
|
|
827
|
+
open && !disabled && createPortal(/* @__PURE__ */ jsx("ul", {
|
|
828
|
+
ref: listRef,
|
|
829
|
+
id: listboxId,
|
|
830
|
+
role: "listbox",
|
|
831
|
+
"aria-labelledby": effectiveTriggerId,
|
|
832
|
+
style: panelStyle,
|
|
833
|
+
className: "overflow-y-auto max-h-60 rounded-xl border border-slate-200 bg-white py-1 shadow-xl",
|
|
834
|
+
children: flatItems.map((fi, i) => {
|
|
835
|
+
if (fi.type === "group") return /* @__PURE__ */ jsx("li", {
|
|
836
|
+
role: "presentation",
|
|
837
|
+
className: "px-3 py-1.5 text-[10px] font-bold uppercase tracking-widest text-slate-400",
|
|
838
|
+
children: fi.label
|
|
839
|
+
}, `group-${fi.label}-${i}`);
|
|
840
|
+
const opt = fi.opt;
|
|
841
|
+
const optIndex = flatOptions.indexOf(opt);
|
|
842
|
+
const isSelected = String(opt.value) === String(value ?? "");
|
|
843
|
+
const isHighlighted = optIndex === highlightIndex;
|
|
844
|
+
return /* @__PURE__ */ jsx("li", {
|
|
845
|
+
id: optionId(optIndex),
|
|
846
|
+
role: "option",
|
|
847
|
+
"aria-selected": isSelected,
|
|
848
|
+
"aria-disabled": opt.disabled,
|
|
849
|
+
onClick: () => handleSelect(opt),
|
|
850
|
+
className: [
|
|
851
|
+
"cursor-pointer px-3 py-2 text-sm transition-colors",
|
|
852
|
+
opt.disabled ? "cursor-not-allowed opacity-50" : "",
|
|
853
|
+
isHighlighted && !opt.disabled ? "bg-blue-50 font-semibold text-brand-blue" : "",
|
|
854
|
+
isSelected && !isHighlighted ? "bg-blue-50 font-semibold text-brand-blue" : "",
|
|
855
|
+
!isHighlighted && !isSelected && !opt.disabled ? "hover:bg-slate-50 text-slate-700" : "",
|
|
856
|
+
opt.disabled ? "text-slate-400" : ""
|
|
857
|
+
].filter(Boolean).join(" "),
|
|
858
|
+
children: renderOption(opt)
|
|
859
|
+
}, opt.value);
|
|
860
|
+
})
|
|
861
|
+
}), document.body)
|
|
862
|
+
]
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
function Select({ items, placeholder, status = "default", helper, disabled, className = "", renderOption, ref, ...props }) {
|
|
866
|
+
if (renderOption) return /* @__PURE__ */ jsxs("div", {
|
|
867
|
+
className: "w-full",
|
|
868
|
+
children: [/* @__PURE__ */ jsx(CustomDropdown, {
|
|
869
|
+
items,
|
|
870
|
+
value: props.value,
|
|
871
|
+
placeholder,
|
|
872
|
+
status,
|
|
873
|
+
disabled,
|
|
874
|
+
renderOption,
|
|
875
|
+
onChange: props.onChange,
|
|
876
|
+
id: props.id,
|
|
877
|
+
"aria-label": props["aria-label"],
|
|
878
|
+
"aria-labelledby": props["aria-labelledby"],
|
|
879
|
+
className
|
|
880
|
+
}), helper && /* @__PURE__ */ jsx("p", {
|
|
881
|
+
className: `mt-1.5 text-xs font-medium ${FIELD_HELPER_COLOR[status]}`,
|
|
882
|
+
children: helper
|
|
883
|
+
})]
|
|
884
|
+
});
|
|
527
885
|
return /* @__PURE__ */ jsxs("div", {
|
|
528
886
|
className: "w-full",
|
|
529
887
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
530
888
|
className: "relative",
|
|
531
889
|
children: [/* @__PURE__ */ jsxs("select", {
|
|
890
|
+
ref,
|
|
532
891
|
disabled,
|
|
533
|
-
className: [
|
|
534
|
-
"w-full appearance-none rounded-md border bg-white py-2.5 pl-4 pr-10 text-sm font-medium text-slate-900 outline-none transition",
|
|
535
|
-
FIELD_STATUS_RING_DIRECT[status],
|
|
536
|
-
disabled ? "cursor-not-allowed bg-slate-50 opacity-60" : "cursor-pointer",
|
|
537
|
-
className
|
|
538
|
-
].filter(Boolean).join(" "),
|
|
892
|
+
className: cn("w-full appearance-none rounded-md border bg-white py-2.5 pl-4 pr-10 text-sm font-medium text-slate-900 outline-none transition", FIELD_STATUS_RING_DIRECT[status], disabled ? "cursor-not-allowed bg-slate-50 opacity-60" : "cursor-pointer", className),
|
|
539
893
|
...props,
|
|
540
894
|
children: [placeholder && /* @__PURE__ */ jsx("option", {
|
|
541
895
|
value: "",
|
|
@@ -565,6 +919,24 @@ function Select({ items, placeholder, status = "default", helper, disabled, clas
|
|
|
565
919
|
});
|
|
566
920
|
}
|
|
567
921
|
//#endregion
|
|
922
|
+
//#region src/lib/composeRefs.ts
|
|
923
|
+
/**
|
|
924
|
+
* Composes multiple React refs into one callback ref.
|
|
925
|
+
* Used when a component needs both an internal ref and a forwarded external ref.
|
|
926
|
+
*
|
|
927
|
+
* Example:
|
|
928
|
+
* <input ref={composeRefs(internalRef, forwardedRef)} />
|
|
929
|
+
*/
|
|
930
|
+
function composeRefs(...refs) {
|
|
931
|
+
return (node) => {
|
|
932
|
+
refs.forEach((ref) => {
|
|
933
|
+
if (!ref) return;
|
|
934
|
+
if (typeof ref === "function") ref(node);
|
|
935
|
+
else ref.current = node;
|
|
936
|
+
});
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
//#endregion
|
|
568
940
|
//#region src/ui-library/gallery/checkbox/Checkbox.tsx
|
|
569
941
|
/**
|
|
570
942
|
* Checkbox — Design System Component
|
|
@@ -575,14 +947,14 @@ function Select({ items, placeholder, status = "default", helper, disabled, clas
|
|
|
575
947
|
*
|
|
576
948
|
* States: unchecked | checked | indeterminate | disabled | error
|
|
577
949
|
*/
|
|
578
|
-
function Checkbox({ label, description, indeterminate = false, error = false, helper, disabled, checked, id: externalId, className = "", ...props }) {
|
|
950
|
+
function Checkbox({ label, description, indeterminate = false, error = false, helper, disabled, checked, id: externalId, className = "", ref, ...props }) {
|
|
579
951
|
const generatedId = useId();
|
|
580
952
|
const id = externalId ?? generatedId;
|
|
581
953
|
const attachIndeterminate = (el) => {
|
|
582
954
|
if (el) el.indeterminate = indeterminate;
|
|
583
955
|
};
|
|
584
956
|
return /* @__PURE__ */ jsxs("div", {
|
|
585
|
-
className:
|
|
957
|
+
className: cn("flex flex-col gap-1", className),
|
|
586
958
|
children: [/* @__PURE__ */ jsxs("label", {
|
|
587
959
|
htmlFor: id,
|
|
588
960
|
className: `group inline-flex cursor-pointer items-start gap-2.5 ${disabled ? "cursor-not-allowed opacity-60" : ""}`,
|
|
@@ -590,7 +962,7 @@ function Checkbox({ label, description, indeterminate = false, error = false, he
|
|
|
590
962
|
className: "relative mt-0.5 shrink-0",
|
|
591
963
|
children: [
|
|
592
964
|
/* @__PURE__ */ jsx("input", {
|
|
593
|
-
ref: attachIndeterminate,
|
|
965
|
+
ref: composeRefs(attachIndeterminate, ref),
|
|
594
966
|
id,
|
|
595
967
|
type: "checkbox",
|
|
596
968
|
checked,
|
|
@@ -685,26 +1057,23 @@ function RadioGroup({ name: externalName, defaultValue = "", value: controlledVa
|
|
|
685
1057
|
"aria-labelledby": ariaLabelledby,
|
|
686
1058
|
"aria-required": required || void 0,
|
|
687
1059
|
"aria-disabled": disabled || void 0,
|
|
688
|
-
className:
|
|
1060
|
+
className: cn(orientation === "horizontal" ? "flex flex-wrap gap-4" : "flex flex-col gap-3", className),
|
|
689
1061
|
children
|
|
690
1062
|
})
|
|
691
1063
|
});
|
|
692
1064
|
}
|
|
693
|
-
function RadioItem({ value, label, description, disabled: itemDisabled = false, className = "" }) {
|
|
1065
|
+
function RadioItem({ value, label, description, disabled: itemDisabled = false, className = "", ref }) {
|
|
694
1066
|
const { name, activeValue, select, disabled: groupDisabled, required } = useRadioGroupContext();
|
|
695
1067
|
const id = useId();
|
|
696
1068
|
const isDisabled = groupDisabled || itemDisabled;
|
|
697
1069
|
const isChecked = activeValue === value;
|
|
698
1070
|
return /* @__PURE__ */ jsxs("label", {
|
|
699
1071
|
htmlFor: id,
|
|
700
|
-
className:
|
|
701
|
-
"group flex cursor-pointer items-start gap-3",
|
|
702
|
-
isDisabled ? "cursor-not-allowed opacity-50" : "",
|
|
703
|
-
className
|
|
704
|
-
].filter(Boolean).join(" "),
|
|
1072
|
+
className: cn("group flex cursor-pointer items-start gap-3", isDisabled && "cursor-not-allowed opacity-50", className),
|
|
705
1073
|
children: [
|
|
706
1074
|
/* @__PURE__ */ jsx("input", {
|
|
707
1075
|
type: "radio",
|
|
1076
|
+
ref,
|
|
708
1077
|
id,
|
|
709
1078
|
name,
|
|
710
1079
|
value,
|
|
@@ -740,14 +1109,24 @@ function RadioItem({ value, label, description, disabled: itemDisabled = false,
|
|
|
740
1109
|
}
|
|
741
1110
|
//#endregion
|
|
742
1111
|
//#region src/ui-library/gallery/switch/Switch.tsx
|
|
743
|
-
function Switch({ checked, onChange, label, description, disabled = false, loading = false, id: externalId }) {
|
|
1112
|
+
function Switch({ checked: controlledChecked, defaultChecked = false, onChange, label, description, disabled = false, loading = false, id: externalId, className = "", ref }) {
|
|
1113
|
+
const [uncontrolled, setUncontrolled] = useState(defaultChecked);
|
|
1114
|
+
const isControlled = controlledChecked !== void 0;
|
|
1115
|
+
const checked = isControlled ? controlledChecked : uncontrolled;
|
|
744
1116
|
const generatedId = useId();
|
|
745
1117
|
const id = externalId ?? generatedId;
|
|
746
1118
|
const labelId = label ? `${id}-label` : void 0;
|
|
747
1119
|
const isInteractive = !disabled && !loading;
|
|
1120
|
+
const handleClick = () => {
|
|
1121
|
+
if (!isInteractive) return;
|
|
1122
|
+
const next = !checked;
|
|
1123
|
+
if (!isControlled) setUncontrolled(next);
|
|
1124
|
+
onChange?.(next);
|
|
1125
|
+
};
|
|
748
1126
|
return /* @__PURE__ */ jsxs("div", {
|
|
749
|
-
className: "flex items-start gap-3",
|
|
1127
|
+
className: cn("flex items-start gap-3", className),
|
|
750
1128
|
children: [/* @__PURE__ */ jsx("button", {
|
|
1129
|
+
ref,
|
|
751
1130
|
id,
|
|
752
1131
|
type: "button",
|
|
753
1132
|
role: "switch",
|
|
@@ -756,7 +1135,7 @@ function Switch({ checked, onChange, label, description, disabled = false, loadi
|
|
|
756
1135
|
"aria-label": !label ? "Toggle" : void 0,
|
|
757
1136
|
"aria-disabled": !isInteractive || void 0,
|
|
758
1137
|
disabled: !isInteractive,
|
|
759
|
-
onClick:
|
|
1138
|
+
onClick: handleClick,
|
|
760
1139
|
className: [
|
|
761
1140
|
"relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200",
|
|
762
1141
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 focus-visible:ring-offset-1",
|
|
@@ -793,13 +1172,17 @@ function Switch({ checked, onChange, label, description, disabled = false, loadi
|
|
|
793
1172
|
*/
|
|
794
1173
|
var fieldInputClass = "w-full rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15 disabled:cursor-not-allowed disabled:opacity-60";
|
|
795
1174
|
var fieldInputErrorClass = "border-rose-300 focus:border-rose-400 focus:ring-rose-100";
|
|
796
|
-
function Combobox({ value, onChange, options, placeholder, className, disabled, loading, error, "aria-label": ariaLabel }) {
|
|
1175
|
+
function Combobox({ value: controlledValue, defaultValue = "", onChange, options, placeholder, className, disabled, loading, error, "aria-label": ariaLabel, onBlur, ref }) {
|
|
1176
|
+
const isControlled = controlledValue !== void 0;
|
|
1177
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
1178
|
+
const value = isControlled ? controlledValue : internalValue;
|
|
797
1179
|
const [isOpen, setIsOpen] = useState(false);
|
|
798
1180
|
const [search, setSearch] = useState(value);
|
|
799
1181
|
const [highlightIndex, setHighlightIndex] = useState(-1);
|
|
800
1182
|
const inputRef = useRef(null);
|
|
801
1183
|
const listRef = useRef(null);
|
|
802
1184
|
const wrapperRef = useRef(null);
|
|
1185
|
+
const [panelStyle, setPanelStyle] = useState({});
|
|
803
1186
|
const uid = useId();
|
|
804
1187
|
const listboxId = `${uid}-listbox`;
|
|
805
1188
|
const optionId = (index) => `${uid}-option-${index}`;
|
|
@@ -816,11 +1199,23 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
|
|
|
816
1199
|
}, [value]);
|
|
817
1200
|
useEffect(() => {
|
|
818
1201
|
function handleClickOutside(e) {
|
|
819
|
-
|
|
1202
|
+
const target = e.target;
|
|
1203
|
+
if (wrapperRef.current && !wrapperRef.current.contains(target) && !(listRef.current && listRef.current.contains(target))) setIsOpen(false);
|
|
820
1204
|
}
|
|
821
1205
|
document.addEventListener("mousedown", handleClickOutside);
|
|
822
1206
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
823
1207
|
}, []);
|
|
1208
|
+
useEffect(() => {
|
|
1209
|
+
if (!isOpen || !wrapperRef.current) return;
|
|
1210
|
+
const rect = wrapperRef.current.getBoundingClientRect();
|
|
1211
|
+
setPanelStyle({
|
|
1212
|
+
position: "fixed",
|
|
1213
|
+
top: rect.bottom + 4,
|
|
1214
|
+
left: rect.left,
|
|
1215
|
+
zIndex: 9999,
|
|
1216
|
+
width: rect.width
|
|
1217
|
+
});
|
|
1218
|
+
}, [isOpen]);
|
|
824
1219
|
useEffect(() => {
|
|
825
1220
|
if (!isOpen) setHighlightIndex(-1);
|
|
826
1221
|
}, [isOpen]);
|
|
@@ -828,7 +1223,9 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
|
|
|
828
1223
|
if (highlightIndex >= 0 && listRef.current) listRef.current.children[highlightIndex]?.scrollIntoView({ block: "nearest" });
|
|
829
1224
|
}, [highlightIndex]);
|
|
830
1225
|
const selectOption = (opt) => {
|
|
831
|
-
|
|
1226
|
+
if (opt.disabled) return;
|
|
1227
|
+
if (!isControlled) setInternalValue(opt.value);
|
|
1228
|
+
onChange?.(opt.value);
|
|
832
1229
|
setSearch(opt.label);
|
|
833
1230
|
setIsOpen(false);
|
|
834
1231
|
inputRef.current?.focus();
|
|
@@ -836,37 +1233,60 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
|
|
|
836
1233
|
const handleInputChange = (e) => {
|
|
837
1234
|
const val = e.target.value;
|
|
838
1235
|
setSearch(val);
|
|
839
|
-
|
|
1236
|
+
if (!isControlled) setInternalValue(val);
|
|
840
1237
|
setIsOpen(true);
|
|
841
1238
|
setHighlightIndex(-1);
|
|
842
1239
|
};
|
|
843
1240
|
const handleKeyDown = (e) => {
|
|
1241
|
+
const nextEnabled = (from, dir) => {
|
|
1242
|
+
let idx = from;
|
|
1243
|
+
while (idx >= 0 && idx < displayed.length) {
|
|
1244
|
+
if (!displayed[idx]?.disabled) return idx;
|
|
1245
|
+
idx += dir;
|
|
1246
|
+
}
|
|
1247
|
+
return -1;
|
|
1248
|
+
};
|
|
844
1249
|
if (e.key === "ArrowDown") {
|
|
845
1250
|
e.preventDefault();
|
|
846
1251
|
if (!isOpen) {
|
|
847
1252
|
setIsOpen(true);
|
|
848
1253
|
return;
|
|
849
1254
|
}
|
|
850
|
-
setHighlightIndex((prev) =>
|
|
1255
|
+
setHighlightIndex((prev) => {
|
|
1256
|
+
const next = nextEnabled(prev + 1, 1);
|
|
1257
|
+
return next === -1 ? prev : next;
|
|
1258
|
+
});
|
|
851
1259
|
} else if (e.key === "ArrowUp") {
|
|
852
1260
|
e.preventDefault();
|
|
853
|
-
setHighlightIndex((prev) =>
|
|
1261
|
+
setHighlightIndex((prev) => {
|
|
1262
|
+
const next = nextEnabled(prev - 1, -1);
|
|
1263
|
+
return next === -1 ? prev : next;
|
|
1264
|
+
});
|
|
854
1265
|
} else if (e.key === "Enter") {
|
|
855
1266
|
e.preventDefault();
|
|
856
|
-
if (highlightIndex >= 0 && displayed[highlightIndex]) selectOption(displayed[highlightIndex]);
|
|
1267
|
+
if (highlightIndex >= 0 && displayed[highlightIndex] && !displayed[highlightIndex].disabled) selectOption(displayed[highlightIndex]);
|
|
857
1268
|
else if (isOpen) setIsOpen(false);
|
|
858
1269
|
} else if (e.key === "Escape") {
|
|
859
1270
|
e.preventDefault();
|
|
860
1271
|
setIsOpen(false);
|
|
861
1272
|
}
|
|
862
1273
|
};
|
|
1274
|
+
const handleBlur = () => {
|
|
1275
|
+
requestAnimationFrame(() => {
|
|
1276
|
+
const active = document.activeElement;
|
|
1277
|
+
if (!wrapperRef.current?.contains(active) && !listRef.current?.contains(active)) {
|
|
1278
|
+
setIsOpen(false);
|
|
1279
|
+
onBlur?.();
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
};
|
|
863
1283
|
return /* @__PURE__ */ jsxs("div", {
|
|
864
1284
|
ref: wrapperRef,
|
|
865
1285
|
className: "relative",
|
|
866
1286
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
867
1287
|
className: "relative",
|
|
868
1288
|
children: [/* @__PURE__ */ jsx("input", {
|
|
869
|
-
ref: inputRef,
|
|
1289
|
+
ref: composeRefs(inputRef, ref),
|
|
870
1290
|
type: "text",
|
|
871
1291
|
role: "combobox",
|
|
872
1292
|
"aria-expanded": isOpen,
|
|
@@ -878,20 +1298,22 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
|
|
|
878
1298
|
value: search,
|
|
879
1299
|
onChange: handleInputChange,
|
|
880
1300
|
onFocus: () => setIsOpen(true),
|
|
1301
|
+
onBlur: handleBlur,
|
|
881
1302
|
onKeyDown: handleKeyDown,
|
|
882
1303
|
placeholder,
|
|
883
1304
|
disabled,
|
|
884
|
-
className:
|
|
1305
|
+
className: cn(fieldInputClass, "pr-8", error && fieldInputErrorClass, className)
|
|
885
1306
|
}), /* @__PURE__ */ jsx(ChevronDown, {
|
|
886
1307
|
size: 16,
|
|
887
1308
|
"aria-hidden": "true",
|
|
888
1309
|
className: `absolute right-3 top-1/2 -translate-y-1/2 text-slate-300 pointer-events-none transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
889
1310
|
})]
|
|
890
|
-
}), isOpen && !disabled && /* @__PURE__ */ jsx("div", {
|
|
1311
|
+
}), isOpen && !disabled && createPortal(/* @__PURE__ */ jsx("div", {
|
|
891
1312
|
ref: listRef,
|
|
892
1313
|
id: listboxId,
|
|
893
1314
|
role: "listbox",
|
|
894
|
-
|
|
1315
|
+
style: panelStyle,
|
|
1316
|
+
className: "bg-white border border-slate-200 rounded-xl shadow-lg max-h-60 overflow-y-auto",
|
|
895
1317
|
children: error ? /* @__PURE__ */ jsx("div", {
|
|
896
1318
|
className: "px-3 py-2 text-sm text-rose-500 font-semibold",
|
|
897
1319
|
children: error
|
|
@@ -905,11 +1327,12 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
|
|
|
905
1327
|
id: optionId(i),
|
|
906
1328
|
role: "option",
|
|
907
1329
|
"aria-selected": opt.value === value,
|
|
1330
|
+
"aria-disabled": opt.disabled,
|
|
908
1331
|
onMouseDown: (e) => {
|
|
909
1332
|
e.preventDefault();
|
|
910
|
-
selectOption(opt);
|
|
1333
|
+
if (!opt.disabled) selectOption(opt);
|
|
911
1334
|
},
|
|
912
|
-
className: `px-3 py-2 text-sm cursor-
|
|
1335
|
+
className: `px-3 py-2 text-sm transition-colors ${opt.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"} ${i === highlightIndex && !opt.disabled ? "bg-blue-50 text-brand-blue font-semibold" : opt.disabled ? "text-slate-400" : "text-slate-700 hover:bg-slate-50"} ${opt.value === value ? "font-medium" : ""}`,
|
|
913
1336
|
children: opt.label
|
|
914
1337
|
}, opt.value)), filtered.length > DISPLAY_LIMIT && /* @__PURE__ */ jsxs("div", {
|
|
915
1338
|
className: "px-3 py-2 text-xs text-slate-400 font-semibold text-center border-t border-slate-100",
|
|
@@ -919,7 +1342,7 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
|
|
|
919
1342
|
" more results — refine your search"
|
|
920
1343
|
]
|
|
921
1344
|
})] })
|
|
922
|
-
})]
|
|
1345
|
+
}), document.body)]
|
|
923
1346
|
});
|
|
924
1347
|
}
|
|
925
1348
|
//#endregion
|
|
@@ -931,10 +1354,9 @@ function Combobox({ value, onChange, options, placeholder, className, disabled,
|
|
|
931
1354
|
* Uses react-calendar and date-fns.
|
|
932
1355
|
* Note: CSS for .pis-datepicker-popover and .pis-rc-calendar is in index.css.
|
|
933
1356
|
*/
|
|
934
|
-
var MAX_DATE = new Date(2026, 11, 31);
|
|
935
1357
|
var POPOVER_WIDTH = 352;
|
|
936
1358
|
var CALENDAR_HEIGHT = 360;
|
|
937
|
-
function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, required }) {
|
|
1359
|
+
function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, maxDate, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, required }) {
|
|
938
1360
|
const [isOpen, setIsOpen] = useState(false);
|
|
939
1361
|
const [popupStyle, setPopupStyle] = useState({});
|
|
940
1362
|
const wrapperRef = useRef(null);
|
|
@@ -1015,12 +1437,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1015
1437
|
else openPopup();
|
|
1016
1438
|
}
|
|
1017
1439
|
}
|
|
1018
|
-
const inputClasses =
|
|
1019
|
-
"w-full rounded-xl border bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 pr-8 cursor-pointer select-none",
|
|
1020
|
-
error ? "border-rose-300 focus:border-rose-400 focus:ring-2 focus:ring-rose-100" : "border-slate-200 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15",
|
|
1021
|
-
disabled ? "cursor-not-allowed opacity-60" : "",
|
|
1022
|
-
className ?? ""
|
|
1023
|
-
].filter(Boolean).join(" ");
|
|
1440
|
+
const inputClasses = cn("w-full rounded-xl border bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 pr-8 cursor-pointer select-none", error ? "border-rose-300 focus:border-rose-400 focus:ring-2 focus:ring-rose-100" : "border-slate-200 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15", disabled && "cursor-not-allowed opacity-60", className);
|
|
1024
1441
|
return /* @__PURE__ */ jsxs("div", {
|
|
1025
1442
|
ref: wrapperRef,
|
|
1026
1443
|
className: "relative",
|
|
@@ -1069,7 +1486,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1069
1486
|
},
|
|
1070
1487
|
defaultActiveStartDate: selectedDate ?? minDate,
|
|
1071
1488
|
minDate,
|
|
1072
|
-
maxDate
|
|
1489
|
+
maxDate,
|
|
1073
1490
|
defaultView: "month",
|
|
1074
1491
|
showNeighboringDecade: true,
|
|
1075
1492
|
showNeighboringCentury: true,
|
|
@@ -1158,7 +1575,7 @@ function OtpInput({ length = 6, value, onChange, disabled = false, error = false
|
|
|
1158
1575
|
].join(" ");
|
|
1159
1576
|
const cellClass = error ? `${cellBase} border-rose-400 bg-rose-50/40 text-rose-800 focus:ring-rose-100` : `${cellBase} border-slate-200 bg-white text-slate-900`;
|
|
1160
1577
|
return /* @__PURE__ */ jsxs("div", {
|
|
1161
|
-
className:
|
|
1578
|
+
className: cn("space-y-2", className),
|
|
1162
1579
|
children: [/* @__PURE__ */ jsx("div", {
|
|
1163
1580
|
role: "group",
|
|
1164
1581
|
"aria-label": ariaLabel,
|
|
@@ -1206,14 +1623,20 @@ function OtpInput({ length = 6, value, onChange, disabled = false, error = false
|
|
|
1206
1623
|
* - Keyboard: Tab to focus the input; Enter/Space to open the picker.
|
|
1207
1624
|
* - Disabled: input has disabled attr; zone has aria-disabled="true".
|
|
1208
1625
|
*/
|
|
1209
|
-
function FileUpload({ onFiles, accept, multiple = false, disabled = false, "aria-label": ariaLabel = "Upload file", className = "" }) {
|
|
1626
|
+
function FileUpload({ onFiles, accept, multiple = false, disabled = false, "aria-label": ariaLabel = "Upload file", className = "", value, onChange, ref }) {
|
|
1210
1627
|
const inputRef = useRef(null);
|
|
1211
1628
|
const [dragging, setDragging] = useState(false);
|
|
1212
|
-
const [
|
|
1629
|
+
const [internalFiles, setInternalFiles] = useState([]);
|
|
1630
|
+
const isControlled = value !== void 0;
|
|
1631
|
+
const selected = isControlled ? value : internalFiles;
|
|
1632
|
+
const setFiles = (next) => {
|
|
1633
|
+
if (!isControlled) setInternalFiles(next);
|
|
1634
|
+
onChange?.(next);
|
|
1635
|
+
};
|
|
1213
1636
|
const handleFiles = (files) => {
|
|
1214
1637
|
if (!files || files.length === 0) return;
|
|
1215
1638
|
const arr = Array.from(files);
|
|
1216
|
-
|
|
1639
|
+
setFiles(multiple ? arr : [arr[0]]);
|
|
1217
1640
|
onFiles?.(multiple ? arr : [arr[0]]);
|
|
1218
1641
|
};
|
|
1219
1642
|
const handleChange = (e) => {
|
|
@@ -1232,15 +1655,9 @@ function FileUpload({ onFiles, accept, multiple = false, disabled = false, "aria
|
|
|
1232
1655
|
};
|
|
1233
1656
|
const handleDragLeave = () => setDragging(false);
|
|
1234
1657
|
const removeFile = (i) => {
|
|
1235
|
-
|
|
1658
|
+
setFiles(selected.filter((_, idx) => idx !== i));
|
|
1236
1659
|
};
|
|
1237
|
-
const zoneClass = [
|
|
1238
|
-
"flex flex-col items-center justify-center gap-3",
|
|
1239
|
-
"rounded-2xl border-2 border-dashed p-8 text-center cursor-pointer",
|
|
1240
|
-
"transition-colors focus-within:outline-none focus-within:ring-2 focus-within:ring-brand-blue/20",
|
|
1241
|
-
dragging ? "border-brand-blue/60 bg-blue-50" : disabled ? "border-slate-100 bg-slate-50/40 cursor-not-allowed" : "border-slate-200 bg-white hover:border-brand-sky/50 hover:bg-[#eef2f8]",
|
|
1242
|
-
className
|
|
1243
|
-
].filter(Boolean).join(" ");
|
|
1660
|
+
const zoneClass = cn("flex flex-col items-center justify-center gap-3", "rounded-2xl border-2 border-dashed p-8 text-center cursor-pointer", "transition-colors focus-within:outline-none focus-within:ring-2 focus-within:ring-brand-blue/20", dragging ? "border-brand-blue/60 bg-blue-50" : disabled ? "border-slate-100 bg-slate-50/40 cursor-not-allowed" : "border-slate-200 bg-white hover:border-brand-sky/50 hover:bg-[#eef2f8]", className);
|
|
1244
1661
|
return /* @__PURE__ */ jsxs("div", {
|
|
1245
1662
|
className: "space-y-3",
|
|
1246
1663
|
children: [/* @__PURE__ */ jsxs("label", {
|
|
@@ -1251,7 +1668,7 @@ function FileUpload({ onFiles, accept, multiple = false, disabled = false, "aria
|
|
|
1251
1668
|
"aria-disabled": disabled,
|
|
1252
1669
|
children: [
|
|
1253
1670
|
/* @__PURE__ */ jsx("input", {
|
|
1254
|
-
ref: inputRef,
|
|
1671
|
+
ref: composeRefs(inputRef, ref),
|
|
1255
1672
|
type: "file",
|
|
1256
1673
|
accept,
|
|
1257
1674
|
multiple,
|
|
@@ -1325,13 +1742,7 @@ function FileUpload({ onFiles, accept, multiple = false, disabled = false, "aria
|
|
|
1325
1742
|
*/
|
|
1326
1743
|
function FilterChip({ label, onRemove, disabled = false, removeLabel = "Remove filter", className = "" }) {
|
|
1327
1744
|
return /* @__PURE__ */ jsxs("span", {
|
|
1328
|
-
className: [
|
|
1329
|
-
"inline-flex max-w-[20rem] items-center gap-1.5 rounded-full border",
|
|
1330
|
-
"py-1 pl-3 text-xs font-semibold",
|
|
1331
|
-
onRemove ? "pr-1.5" : "pr-3",
|
|
1332
|
-
disabled ? "border-slate-200 bg-slate-50 text-slate-400" : "border-brand-blue/30 bg-blue-50 text-brand-blue",
|
|
1333
|
-
className
|
|
1334
|
-
].filter(Boolean).join(" "),
|
|
1745
|
+
className: cn("inline-flex max-w-[20rem] items-center gap-1.5 rounded-full border", "py-1 pl-3 text-xs font-semibold", onRemove ? "pr-1.5" : "pr-3", disabled ? "border-slate-200 bg-slate-50 text-slate-400" : "border-brand-blue/30 bg-blue-50 text-brand-blue", className),
|
|
1335
1746
|
children: [/* @__PURE__ */ jsx("span", {
|
|
1336
1747
|
className: "truncate",
|
|
1337
1748
|
children: label
|
|
@@ -1340,11 +1751,7 @@ function FilterChip({ label, onRemove, disabled = false, removeLabel = "Remove f
|
|
|
1340
1751
|
onClick: !disabled ? onRemove : void 0,
|
|
1341
1752
|
disabled,
|
|
1342
1753
|
"aria-label": removeLabel,
|
|
1343
|
-
className:
|
|
1344
|
-
"flex h-4 w-4 shrink-0 items-center justify-center rounded-full transition",
|
|
1345
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30",
|
|
1346
|
-
disabled ? "cursor-not-allowed text-slate-300" : "text-brand-blue hover:bg-blue-100 hover:text-brand-navy"
|
|
1347
|
-
].filter(Boolean).join(" "),
|
|
1754
|
+
className: cn("flex h-4 w-4 shrink-0 items-center justify-center rounded-full transition", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30", disabled ? "cursor-not-allowed text-slate-300" : "text-brand-blue hover:bg-blue-100 hover:text-brand-navy"),
|
|
1348
1755
|
children: /* @__PURE__ */ jsx(X, {
|
|
1349
1756
|
size: 10,
|
|
1350
1757
|
"aria-hidden": "true",
|
|
@@ -1354,6 +1761,52 @@ function FilterChip({ label, onRemove, disabled = false, removeLabel = "Remove f
|
|
|
1354
1761
|
});
|
|
1355
1762
|
}
|
|
1356
1763
|
//#endregion
|
|
1764
|
+
//#region src/ui-library/gallery/search/Search.tsx
|
|
1765
|
+
/**
|
|
1766
|
+
* Search — Design System Component
|
|
1767
|
+
*
|
|
1768
|
+
* A search input with a built-in search icon prefix and optional clear button.
|
|
1769
|
+
* Built for filtering and discovery use cases — not for form submission fields
|
|
1770
|
+
* (use Input for those).
|
|
1771
|
+
*
|
|
1772
|
+
* Features:
|
|
1773
|
+
* - Search icon in prefix by default
|
|
1774
|
+
* - Optional × clear button when value is non-empty (pass onClear)
|
|
1775
|
+
* - Controlled via value + onChange (standard input event)
|
|
1776
|
+
* - Forwards ref to the underlying <input>
|
|
1777
|
+
* - All native <input> attributes are forwarded
|
|
1778
|
+
*/
|
|
1779
|
+
function Search({ value, onChange, onClear, placeholder = "Search…", disabled = false, className = "", ref, ...props }) {
|
|
1780
|
+
const hasValue = value !== void 0 && value !== "";
|
|
1781
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1782
|
+
className: cn("flex w-full items-center rounded-xl border bg-slate-50 transition-all", "border-slate-200 focus-within:border-brand-blue/50 focus-within:bg-white focus-within:ring-2 focus-within:ring-brand-blue/15", disabled && "cursor-not-allowed opacity-60", className),
|
|
1783
|
+
children: [
|
|
1784
|
+
/* @__PURE__ */ jsx("span", {
|
|
1785
|
+
className: "flex shrink-0 items-center pl-3.5 text-slate-400",
|
|
1786
|
+
"aria-hidden": "true",
|
|
1787
|
+
children: /* @__PURE__ */ jsx(Search$1, { size: 15 })
|
|
1788
|
+
}),
|
|
1789
|
+
/* @__PURE__ */ jsx("input", {
|
|
1790
|
+
ref,
|
|
1791
|
+
type: "search",
|
|
1792
|
+
value,
|
|
1793
|
+
onChange,
|
|
1794
|
+
placeholder,
|
|
1795
|
+
disabled,
|
|
1796
|
+
className: "w-full bg-transparent py-2.5 pl-2.5 pr-3 text-sm font-medium text-slate-900 outline-none placeholder:text-slate-400 disabled:cursor-not-allowed [&::-webkit-search-cancel-button]:hidden [&::-webkit-search-decoration]:hidden",
|
|
1797
|
+
...props
|
|
1798
|
+
}),
|
|
1799
|
+
onClear && hasValue && !disabled && /* @__PURE__ */ jsx("button", {
|
|
1800
|
+
type: "button",
|
|
1801
|
+
onClick: onClear,
|
|
1802
|
+
"aria-label": "Clear search",
|
|
1803
|
+
className: "flex shrink-0 items-center pr-3 text-slate-400 transition-colors hover:text-slate-600",
|
|
1804
|
+
children: /* @__PURE__ */ jsx(X, { size: 14 })
|
|
1805
|
+
})
|
|
1806
|
+
]
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
//#endregion
|
|
1357
1810
|
//#region src/ui-library/gallery/segmented-control/SegmentedControl.tsx
|
|
1358
1811
|
/**
|
|
1359
1812
|
* SegmentedControl — Design System Component
|
|
@@ -1421,11 +1874,7 @@ function SegmentedControl({ options, defaultValue, value: controlledValue, onVal
|
|
|
1421
1874
|
"aria-labelledby": ariaLabelledby,
|
|
1422
1875
|
"aria-disabled": disabled || void 0,
|
|
1423
1876
|
onKeyDown: handleKeyDown,
|
|
1424
|
-
className:
|
|
1425
|
-
"inline-flex rounded-xl bg-slate-100 p-1",
|
|
1426
|
-
disabled ? "opacity-50 pointer-events-none" : "",
|
|
1427
|
-
className
|
|
1428
|
-
].filter(Boolean).join(" "),
|
|
1877
|
+
className: cn("inline-flex rounded-xl bg-slate-100 p-1", disabled && "opacity-50 pointer-events-none", className),
|
|
1429
1878
|
children: options.map((opt) => {
|
|
1430
1879
|
const isSelected = opt.value === activeValue;
|
|
1431
1880
|
const isDisabled = disabled || opt.disabled;
|
|
@@ -1450,6 +1899,33 @@ function SegmentedControl({ options, defaultValue, value: controlledValue, onVal
|
|
|
1450
1899
|
}
|
|
1451
1900
|
//#endregion
|
|
1452
1901
|
//#region src/ui-library/gallery/validation-summary/ValidationSummary.tsx
|
|
1902
|
+
/**
|
|
1903
|
+
* ValidationSummary — Design System Component
|
|
1904
|
+
*
|
|
1905
|
+
* Renders a list of validation errors or warnings before a form is submitted.
|
|
1906
|
+
* Matches the production implementation in shared/components/ValidationSummary.tsx.
|
|
1907
|
+
*
|
|
1908
|
+
* Accessibility:
|
|
1909
|
+
* - role="alert" causes immediate announcement when injected into the DOM.
|
|
1910
|
+
* - <ul> with <li> items provides proper list semantics.
|
|
1911
|
+
* - The heading is a <div role="heading" aria-level="3"> to avoid disrupting
|
|
1912
|
+
* page outline; callers may override via headingLevel.
|
|
1913
|
+
* - Each issue is identified by field name + message.
|
|
1914
|
+
*
|
|
1915
|
+
* Usage:
|
|
1916
|
+
* const [issues, setIssues] = useState<ValidationIssue[]>([]);
|
|
1917
|
+
* // ... after validation:
|
|
1918
|
+
* setIssues([{ field: 'Employee ID', message: 'is required' }]);
|
|
1919
|
+
* // Render:
|
|
1920
|
+
* <ValidationSummary issues={issues} />
|
|
1921
|
+
*
|
|
1922
|
+
* // With scroll-to-field (wizard steps):
|
|
1923
|
+
* <ValidationSummary
|
|
1924
|
+
* issues={issues}
|
|
1925
|
+
* fieldIds={{ 'Employee ID': 'employee-id-input', 'Position': 'position-select' }}
|
|
1926
|
+
* fieldLabels={{ 'Employee ID': 'Employee ID', 'Position': 'Position Title' }}
|
|
1927
|
+
* />
|
|
1928
|
+
*/
|
|
1453
1929
|
function scrollToField(domId) {
|
|
1454
1930
|
const el = document.getElementById(domId);
|
|
1455
1931
|
if (!el) return;
|
|
@@ -1464,7 +1940,7 @@ function ValidationSummary({ issues, heading = "Review these fields before savin
|
|
|
1464
1940
|
if (issues.length === 0) return null;
|
|
1465
1941
|
return /* @__PURE__ */ jsxs("div", {
|
|
1466
1942
|
role: "alert",
|
|
1467
|
-
className:
|
|
1943
|
+
className: cn("rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900", className),
|
|
1468
1944
|
children: [/* @__PURE__ */ jsx("div", {
|
|
1469
1945
|
className: "font-bold",
|
|
1470
1946
|
children: heading
|
|
@@ -1528,7 +2004,7 @@ function Alert({ tone, title, children, icon = true, onDismiss, subtle = false,
|
|
|
1528
2004
|
const colorClass = subtle ? TONE_SUBTLE[tone] : TONE_FULL[tone];
|
|
1529
2005
|
return /* @__PURE__ */ jsxs("div", {
|
|
1530
2006
|
role: "alert",
|
|
1531
|
-
className:
|
|
2007
|
+
className: cn("flex gap-3 rounded-md pl-4 pr-4 py-3.5", colorClass, className),
|
|
1532
2008
|
children: [
|
|
1533
2009
|
icon && /* @__PURE__ */ jsx(Icon, {
|
|
1534
2010
|
size: 20,
|
|
@@ -1569,12 +2045,33 @@ function ErrorBanner({ message, tone = "error", className = "" }) {
|
|
|
1569
2045
|
return /* @__PURE__ */ jsx("div", {
|
|
1570
2046
|
role: tone === "error" ? "alert" : void 0,
|
|
1571
2047
|
"aria-live": tone !== "error" ? "polite" : void 0,
|
|
1572
|
-
className:
|
|
2048
|
+
className: cn("rounded-2xl border px-5 py-4 text-sm font-bold", STYLES[tone], className),
|
|
1573
2049
|
children: message
|
|
1574
2050
|
});
|
|
1575
2051
|
}
|
|
1576
2052
|
//#endregion
|
|
1577
2053
|
//#region src/ui-library/gallery/progress/Progress.tsx
|
|
2054
|
+
/**
|
|
2055
|
+
* Progress — Design System Component
|
|
2056
|
+
*
|
|
2057
|
+
* Determinate and indeterminate linear progress bar.
|
|
2058
|
+
*
|
|
2059
|
+
* Accessibility:
|
|
2060
|
+
* - role="progressbar"
|
|
2061
|
+
* - aria-valuenow, aria-valuemin, aria-valuemax (determinate)
|
|
2062
|
+
* - aria-label for screen-reader context
|
|
2063
|
+
* - When indeterminate: aria-valuenow is omitted
|
|
2064
|
+
*
|
|
2065
|
+
* Usage:
|
|
2066
|
+
* // Determinate (0–100)
|
|
2067
|
+
* <Progress value={65} aria-label="Upload progress" />
|
|
2068
|
+
*
|
|
2069
|
+
* // Indeterminate
|
|
2070
|
+
* <Progress aria-label="Loading" />
|
|
2071
|
+
*
|
|
2072
|
+
* // Custom max
|
|
2073
|
+
* <Progress value={3} max={5} aria-label="Step 3 of 5" />
|
|
2074
|
+
*/
|
|
1578
2075
|
function Progress({ value, max = 100, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className = "" }) {
|
|
1579
2076
|
const isIndeterminate = value === void 0;
|
|
1580
2077
|
const clamped = isIndeterminate ? 0 : Math.min(Math.max(value, 0), max);
|
|
@@ -1586,7 +2083,7 @@ function Progress({ value, max = 100, "aria-label": ariaLabel, "aria-labelledby"
|
|
|
1586
2083
|
"aria-valuemax": max,
|
|
1587
2084
|
"aria-label": ariaLabel,
|
|
1588
2085
|
"aria-labelledby": ariaLabelledby,
|
|
1589
|
-
className:
|
|
2086
|
+
className: cn("h-2 w-full overflow-hidden rounded-full bg-slate-200", className),
|
|
1590
2087
|
children: /* @__PURE__ */ jsx("div", {
|
|
1591
2088
|
className: ["h-full rounded-full bg-brand-blue transition-[width] duration-300", isIndeterminate ? "w-1/3 motion-safe:animate-pulse opacity-75" : ""].filter(Boolean).join(" "),
|
|
1592
2089
|
style: isIndeterminate ? void 0 : { width: `${percent}%` },
|
|
@@ -1596,17 +2093,20 @@ function Progress({ value, max = 100, "aria-label": ariaLabel, "aria-labelledby"
|
|
|
1596
2093
|
}
|
|
1597
2094
|
//#endregion
|
|
1598
2095
|
//#region src/ui-library/gallery/skeleton/Skeleton.tsx
|
|
1599
|
-
function Skeleton({ className = "" }) {
|
|
2096
|
+
function Skeleton({ className = "", variant = "pulse" }) {
|
|
1600
2097
|
return /* @__PURE__ */ jsx("div", {
|
|
1601
2098
|
"aria-hidden": "true",
|
|
1602
|
-
className:
|
|
2099
|
+
className: cn("rounded-lg", variant === "shimmer" ? "skeleton-shimmer" : "animate-pulse bg-slate-200", className)
|
|
1603
2100
|
});
|
|
1604
2101
|
}
|
|
1605
|
-
function SkeletonText({ lines = 3, className = "" }) {
|
|
2102
|
+
function SkeletonText({ lines = 3, className = "", variant = "pulse" }) {
|
|
1606
2103
|
return /* @__PURE__ */ jsx("div", {
|
|
1607
|
-
className:
|
|
2104
|
+
className: cn("space-y-2", className),
|
|
1608
2105
|
"aria-hidden": "true",
|
|
1609
|
-
children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx(Skeleton, {
|
|
2106
|
+
children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx(Skeleton, {
|
|
2107
|
+
variant,
|
|
2108
|
+
className: `h-3.5 ${i === lines - 1 && lines > 1 ? "w-2/3" : "w-full"}`
|
|
2109
|
+
}, i))
|
|
1610
2110
|
});
|
|
1611
2111
|
}
|
|
1612
2112
|
var AVATAR_SIZE = {
|
|
@@ -1614,17 +2114,23 @@ var AVATAR_SIZE = {
|
|
|
1614
2114
|
md: "h-10 w-10",
|
|
1615
2115
|
lg: "h-14 w-14"
|
|
1616
2116
|
};
|
|
1617
|
-
function SkeletonAvatar({ size = "md", className = "" }) {
|
|
2117
|
+
function SkeletonAvatar({ size = "md", className = "", variant = "pulse" }) {
|
|
1618
2118
|
return /* @__PURE__ */ jsx("div", {
|
|
1619
2119
|
"aria-hidden": "true",
|
|
1620
|
-
className:
|
|
2120
|
+
className: cn("rounded-full shrink-0", variant === "shimmer" ? "skeleton-shimmer" : "animate-pulse bg-slate-200", AVATAR_SIZE[size], className)
|
|
1621
2121
|
});
|
|
1622
2122
|
}
|
|
1623
|
-
function SkeletonCard({ className = "", children }) {
|
|
2123
|
+
function SkeletonCard({ className = "", children, variant = "pulse" }) {
|
|
1624
2124
|
return /* @__PURE__ */ jsx("div", {
|
|
1625
|
-
className:
|
|
2125
|
+
className: cn("rounded-2xl border border-slate-100 bg-white p-5 space-y-3", className),
|
|
1626
2126
|
"aria-hidden": "true",
|
|
1627
|
-
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Skeleton, {
|
|
2127
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Skeleton, {
|
|
2128
|
+
variant,
|
|
2129
|
+
className: "h-4 w-1/3"
|
|
2130
|
+
}), /* @__PURE__ */ jsx(SkeletonText, {
|
|
2131
|
+
variant,
|
|
2132
|
+
lines: 2
|
|
2133
|
+
})] })
|
|
1628
2134
|
});
|
|
1629
2135
|
}
|
|
1630
2136
|
function SkeletonTableRow({ rows = 5, columns = [
|
|
@@ -1632,12 +2138,15 @@ function SkeletonTableRow({ rows = 5, columns = [
|
|
|
1632
2138
|
"w-24",
|
|
1633
2139
|
"w-20",
|
|
1634
2140
|
"w-28"
|
|
1635
|
-
] }) {
|
|
2141
|
+
], variant = "pulse" }) {
|
|
1636
2142
|
return /* @__PURE__ */ jsx(Fragment, { children: Array.from({ length: rows }, (_, r) => /* @__PURE__ */ jsx("tr", {
|
|
1637
2143
|
"aria-hidden": "true",
|
|
1638
2144
|
children: columns.map((width, c) => /* @__PURE__ */ jsx("td", {
|
|
1639
2145
|
className: "px-5 py-3.5",
|
|
1640
|
-
children: /* @__PURE__ */ jsx(Skeleton, {
|
|
2146
|
+
children: /* @__PURE__ */ jsx(Skeleton, {
|
|
2147
|
+
variant,
|
|
2148
|
+
className: `h-3.5 ${width}`
|
|
2149
|
+
})
|
|
1641
2150
|
}, c))
|
|
1642
2151
|
}, r)) });
|
|
1643
2152
|
}
|
|
@@ -1653,12 +2162,7 @@ var TONE_STYLES = {
|
|
|
1653
2162
|
};
|
|
1654
2163
|
function StatusBadge({ tone = "neutral", children, className = "" }) {
|
|
1655
2164
|
return /* @__PURE__ */ jsx("span", {
|
|
1656
|
-
className: [
|
|
1657
|
-
"inline-flex items-center rounded-lg border px-2.5 py-1",
|
|
1658
|
-
"text-[10px] font-bold uppercase tracking-wider",
|
|
1659
|
-
TONE_STYLES[tone],
|
|
1660
|
-
className
|
|
1661
|
-
].filter(Boolean).join(" "),
|
|
2165
|
+
className: cn("inline-flex items-center rounded-lg border px-2.5 py-1", "text-[10px] font-bold uppercase tracking-wider", TONE_STYLES[tone], className),
|
|
1662
2166
|
children
|
|
1663
2167
|
});
|
|
1664
2168
|
}
|
|
@@ -1735,7 +2239,7 @@ var typography = {
|
|
|
1735
2239
|
* - Close button styling
|
|
1736
2240
|
* - Danger tone (rose badge, rose title, rose submit button)
|
|
1737
2241
|
*/
|
|
1738
|
-
function Modal({ isOpen, onClose, title, children, icon, subtitle, headerMeta, footer, onSubmit, submitLabel = "Submit", submittingLabel = "Saving...", submitting = false, danger = false, error, maxWidth = "max-w-xl", closeLabel = "Close" }) {
|
|
2242
|
+
function Modal({ isOpen, onClose, title, children, icon, subtitle, headerMeta, footer, onSubmit, submitLabel = "Submit", submittingLabel = "Saving...", submitting = false, danger = false, error, maxWidth = "max-w-xl", closeLabel = "Close", preventClose = false, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onInteractOutside }) {
|
|
1739
2243
|
const open = isOpen !== false;
|
|
1740
2244
|
const defaultFooter = onSubmit ? /* @__PURE__ */ jsxs("div", {
|
|
1741
2245
|
className: "flex items-center justify-end gap-3",
|
|
@@ -1768,13 +2272,17 @@ function Modal({ isOpen, onClose, title, children, icon, subtitle, headerMeta, f
|
|
|
1768
2272
|
return /* @__PURE__ */ jsx(DialogPrimitive.Root, {
|
|
1769
2273
|
open,
|
|
1770
2274
|
onOpenChange: (isOpen) => {
|
|
1771
|
-
if (!isOpen) onClose();
|
|
2275
|
+
if (!isOpen && !preventClose) onClose();
|
|
1772
2276
|
},
|
|
1773
|
-
children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [/* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-brand-navy/50 backdrop-blur-sm" }), /* @__PURE__ */ jsxs(DialogPrimitive.Content, {
|
|
1774
|
-
className: cn("fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2", "flex w-full flex-col", "rounded-lg border border-slate-200 bg-white shadow-xl", "max-h-[85vh] outline-none", "
|
|
2277
|
+
children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [/* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-brand-navy/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 duration-200" }), /* @__PURE__ */ jsxs(DialogPrimitive.Content, {
|
|
2278
|
+
className: cn("fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2", "flex w-full flex-col", "rounded-lg border border-slate-200 bg-white shadow-xl", "max-h-[85vh] outline-none", maxWidth, "data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0", "data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95", "duration-200"),
|
|
1775
2279
|
style: { padding: 0 },
|
|
2280
|
+
onOpenAutoFocus,
|
|
2281
|
+
onCloseAutoFocus,
|
|
2282
|
+
onEscapeKeyDown: preventClose ? (e) => e.preventDefault() : onEscapeKeyDown,
|
|
2283
|
+
onInteractOutside: preventClose ? (e) => e.preventDefault() : onInteractOutside,
|
|
1776
2284
|
children: [
|
|
1777
|
-
/* @__PURE__ */ jsx(DialogPrimitive.Close, {
|
|
2285
|
+
!preventClose && /* @__PURE__ */ jsx(DialogPrimitive.Close, {
|
|
1778
2286
|
asChild: true,
|
|
1779
2287
|
children: /* @__PURE__ */ jsx("button", {
|
|
1780
2288
|
type: "button",
|
|
@@ -1865,17 +2373,17 @@ var SIZE_CLASS = {
|
|
|
1865
2373
|
};
|
|
1866
2374
|
function DialogBody({ children, className = "" }) {
|
|
1867
2375
|
return /* @__PURE__ */ jsx("div", {
|
|
1868
|
-
className:
|
|
2376
|
+
className: cn("min-h-0 overflow-y-auto overscroll-contain px-6 py-4", className),
|
|
1869
2377
|
children
|
|
1870
2378
|
});
|
|
1871
2379
|
}
|
|
1872
2380
|
function DialogFooter({ children, className = "" }) {
|
|
1873
2381
|
return /* @__PURE__ */ jsx("div", {
|
|
1874
|
-
className:
|
|
2382
|
+
className: cn("flex items-center justify-end gap-3 border-t border-slate-100 px-6 py-4", className),
|
|
1875
2383
|
children
|
|
1876
2384
|
});
|
|
1877
2385
|
}
|
|
1878
|
-
function Dialog({ open, onClose, title, description, preventClose = false, size = "md", children }) {
|
|
2386
|
+
function Dialog({ open, onClose, title, description, preventClose = false, size = "md", children, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onInteractOutside }) {
|
|
1879
2387
|
const hasTitle = Boolean(title);
|
|
1880
2388
|
const hasDesc = Boolean(description);
|
|
1881
2389
|
return /* @__PURE__ */ jsx(DialogPrimitive.Root, {
|
|
@@ -1883,10 +2391,12 @@ function Dialog({ open, onClose, title, description, preventClose = false, size
|
|
|
1883
2391
|
onOpenChange: (isOpen) => {
|
|
1884
2392
|
if (!isOpen && !preventClose) onClose();
|
|
1885
2393
|
},
|
|
1886
|
-
children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [/* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-brand-navy/50 backdrop-blur-sm" }), /* @__PURE__ */ jsxs(DialogPrimitive.Content, {
|
|
1887
|
-
className: cn("fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2", "flex w-full flex-col overflow-hidden", "rounded-lg bg-white shadow-xl", "max-h-[90vh] outline-none", "
|
|
1888
|
-
onEscapeKeyDown: preventClose ? (e) => e.preventDefault() :
|
|
1889
|
-
onInteractOutside: preventClose ? (e) => e.preventDefault() :
|
|
2394
|
+
children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [/* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-brand-navy/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 duration-200" }), /* @__PURE__ */ jsxs(DialogPrimitive.Content, {
|
|
2395
|
+
className: cn("fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2", "flex w-full flex-col overflow-hidden", "rounded-lg bg-white shadow-xl", "max-h-[90vh] outline-none", SIZE_CLASS[size], "data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0", "data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95", "duration-200"),
|
|
2396
|
+
onEscapeKeyDown: preventClose ? (e) => e.preventDefault() : onEscapeKeyDown,
|
|
2397
|
+
onInteractOutside: preventClose ? (e) => e.preventDefault() : onInteractOutside,
|
|
2398
|
+
onOpenAutoFocus,
|
|
2399
|
+
onCloseAutoFocus,
|
|
1890
2400
|
style: { padding: 0 },
|
|
1891
2401
|
children: [
|
|
1892
2402
|
hasTitle ? /* @__PURE__ */ jsxs("div", {
|
|
@@ -1936,7 +2446,7 @@ var PLACEMENT_PANEL_CLASS = {
|
|
|
1936
2446
|
right: "fixed top-0 right-0 bottom-0 flex flex-col",
|
|
1937
2447
|
bottom: "fixed bottom-0 left-0 right-0 flex flex-col rounded-t-xl"
|
|
1938
2448
|
};
|
|
1939
|
-
function Drawer({ open, onClose, title, description, placement = "right", width = "w-80", maxHeight = "max-h-[85vh]", closeLabel = "Close drawer", children }) {
|
|
2449
|
+
function Drawer({ open, onClose, title, description, placement = "right", width = "w-80", maxHeight = "max-h-[85vh]", closeLabel = "Close drawer", children, className = "" }) {
|
|
1940
2450
|
const panelRef = useRef(null);
|
|
1941
2451
|
const titleId = useId();
|
|
1942
2452
|
const [rendered, setRendered] = useState(open);
|
|
@@ -1997,14 +2507,7 @@ function Drawer({ open, onClose, title, description, placement = "right", width
|
|
|
1997
2507
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1998
2508
|
}, [open, onClose]);
|
|
1999
2509
|
if (!rendered) return null;
|
|
2000
|
-
const panelClass = [
|
|
2001
|
-
PLACEMENT_PANEL_CLASS[placement],
|
|
2002
|
-
placement === "right" ? width : maxHeight,
|
|
2003
|
-
"bg-white shadow-xl focus:outline-none",
|
|
2004
|
-
placement === "bottom" ? "overflow-y-auto" : "overflow-hidden",
|
|
2005
|
-
"transition-transform duration-300 ease-out",
|
|
2006
|
-
placement === "right" ? visible ? "translate-x-0" : "translate-x-full" : visible ? "translate-y-0" : "translate-y-full"
|
|
2007
|
-
].filter(Boolean).join(" ");
|
|
2510
|
+
const panelClass = cn(PLACEMENT_PANEL_CLASS[placement], placement === "right" ? width : maxHeight, "bg-white shadow-xl focus:outline-none", placement === "bottom" ? "overflow-y-auto" : "overflow-hidden", "transition-transform duration-300 ease-out", placement === "right" ? visible ? "translate-x-0" : "translate-x-full" : visible ? "translate-y-0" : "translate-y-full", className);
|
|
2008
2511
|
return createPortal(/* @__PURE__ */ jsxs("div", {
|
|
2009
2512
|
className: "fixed inset-0 z-50",
|
|
2010
2513
|
children: [/* @__PURE__ */ jsx("div", {
|
|
@@ -2115,6 +2618,30 @@ function toRadixPlacement(placement) {
|
|
|
2115
2618
|
side: "top",
|
|
2116
2619
|
align: "end"
|
|
2117
2620
|
};
|
|
2621
|
+
case "left-start": return {
|
|
2622
|
+
side: "left",
|
|
2623
|
+
align: "start"
|
|
2624
|
+
};
|
|
2625
|
+
case "left": return {
|
|
2626
|
+
side: "left",
|
|
2627
|
+
align: "center"
|
|
2628
|
+
};
|
|
2629
|
+
case "left-end": return {
|
|
2630
|
+
side: "left",
|
|
2631
|
+
align: "end"
|
|
2632
|
+
};
|
|
2633
|
+
case "right-start": return {
|
|
2634
|
+
side: "right",
|
|
2635
|
+
align: "start"
|
|
2636
|
+
};
|
|
2637
|
+
case "right": return {
|
|
2638
|
+
side: "right",
|
|
2639
|
+
align: "center"
|
|
2640
|
+
};
|
|
2641
|
+
case "right-end": return {
|
|
2642
|
+
side: "right",
|
|
2643
|
+
align: "end"
|
|
2644
|
+
};
|
|
2118
2645
|
}
|
|
2119
2646
|
}
|
|
2120
2647
|
function Popover({ open, onOpenChange, defaultOpen = false, placement = "bottom-start", children }) {
|
|
@@ -2139,12 +2666,12 @@ var PopoverPlacementContext = createContext({
|
|
|
2139
2666
|
function usePlacement() {
|
|
2140
2667
|
return useContext(PopoverPlacementContext);
|
|
2141
2668
|
}
|
|
2142
|
-
function PopoverTrigger({ children }) {
|
|
2669
|
+
function PopoverTrigger({ children, className = "" }) {
|
|
2143
2670
|
return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, {
|
|
2144
2671
|
asChild: true,
|
|
2145
2672
|
children: /* @__PURE__ */ jsx("button", {
|
|
2146
2673
|
type: "button",
|
|
2147
|
-
className: "inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm font-semibold text-slate-700 shadow-sm transition hover:border-slate-300 hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30",
|
|
2674
|
+
className: cn("inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm font-semibold text-slate-700 shadow-sm transition hover:border-slate-300 hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30", className),
|
|
2148
2675
|
children
|
|
2149
2676
|
})
|
|
2150
2677
|
});
|
|
@@ -2155,7 +2682,7 @@ function PopoverContent({ title, children, maxWidth = "max-w-xs", className = ""
|
|
|
2155
2682
|
side,
|
|
2156
2683
|
align,
|
|
2157
2684
|
sideOffset: 8,
|
|
2158
|
-
className: cn("z-50 w-max rounded-xl border border-slate-200 bg-white shadow-lg", "outline-none", maxWidth, className),
|
|
2685
|
+
className: cn("z-50 w-max rounded-xl border border-slate-200 bg-white shadow-lg", "outline-none", "data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0", "data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95", "duration-200", maxWidth, className),
|
|
2159
2686
|
children: [title && /* @__PURE__ */ jsx("div", {
|
|
2160
2687
|
className: "border-b border-slate-100 px-4 py-3",
|
|
2161
2688
|
children: /* @__PURE__ */ jsx("h3", {
|
|
@@ -2173,8 +2700,8 @@ function PopoverContent({ title, children, maxWidth = "max-w-xs", className = ""
|
|
|
2173
2700
|
/**
|
|
2174
2701
|
* Tooltip — Design System Component
|
|
2175
2702
|
*
|
|
2176
|
-
* A short
|
|
2177
|
-
* an element.
|
|
2703
|
+
* A short label or non-interactive formatted content that appears on hover
|
|
2704
|
+
* or focus to describe an element.
|
|
2178
2705
|
*
|
|
2179
2706
|
* Behavior is provided by @radix-ui/react-tooltip, which handles:
|
|
2180
2707
|
* - Trigger scoping (fires only on the direct trigger, not descendants)
|
|
@@ -2191,14 +2718,16 @@ function PopoverContent({ title, children, maxWidth = "max-w-xs", className = ""
|
|
|
2191
2718
|
* - Typography and spacing
|
|
2192
2719
|
*
|
|
2193
2720
|
* Rules:
|
|
2194
|
-
* - Tooltip content must be
|
|
2721
|
+
* - Tooltip content must be non-interactive. Interactive elements (links,
|
|
2722
|
+
* buttons) inside `content` will be unclickable due to `pointer-events-none`
|
|
2723
|
+
* on the tooltip panel.
|
|
2195
2724
|
* - Do not put ESSENTIAL information only in a tooltip.
|
|
2196
2725
|
* - Use for supplementary descriptions: icon button labels, abbrev. meanings.
|
|
2197
2726
|
*
|
|
2198
2727
|
* Placement: 'top' | 'bottom' | 'left' | 'right'
|
|
2199
2728
|
*
|
|
2200
2729
|
* Difference from Popover:
|
|
2201
|
-
* - Tooltip is
|
|
2730
|
+
* - Tooltip is for non-interactive content, triggered by hover/focus.
|
|
2202
2731
|
* - Popover contains interactive content, triggered by explicit click.
|
|
2203
2732
|
*/
|
|
2204
2733
|
function Tooltip({ content, placement = "top", delayMs = 400, children, className = "" }) {
|
|
@@ -2214,7 +2743,7 @@ function Tooltip({ content, placement = "top", delayMs = 400, children, classNam
|
|
|
2214
2743
|
}), /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Content, {
|
|
2215
2744
|
side: placement,
|
|
2216
2745
|
sideOffset: 8,
|
|
2217
|
-
className: cn("pointer-events-none z-50 whitespace-nowrap", "rounded-lg bg-slate-900 px-2.5 py-1.5 text-xs font-semibold text-white shadow-lg", "border-b-2 border-brand-sky/60"),
|
|
2746
|
+
className: cn("pointer-events-none z-50 whitespace-nowrap", "rounded-lg bg-slate-900 px-2.5 py-1.5 text-xs font-semibold text-white shadow-lg", "border-b-2 border-brand-sky/60", "data-[state=open]:animate-in data-[state=open]:fade-in-0", "duration-150"),
|
|
2218
2747
|
children: content
|
|
2219
2748
|
}) })] })
|
|
2220
2749
|
});
|
|
@@ -2274,7 +2803,7 @@ var BTN_CANCEL = [
|
|
|
2274
2803
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/15",
|
|
2275
2804
|
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
2276
2805
|
].join(" ");
|
|
2277
|
-
function ConfirmDialog({ open, onClose, onConfirm, title, description, confirmLabel = "Confirm", cancelLabel = "Cancel", tone = "danger" }) {
|
|
2806
|
+
function ConfirmDialog({ open, onClose, onConfirm, title, description, confirmLabel = "Confirm", cancelLabel = "Cancel", tone = "danger", className = "" }) {
|
|
2278
2807
|
const [loading, setLoading] = useState(false);
|
|
2279
2808
|
const handleConfirm = async () => {
|
|
2280
2809
|
setLoading(true);
|
|
@@ -2292,17 +2821,20 @@ function ConfirmDialog({ open, onClose, onConfirm, title, description, confirmLa
|
|
|
2292
2821
|
title,
|
|
2293
2822
|
description: typeof description === "string" ? description : void 0,
|
|
2294
2823
|
size: "sm",
|
|
2295
|
-
children: [/* @__PURE__ */ jsx(DialogBody, {
|
|
2296
|
-
className
|
|
2297
|
-
children:
|
|
2298
|
-
className:
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2824
|
+
children: [/* @__PURE__ */ jsx(DialogBody, {
|
|
2825
|
+
className,
|
|
2826
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2827
|
+
className: "flex items-start gap-3",
|
|
2828
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2829
|
+
className: `mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-md ${ICON_WRAPPER[tone]}`,
|
|
2830
|
+
"aria-hidden": "true",
|
|
2831
|
+
children: tone === "danger" ? /* @__PURE__ */ jsx(AlertTriangle, { size: 20 }) : /* @__PURE__ */ jsx(Info, { size: 20 })
|
|
2832
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2833
|
+
className: "text-sm font-medium leading-relaxed text-slate-600",
|
|
2834
|
+
children: description
|
|
2835
|
+
})]
|
|
2836
|
+
})
|
|
2837
|
+
}), /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx("button", {
|
|
2306
2838
|
type: "button",
|
|
2307
2839
|
className: BTN_CANCEL,
|
|
2308
2840
|
onClick: onClose,
|
|
@@ -2396,7 +2928,7 @@ var radius = {
|
|
|
2396
2928
|
* - Use gallery Button component (Phase 11 — replaces legacy inlined btn* strings)
|
|
2397
2929
|
* - Use a simple inline ErrorBanner instead of importing from ui.tsx
|
|
2398
2930
|
*/
|
|
2399
|
-
function ConfirmAction({ title, message, label, description, confirmLabel = "Confirm", tone = "danger", disabled = false, onConfirm, children }) {
|
|
2931
|
+
function ConfirmAction({ title, message, label, description, confirmLabel = "Confirm", tone = "danger", disabled = false, onConfirm, children, className = "" }) {
|
|
2400
2932
|
const [open, setOpen] = useState(false);
|
|
2401
2933
|
const [pending, setPending] = useState(false);
|
|
2402
2934
|
const [error, setError] = useState("");
|
|
@@ -2420,7 +2952,7 @@ function ConfirmAction({ title, message, label, description, confirmLabel = "Con
|
|
|
2420
2952
|
},
|
|
2421
2953
|
disabled
|
|
2422
2954
|
}) : /* @__PURE__ */ jsx("span", {
|
|
2423
|
-
className: "inline-flex",
|
|
2955
|
+
className: cn("inline-flex", className),
|
|
2424
2956
|
onClick: () => {
|
|
2425
2957
|
if (!disabled) setOpen(true);
|
|
2426
2958
|
},
|
|
@@ -2480,7 +3012,7 @@ function ConfirmAction({ title, message, label, description, confirmLabel = "Con
|
|
|
2480
3012
|
* This component is presentation-only: callers provide commands and
|
|
2481
3013
|
* handle the query / selection logic.
|
|
2482
3014
|
*/
|
|
2483
|
-
function CommandPalette({ open, onClose, items, query, onQueryChange, placeholder = "Search commands…", "aria-label": ariaLabel = "Command palette" }) {
|
|
3015
|
+
function CommandPalette({ open, onClose, items, query, onQueryChange, placeholder = "Search commands…", "aria-label": ariaLabel = "Command palette", panelClassName = "" }) {
|
|
2484
3016
|
const inputRef = useRef(null);
|
|
2485
3017
|
const panelRef = useRef(null);
|
|
2486
3018
|
const listboxId = useId();
|
|
@@ -2514,6 +3046,23 @@ function CommandPalette({ open, onClose, items, query, onQueryChange, placeholde
|
|
|
2514
3046
|
e.preventDefault();
|
|
2515
3047
|
items[activeIndex]?.onSelect();
|
|
2516
3048
|
onClose();
|
|
3049
|
+
} else if (e.key === "Tab") {
|
|
3050
|
+
const panel = panelRef.current;
|
|
3051
|
+
if (!panel) return;
|
|
3052
|
+
const focusable = Array.from(panel.querySelectorAll("a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex=\"-1\"])"));
|
|
3053
|
+
if (!focusable.length) {
|
|
3054
|
+
e.preventDefault();
|
|
3055
|
+
return;
|
|
3056
|
+
}
|
|
3057
|
+
const first = focusable[0];
|
|
3058
|
+
const last = focusable[focusable.length - 1];
|
|
3059
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
3060
|
+
e.preventDefault();
|
|
3061
|
+
last.focus();
|
|
3062
|
+
} else if (!e.shiftKey && document.activeElement === last) {
|
|
3063
|
+
e.preventDefault();
|
|
3064
|
+
first.focus();
|
|
3065
|
+
}
|
|
2517
3066
|
}
|
|
2518
3067
|
};
|
|
2519
3068
|
document.addEventListener("keydown", handle);
|
|
@@ -2543,12 +3092,12 @@ function CommandPalette({ open, onClose, items, query, onQueryChange, placeholde
|
|
|
2543
3092
|
role: "dialog",
|
|
2544
3093
|
"aria-modal": "true",
|
|
2545
3094
|
"aria-label": ariaLabel,
|
|
2546
|
-
className: "relative z-10 w-full max-w-lg rounded-2xl border border-slate-200 bg-white shadow-2xl overflow-hidden",
|
|
3095
|
+
className: cn("relative z-10 w-full max-w-lg rounded-2xl border border-slate-200 bg-white shadow-2xl overflow-hidden", panelClassName),
|
|
2547
3096
|
children: [
|
|
2548
3097
|
/* @__PURE__ */ jsxs("div", {
|
|
2549
3098
|
className: "flex items-center gap-3 px-4 py-3 border-b border-slate-100",
|
|
2550
3099
|
children: [
|
|
2551
|
-
/* @__PURE__ */ jsx(Search, {
|
|
3100
|
+
/* @__PURE__ */ jsx(Search$1, {
|
|
2552
3101
|
size: 16,
|
|
2553
3102
|
className: "shrink-0 text-slate-400",
|
|
2554
3103
|
"aria-hidden": "true"
|
|
@@ -2654,10 +3203,11 @@ function CommandPalette({ open, onClose, items, query, onQueryChange, placeholde
|
|
|
2654
3203
|
* ]}
|
|
2655
3204
|
* />
|
|
2656
3205
|
*/
|
|
2657
|
-
function Breadcrumb({ items, showHome = true, ariaLabel = "Breadcrumb" }) {
|
|
3206
|
+
function Breadcrumb({ items, showHome = true, ariaLabel = "Breadcrumb", className = "" }) {
|
|
2658
3207
|
if (items.length === 0) return null;
|
|
2659
3208
|
return /* @__PURE__ */ jsx("nav", {
|
|
2660
3209
|
"aria-label": ariaLabel,
|
|
3210
|
+
className: cn(className),
|
|
2661
3211
|
children: /* @__PURE__ */ jsxs("ol", {
|
|
2662
3212
|
className: "flex flex-wrap items-center gap-1 text-sm font-semibold text-slate-400",
|
|
2663
3213
|
children: [showHome && /* @__PURE__ */ jsx("li", {
|
|
@@ -2798,7 +3348,7 @@ function TabList({ "aria-label": ariaLabel, children, className = "" }) {
|
|
|
2798
3348
|
role: "tablist",
|
|
2799
3349
|
"aria-label": ariaLabel,
|
|
2800
3350
|
onKeyDown: handleKeyDown,
|
|
2801
|
-
className:
|
|
3351
|
+
className: cn("flex border-b-2 border-slate-200", className),
|
|
2802
3352
|
children
|
|
2803
3353
|
});
|
|
2804
3354
|
}
|
|
@@ -2818,12 +3368,7 @@ function Tab({ value, disabled = false, children, className = "" }) {
|
|
|
2818
3368
|
disabled,
|
|
2819
3369
|
tabIndex: isActive ? 0 : -1,
|
|
2820
3370
|
onClick: () => activate(value),
|
|
2821
|
-
className:
|
|
2822
|
-
"relative px-5 py-3 text-sm font-semibold font-heading border-b-4 transition-colors",
|
|
2823
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30",
|
|
2824
|
-
isActive ? "border-brand-blue text-brand-blue" : disabled ? "border-transparent text-slate-300 cursor-not-allowed" : "border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300",
|
|
2825
|
-
className
|
|
2826
|
-
].filter(Boolean).join(" "),
|
|
3371
|
+
className: cn("relative px-5 py-3 text-sm font-semibold font-heading border-b-4 transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30", isActive ? "border-brand-blue text-brand-blue" : disabled ? "border-transparent text-slate-300 cursor-not-allowed" : "border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300", className),
|
|
2827
3372
|
children
|
|
2828
3373
|
});
|
|
2829
3374
|
}
|
|
@@ -2841,7 +3386,7 @@ function TabPanel({ value, children, className = "" }) {
|
|
|
2841
3386
|
role: "tabpanel",
|
|
2842
3387
|
"aria-labelledby": tabId(baseId, value),
|
|
2843
3388
|
tabIndex: 0,
|
|
2844
|
-
className:
|
|
3389
|
+
className: cn("focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30 rounded-sm", className),
|
|
2845
3390
|
children
|
|
2846
3391
|
});
|
|
2847
3392
|
}
|
|
@@ -2874,14 +3419,14 @@ function getPageNumbers(current, total) {
|
|
|
2874
3419
|
pages.push(total);
|
|
2875
3420
|
return pages;
|
|
2876
3421
|
}
|
|
2877
|
-
function Pagination({ page, totalPages, onPageChange, ariaLabel = "Pagination", totalItems, pageSize, itemLabel = "items" }) {
|
|
3422
|
+
function Pagination({ page, totalPages, onPageChange, ariaLabel = "Pagination", totalItems, pageSize, itemLabel = "items", className = "" }) {
|
|
2878
3423
|
if (totalPages <= 1 && !totalItems) return null;
|
|
2879
3424
|
const showRecordCount = typeof totalItems === "number" && typeof pageSize === "number";
|
|
2880
3425
|
const rangeStart = showRecordCount ? (page - 1) * pageSize + 1 : null;
|
|
2881
3426
|
const rangeEnd = showRecordCount ? Math.min(page * pageSize, totalItems) : null;
|
|
2882
3427
|
const pageNumbers = getPageNumbers(page, totalPages);
|
|
2883
3428
|
return /* @__PURE__ */ jsxs("div", {
|
|
2884
|
-
className: "flex items-center justify-between gap-4",
|
|
3429
|
+
className: cn("flex items-center justify-between gap-4", className),
|
|
2885
3430
|
children: [showRecordCount ? /* @__PURE__ */ jsxs("p", {
|
|
2886
3431
|
className: "text-[11px] font-bold tabular-nums text-slate-400",
|
|
2887
3432
|
"aria-live": "polite",
|
|
@@ -2950,14 +3495,19 @@ function resolveState(id, currentStep, completedSteps, disabledSteps) {
|
|
|
2950
3495
|
if (id === currentStep) return "current";
|
|
2951
3496
|
return "upcoming";
|
|
2952
3497
|
}
|
|
2953
|
-
function StepCircle({ state, number, icon }) {
|
|
3498
|
+
function StepCircle({ state, number, icon, dark = false }) {
|
|
2954
3499
|
return /* @__PURE__ */ jsx("div", {
|
|
2955
|
-
className: `flex h-9 w-9 shrink-0 items-center justify-center rounded-full border-2 text-sm font-bold transition-all ${{
|
|
3500
|
+
className: `flex h-9 w-9 shrink-0 items-center justify-center rounded-full border-2 text-sm font-bold transition-all ${(dark ? {
|
|
3501
|
+
completed: "border-[#2D8ACA] bg-[#2D8ACA] text-white",
|
|
3502
|
+
current: "border-white bg-white text-[#00377B] shadow-md shadow-black/20",
|
|
3503
|
+
upcoming: "border-white/30 bg-white/10 text-white/60",
|
|
3504
|
+
disabled: "border-white/10 bg-white/5 text-white/20"
|
|
3505
|
+
} : {
|
|
2956
3506
|
completed: "border-brand-blue bg-brand-blue text-white",
|
|
2957
3507
|
current: "border-brand-blue bg-white text-brand-blue shadow-md shadow-brand-blue/15",
|
|
2958
3508
|
upcoming: "border-slate-300 bg-white text-slate-400",
|
|
2959
3509
|
disabled: "border-slate-200 bg-slate-50 text-slate-300"
|
|
2960
|
-
}[state]}`,
|
|
3510
|
+
})[state]}`,
|
|
2961
3511
|
"aria-hidden": "true",
|
|
2962
3512
|
children: state === "completed" ? icon ?? /* @__PURE__ */ jsx(Check, {
|
|
2963
3513
|
size: 16,
|
|
@@ -2965,17 +3515,31 @@ function StepCircle({ state, number, icon }) {
|
|
|
2965
3515
|
}) : icon ?? /* @__PURE__ */ jsx("span", { children: number })
|
|
2966
3516
|
});
|
|
2967
3517
|
}
|
|
2968
|
-
function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [], orientation = "horizontal", className = "" }) {
|
|
2969
|
-
|
|
3518
|
+
function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [], orientation = "horizontal", theme = "light", className = "" }) {
|
|
3519
|
+
const isHorizontal = orientation === "horizontal";
|
|
3520
|
+
const dark = theme === "dark";
|
|
3521
|
+
if (!isHorizontal) return /* @__PURE__ */ jsx("div", {
|
|
2970
3522
|
role: "group",
|
|
2971
3523
|
"aria-label": "Progress",
|
|
2972
|
-
className:
|
|
3524
|
+
className: cn("flex flex-col", className),
|
|
2973
3525
|
children: /* @__PURE__ */ jsx("ol", {
|
|
2974
3526
|
className: "flex flex-col",
|
|
2975
3527
|
children: steps.map((step, idx) => {
|
|
2976
3528
|
const state = resolveState(step.id, currentStep, completedSteps, disabledSteps);
|
|
2977
3529
|
const isCurrent = state === "current";
|
|
2978
3530
|
const isLast = idx === steps.length - 1;
|
|
3531
|
+
const labelColor = dark ? {
|
|
3532
|
+
completed: "text-[#2D8ACA]",
|
|
3533
|
+
current: "text-white font-bold",
|
|
3534
|
+
upcoming: "text-white/60",
|
|
3535
|
+
disabled: "text-white/20"
|
|
3536
|
+
} : {
|
|
3537
|
+
completed: "text-brand-blue",
|
|
3538
|
+
current: "text-brand-navy font-bold",
|
|
3539
|
+
upcoming: "text-slate-500",
|
|
3540
|
+
disabled: "text-slate-300"
|
|
3541
|
+
};
|
|
3542
|
+
const connectorColor = dark ? state === "completed" ? "bg-[#2D8ACA]/50" : "bg-white/15" : state === "completed" ? "bg-brand-blue/50" : "bg-slate-200";
|
|
2979
3543
|
return /* @__PURE__ */ jsxs("li", {
|
|
2980
3544
|
"aria-current": isCurrent ? "step" : void 0,
|
|
2981
3545
|
className: "flex items-start gap-4 pb-8 last:pb-0",
|
|
@@ -2984,23 +3548,19 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
|
|
|
2984
3548
|
children: [/* @__PURE__ */ jsx(StepCircle, {
|
|
2985
3549
|
state,
|
|
2986
3550
|
number: idx + 1,
|
|
2987
|
-
icon: step.icon
|
|
3551
|
+
icon: step.icon,
|
|
3552
|
+
dark
|
|
2988
3553
|
}), !isLast && /* @__PURE__ */ jsx("div", {
|
|
2989
|
-
className: `mt-1 w-0.5 flex-1 min-h-[32px] ${
|
|
3554
|
+
className: `mt-1 w-0.5 flex-1 min-h-[32px] ${connectorColor}`,
|
|
2990
3555
|
"aria-hidden": "true"
|
|
2991
3556
|
})]
|
|
2992
3557
|
}), /* @__PURE__ */ jsxs("div", {
|
|
2993
3558
|
className: "min-w-0 flex-1 pt-1",
|
|
2994
3559
|
children: [/* @__PURE__ */ jsx("p", {
|
|
2995
|
-
className: `text-sm leading-tight ${
|
|
2996
|
-
completed: "text-brand-blue",
|
|
2997
|
-
current: "text-brand-navy font-bold",
|
|
2998
|
-
upcoming: "text-slate-500",
|
|
2999
|
-
disabled: "text-slate-300"
|
|
3000
|
-
}[state]}`,
|
|
3560
|
+
className: `text-sm leading-tight ${labelColor[state]}`,
|
|
3001
3561
|
children: step.label
|
|
3002
3562
|
}), step.description && /* @__PURE__ */ jsx("p", {
|
|
3003
|
-
className:
|
|
3563
|
+
className: `mt-0.5 text-xs leading-tight ${dark ? "text-white/40" : "text-slate-400"}`,
|
|
3004
3564
|
children: step.description
|
|
3005
3565
|
})]
|
|
3006
3566
|
})]
|
|
@@ -3009,7 +3569,12 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
|
|
|
3009
3569
|
})
|
|
3010
3570
|
});
|
|
3011
3571
|
const resolvedStates = steps.map((step) => resolveState(step.id, currentStep, completedSteps, disabledSteps));
|
|
3012
|
-
const labelColor = {
|
|
3572
|
+
const labelColor = dark ? {
|
|
3573
|
+
completed: "text-[#2D8ACA]",
|
|
3574
|
+
current: "text-white font-bold",
|
|
3575
|
+
upcoming: "text-white/60",
|
|
3576
|
+
disabled: "text-white/20"
|
|
3577
|
+
} : {
|
|
3013
3578
|
completed: "text-brand-blue",
|
|
3014
3579
|
current: "text-brand-navy font-bold",
|
|
3015
3580
|
upcoming: "text-slate-500",
|
|
@@ -3018,7 +3583,7 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
|
|
|
3018
3583
|
return /* @__PURE__ */ jsx("div", {
|
|
3019
3584
|
role: "group",
|
|
3020
3585
|
"aria-label": "Progress",
|
|
3021
|
-
className:
|
|
3586
|
+
className: cn("w-full", className),
|
|
3022
3587
|
children: /* @__PURE__ */ jsx("ol", {
|
|
3023
3588
|
className: "grid w-full",
|
|
3024
3589
|
style: { gridTemplateColumns: `repeat(${steps.length}, 1fr)` },
|
|
@@ -3027,6 +3592,9 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
|
|
|
3027
3592
|
const isCurrent = state === "current";
|
|
3028
3593
|
const isLast = idx === steps.length - 1;
|
|
3029
3594
|
const prevState = idx > 0 ? resolvedStates[idx - 1] : null;
|
|
3595
|
+
const connectorDone = prevState === "completed" || prevState === "current";
|
|
3596
|
+
const connectorLeft = dark ? connectorDone ? "bg-[#2D8ACA]/50" : "bg-white/15" : connectorDone ? "bg-brand-blue/50" : "bg-slate-200";
|
|
3597
|
+
const connectorRight = dark ? state === "completed" ? "bg-[#2D8ACA]/50" : "bg-white/15" : state === "completed" ? "bg-brand-blue/50" : "bg-slate-200";
|
|
3030
3598
|
return /* @__PURE__ */ jsxs("li", {
|
|
3031
3599
|
"aria-current": isCurrent ? "step" : void 0,
|
|
3032
3600
|
className: "flex flex-col items-center",
|
|
@@ -3034,7 +3602,7 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
|
|
|
3034
3602
|
className: "flex w-full items-center",
|
|
3035
3603
|
children: [
|
|
3036
3604
|
idx > 0 ? /* @__PURE__ */ jsx("div", {
|
|
3037
|
-
className: `h-0.5 flex-1 ${
|
|
3605
|
+
className: `h-0.5 flex-1 ${connectorLeft}`,
|
|
3038
3606
|
"aria-hidden": "true"
|
|
3039
3607
|
}) : /* @__PURE__ */ jsx("div", {
|
|
3040
3608
|
className: "flex-1",
|
|
@@ -3045,11 +3613,12 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
|
|
|
3045
3613
|
children: /* @__PURE__ */ jsx(StepCircle, {
|
|
3046
3614
|
state,
|
|
3047
3615
|
number: idx + 1,
|
|
3048
|
-
icon: step.icon
|
|
3616
|
+
icon: step.icon,
|
|
3617
|
+
dark
|
|
3049
3618
|
})
|
|
3050
3619
|
}),
|
|
3051
3620
|
!isLast ? /* @__PURE__ */ jsx("div", {
|
|
3052
|
-
className: `h-0.5 flex-1 ${
|
|
3621
|
+
className: `h-0.5 flex-1 ${connectorRight}`,
|
|
3053
3622
|
"aria-hidden": "true"
|
|
3054
3623
|
}) : /* @__PURE__ */ jsx("div", {
|
|
3055
3624
|
className: "flex-1",
|
|
@@ -3062,7 +3631,7 @@ function Stepper({ steps, currentStep, completedSteps = [], disabledSteps = [],
|
|
|
3062
3631
|
className: `text-sm leading-tight ${labelColor[state]}`,
|
|
3063
3632
|
children: step.label
|
|
3064
3633
|
}), step.description && /* @__PURE__ */ jsx("p", {
|
|
3065
|
-
className:
|
|
3634
|
+
className: `mt-0.5 text-xs leading-tight ${dark ? "text-white/40" : "text-slate-400"}`,
|
|
3066
3635
|
children: step.description
|
|
3067
3636
|
})]
|
|
3068
3637
|
})]
|
|
@@ -3216,10 +3785,23 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
|
|
|
3216
3785
|
const ref = useRef(null);
|
|
3217
3786
|
const triggerRef = useRef(null);
|
|
3218
3787
|
const panelId = `${useId().replace(/:/g, "")}-panel`;
|
|
3788
|
+
const [panelStyle, setPanelStyle] = useState({});
|
|
3789
|
+
useEffect(() => {
|
|
3790
|
+
if (!isOpen || !triggerRef.current) return;
|
|
3791
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
3792
|
+
setPanelStyle({
|
|
3793
|
+
position: "fixed",
|
|
3794
|
+
top: rect.bottom + 4,
|
|
3795
|
+
left: rect.left,
|
|
3796
|
+
zIndex: 9999,
|
|
3797
|
+
minWidth: Math.max(rect.width, 180)
|
|
3798
|
+
});
|
|
3799
|
+
}, [isOpen]);
|
|
3219
3800
|
useEffect(() => {
|
|
3220
3801
|
if (!isOpen) return;
|
|
3221
3802
|
const handlePointerDown = (e) => {
|
|
3222
|
-
|
|
3803
|
+
const target = e.target;
|
|
3804
|
+
if (ref.current && !ref.current.contains(target)) {
|
|
3223
3805
|
onClose();
|
|
3224
3806
|
triggerRef.current?.focus();
|
|
3225
3807
|
}
|
|
@@ -3249,21 +3831,14 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
|
|
|
3249
3831
|
"aria-expanded": isOpen,
|
|
3250
3832
|
"aria-haspopup": "true",
|
|
3251
3833
|
"aria-controls": isOpen ? panelId : void 0,
|
|
3252
|
-
className:
|
|
3253
|
-
"inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-bold text-slate-600 transition-all",
|
|
3254
|
-
"hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30",
|
|
3255
|
-
triggerClassName
|
|
3256
|
-
].filter(Boolean).join(" "),
|
|
3834
|
+
className: cn("inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-bold text-slate-600 transition-all", "hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30", triggerClassName),
|
|
3257
3835
|
children: trigger
|
|
3258
|
-
}), isOpen && /* @__PURE__ */ jsx("div", {
|
|
3836
|
+
}), isOpen && createPortal(/* @__PURE__ */ jsx("div", {
|
|
3259
3837
|
id: panelId,
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
"rounded-xl border border-slate-200 bg-white shadow-lg",
|
|
3263
|
-
panelClassName
|
|
3264
|
-
].filter(Boolean).join(" "),
|
|
3838
|
+
style: panelStyle,
|
|
3839
|
+
className: cn("max-h-[280px] overflow-y-auto", "rounded-xl border border-slate-200 bg-white shadow-lg", panelClassName),
|
|
3265
3840
|
children
|
|
3266
|
-
})]
|
|
3841
|
+
}), document.body)]
|
|
3267
3842
|
});
|
|
3268
3843
|
}
|
|
3269
3844
|
//#endregion
|
|
@@ -3290,15 +3865,36 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
|
|
|
3290
3865
|
* ]}
|
|
3291
3866
|
* />
|
|
3292
3867
|
*/
|
|
3293
|
-
function Menu({ trigger, items, ariaLabel = "Menu", align = "right" }) {
|
|
3294
|
-
const [
|
|
3868
|
+
function Menu({ trigger, items, ariaLabel = "Menu", align = "right", open: controlledOpen, onOpenChange, panelClassName = "" }) {
|
|
3869
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
3870
|
+
const isControlled = controlledOpen !== void 0;
|
|
3871
|
+
const open = isControlled ? controlledOpen : internalOpen;
|
|
3872
|
+
const setOpen = (next) => {
|
|
3873
|
+
if (!isControlled) setInternalOpen(next);
|
|
3874
|
+
onOpenChange?.(next);
|
|
3875
|
+
};
|
|
3295
3876
|
const containerRef = useRef(null);
|
|
3296
3877
|
const triggerRef = useRef(null);
|
|
3878
|
+
const panelRef = useRef(null);
|
|
3297
3879
|
const itemRefs = useRef([]);
|
|
3880
|
+
const [panelStyle, setPanelStyle] = useState({});
|
|
3881
|
+
useEffect(() => {
|
|
3882
|
+
if (!open || !triggerRef.current) return;
|
|
3883
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
3884
|
+
const PANEL_MIN_WIDTH = 176;
|
|
3885
|
+
setPanelStyle({
|
|
3886
|
+
position: "fixed",
|
|
3887
|
+
top: rect.bottom + 4,
|
|
3888
|
+
left: align === "left" ? rect.left : Math.max(0, rect.right - PANEL_MIN_WIDTH),
|
|
3889
|
+
zIndex: 9999,
|
|
3890
|
+
minWidth: Math.max(rect.width, PANEL_MIN_WIDTH)
|
|
3891
|
+
});
|
|
3892
|
+
}, [open, align]);
|
|
3298
3893
|
useEffect(() => {
|
|
3299
3894
|
if (!open) return;
|
|
3300
3895
|
const handlePointerDown = (e) => {
|
|
3301
|
-
|
|
3896
|
+
const target = e.target;
|
|
3897
|
+
if (containerRef.current && !containerRef.current.contains(target) && !(panelRef.current && panelRef.current.contains(target))) {
|
|
3302
3898
|
setOpen(false);
|
|
3303
3899
|
(triggerRef.current?.querySelector("button,a,[tabindex]"))?.focus();
|
|
3304
3900
|
}
|
|
@@ -3339,22 +3935,23 @@ function Menu({ trigger, items, ariaLabel = "Menu", align = "right" }) {
|
|
|
3339
3935
|
focusItem(items.length - 1);
|
|
3340
3936
|
}
|
|
3341
3937
|
};
|
|
3342
|
-
const panelAlign = align === "left" ? "left-0" : "right-0";
|
|
3343
3938
|
return /* @__PURE__ */ jsxs("div", {
|
|
3344
3939
|
className: "relative inline-block",
|
|
3345
3940
|
ref: containerRef,
|
|
3346
3941
|
children: [/* @__PURE__ */ jsx("div", {
|
|
3347
3942
|
ref: triggerRef,
|
|
3348
|
-
onClick: () => setOpen(
|
|
3943
|
+
onClick: () => setOpen(!open),
|
|
3349
3944
|
className: "cursor-pointer",
|
|
3350
3945
|
children: isValidElement(trigger) ? cloneElement(trigger, {
|
|
3351
3946
|
"aria-expanded": open,
|
|
3352
3947
|
"aria-haspopup": "menu"
|
|
3353
3948
|
}) : trigger
|
|
3354
|
-
}), open && /* @__PURE__ */ jsx("div", {
|
|
3949
|
+
}), open && createPortal(/* @__PURE__ */ jsx("div", {
|
|
3950
|
+
ref: panelRef,
|
|
3355
3951
|
role: "menu",
|
|
3356
3952
|
"aria-label": ariaLabel,
|
|
3357
|
-
|
|
3953
|
+
style: panelStyle,
|
|
3954
|
+
className: cn("overflow-hidden rounded-xl border border-slate-200 bg-white py-1 shadow-xl", panelClassName),
|
|
3358
3955
|
children: items.map((item, index) => /* @__PURE__ */ jsxs("button", {
|
|
3359
3956
|
ref: (node) => {
|
|
3360
3957
|
itemRefs.current[index] = node;
|
|
@@ -3380,7 +3977,7 @@ function Menu({ trigger, items, ariaLabel = "Menu", align = "right" }) {
|
|
|
3380
3977
|
children: item.icon
|
|
3381
3978
|
}), item.label]
|
|
3382
3979
|
}, item.label))
|
|
3383
|
-
})]
|
|
3980
|
+
}), document.body)]
|
|
3384
3981
|
});
|
|
3385
3982
|
}
|
|
3386
3983
|
//#endregion
|
|
@@ -3395,13 +3992,13 @@ function Card({ variant = "default", children, className = "", onClick }) {
|
|
|
3395
3992
|
return /* @__PURE__ */ jsx(onClick ? "button" : "div", {
|
|
3396
3993
|
type: onClick ? "button" : void 0,
|
|
3397
3994
|
onClick,
|
|
3398
|
-
className:
|
|
3995
|
+
className: cn("overflow-hidden rounded-lg", VARIANT_CLASS[variant], className),
|
|
3399
3996
|
children
|
|
3400
3997
|
});
|
|
3401
3998
|
}
|
|
3402
|
-
function CardHeader({ title, description, actions }) {
|
|
3999
|
+
function CardHeader({ title, description, actions, className = "" }) {
|
|
3403
4000
|
return /* @__PURE__ */ jsxs("div", {
|
|
3404
|
-
className: "flex items-start justify-between gap-3 px-5 py-4 border-b-2 border-slate-100",
|
|
4001
|
+
className: cn("flex items-start justify-between gap-3 px-5 py-4 border-b-2 border-slate-100", className),
|
|
3405
4002
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
3406
4003
|
className: "min-w-0",
|
|
3407
4004
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
@@ -3419,13 +4016,13 @@ function CardHeader({ title, description, actions }) {
|
|
|
3419
4016
|
}
|
|
3420
4017
|
function CardContent({ children, className = "" }) {
|
|
3421
4018
|
return /* @__PURE__ */ jsx("div", {
|
|
3422
|
-
className:
|
|
4019
|
+
className: cn("px-5 py-4", className),
|
|
3423
4020
|
children
|
|
3424
4021
|
});
|
|
3425
4022
|
}
|
|
3426
4023
|
function CardFooter({ children, className = "" }) {
|
|
3427
4024
|
return /* @__PURE__ */ jsx("div", {
|
|
3428
|
-
className:
|
|
4025
|
+
className: cn("flex items-center justify-end gap-2 border-t border-slate-100 px-5 py-3", className),
|
|
3429
4026
|
children
|
|
3430
4027
|
});
|
|
3431
4028
|
}
|
|
@@ -3491,7 +4088,7 @@ function Accordion({ type = "single", defaultValue, value: controlledValue, onVa
|
|
|
3491
4088
|
toggle
|
|
3492
4089
|
},
|
|
3493
4090
|
children: /* @__PURE__ */ jsx("div", {
|
|
3494
|
-
className:
|
|
4091
|
+
className: cn("divide-y divide-slate-200 rounded-xl border border-slate-200", className),
|
|
3495
4092
|
children
|
|
3496
4093
|
})
|
|
3497
4094
|
});
|
|
@@ -3508,7 +4105,7 @@ function AccordionItem({ value, disabled = false, children, className = "" }) {
|
|
|
3508
4105
|
triggerId
|
|
3509
4106
|
},
|
|
3510
4107
|
children: /* @__PURE__ */ jsx("div", {
|
|
3511
|
-
className:
|
|
4108
|
+
className: cn(className),
|
|
3512
4109
|
children
|
|
3513
4110
|
})
|
|
3514
4111
|
});
|
|
@@ -3525,12 +4122,7 @@ function AccordionTrigger({ children, className = "" }) {
|
|
|
3525
4122
|
"aria-disabled": disabled || void 0,
|
|
3526
4123
|
disabled,
|
|
3527
4124
|
onClick: () => toggle(value),
|
|
3528
|
-
className:
|
|
3529
|
-
"flex w-full items-center justify-between px-5 py-4 text-left text-sm font-semibold",
|
|
3530
|
-
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30",
|
|
3531
|
-
disabled ? "cursor-not-allowed text-slate-300" : "text-slate-800 hover:bg-slate-50",
|
|
3532
|
-
className
|
|
3533
|
-
].filter(Boolean).join(" "),
|
|
4125
|
+
className: cn("flex w-full items-center justify-between px-5 py-4 text-left text-sm font-semibold", "transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30", disabled ? "cursor-not-allowed text-slate-300" : "text-slate-800 hover:bg-slate-50", className),
|
|
3534
4126
|
children: [/* @__PURE__ */ jsx("span", { children }), /* @__PURE__ */ jsx(ChevronDown, {
|
|
3535
4127
|
size: 16,
|
|
3536
4128
|
"aria-hidden": "true",
|
|
@@ -3541,13 +4133,21 @@ function AccordionTrigger({ children, className = "" }) {
|
|
|
3541
4133
|
function AccordionContent({ children, className = "" }) {
|
|
3542
4134
|
const { openValues } = useAccordionContext();
|
|
3543
4135
|
const { value, panelId, triggerId } = useItemContext();
|
|
3544
|
-
|
|
4136
|
+
const isOpen = openValues.has(value);
|
|
3545
4137
|
return /* @__PURE__ */ jsx("div", {
|
|
3546
4138
|
id: panelId,
|
|
3547
4139
|
role: "region",
|
|
3548
4140
|
"aria-labelledby": triggerId,
|
|
3549
|
-
|
|
3550
|
-
|
|
4141
|
+
"aria-hidden": !isOpen || void 0,
|
|
4142
|
+
"data-state": isOpen ? "open" : "closed",
|
|
4143
|
+
className: cn("grid overflow-hidden transition-[grid-template-rows] duration-200 ease-out", isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"),
|
|
4144
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
4145
|
+
className: "min-h-0",
|
|
4146
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
4147
|
+
className: cn("border-t border-slate-100 px-5 py-4 text-sm font-medium text-slate-600", className),
|
|
4148
|
+
children
|
|
4149
|
+
})
|
|
4150
|
+
})
|
|
3551
4151
|
});
|
|
3552
4152
|
}
|
|
3553
4153
|
//#endregion
|
|
@@ -3559,25 +4159,17 @@ var LAYOUT_CLASS = {
|
|
|
3559
4159
|
};
|
|
3560
4160
|
function DescriptionList({ layout = "vertical", children, className = "" }) {
|
|
3561
4161
|
return /* @__PURE__ */ jsx("dl", {
|
|
3562
|
-
className:
|
|
4162
|
+
className: cn(LAYOUT_CLASS[layout], className),
|
|
3563
4163
|
children
|
|
3564
4164
|
});
|
|
3565
4165
|
}
|
|
3566
4166
|
function DescriptionItem({ label, value, fullWidth = false, className = "" }) {
|
|
3567
4167
|
const isEmpty = value === void 0 || value === null || value === "";
|
|
3568
4168
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", {
|
|
3569
|
-
className: [
|
|
3570
|
-
"text-xs font-bold uppercase tracking-[0.12em] text-slate-500",
|
|
3571
|
-
fullWidth ? "sm:col-span-2" : "",
|
|
3572
|
-
className
|
|
3573
|
-
].filter(Boolean).join(" "),
|
|
4169
|
+
className: cn("text-xs font-bold uppercase tracking-[0.12em] text-slate-500", fullWidth && "sm:col-span-2", className),
|
|
3574
4170
|
children: label
|
|
3575
4171
|
}), /* @__PURE__ */ jsx("dd", {
|
|
3576
|
-
className:
|
|
3577
|
-
"text-sm font-medium text-slate-800",
|
|
3578
|
-
fullWidth ? "sm:col-span-2" : "",
|
|
3579
|
-
isEmpty ? "text-slate-300" : ""
|
|
3580
|
-
].filter(Boolean).join(" "),
|
|
4172
|
+
className: cn("text-sm font-medium text-slate-800", fullWidth && "sm:col-span-2", isEmpty && "text-slate-300"),
|
|
3581
4173
|
children: isEmpty ? "—" : value
|
|
3582
4174
|
})] });
|
|
3583
4175
|
}
|
|
@@ -3587,7 +4179,7 @@ function ActivityFeed({ events, "aria-label": ariaLabel = "Activity feed", class
|
|
|
3587
4179
|
if (events.length === 0) return null;
|
|
3588
4180
|
return /* @__PURE__ */ jsx("ol", {
|
|
3589
4181
|
"aria-label": ariaLabel,
|
|
3590
|
-
className:
|
|
4182
|
+
className: cn("space-y-0", className),
|
|
3591
4183
|
children: events.map((event, i) => {
|
|
3592
4184
|
const isLast = i === events.length - 1;
|
|
3593
4185
|
return /* @__PURE__ */ jsxs("li", {
|
|
@@ -3668,7 +4260,7 @@ var STATUS_LABEL = {
|
|
|
3668
4260
|
function ApprovalTimeline({ steps, "aria-label": ariaLabel = "Approval workflow", className = "" }) {
|
|
3669
4261
|
return /* @__PURE__ */ jsx("ol", {
|
|
3670
4262
|
"aria-label": ariaLabel,
|
|
3671
|
-
className:
|
|
4263
|
+
className: cn("space-y-0", className),
|
|
3672
4264
|
children: steps.map((step, i) => {
|
|
3673
4265
|
const isLast = i === steps.length - 1;
|
|
3674
4266
|
return /* @__PURE__ */ jsxs("li", {
|
|
@@ -3720,13 +4312,13 @@ function ApprovalTimeline({ steps, "aria-label": ariaLabel = "Approval workflow"
|
|
|
3720
4312
|
//#region src/ui-library/gallery/timeline/Timeline.tsx
|
|
3721
4313
|
function Timeline({ children, className = "" }) {
|
|
3722
4314
|
return /* @__PURE__ */ jsx("div", {
|
|
3723
|
-
className:
|
|
4315
|
+
className: cn("w-full space-y-0", className),
|
|
3724
4316
|
children
|
|
3725
4317
|
});
|
|
3726
4318
|
}
|
|
3727
|
-
function TimelineItem({ isFirst, isLast, children }) {
|
|
4319
|
+
function TimelineItem({ isFirst, isLast, children, className = "" }) {
|
|
3728
4320
|
return /* @__PURE__ */ jsxs("div", {
|
|
3729
|
-
className: "flex gap-3",
|
|
4321
|
+
className: cn("flex gap-3", className),
|
|
3730
4322
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
3731
4323
|
className: "flex flex-col items-center shrink-0 pt-4",
|
|
3732
4324
|
"aria-hidden": "true",
|
|
@@ -3806,9 +4398,9 @@ function TimelineFooter({ reason, source }) {
|
|
|
3806
4398
|
}), source] })]
|
|
3807
4399
|
});
|
|
3808
4400
|
}
|
|
3809
|
-
function TimelineEmptyState({ icon, title, description }) {
|
|
4401
|
+
function TimelineEmptyState({ icon, title, description, className = "" }) {
|
|
3810
4402
|
return /* @__PURE__ */ jsxs("div", {
|
|
3811
|
-
className: "py-16 text-center",
|
|
4403
|
+
className: cn("py-16 text-center", className),
|
|
3812
4404
|
children: [
|
|
3813
4405
|
/* @__PURE__ */ jsx("div", {
|
|
3814
4406
|
className: "mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-slate-50",
|
|
@@ -3833,12 +4425,7 @@ function TimelineEmptyState({ icon, title, description }) {
|
|
|
3833
4425
|
//#region src/ui-library/gallery/empty-state/EmptyState.tsx
|
|
3834
4426
|
function EmptyState({ title, hint, icon, action, className = "" }) {
|
|
3835
4427
|
return /* @__PURE__ */ jsxs("div", {
|
|
3836
|
-
className: [
|
|
3837
|
-
"flex flex-col items-center justify-center gap-2",
|
|
3838
|
-
"rounded-lg border border-brand-sky/20 bg-brand-sky/[0.04]",
|
|
3839
|
-
"px-6 py-12 text-center",
|
|
3840
|
-
className
|
|
3841
|
-
].filter(Boolean).join(" "),
|
|
4428
|
+
className: cn("flex flex-col items-center justify-center gap-2", "rounded-lg border border-brand-sky/20 bg-brand-sky/[0.04]", "px-6 py-12 text-center", className),
|
|
3842
4429
|
children: [
|
|
3843
4430
|
icon && /* @__PURE__ */ jsx("div", {
|
|
3844
4431
|
className: "mb-1 text-brand-sky/50",
|
|
@@ -3911,7 +4498,7 @@ function ActionButton({ action, variant }) {
|
|
|
3911
4498
|
function StatusPage({ eyebrow, title, description, code, icon, primaryAction, secondaryAction, className = "" }) {
|
|
3912
4499
|
const hasActions = primaryAction || secondaryAction;
|
|
3913
4500
|
return /* @__PURE__ */ jsxs("div", {
|
|
3914
|
-
className:
|
|
4501
|
+
className: cn("relative flex min-h-screen items-center justify-center bg-surface-page px-6 py-16 overflow-hidden", className),
|
|
3915
4502
|
children: [code ? /* @__PURE__ */ jsx("span", {
|
|
3916
4503
|
"aria-hidden": "true",
|
|
3917
4504
|
className: "pointer-events-none absolute select-none font-heading font-bold text-brand-navy opacity-[0.07] text-[80px] sm:text-[120px] leading-none",
|
|
@@ -3957,7 +4544,7 @@ function StatusPage({ eyebrow, title, description, code, icon, primaryAction, se
|
|
|
3957
4544
|
//#region src/ui-library/gallery/employee-card/EmployeeCard.tsx
|
|
3958
4545
|
function EmployeeCard({ name, role, avatarSrc, status, meta, actions, className = "" }) {
|
|
3959
4546
|
return /* @__PURE__ */ jsxs("article", {
|
|
3960
|
-
className:
|
|
4547
|
+
className: cn("rounded-2xl border border-slate-200 bg-white shadow-sm overflow-hidden", className),
|
|
3961
4548
|
"aria-label": `${name}${role ? ", " + role : ""}`,
|
|
3962
4549
|
children: [/* @__PURE__ */ jsx("div", {
|
|
3963
4550
|
className: "h-1.5 bg-gradient-to-r from-brand-navy to-brand-blue",
|
|
@@ -4204,7 +4791,7 @@ function TreeView({ items, selectedId, onSelect, "aria-label": ariaLabel, classN
|
|
|
4204
4791
|
role: "tree",
|
|
4205
4792
|
"aria-label": ariaLabel,
|
|
4206
4793
|
onKeyDown: handleKeyDown,
|
|
4207
|
-
className:
|
|
4794
|
+
className: cn("flex flex-col gap-0.5 outline-none", className),
|
|
4208
4795
|
tabIndex: 0,
|
|
4209
4796
|
children: items.map((item) => /* @__PURE__ */ jsx(TreeNode, {
|
|
4210
4797
|
item,
|
|
@@ -7407,23 +7994,26 @@ var TREND_CONFIG = {
|
|
|
7407
7994
|
label: "No change"
|
|
7408
7995
|
}
|
|
7409
7996
|
};
|
|
7410
|
-
function Statistic({ label, value, helper, icon: Icon, trend, trendLabel, variant = "default" }) {
|
|
7411
|
-
if (variant === "minimal") return /* @__PURE__ */ jsxs("div", {
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7997
|
+
function Statistic({ label, value, helper, icon: Icon, trend, trendLabel, variant = "default", className = "" }) {
|
|
7998
|
+
if (variant === "minimal") return /* @__PURE__ */ jsxs("div", {
|
|
7999
|
+
className: cn(className),
|
|
8000
|
+
children: [
|
|
8001
|
+
/* @__PURE__ */ jsx("p", {
|
|
8002
|
+
className: "text-[11px] font-bold uppercase tracking-[0.18em] text-brand-sky",
|
|
8003
|
+
children: label
|
|
8004
|
+
}),
|
|
8005
|
+
/* @__PURE__ */ jsx("p", {
|
|
8006
|
+
className: "mt-1 font-heading text-4xl font-bold tabular-nums text-brand-navy",
|
|
8007
|
+
children: value
|
|
8008
|
+
}),
|
|
8009
|
+
helper && /* @__PURE__ */ jsx("p", {
|
|
8010
|
+
className: "mt-1 text-xs font-medium text-slate-400",
|
|
8011
|
+
children: helper
|
|
8012
|
+
})
|
|
8013
|
+
]
|
|
8014
|
+
});
|
|
7425
8015
|
if (variant === "compact") return /* @__PURE__ */ jsxs("div", {
|
|
7426
|
-
className: "flex items-center gap-4 rounded-2xl border border-slate-200 bg-white px-5 py-4 shadow-sm",
|
|
8016
|
+
className: cn("flex items-center gap-4 rounded-2xl border border-slate-200 bg-white px-5 py-4 shadow-sm", className),
|
|
7427
8017
|
children: [Icon && /* @__PURE__ */ jsx("div", {
|
|
7428
8018
|
className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-brand-navy/[0.06] text-brand-navy",
|
|
7429
8019
|
children: /* @__PURE__ */ jsx(Icon, {
|
|
@@ -7448,10 +8038,11 @@ function Statistic({ label, value, helper, icon: Icon, trend, trendLabel, varian
|
|
|
7448
8038
|
]
|
|
7449
8039
|
})]
|
|
7450
8040
|
});
|
|
8041
|
+
const stripColor = variant === "accent" ? "bg-brand-blue" : "bg-brand-navy";
|
|
7451
8042
|
return /* @__PURE__ */ jsxs("div", {
|
|
7452
|
-
className: "relative overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm",
|
|
8043
|
+
className: cn("relative overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm", className),
|
|
7453
8044
|
children: [/* @__PURE__ */ jsx("div", {
|
|
7454
|
-
className: `absolute inset-y-0 left-0 w-1 ${
|
|
8045
|
+
className: `absolute inset-y-0 left-0 w-1 ${stripColor}`,
|
|
7455
8046
|
"aria-hidden": "true"
|
|
7456
8047
|
}), /* @__PURE__ */ jsxs("div", {
|
|
7457
8048
|
className: "px-6 py-5",
|
|
@@ -7497,6 +8088,18 @@ function Statistic({ label, value, helper, icon: Icon, trend, trendLabel, varian
|
|
|
7497
8088
|
}
|
|
7498
8089
|
//#endregion
|
|
7499
8090
|
//#region src/ui-library/gallery/status-dot/StatusDot.tsx
|
|
8091
|
+
/**
|
|
8092
|
+
* StatusDot — Design System Component
|
|
8093
|
+
*
|
|
8094
|
+
* A coloured glowing dot paired with a label. Used in tables to indicate
|
|
8095
|
+
* account or entity status at a glance.
|
|
8096
|
+
*
|
|
8097
|
+
* Self-contained: uses inline styles so it works without any external CSS.
|
|
8098
|
+
*
|
|
8099
|
+
* Usage:
|
|
8100
|
+
* <StatusDot status="active" label="Active" />
|
|
8101
|
+
* <StatusDot status="locked" label="Locked" />
|
|
8102
|
+
*/
|
|
7500
8103
|
var DOT_STYLES = {
|
|
7501
8104
|
active: {
|
|
7502
8105
|
bg: "#10b981",
|
|
@@ -7518,15 +8121,7 @@ var DOT_STYLES = {
|
|
|
7518
8121
|
function StatusDot({ status, label, className = "" }) {
|
|
7519
8122
|
const dot = DOT_STYLES[status];
|
|
7520
8123
|
return /* @__PURE__ */ jsxs("div", {
|
|
7521
|
-
|
|
7522
|
-
display: "inline-flex",
|
|
7523
|
-
alignItems: "center",
|
|
7524
|
-
gap: 8,
|
|
7525
|
-
fontWeight: 600,
|
|
7526
|
-
fontSize: "0.8125rem",
|
|
7527
|
-
color: "#334155"
|
|
7528
|
-
},
|
|
7529
|
-
className,
|
|
8124
|
+
className: cn("inline-flex items-center gap-2 text-[0.8125rem] font-semibold text-slate-700", className),
|
|
7530
8125
|
children: [/* @__PURE__ */ jsx("span", {
|
|
7531
8126
|
"aria-hidden": "true",
|
|
7532
8127
|
style: {
|
|
@@ -7597,7 +8192,7 @@ function applyColumnOrder(columns, order) {
|
|
|
7597
8192
|
for (const col of columns) if (!seen.has(col.key)) result.push(col);
|
|
7598
8193
|
return result;
|
|
7599
8194
|
}
|
|
7600
|
-
function ColumnManager({ columns, hiddenColumnKeys, columnOrder, onHiddenColumnKeysChange, onColumnOrderChange, onReset, triggerLabel = "Columns" }) {
|
|
8195
|
+
function ColumnManager({ columns, hiddenColumnKeys, columnOrder, onHiddenColumnKeysChange, onColumnOrderChange, onReset, triggerLabel = "Columns", className = "" }) {
|
|
7601
8196
|
const [open, setOpen] = useState(false);
|
|
7602
8197
|
const triggerRef = useRef(null);
|
|
7603
8198
|
const panelRef = useRef(null);
|
|
@@ -7641,7 +8236,7 @@ function ColumnManager({ columns, hiddenColumnKeys, columnOrder, onHiddenColumnK
|
|
|
7641
8236
|
onColumnOrderChange(next.map((c) => c.key));
|
|
7642
8237
|
}
|
|
7643
8238
|
return /* @__PURE__ */ jsxs("div", {
|
|
7644
|
-
className: "relative inline-block",
|
|
8239
|
+
className: cn("relative inline-block", className),
|
|
7645
8240
|
children: [/* @__PURE__ */ jsxs("button", {
|
|
7646
8241
|
ref: triggerRef,
|
|
7647
8242
|
type: "button",
|
|
@@ -7930,4 +8525,4 @@ var shadow = {
|
|
|
7930
8525
|
overlay: "shadow-xl"
|
|
7931
8526
|
};
|
|
7932
8527
|
//#endregion
|
|
7933
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActivityFeed, Alert, ApprovalTimeline, AreaChart, Avatar, Badge, BarChart, BarList, Breadcrumb, Button, CHART_PALETTE, Calendar, Card, CardContent, CardFooter, CardHeader, Checkbox, ColumnManager, Combobox, CommandPalette, ConfirmAction, ConfirmDialog, DatePicker, DescriptionItem, DescriptionList, Dialog, DialogBody, DialogFooter, Divider, Drawer, Dropdown, EmployeeCard, EmptyState, ErrorBanner, Field, FieldContext, FieldInput, FileUpload, FilterChip, Heatmap, IconButton, Input, IsoCubeBlock, Kanban, LineChart, MaskedValue, Menu, Modal, OrgChart, OrgUnitTree, OtpInput, PafTemplate, PageHeader, Pagination, PayslipTemplate, PermissionMatrix, Popover, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioItem, ReportTemplate, STATUS_PAGE_PRESETS, Section, SegmentedControl, Select, SidebarGroup, SidebarItem, SidebarNav, SidebarSection, Skeleton, SkeletonAvatar, SkeletonCard, SkeletonTableRow, SkeletonText, Spinner, Statistic, StatusBadge, StatusDot, StatusPage, Stepper, Switch, Tab, TabList, TabPanel, TabPanels, Tabs, Textarea, TimekeepingTemplate, Timeline, TimelineEmptyState, TimelineFooter, TimelineItem, TimelineValueCard, Toaster, Toolbar, Tooltip, TreeView, ValidationSummary, applyColumnOrder, colors_exports as colors, dimension_exports as dimension, radius_exports as radius, shadow_exports as shadow, statusMenuItems, toast, typography_exports as typography, useFieldContext };
|
|
8528
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActivityFeed, Alert, ApprovalTimeline, AreaChart, Avatar, Badge, BarChart, BarList, Breadcrumb, Button, CHART_PALETTE, Calendar, Card, CardContent, CardFooter, CardHeader, Checkbox, ColumnManager, Combobox, CommandPalette, ConfirmAction, ConfirmDialog, DatePicker, DescriptionItem, DescriptionList, Dialog, DialogBody, DialogFooter, Divider, Drawer, Dropdown, EmployeeCard, EmptyState, ErrorBanner, Field, FieldContext, FieldInput, FileUpload, FilterChip, Heatmap, IconButton, Input, IsoCubeBlock, Kanban, LineChart, MaskedValue, Menu, Modal, OrgChart, OrgUnitTree, OtpInput, PafTemplate, PageHeader, Pagination, PayslipTemplate, PermissionMatrix, Popover, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioItem, ReportTemplate, STATUS_PAGE_PRESETS, Search, Section, SegmentedControl, Select, SidebarGroup, SidebarItem, SidebarNav, SidebarSection, Skeleton, SkeletonAvatar, SkeletonCard, SkeletonTableRow, SkeletonText, Spinner, Statistic, StatusBadge, StatusDot, StatusPage, Stepper, Switch, Tab, TabList, TabPanel, TabPanels, Tabs, Textarea, TimekeepingTemplate, Timeline, TimelineEmptyState, TimelineFooter, TimelineItem, TimelineValueCard, Toaster, Toolbar, Tooltip, TreeView, ValidationSummary, applyColumnOrder, colors_exports as colors, dimension_exports as dimension, radius_exports as radius, shadow_exports as shadow, statusMenuItems, toast, typography_exports as typography, useFieldContext };
|