@gamecp/ui 0.1.0 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +198 -70
- package/dist/index.d.ts +198 -70
- package/dist/index.js +1349 -567
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1343 -558
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,22 +1,76 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var React4 = require('react');
|
|
4
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React4 = require('react');
|
|
5
5
|
var ri = require('react-icons/ri');
|
|
6
|
-
var NextLink = require('next/link');
|
|
7
6
|
var reactDom = require('react-dom');
|
|
8
7
|
var framerMotion = require('framer-motion');
|
|
8
|
+
var NextLink = require('next/link');
|
|
9
9
|
|
|
10
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
|
|
12
12
|
var React4__default = /*#__PURE__*/_interopDefault(React4);
|
|
13
13
|
var NextLink__default = /*#__PURE__*/_interopDefault(NextLink);
|
|
14
14
|
|
|
15
|
-
// src/
|
|
15
|
+
// src/Badge.tsx
|
|
16
|
+
var badgeVariants = {
|
|
17
|
+
default: "bg-gray-100 text-foreground border-border",
|
|
18
|
+
primary: "bg-primary-100 text-primary-800 border-primary-200",
|
|
19
|
+
secondary: "bg-gray-100 text-foreground border-border",
|
|
20
|
+
success: "bg-success text-success-dark border-success-light",
|
|
21
|
+
warning: "bg-yellow-100 text-yellow-800 border-yellow-200",
|
|
22
|
+
error: "bg-red-100 text-red-800 border-red-200",
|
|
23
|
+
info: "bg-muted text-muted-foreground border-ring",
|
|
24
|
+
gray: "bg-gray-100 text-foreground border-border",
|
|
25
|
+
purple: "bg-purple-100 text-purple-800 border-purple-200",
|
|
26
|
+
pink: "bg-pink-100 text-pink-800 border-pink-200",
|
|
27
|
+
indigo: "bg-indigo-100 text-indigo-800 border-indigo-200",
|
|
28
|
+
yellow: "bg-yellow-100 text-yellow-800 border-yellow-200",
|
|
29
|
+
orange: "bg-orange-100 text-orange-800 border-orange-200",
|
|
30
|
+
teal: "bg-teal-100 text-teal-800 border-teal-200",
|
|
31
|
+
cyan: "bg-cyan-100 text-cyan-800 border-cyan-200",
|
|
32
|
+
lime: "bg-lime-100 text-lime-800 border-lime-200",
|
|
33
|
+
emerald: "bg-emerald-100 text-emerald-800 border-emerald-200",
|
|
34
|
+
rose: "bg-rose-100 text-rose-800 border-rose-200",
|
|
35
|
+
sky: "bg-sky-100 text-sky-800 border-sky-200",
|
|
36
|
+
violet: "bg-violet-100 text-violet-800 border-violet-200",
|
|
37
|
+
fuchsia: "bg-fuchsia-100 text-fuchsia-800 border-fuchsia-200",
|
|
38
|
+
amber: "bg-amber-100 text-amber-800 border-amber-200"
|
|
39
|
+
};
|
|
40
|
+
var badgeSizes = {
|
|
41
|
+
sm: "px-2 py-0.5 text-xs",
|
|
42
|
+
md: "px-2.5 py-0.5 text-xs",
|
|
43
|
+
lg: "px-3 py-1 text-sm"
|
|
44
|
+
};
|
|
45
|
+
function Badge({
|
|
46
|
+
children,
|
|
47
|
+
variant = "default",
|
|
48
|
+
size = "md",
|
|
49
|
+
className = "",
|
|
50
|
+
customColors
|
|
51
|
+
}) {
|
|
52
|
+
const baseClasses = "inline-flex items-center font-medium rounded-full border";
|
|
53
|
+
const variantClasses5 = variant === "custom" ? "" : badgeVariants[variant];
|
|
54
|
+
const sizeClasses5 = badgeSizes[size];
|
|
55
|
+
const customStyles = variant === "custom" && customColors ? {
|
|
56
|
+
backgroundColor: customColors.background,
|
|
57
|
+
color: customColors.text,
|
|
58
|
+
borderColor: customColors.border || customColors.background
|
|
59
|
+
} : {};
|
|
60
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
61
|
+
"span",
|
|
62
|
+
{
|
|
63
|
+
className: `${baseClasses} ${variantClasses5} ${sizeClasses5} ${className}`,
|
|
64
|
+
style: customStyles,
|
|
65
|
+
children
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
16
69
|
var variantClasses = {
|
|
17
70
|
primary: "bg-primary text-primary-foreground hover:bg-primary/90 border-transparent",
|
|
18
71
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent",
|
|
19
72
|
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 border-transparent",
|
|
73
|
+
danger: "bg-red-600 text-white hover:bg-red-700 border-transparent",
|
|
20
74
|
ghost: "bg-transparent hover:bg-muted hover:text-foreground border-transparent",
|
|
21
75
|
link: "bg-transparent text-primary underline-offset-4 hover:underline border-transparent p-0",
|
|
22
76
|
outline: "bg-transparent border-border hover:bg-muted hover:text-foreground"
|
|
@@ -95,73 +149,6 @@ var Button = React4.forwardRef(
|
|
|
95
149
|
);
|
|
96
150
|
Button.displayName = "Button";
|
|
97
151
|
var Button_default = Button;
|
|
98
|
-
var badgeVariants = {
|
|
99
|
-
default: "bg-gray-100 text-foreground border-border",
|
|
100
|
-
primary: "bg-primary-100 text-primary-800 border-primary-200",
|
|
101
|
-
secondary: "bg-gray-100 text-foreground border-border",
|
|
102
|
-
success: "bg-success text-success-dark border-success-light",
|
|
103
|
-
warning: "bg-yellow-100 text-yellow-800 border-yellow-200",
|
|
104
|
-
error: "bg-red-100 text-red-800 border-red-200",
|
|
105
|
-
info: "bg-muted text-muted-foreground border-ring",
|
|
106
|
-
gray: "bg-gray-100 text-foreground border-border",
|
|
107
|
-
purple: "bg-purple-100 text-purple-800 border-purple-200",
|
|
108
|
-
pink: "bg-pink-100 text-pink-800 border-pink-200",
|
|
109
|
-
indigo: "bg-indigo-100 text-indigo-800 border-indigo-200",
|
|
110
|
-
yellow: "bg-yellow-100 text-yellow-800 border-yellow-200",
|
|
111
|
-
orange: "bg-orange-100 text-orange-800 border-orange-200",
|
|
112
|
-
teal: "bg-teal-100 text-teal-800 border-teal-200",
|
|
113
|
-
cyan: "bg-cyan-100 text-cyan-800 border-cyan-200",
|
|
114
|
-
lime: "bg-lime-100 text-lime-800 border-lime-200",
|
|
115
|
-
emerald: "bg-emerald-100 text-emerald-800 border-emerald-200",
|
|
116
|
-
rose: "bg-rose-100 text-rose-800 border-rose-200",
|
|
117
|
-
sky: "bg-sky-100 text-sky-800 border-sky-200",
|
|
118
|
-
violet: "bg-violet-100 text-violet-800 border-violet-200",
|
|
119
|
-
fuchsia: "bg-fuchsia-100 text-fuchsia-800 border-fuchsia-200",
|
|
120
|
-
amber: "bg-amber-100 text-amber-800 border-amber-200"
|
|
121
|
-
};
|
|
122
|
-
var badgeSizes = {
|
|
123
|
-
sm: "px-2 py-0.5 text-xs",
|
|
124
|
-
md: "px-2.5 py-0.5 text-xs",
|
|
125
|
-
lg: "px-3 py-1 text-sm"
|
|
126
|
-
};
|
|
127
|
-
function Badge({
|
|
128
|
-
children,
|
|
129
|
-
variant = "default",
|
|
130
|
-
size = "md",
|
|
131
|
-
className = "",
|
|
132
|
-
customColors
|
|
133
|
-
}) {
|
|
134
|
-
const baseClasses = "inline-flex items-center font-medium rounded-full border";
|
|
135
|
-
const variantClasses4 = variant === "custom" ? "" : badgeVariants[variant];
|
|
136
|
-
const sizeClasses4 = badgeSizes[size];
|
|
137
|
-
const customStyles = variant === "custom" && customColors ? {
|
|
138
|
-
backgroundColor: customColors.background,
|
|
139
|
-
color: customColors.text,
|
|
140
|
-
borderColor: customColors.border || customColors.background
|
|
141
|
-
} : {};
|
|
142
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
143
|
-
"span",
|
|
144
|
-
{
|
|
145
|
-
className: `${baseClasses} ${variantClasses4} ${sizeClasses4} ${className}`,
|
|
146
|
-
style: customStyles,
|
|
147
|
-
children
|
|
148
|
-
}
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
var SuccessBadge = (props) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...props, variant: "success" });
|
|
152
|
-
var WarningBadge = (props) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...props, variant: "warning" });
|
|
153
|
-
var ErrorBadge = (props) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...props, variant: "error" });
|
|
154
|
-
var InfoBadge = (props) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...props, variant: "info" });
|
|
155
|
-
var PrimaryBadge = (props) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...props, variant: "primary" });
|
|
156
|
-
var GrayBadge = (props) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...props, variant: "gray" });
|
|
157
|
-
function StatusBadge({
|
|
158
|
-
isActive,
|
|
159
|
-
activeText = "Active",
|
|
160
|
-
inactiveText = "Inactive",
|
|
161
|
-
...props
|
|
162
|
-
}) {
|
|
163
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...props, variant: isActive ? "success" : "error", children: isActive ? activeText : inactiveText });
|
|
164
|
-
}
|
|
165
152
|
var sizeClasses2 = {
|
|
166
153
|
xs: "w-3 h-3",
|
|
167
154
|
sm: "w-4 h-4",
|
|
@@ -267,7 +254,8 @@ function Card({
|
|
|
267
254
|
contentClassName = "",
|
|
268
255
|
status,
|
|
269
256
|
statusIcon,
|
|
270
|
-
statusText
|
|
257
|
+
statusText,
|
|
258
|
+
id
|
|
271
259
|
}) {
|
|
272
260
|
const [isExpanded, setIsExpanded] = React4.useState(defaultExpanded);
|
|
273
261
|
const baseClasses = [
|
|
@@ -297,6 +285,7 @@ function Card({
|
|
|
297
285
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
298
286
|
"div",
|
|
299
287
|
{
|
|
288
|
+
id,
|
|
300
289
|
className: `${baseClasses} ${className}`,
|
|
301
290
|
style,
|
|
302
291
|
onClick: clickable || onClick ? handleClick : void 0,
|
|
@@ -350,131 +339,1031 @@ function Card({
|
|
|
350
339
|
}
|
|
351
340
|
);
|
|
352
341
|
}
|
|
353
|
-
|
|
342
|
+
var sizeClasses3 = {
|
|
343
|
+
sm: "max-w-md",
|
|
344
|
+
md: "max-w-2xl",
|
|
345
|
+
lg: "max-w-4xl",
|
|
346
|
+
xl: "max-w-6xl",
|
|
347
|
+
full: "max-w-full mx-4"
|
|
348
|
+
};
|
|
349
|
+
function Modal({
|
|
350
|
+
isOpen,
|
|
351
|
+
onClose,
|
|
354
352
|
children,
|
|
355
|
-
className = "",
|
|
356
|
-
...props
|
|
357
|
-
}) {
|
|
358
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, ...props, children });
|
|
359
|
-
}
|
|
360
|
-
function HeaderCard({
|
|
361
353
|
title,
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
iconColor,
|
|
366
|
-
iconSize,
|
|
367
|
-
actionButton,
|
|
368
|
-
children,
|
|
354
|
+
header,
|
|
355
|
+
blocking = false,
|
|
356
|
+
size = "md",
|
|
369
357
|
className = "",
|
|
370
|
-
|
|
358
|
+
footer,
|
|
359
|
+
fullScreen = false,
|
|
360
|
+
noPadding = false,
|
|
361
|
+
footerBg = "gray",
|
|
362
|
+
variant = "default",
|
|
363
|
+
scrollable = true,
|
|
364
|
+
"aria-describedby": ariaDescribedBy,
|
|
365
|
+
customStyles = {}
|
|
371
366
|
}) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
367
|
+
const modalContentRef = React4.useRef(null);
|
|
368
|
+
const previousActiveElementRef = React4.useRef(null);
|
|
369
|
+
const hasPerformedInitialFocusRef = React4.useRef(false);
|
|
370
|
+
const getFocusableElements = () => {
|
|
371
|
+
if (!modalContentRef.current) return [];
|
|
372
|
+
const focusableSelectors = [
|
|
373
|
+
"button:not([disabled])",
|
|
374
|
+
"a[href]",
|
|
375
|
+
"input:not([disabled])",
|
|
376
|
+
"select:not([disabled])",
|
|
377
|
+
"textarea:not([disabled])",
|
|
378
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
379
|
+
].join(", ");
|
|
380
|
+
return Array.from(
|
|
381
|
+
modalContentRef.current.querySelectorAll(focusableSelectors)
|
|
382
|
+
);
|
|
383
|
+
};
|
|
384
|
+
React4.useEffect(() => {
|
|
385
|
+
if (!isOpen) {
|
|
386
|
+
hasPerformedInitialFocusRef.current = false;
|
|
387
|
+
return;
|
|
385
388
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
function StatusCard({
|
|
389
|
-
status,
|
|
390
|
-
statusIcon,
|
|
391
|
-
statusText,
|
|
392
|
-
children,
|
|
393
|
-
className = "",
|
|
394
|
-
...props
|
|
395
|
-
}) {
|
|
396
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
397
|
-
Card,
|
|
398
|
-
{
|
|
399
|
-
status,
|
|
400
|
-
statusIcon,
|
|
401
|
-
statusText,
|
|
402
|
-
className,
|
|
403
|
-
...props,
|
|
404
|
-
children
|
|
389
|
+
if (!hasPerformedInitialFocusRef.current) {
|
|
390
|
+
previousActiveElementRef.current = document.activeElement;
|
|
405
391
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
default: "text-foreground hover:text-primary",
|
|
426
|
-
primary: "text-primary hover:text-primary/80",
|
|
427
|
-
muted: "text-muted-foreground hover:text-foreground"
|
|
428
|
-
};
|
|
429
|
-
var Link = React4.forwardRef(
|
|
430
|
-
({
|
|
431
|
-
href,
|
|
432
|
-
variant = "default",
|
|
433
|
-
underline = false,
|
|
434
|
-
external = false,
|
|
435
|
-
className = "",
|
|
436
|
-
children,
|
|
437
|
-
...props
|
|
438
|
-
}, ref) => {
|
|
439
|
-
const classes = [
|
|
440
|
-
"transition-colors",
|
|
441
|
-
variantClasses3[variant],
|
|
442
|
-
underline ? "underline underline-offset-4" : "hover:underline hover:underline-offset-4",
|
|
443
|
-
className
|
|
444
|
-
].filter(Boolean).join(" ");
|
|
445
|
-
if (external || href.startsWith("http")) {
|
|
446
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
447
|
-
"a",
|
|
448
|
-
{
|
|
449
|
-
ref,
|
|
450
|
-
href,
|
|
451
|
-
className: classes,
|
|
452
|
-
target: "_blank",
|
|
453
|
-
rel: "noopener noreferrer",
|
|
454
|
-
...props,
|
|
455
|
-
children
|
|
392
|
+
let timeoutId = null;
|
|
393
|
+
if (!hasPerformedInitialFocusRef.current) {
|
|
394
|
+
const focusableElements = getFocusableElements();
|
|
395
|
+
const firstFocusable = focusableElements[0];
|
|
396
|
+
timeoutId = setTimeout(() => {
|
|
397
|
+
const activeElement = document.activeElement;
|
|
398
|
+
const isHTMLElement = activeElement instanceof HTMLElement;
|
|
399
|
+
const isUserTyping = activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || isHTMLElement && activeElement.isContentEditable);
|
|
400
|
+
const isFocusInModal = modalContentRef.current?.contains(activeElement);
|
|
401
|
+
if (!isUserTyping && !isFocusInModal) {
|
|
402
|
+
if (firstFocusable) {
|
|
403
|
+
firstFocusable.focus();
|
|
404
|
+
hasPerformedInitialFocusRef.current = true;
|
|
405
|
+
} else if (modalContentRef.current) {
|
|
406
|
+
modalContentRef.current.focus();
|
|
407
|
+
hasPerformedInitialFocusRef.current = true;
|
|
408
|
+
}
|
|
409
|
+
} else if (isFocusInModal) {
|
|
410
|
+
hasPerformedInitialFocusRef.current = true;
|
|
456
411
|
}
|
|
457
|
-
);
|
|
412
|
+
}, 100);
|
|
458
413
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
414
|
+
const handleTab = (event) => {
|
|
415
|
+
if (event.key !== "Tab") return;
|
|
416
|
+
const focusableElements = getFocusableElements();
|
|
417
|
+
if (focusableElements.length === 0) return;
|
|
418
|
+
const firstElement = focusableElements[0];
|
|
419
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
420
|
+
if (event.shiftKey) {
|
|
421
|
+
if (document.activeElement === firstElement) {
|
|
422
|
+
event.preventDefault();
|
|
423
|
+
lastElement.focus();
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
if (document.activeElement === lastElement) {
|
|
427
|
+
event.preventDefault();
|
|
428
|
+
firstElement.focus();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
const handleEsc = (event) => {
|
|
433
|
+
if (event.key === "Escape" && !blocking) {
|
|
434
|
+
onClose();
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
document.addEventListener("keydown", handleTab);
|
|
438
|
+
document.addEventListener("keydown", handleEsc);
|
|
439
|
+
document.body.style.overflow = "hidden";
|
|
440
|
+
return () => {
|
|
441
|
+
if (timeoutId) {
|
|
442
|
+
clearTimeout(timeoutId);
|
|
443
|
+
}
|
|
444
|
+
document.removeEventListener("keydown", handleTab);
|
|
445
|
+
document.removeEventListener("keydown", handleEsc);
|
|
446
|
+
document.body.style.overflow = "unset";
|
|
447
|
+
if (!isOpen && previousActiveElementRef.current) {
|
|
448
|
+
previousActiveElementRef.current.focus();
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
}, [isOpen, onClose, blocking]);
|
|
452
|
+
const modalRoot = (() => {
|
|
453
|
+
if (typeof document === "undefined") return null;
|
|
454
|
+
let root = document.getElementById("modal-root");
|
|
455
|
+
if (!root) {
|
|
456
|
+
root = document.createElement("div");
|
|
457
|
+
root.id = "modal-root";
|
|
458
|
+
document.body.appendChild(root);
|
|
459
|
+
}
|
|
460
|
+
return root;
|
|
461
|
+
})();
|
|
462
|
+
if (!modalRoot) {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
const backdropVariants = {
|
|
466
|
+
hidden: { opacity: 0 },
|
|
467
|
+
visible: { opacity: 1 }
|
|
468
|
+
};
|
|
469
|
+
const modalVariants = {
|
|
470
|
+
hidden: {
|
|
471
|
+
opacity: 0,
|
|
472
|
+
scale: 0.95,
|
|
473
|
+
y: 20
|
|
474
|
+
},
|
|
475
|
+
visible: {
|
|
476
|
+
opacity: 1,
|
|
477
|
+
scale: 1,
|
|
478
|
+
y: 0,
|
|
479
|
+
transition: {
|
|
480
|
+
duration: 0.2,
|
|
481
|
+
ease: "easeOut"
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
exit: {
|
|
485
|
+
opacity: 0,
|
|
486
|
+
scale: 0.9,
|
|
487
|
+
y: 100,
|
|
488
|
+
// Slide down much further for reverse effect
|
|
489
|
+
transition: {
|
|
490
|
+
duration: 0.3,
|
|
491
|
+
ease: "easeIn"
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
if (!isOpen) return null;
|
|
496
|
+
if (variant === "plain") {
|
|
497
|
+
return reactDom.createPortal(
|
|
498
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
499
|
+
framerMotion.motion.div,
|
|
500
|
+
{
|
|
501
|
+
className: `modal-backdrop fixed inset-0 w-screen h-screen flex items-center ${customStyles.backdrop?.includes("justify-") ? customStyles.backdrop : customStyles.backdrop ? `${customStyles.backdrop} justify-center` : "justify-center bg-black/10"} z-[999999] m-0 ${fullScreen ? "p-0" : "p-4"}`,
|
|
502
|
+
variants: backdropVariants,
|
|
503
|
+
initial: "hidden",
|
|
504
|
+
animate: isOpen ? "visible" : "hidden",
|
|
505
|
+
exit: "hidden",
|
|
506
|
+
onClick: blocking ? void 0 : onClose,
|
|
507
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
508
|
+
framerMotion.motion.div,
|
|
509
|
+
{
|
|
510
|
+
ref: modalContentRef,
|
|
511
|
+
role: "dialog",
|
|
512
|
+
"aria-modal": "true",
|
|
513
|
+
"aria-labelledby": title ? "modal-title-plain" : void 0,
|
|
514
|
+
"aria-describedby": ariaDescribedBy || "modal-content-plain",
|
|
515
|
+
tabIndex: -1,
|
|
516
|
+
className: `w-full flex flex-col overflow-hidden relative z-[1000000] ${customStyles.container || "bg-card shadow-xl"} ${fullScreen ? "h-full rounded-none" : `rounded-lg ${className} ${sizeClasses3[size]} max-h-[90vh]`}`,
|
|
517
|
+
variants: modalVariants,
|
|
518
|
+
initial: "hidden",
|
|
519
|
+
animate: isOpen ? "visible" : "exit",
|
|
520
|
+
exit: "exit",
|
|
521
|
+
onClick: (e) => e.stopPropagation(),
|
|
522
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
523
|
+
"div",
|
|
524
|
+
{
|
|
525
|
+
id: "modal-content-plain",
|
|
526
|
+
className: `flex-1 ${customStyles.content || ""}`,
|
|
527
|
+
children
|
|
528
|
+
}
|
|
529
|
+
)
|
|
530
|
+
},
|
|
531
|
+
"modal-content"
|
|
532
|
+
)
|
|
533
|
+
},
|
|
534
|
+
"modal-backdrop"
|
|
535
|
+
) }),
|
|
536
|
+
modalRoot
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
return reactDom.createPortal(
|
|
540
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
541
|
+
framerMotion.motion.div,
|
|
542
|
+
{
|
|
543
|
+
className: `modal-backdrop fixed inset-0 w-screen h-screen bg-black/10 flex items-center ${customStyles.backdrop || "justify-center"} z-[999999] m-0 ${fullScreen ? "p-0" : "p-4"}`,
|
|
544
|
+
variants: backdropVariants,
|
|
545
|
+
initial: "hidden",
|
|
546
|
+
animate: isOpen ? "visible" : "hidden",
|
|
547
|
+
exit: "hidden",
|
|
548
|
+
onClick: blocking ? void 0 : onClose,
|
|
549
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
550
|
+
framerMotion.motion.div,
|
|
551
|
+
{
|
|
552
|
+
ref: modalContentRef,
|
|
553
|
+
role: "dialog",
|
|
554
|
+
"aria-modal": "true",
|
|
555
|
+
"aria-labelledby": title ? "modal-title" : void 0,
|
|
556
|
+
"aria-describedby": ariaDescribedBy || "modal-content",
|
|
557
|
+
tabIndex: -1,
|
|
558
|
+
className: `bg-card border border-border shadow-xl w-full flex flex-col overflow-hidden relative z-[1000000] ${fullScreen ? "h-full rounded-none" : `rounded-lg ${customStyles.container || className || sizeClasses3[size]} max-h-[90vh]`}`,
|
|
559
|
+
variants: modalVariants,
|
|
560
|
+
initial: "hidden",
|
|
561
|
+
animate: isOpen ? "visible" : "exit",
|
|
562
|
+
exit: "exit",
|
|
563
|
+
onClick: (e) => e.stopPropagation(),
|
|
564
|
+
children: [
|
|
565
|
+
header ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: header }) : title ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
566
|
+
"div",
|
|
567
|
+
{
|
|
568
|
+
className: `px-6 py-4 border-b border-border flex justify-between items-center flex-shrink-0 ${customStyles.header || ""}`,
|
|
569
|
+
children: [
|
|
570
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
571
|
+
"h2",
|
|
572
|
+
{
|
|
573
|
+
id: "modal-title",
|
|
574
|
+
className: "text-xl font-semibold text-foreground",
|
|
575
|
+
children: title
|
|
576
|
+
}
|
|
577
|
+
),
|
|
578
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
579
|
+
"button",
|
|
580
|
+
{
|
|
581
|
+
onClick: onClose,
|
|
582
|
+
className: "p-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-full transition-colors",
|
|
583
|
+
title: "Close",
|
|
584
|
+
"aria-label": "Close modal",
|
|
585
|
+
disabled: blocking,
|
|
586
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ri.RiCloseLine, { className: "w-5 h-5", "aria-hidden": "true" })
|
|
587
|
+
}
|
|
588
|
+
)
|
|
589
|
+
]
|
|
590
|
+
}
|
|
591
|
+
) : null,
|
|
592
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
593
|
+
"div",
|
|
594
|
+
{
|
|
595
|
+
id: "modal-content",
|
|
596
|
+
className: `bg-background text-foreground flex-1 ${scrollable ? "overflow-y-auto" : ""} ${fullScreen || noPadding ? "p-0" : "px-6 py-4"}`,
|
|
597
|
+
children
|
|
598
|
+
}
|
|
599
|
+
),
|
|
600
|
+
footer && /* @__PURE__ */ jsxRuntime.jsx(
|
|
601
|
+
"div",
|
|
602
|
+
{
|
|
603
|
+
className: `flex-shrink-0 px-6 py-4 border-t border-border ${footerBg === "white" ? "bg-card" : "bg-muted"} ${customStyles.footer || ""}`,
|
|
604
|
+
children: footer
|
|
605
|
+
}
|
|
606
|
+
)
|
|
607
|
+
]
|
|
608
|
+
},
|
|
609
|
+
"modal-content"
|
|
610
|
+
)
|
|
611
|
+
},
|
|
612
|
+
"modal-backdrop"
|
|
613
|
+
) }),
|
|
614
|
+
modalRoot
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
function ConfirmDialog({ isOpen, options, onConfirm, onCancel }) {
|
|
618
|
+
const { title, message, confirmText, cancelText = "Cancel", confirmButtonColor = "blue" } = options;
|
|
619
|
+
const getConfirmVariant = () => {
|
|
620
|
+
switch (confirmButtonColor) {
|
|
621
|
+
case "red":
|
|
622
|
+
return "danger";
|
|
623
|
+
case "green":
|
|
624
|
+
return "primary";
|
|
625
|
+
case "blue":
|
|
626
|
+
default:
|
|
627
|
+
return "primary";
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose: onCancel, title, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
631
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground", children: message }),
|
|
632
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 justify-end", children: [
|
|
633
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button_default, { variant: "secondary", onClick: onCancel, children: cancelText }),
|
|
634
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button_default, { variant: getConfirmVariant(), onClick: onConfirm, children: confirmText })
|
|
635
|
+
] })
|
|
636
|
+
] }) });
|
|
637
|
+
}
|
|
638
|
+
function useConfirmDialog() {
|
|
639
|
+
const [isOpen, setIsOpen] = React4.useState(false);
|
|
640
|
+
const [options, setOptions] = React4.useState({
|
|
641
|
+
title: "",
|
|
642
|
+
message: "",
|
|
643
|
+
confirmText: "Confirm"
|
|
644
|
+
});
|
|
645
|
+
const [resolver, setResolver] = React4.useState(null);
|
|
646
|
+
const confirm = (opts) => {
|
|
647
|
+
setOptions(opts);
|
|
648
|
+
setIsOpen(true);
|
|
649
|
+
return new Promise((resolve) => {
|
|
650
|
+
setResolver(() => resolve);
|
|
651
|
+
});
|
|
652
|
+
};
|
|
653
|
+
const handleConfirm = () => {
|
|
654
|
+
setIsOpen(false);
|
|
655
|
+
if (resolver) {
|
|
656
|
+
resolver(true);
|
|
657
|
+
setResolver(null);
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
const handleCancel = () => {
|
|
661
|
+
setIsOpen(false);
|
|
662
|
+
if (resolver) {
|
|
663
|
+
resolver(false);
|
|
664
|
+
setResolver(null);
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
const dialog = /* @__PURE__ */ jsxRuntime.jsx(
|
|
668
|
+
ConfirmDialog,
|
|
669
|
+
{
|
|
670
|
+
isOpen,
|
|
671
|
+
options,
|
|
672
|
+
onConfirm: handleConfirm,
|
|
673
|
+
onCancel: handleCancel
|
|
674
|
+
}
|
|
675
|
+
);
|
|
676
|
+
return { confirm, dialog };
|
|
677
|
+
}
|
|
678
|
+
var ConfirmDialog_default = ConfirmDialog;
|
|
679
|
+
var paddingClasses2 = {
|
|
680
|
+
none: "",
|
|
681
|
+
sm: "p-4",
|
|
682
|
+
md: "p-6",
|
|
683
|
+
lg: "p-8"
|
|
684
|
+
};
|
|
685
|
+
function Container({
|
|
686
|
+
children,
|
|
687
|
+
className = "",
|
|
688
|
+
padding = "md",
|
|
689
|
+
id
|
|
690
|
+
}) {
|
|
691
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { id, className: `${paddingClasses2[padding]} ${className}`, children });
|
|
692
|
+
}
|
|
693
|
+
var EmptyState = ({
|
|
694
|
+
icon: Icon,
|
|
695
|
+
title,
|
|
696
|
+
subtitle,
|
|
697
|
+
action,
|
|
698
|
+
className = ""
|
|
699
|
+
}) => {
|
|
700
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
701
|
+
"div",
|
|
702
|
+
{
|
|
703
|
+
className: `text-center py-12 text-secondary-foreground p-6 lg:p-12 ${className}`,
|
|
704
|
+
role: "status",
|
|
705
|
+
"aria-live": "polite",
|
|
706
|
+
children: [
|
|
707
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
708
|
+
Icon,
|
|
709
|
+
{
|
|
710
|
+
className: "w-12 h-12 mx-auto mb-3 text-muted-foreground",
|
|
711
|
+
"aria-hidden": "true"
|
|
712
|
+
}
|
|
713
|
+
),
|
|
714
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium mb-1", children: title }),
|
|
715
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-4", children: subtitle }),
|
|
716
|
+
action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: action })
|
|
717
|
+
]
|
|
718
|
+
}
|
|
719
|
+
);
|
|
720
|
+
};
|
|
721
|
+
var EmptyState_default = EmptyState;
|
|
722
|
+
function useKeyboardNavigation({
|
|
723
|
+
isOpen,
|
|
724
|
+
optionsLength,
|
|
725
|
+
onSelect,
|
|
726
|
+
onClose,
|
|
727
|
+
onOpen
|
|
728
|
+
}) {
|
|
729
|
+
const [focusedIndex, setFocusedIndex] = React4.useState(-1);
|
|
730
|
+
const resetFocus = React4.useCallback(() => {
|
|
731
|
+
setFocusedIndex(-1);
|
|
732
|
+
}, []);
|
|
733
|
+
const handleKeyDown = React4.useCallback(
|
|
734
|
+
(e) => {
|
|
735
|
+
if (!isOpen) {
|
|
736
|
+
if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
|
|
737
|
+
e.preventDefault();
|
|
738
|
+
onOpen?.();
|
|
739
|
+
}
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
switch (e.key) {
|
|
743
|
+
case "ArrowDown":
|
|
744
|
+
e.preventDefault();
|
|
745
|
+
setFocusedIndex((prev) => prev < optionsLength - 1 ? prev + 1 : 0);
|
|
746
|
+
break;
|
|
747
|
+
case "ArrowUp":
|
|
748
|
+
e.preventDefault();
|
|
749
|
+
setFocusedIndex((prev) => prev > 0 ? prev - 1 : optionsLength - 1);
|
|
750
|
+
break;
|
|
751
|
+
case "Enter":
|
|
752
|
+
e.preventDefault();
|
|
753
|
+
if (focusedIndex >= 0 && focusedIndex < optionsLength) {
|
|
754
|
+
onSelect(focusedIndex);
|
|
755
|
+
}
|
|
756
|
+
break;
|
|
757
|
+
case "Escape":
|
|
758
|
+
e.preventDefault();
|
|
759
|
+
onClose();
|
|
760
|
+
resetFocus();
|
|
761
|
+
break;
|
|
762
|
+
case "Tab":
|
|
763
|
+
onClose();
|
|
764
|
+
resetFocus();
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
[isOpen, optionsLength, focusedIndex, onSelect, onClose, onOpen, resetFocus]
|
|
769
|
+
);
|
|
770
|
+
return {
|
|
771
|
+
focusedIndex,
|
|
772
|
+
handleKeyDown,
|
|
773
|
+
resetFocus,
|
|
774
|
+
setFocusedIndex
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
function SmartDropdown({
|
|
778
|
+
isOpen,
|
|
779
|
+
onClose,
|
|
780
|
+
trigger,
|
|
781
|
+
children,
|
|
782
|
+
className = "",
|
|
783
|
+
width = 384,
|
|
784
|
+
maxHeight = 450,
|
|
785
|
+
offset = 8,
|
|
786
|
+
margin = 16,
|
|
787
|
+
id = "dropdown-listbox",
|
|
788
|
+
position = "auto"
|
|
789
|
+
}) {
|
|
790
|
+
const [dropdownPosition, setDropdownPosition] = React4.useState({
|
|
791
|
+
top: 0,
|
|
792
|
+
left: 0,
|
|
793
|
+
right: void 0,
|
|
794
|
+
width: 0,
|
|
795
|
+
maxHeight: 0,
|
|
796
|
+
isAbove: false
|
|
797
|
+
});
|
|
798
|
+
const dropdownRef = React4.useRef(null);
|
|
799
|
+
const triggerRef = React4.useRef(null);
|
|
800
|
+
const calculateDropdownPosition = React4.useCallback(() => {
|
|
801
|
+
if (!triggerRef.current) return;
|
|
802
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
803
|
+
const viewportWidth = window.innerWidth;
|
|
804
|
+
const viewportHeight = window.innerHeight;
|
|
805
|
+
const spaceAbove = triggerRect.top - margin;
|
|
806
|
+
const spaceBelow = viewportHeight - triggerRect.bottom - margin;
|
|
807
|
+
let calculatedWidth;
|
|
808
|
+
if (width === "fit-content") {
|
|
809
|
+
calculatedWidth = triggerRect.width;
|
|
810
|
+
} else if (width === "auto") {
|
|
811
|
+
calculatedWidth = triggerRect.width;
|
|
812
|
+
} else if (typeof width === "number") {
|
|
813
|
+
calculatedWidth = Math.min(width, viewportWidth - margin * 2);
|
|
814
|
+
} else {
|
|
815
|
+
calculatedWidth = triggerRect.width;
|
|
816
|
+
}
|
|
817
|
+
const calculatedMaxHeight = Math.min(
|
|
818
|
+
maxHeight,
|
|
819
|
+
Math.max(spaceAbove, spaceBelow)
|
|
820
|
+
);
|
|
821
|
+
let left = triggerRect.left;
|
|
822
|
+
let right = void 0;
|
|
823
|
+
if (position === "top-right" || position === "bottom-right") {
|
|
824
|
+
left = triggerRect.right - calculatedWidth;
|
|
825
|
+
} else if (position === "top-left" || position === "bottom-left") {
|
|
826
|
+
left = triggerRect.left;
|
|
827
|
+
} else if (position === "top-left-aligned" || position === "bottom-left-aligned") {
|
|
828
|
+
const availableLeftSpace = triggerRect.left - margin;
|
|
829
|
+
const dynamicOffset = Math.max(20, availableLeftSpace * 0.2);
|
|
830
|
+
right = viewportWidth - triggerRect.left + dynamicOffset;
|
|
831
|
+
left = 0;
|
|
832
|
+
calculatedWidth = Math.min(
|
|
833
|
+
calculatedWidth,
|
|
834
|
+
triggerRect.left - dynamicOffset - margin
|
|
835
|
+
);
|
|
836
|
+
} else {
|
|
837
|
+
if (left + calculatedWidth > viewportWidth - margin) {
|
|
838
|
+
left = triggerRect.right - calculatedWidth;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
if (left !== void 0 && left < margin) {
|
|
842
|
+
left = margin;
|
|
843
|
+
}
|
|
844
|
+
let top = triggerRect.bottom + offset;
|
|
845
|
+
let finalMaxHeight = calculatedMaxHeight;
|
|
846
|
+
let isAbove = false;
|
|
847
|
+
if (spaceAbove > spaceBelow && top + calculatedMaxHeight > viewportHeight - margin) {
|
|
848
|
+
isAbove = true;
|
|
849
|
+
top = triggerRect.top - calculatedMaxHeight - offset;
|
|
850
|
+
finalMaxHeight = Math.min(calculatedMaxHeight, spaceAbove);
|
|
851
|
+
if (top < margin) {
|
|
852
|
+
top = margin;
|
|
853
|
+
finalMaxHeight = triggerRect.top - margin - offset;
|
|
854
|
+
}
|
|
855
|
+
} else {
|
|
856
|
+
finalMaxHeight = Math.min(calculatedMaxHeight, spaceBelow);
|
|
857
|
+
if (top + finalMaxHeight > viewportHeight - margin) {
|
|
858
|
+
top = viewportHeight - margin - finalMaxHeight;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
if (position === "top-right") {
|
|
862
|
+
left = triggerRect.right - calculatedWidth;
|
|
863
|
+
top = triggerRect.top - offset;
|
|
864
|
+
isAbove = true;
|
|
865
|
+
finalMaxHeight = Math.min(maxHeight, spaceAbove);
|
|
866
|
+
} else if (position === "top-left") {
|
|
867
|
+
left = triggerRect.left;
|
|
868
|
+
top = triggerRect.top - offset;
|
|
869
|
+
isAbove = true;
|
|
870
|
+
finalMaxHeight = Math.min(maxHeight, spaceAbove);
|
|
871
|
+
} else if (position === "bottom-right") {
|
|
872
|
+
left = triggerRect.right - calculatedWidth;
|
|
873
|
+
top = triggerRect.bottom + offset;
|
|
874
|
+
isAbove = false;
|
|
875
|
+
finalMaxHeight = Math.min(maxHeight, spaceBelow);
|
|
876
|
+
} else if (position === "bottom-left") {
|
|
877
|
+
left = triggerRect.left;
|
|
878
|
+
top = triggerRect.bottom + offset;
|
|
879
|
+
isAbove = false;
|
|
880
|
+
finalMaxHeight = Math.min(maxHeight, spaceBelow);
|
|
881
|
+
} else if (position === "top-left-aligned") {
|
|
882
|
+
right = viewportWidth - triggerRect.right;
|
|
883
|
+
left = 0;
|
|
884
|
+
top = triggerRect.top - offset;
|
|
885
|
+
isAbove = true;
|
|
886
|
+
finalMaxHeight = Math.min(maxHeight, spaceAbove);
|
|
887
|
+
} else if (position === "bottom-left-aligned") {
|
|
888
|
+
right = viewportWidth - triggerRect.right;
|
|
889
|
+
left = 0;
|
|
890
|
+
top = triggerRect.bottom + offset;
|
|
891
|
+
isAbove = false;
|
|
892
|
+
finalMaxHeight = Math.min(maxHeight, spaceBelow);
|
|
893
|
+
}
|
|
894
|
+
setDropdownPosition({
|
|
895
|
+
top,
|
|
896
|
+
left,
|
|
897
|
+
right,
|
|
898
|
+
width: calculatedWidth,
|
|
899
|
+
maxHeight: finalMaxHeight,
|
|
900
|
+
isAbove
|
|
901
|
+
});
|
|
902
|
+
}, [width, maxHeight, margin, offset, position]);
|
|
903
|
+
React4.useEffect(() => {
|
|
904
|
+
const handleClickOutside = (event) => {
|
|
905
|
+
const target = event.target;
|
|
906
|
+
const isInsideDropdown = dropdownRef.current?.contains(target);
|
|
907
|
+
const isInsideTrigger = triggerRef.current?.contains(target);
|
|
908
|
+
if (!isInsideDropdown && !isInsideTrigger) {
|
|
909
|
+
onClose();
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
913
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
914
|
+
}, [onClose]);
|
|
915
|
+
React4.useEffect(() => {
|
|
916
|
+
if (isOpen) {
|
|
917
|
+
calculateDropdownPosition();
|
|
918
|
+
}
|
|
919
|
+
}, [isOpen, calculateDropdownPosition]);
|
|
920
|
+
React4.useEffect(() => {
|
|
921
|
+
if (!isOpen) return;
|
|
922
|
+
const handleResize = () => {
|
|
923
|
+
calculateDropdownPosition();
|
|
924
|
+
};
|
|
925
|
+
const handleScroll = () => {
|
|
926
|
+
calculateDropdownPosition();
|
|
927
|
+
};
|
|
928
|
+
window.addEventListener("resize", handleResize);
|
|
929
|
+
window.addEventListener("scroll", handleScroll, true);
|
|
930
|
+
return () => {
|
|
931
|
+
window.removeEventListener("resize", handleResize);
|
|
932
|
+
window.removeEventListener("scroll", handleScroll, true);
|
|
933
|
+
};
|
|
934
|
+
}, [isOpen, calculateDropdownPosition]);
|
|
935
|
+
React4.useEffect(() => {
|
|
936
|
+
if (!isOpen || !dropdownRef.current || !triggerRef.current) return;
|
|
937
|
+
if (dropdownPosition.isAbove) {
|
|
938
|
+
const adjustPosition = () => {
|
|
939
|
+
const dropdownRect = dropdownRef.current?.getBoundingClientRect();
|
|
940
|
+
const triggerRect = triggerRef.current?.getBoundingClientRect();
|
|
941
|
+
if (!dropdownRect || !triggerRect) return;
|
|
942
|
+
const actualHeight = dropdownRect.height;
|
|
943
|
+
const newTop = triggerRect.top - actualHeight - offset;
|
|
944
|
+
if (newTop !== dropdownPosition.top && newTop >= margin) {
|
|
945
|
+
setDropdownPosition((prev) => ({
|
|
946
|
+
...prev,
|
|
947
|
+
top: newTop
|
|
948
|
+
}));
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
952
|
+
setTimeout(adjustPosition, 0);
|
|
953
|
+
});
|
|
954
|
+
resizeObserver.observe(dropdownRef.current);
|
|
955
|
+
adjustPosition();
|
|
956
|
+
return () => {
|
|
957
|
+
resizeObserver.disconnect();
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
}, [isOpen, dropdownPosition.isAbove, dropdownPosition.top, offset, margin]);
|
|
961
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
962
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
963
|
+
"div",
|
|
964
|
+
{
|
|
965
|
+
ref: triggerRef,
|
|
966
|
+
className: "w-full",
|
|
967
|
+
role: "combobox",
|
|
968
|
+
"aria-expanded": isOpen,
|
|
969
|
+
"aria-haspopup": "listbox",
|
|
970
|
+
"aria-controls": "dropdown-listbox",
|
|
971
|
+
children: trigger
|
|
972
|
+
}
|
|
973
|
+
),
|
|
974
|
+
isOpen && typeof window !== "undefined" && reactDom.createPortal(
|
|
975
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
976
|
+
"div",
|
|
977
|
+
{
|
|
978
|
+
ref: dropdownRef,
|
|
979
|
+
id,
|
|
980
|
+
"data-smart-dropdown": true,
|
|
981
|
+
role: "listbox",
|
|
982
|
+
"aria-label": "Dropdown options",
|
|
983
|
+
className: `fixed z-[1000001] card overflow-hidden`,
|
|
984
|
+
style: {
|
|
985
|
+
top: dropdownPosition.top,
|
|
986
|
+
...dropdownPosition.left !== void 0 ? { left: dropdownPosition.left } : {},
|
|
987
|
+
...dropdownPosition.right !== void 0 ? { right: dropdownPosition.right } : {},
|
|
988
|
+
width: width === "fit-content" ? "auto" : dropdownPosition.width,
|
|
989
|
+
maxHeight: dropdownPosition.maxHeight
|
|
990
|
+
},
|
|
991
|
+
onClick: (e) => {
|
|
992
|
+
e.stopPropagation();
|
|
993
|
+
},
|
|
994
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
995
|
+
"div",
|
|
996
|
+
{
|
|
997
|
+
className: className ? className : "overflow-y-auto",
|
|
998
|
+
style: { maxHeight: dropdownPosition.maxHeight },
|
|
999
|
+
children: typeof children === "function" ? children({ isAbove: dropdownPosition.isAbove }) : children
|
|
1000
|
+
}
|
|
1001
|
+
)
|
|
1002
|
+
}
|
|
1003
|
+
),
|
|
1004
|
+
document.body
|
|
1005
|
+
)
|
|
1006
|
+
] });
|
|
1007
|
+
}
|
|
1008
|
+
function SmartSelect({
|
|
1009
|
+
options,
|
|
1010
|
+
value,
|
|
1011
|
+
onChange,
|
|
1012
|
+
placeholder = "Select option...",
|
|
1013
|
+
className = "",
|
|
1014
|
+
description,
|
|
1015
|
+
disabled = false,
|
|
1016
|
+
multiple = false,
|
|
1017
|
+
width,
|
|
1018
|
+
searchable = false,
|
|
1019
|
+
keepOpen = false,
|
|
1020
|
+
clearable = true,
|
|
1021
|
+
// API integration props
|
|
1022
|
+
onOpen,
|
|
1023
|
+
onClose,
|
|
1024
|
+
onSearch,
|
|
1025
|
+
isLoading = false
|
|
1026
|
+
}) {
|
|
1027
|
+
const [isOpen, setIsOpen] = React4.useState(false);
|
|
1028
|
+
const [triggerWidth, setTriggerWidth] = React4.useState(
|
|
1029
|
+
void 0
|
|
1030
|
+
);
|
|
1031
|
+
const [searchTerm, setSearchTerm] = React4.useState("");
|
|
1032
|
+
const [displayValue, setDisplayValue] = React4.useState("");
|
|
1033
|
+
const inputRef = React4.useRef(null);
|
|
1034
|
+
const buttonRef = React4.useRef(null);
|
|
1035
|
+
const selectedValues = multiple ? value || [] : [value];
|
|
1036
|
+
const selectedOptions = options.filter(
|
|
1037
|
+
(opt) => selectedValues.includes(opt.value)
|
|
1038
|
+
);
|
|
1039
|
+
const hasSelection = multiple ? selectedValues.length > 0 : value && value !== "";
|
|
1040
|
+
const filteredOptions = searchable && searchTerm.trim() ? options.filter(
|
|
1041
|
+
(option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()) || option.value.toLowerCase().includes(searchTerm.toLowerCase()) || option.description?.toLowerCase().includes(searchTerm.toLowerCase())
|
|
1042
|
+
) : options;
|
|
1043
|
+
const { focusedIndex, handleKeyDown, resetFocus } = useKeyboardNavigation({
|
|
1044
|
+
isOpen,
|
|
1045
|
+
optionsLength: filteredOptions.length,
|
|
1046
|
+
onSelect: (index) => handleSelect(filteredOptions[index].value),
|
|
1047
|
+
onClose: () => setIsOpen(false),
|
|
1048
|
+
onOpen: () => setIsOpen(true)
|
|
1049
|
+
});
|
|
1050
|
+
React4.useEffect(() => {
|
|
1051
|
+
if (selectedOptions.length > 0) {
|
|
1052
|
+
if (multiple) {
|
|
1053
|
+
setDisplayValue(selectedOptions.map((opt) => opt.label).join(", "));
|
|
1054
|
+
} else {
|
|
1055
|
+
setDisplayValue(selectedOptions[0].label);
|
|
1056
|
+
}
|
|
1057
|
+
} else {
|
|
1058
|
+
setDisplayValue("");
|
|
1059
|
+
}
|
|
1060
|
+
}, [selectedOptions, multiple]);
|
|
1061
|
+
const handleSelect = (optionValue) => {
|
|
1062
|
+
if (multiple) {
|
|
1063
|
+
const currentValues = value || [];
|
|
1064
|
+
const newValues = currentValues.includes(optionValue) ? currentValues.filter((v) => v !== optionValue) : [...currentValues, optionValue];
|
|
1065
|
+
onChange(newValues);
|
|
1066
|
+
} else {
|
|
1067
|
+
onChange(optionValue);
|
|
1068
|
+
setSearchTerm("");
|
|
1069
|
+
setIsOpen(false);
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
const currentTriggerRef = searchable ? inputRef : buttonRef;
|
|
1073
|
+
React4.useEffect(() => {
|
|
1074
|
+
if (currentTriggerRef.current) {
|
|
1075
|
+
const rect = currentTriggerRef.current.getBoundingClientRect();
|
|
1076
|
+
setTriggerWidth(rect.width);
|
|
1077
|
+
}
|
|
1078
|
+
}, [isOpen, currentTriggerRef]);
|
|
1079
|
+
React4.useEffect(() => {
|
|
1080
|
+
if (!currentTriggerRef.current) return;
|
|
1081
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1082
|
+
if (currentTriggerRef.current) {
|
|
1083
|
+
const rect = currentTriggerRef.current.getBoundingClientRect();
|
|
1084
|
+
setTriggerWidth(rect.width);
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
resizeObserver.observe(currentTriggerRef.current);
|
|
1088
|
+
return () => {
|
|
1089
|
+
resizeObserver.disconnect();
|
|
1090
|
+
};
|
|
1091
|
+
}, [currentTriggerRef]);
|
|
1092
|
+
React4.useEffect(() => {
|
|
1093
|
+
if (isOpen && searchable && inputRef.current) {
|
|
1094
|
+
setTimeout(() => {
|
|
1095
|
+
inputRef.current?.focus();
|
|
1096
|
+
}, 0);
|
|
1097
|
+
} else if (!isOpen) {
|
|
1098
|
+
setSearchTerm("");
|
|
1099
|
+
resetFocus();
|
|
1100
|
+
}
|
|
1101
|
+
}, [isOpen, searchable, resetFocus]);
|
|
1102
|
+
const handleOpen = () => {
|
|
1103
|
+
setIsOpen(true);
|
|
1104
|
+
onOpen?.();
|
|
1105
|
+
};
|
|
1106
|
+
const handleClose = () => {
|
|
1107
|
+
setIsOpen(false);
|
|
1108
|
+
onClose?.();
|
|
1109
|
+
};
|
|
1110
|
+
const handleSearchChange = (search) => {
|
|
1111
|
+
setSearchTerm(search);
|
|
1112
|
+
onSearch?.(search);
|
|
1113
|
+
};
|
|
1114
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", "data-smart-select": true, children: [
|
|
1115
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "form-description", children: description }),
|
|
1116
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1117
|
+
SmartDropdown,
|
|
1118
|
+
{
|
|
1119
|
+
isOpen,
|
|
1120
|
+
onClose: handleClose,
|
|
1121
|
+
width: width !== void 0 ? width : triggerWidth,
|
|
1122
|
+
maxHeight: 200,
|
|
1123
|
+
trigger: searchable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1124
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1125
|
+
"input",
|
|
1126
|
+
{
|
|
1127
|
+
ref: inputRef,
|
|
1128
|
+
type: "text",
|
|
1129
|
+
value: isOpen ? searchTerm : displayValue,
|
|
1130
|
+
onChange: (e) => {
|
|
1131
|
+
if (isOpen) {
|
|
1132
|
+
handleSearchChange(e.target.value);
|
|
1133
|
+
resetFocus();
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
onFocus: () => !disabled && handleOpen(),
|
|
1137
|
+
onClick: (e) => {
|
|
1138
|
+
e.stopPropagation();
|
|
1139
|
+
!disabled && handleOpen();
|
|
1140
|
+
},
|
|
1141
|
+
onKeyDown: handleKeyDown,
|
|
1142
|
+
placeholder,
|
|
1143
|
+
disabled,
|
|
1144
|
+
role: "combobox",
|
|
1145
|
+
"aria-expanded": isOpen,
|
|
1146
|
+
"aria-haspopup": "listbox",
|
|
1147
|
+
"aria-controls": "dropdown-listbox",
|
|
1148
|
+
"aria-autocomplete": "list",
|
|
1149
|
+
"aria-activedescendant": focusedIndex >= 0 ? `option-${focusedIndex}` : void 0,
|
|
1150
|
+
className: `form-input truncate ${hasSelection ? "pr-12" : "pr-8"} ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`
|
|
1151
|
+
}
|
|
1152
|
+
),
|
|
1153
|
+
hasSelection && clearable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1154
|
+
"button",
|
|
1155
|
+
{
|
|
1156
|
+
type: "button",
|
|
1157
|
+
onClick: (e) => {
|
|
1158
|
+
e.stopPropagation();
|
|
1159
|
+
onChange(multiple ? [] : "");
|
|
1160
|
+
},
|
|
1161
|
+
className: "absolute right-6 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground hover:text-muted-foreground transition-colors",
|
|
1162
|
+
"aria-label": "Clear selection",
|
|
1163
|
+
title: "Clear selection",
|
|
1164
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ri.RiCloseLine, { className: "w-4 h-4", "aria-hidden": true })
|
|
1165
|
+
}
|
|
1166
|
+
),
|
|
1167
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1168
|
+
"button",
|
|
1169
|
+
{
|
|
1170
|
+
type: "button",
|
|
1171
|
+
onClick: (e) => {
|
|
1172
|
+
e.stopPropagation();
|
|
1173
|
+
!disabled && setIsOpen(!isOpen);
|
|
1174
|
+
},
|
|
1175
|
+
className: `absolute right-2 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground hover:text-muted-foreground transition-colors ${disabled ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
1176
|
+
disabled,
|
|
1177
|
+
"aria-label": isOpen ? "Close dropdown" : "Open dropdown",
|
|
1178
|
+
"aria-expanded": isOpen,
|
|
1179
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1180
|
+
DropDownArrow,
|
|
1181
|
+
{
|
|
1182
|
+
isOpen,
|
|
1183
|
+
disabled,
|
|
1184
|
+
size: "sm",
|
|
1185
|
+
color: "gray",
|
|
1186
|
+
"aria-hidden": true
|
|
1187
|
+
}
|
|
1188
|
+
)
|
|
1189
|
+
}
|
|
1190
|
+
)
|
|
1191
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group", children: [
|
|
1192
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1193
|
+
"button",
|
|
1194
|
+
{
|
|
1195
|
+
ref: buttonRef,
|
|
1196
|
+
type: "button",
|
|
1197
|
+
onClick: (e) => {
|
|
1198
|
+
e.stopPropagation();
|
|
1199
|
+
!disabled && (isOpen ? handleClose() : handleOpen());
|
|
1200
|
+
},
|
|
1201
|
+
onKeyDown: handleKeyDown,
|
|
1202
|
+
disabled,
|
|
1203
|
+
role: "combobox",
|
|
1204
|
+
"aria-expanded": isOpen,
|
|
1205
|
+
"aria-haspopup": "listbox",
|
|
1206
|
+
"aria-controls": "dropdown-listbox",
|
|
1207
|
+
"aria-label": placeholder,
|
|
1208
|
+
"aria-activedescendant": focusedIndex >= 0 ? `option-${focusedIndex}` : void 0,
|
|
1209
|
+
className: `form-input flex items-center justify-between text-left ${hasSelection ? "pr-12" : "pr-8"} ${disabled ? "opacity-60 cursor-not-allowed" : ""} ${className}`,
|
|
1210
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1211
|
+
"span",
|
|
1212
|
+
{
|
|
1213
|
+
className: `flex items-center gap-2 min-w-0 flex-1 ${selectedOptions.length > 0 ? "" : "text-muted-foreground opacity-60"}`,
|
|
1214
|
+
children: multiple ? selectedOptions.length > 0 ? (() => {
|
|
1215
|
+
const displayText = selectedOptions.map((opt) => opt.label).join(", ");
|
|
1216
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 min-w-0 flex-1", children: [
|
|
1217
|
+
selectedOptions[0].icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: selectedOptions[0].icon }),
|
|
1218
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: displayText })
|
|
1219
|
+
] });
|
|
1220
|
+
})() : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: placeholder }) : selectedOptions[0] ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 min-w-0 flex-1", children: [
|
|
1221
|
+
selectedOptions[0].icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: selectedOptions[0].icon }),
|
|
1222
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: selectedOptions[0].label })
|
|
1223
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: placeholder })
|
|
1224
|
+
}
|
|
1225
|
+
)
|
|
1226
|
+
}
|
|
1227
|
+
),
|
|
1228
|
+
hasSelection && clearable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1229
|
+
"button",
|
|
1230
|
+
{
|
|
1231
|
+
type: "button",
|
|
1232
|
+
onClick: (e) => {
|
|
1233
|
+
e.stopPropagation();
|
|
1234
|
+
onChange(multiple ? [] : "");
|
|
1235
|
+
},
|
|
1236
|
+
className: "absolute right-6 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground hover:text-muted-foreground transition-all duration-200 opacity-0 group-hover:opacity-100",
|
|
1237
|
+
"aria-label": "Clear selection",
|
|
1238
|
+
title: "Clear selection",
|
|
1239
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ri.RiCloseLine, { className: "w-4 h-4", "aria-hidden": true })
|
|
1240
|
+
}
|
|
1241
|
+
),
|
|
1242
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1243
|
+
"button",
|
|
1244
|
+
{
|
|
1245
|
+
type: "button",
|
|
1246
|
+
onClick: (e) => {
|
|
1247
|
+
e.stopPropagation();
|
|
1248
|
+
!disabled && setIsOpen(!isOpen);
|
|
1249
|
+
},
|
|
1250
|
+
className: `absolute right-2 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground hover:text-muted-foreground transition-colors ${disabled ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
1251
|
+
disabled,
|
|
1252
|
+
"aria-label": isOpen ? "Close dropdown" : "Open dropdown",
|
|
1253
|
+
"aria-expanded": isOpen,
|
|
1254
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1255
|
+
DropDownArrow,
|
|
1256
|
+
{
|
|
1257
|
+
isOpen,
|
|
1258
|
+
disabled,
|
|
1259
|
+
size: "sm",
|
|
1260
|
+
color: "gray",
|
|
1261
|
+
"aria-hidden": true
|
|
1262
|
+
}
|
|
1263
|
+
)
|
|
1264
|
+
}
|
|
1265
|
+
)
|
|
1266
|
+
] }),
|
|
1267
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2", children: filteredOptions.length > 0 ? filteredOptions.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1268
|
+
"button",
|
|
1269
|
+
{
|
|
1270
|
+
id: `option-${index}`,
|
|
1271
|
+
type: "button",
|
|
1272
|
+
role: "option",
|
|
1273
|
+
"aria-selected": selectedValues.includes(option.value),
|
|
1274
|
+
onMouseDown: (e) => {
|
|
1275
|
+
e.preventDefault();
|
|
1276
|
+
e.stopPropagation();
|
|
1277
|
+
handleSelect(option.value);
|
|
1278
|
+
},
|
|
1279
|
+
className: `w-full px-3 py-2 text-left text-sm hover:bg-accent flex items-center justify-between min-h-[40px] transition-colors ${selectedValues.includes(option.value) ? "bg-accent border-l-2 border-l-ring" : index === focusedIndex ? "bg-muted ring-2 ring-ring" : ""}`,
|
|
1280
|
+
children: [
|
|
1281
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
|
|
1282
|
+
option.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: option.icon }),
|
|
1283
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1284
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1285
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-foreground truncate", children: option.label }),
|
|
1286
|
+
option.metadata?.isDefault && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium success-badge flex-shrink-0", children: "Default" })
|
|
1287
|
+
] }),
|
|
1288
|
+
option.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground truncate", children: option.description }),
|
|
1289
|
+
option.metadata?.args && option.metadata.args.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
|
|
1290
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-secondary-foreground mb-1", children: "Arguments:" }),
|
|
1291
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
1292
|
+
option.metadata.args.slice(0, 3).map((arg, argIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1293
|
+
"span",
|
|
1294
|
+
{
|
|
1295
|
+
className: "inline-flex items-center px-1.5 py-0.5 rounded text-xs font-mono bg-muted text-muted-foreground",
|
|
1296
|
+
children: arg
|
|
1297
|
+
},
|
|
1298
|
+
argIndex
|
|
1299
|
+
)),
|
|
1300
|
+
option.metadata.args.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-secondary-foreground", children: [
|
|
1301
|
+
"+",
|
|
1302
|
+
option.metadata.args.length - 3,
|
|
1303
|
+
" more"
|
|
1304
|
+
] })
|
|
1305
|
+
] })
|
|
1306
|
+
] })
|
|
1307
|
+
] })
|
|
1308
|
+
] }),
|
|
1309
|
+
multiple ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1310
|
+
"input",
|
|
1311
|
+
{
|
|
1312
|
+
type: "checkbox",
|
|
1313
|
+
checked: selectedValues.includes(option.value),
|
|
1314
|
+
onChange: () => {
|
|
1315
|
+
},
|
|
1316
|
+
className: "w-4 h-4 text-primary bg-muted border-border rounded focus:ring-primary focus:ring-2"
|
|
1317
|
+
}
|
|
1318
|
+
) : selectedValues.includes(option.value) && /* @__PURE__ */ jsxRuntime.jsx(ri.RiCheckLine, { className: "w-4 h-4 text-primary flex-shrink-0" })
|
|
1319
|
+
]
|
|
1320
|
+
},
|
|
1321
|
+
option.value
|
|
1322
|
+
)) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-secondary-foreground flex items-center gap-2", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1323
|
+
/* @__PURE__ */ jsxRuntime.jsx(ri.RiLoader4Line, { className: "w-4 h-4 animate-spin" }),
|
|
1324
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading..." })
|
|
1325
|
+
] }) : searchTerm.trim() ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "No results found" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "No options available" }) }) })
|
|
1326
|
+
}
|
|
1327
|
+
)
|
|
1328
|
+
] });
|
|
1329
|
+
}
|
|
1330
|
+
function Skeleton({ className = "", children }) {
|
|
1331
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `animate-pulse ${className}`, children });
|
|
1332
|
+
}
|
|
1333
|
+
function SkeletonItem({
|
|
1334
|
+
className = "",
|
|
1335
|
+
width = "w-full",
|
|
1336
|
+
height = "h-4",
|
|
1337
|
+
rounded = true,
|
|
1338
|
+
animate = true
|
|
1339
|
+
}) {
|
|
1340
|
+
const isArbitraryHeight = height.includes("[") && height.includes("]");
|
|
1341
|
+
const baseClasses = isArbitraryHeight ? `bg-muted ${width}` : `${height} bg-muted ${width}`;
|
|
1342
|
+
const roundedClasses = rounded ? "rounded" : "";
|
|
1343
|
+
const animateClasses = animate ? "animate-pulse" : "";
|
|
1344
|
+
const style = isArbitraryHeight ? { height: height.replace("h-[", "").replace("]", "") } : {};
|
|
1345
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1346
|
+
"div",
|
|
1347
|
+
{
|
|
1348
|
+
className: `${baseClasses} ${roundedClasses} ${animateClasses} ${className}`,
|
|
1349
|
+
style
|
|
1350
|
+
}
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
function FormInput({
|
|
1354
|
+
label,
|
|
1355
|
+
name,
|
|
1356
|
+
type = "text",
|
|
1357
|
+
value,
|
|
1358
|
+
onChange,
|
|
1359
|
+
placeholder,
|
|
1360
|
+
required = false,
|
|
1361
|
+
disabled = false,
|
|
1362
|
+
error,
|
|
1363
|
+
className = "",
|
|
1364
|
+
inputClassName = "",
|
|
1365
|
+
min,
|
|
1366
|
+
max,
|
|
478
1367
|
step,
|
|
479
1368
|
maxLength,
|
|
480
1369
|
autoComplete,
|
|
@@ -484,12 +1373,17 @@ function FormInput({
|
|
|
484
1373
|
onKeyDown,
|
|
485
1374
|
onBlur,
|
|
486
1375
|
icon,
|
|
1376
|
+
options = [],
|
|
1377
|
+
multiSelect = false,
|
|
1378
|
+
selectWidth,
|
|
1379
|
+
searchable = false,
|
|
1380
|
+
clearable = true,
|
|
487
1381
|
rows = 3,
|
|
488
1382
|
showHidePassword = false,
|
|
489
1383
|
onGeneratePassword,
|
|
1384
|
+
isLoading = false,
|
|
490
1385
|
copyable = false,
|
|
491
|
-
readOnly = false
|
|
492
|
-
clearable = true
|
|
1386
|
+
readOnly = false
|
|
493
1387
|
}) {
|
|
494
1388
|
const [showPassword, setShowPassword] = React4.useState(false);
|
|
495
1389
|
const [copied, setCopied] = React4.useState(false);
|
|
@@ -531,14 +1425,82 @@ function FormInput({
|
|
|
531
1425
|
};
|
|
532
1426
|
const getInputPaddingClasses = (inputType, iconConfig) => {
|
|
533
1427
|
if (!shouldShowIcons(inputType)) return "";
|
|
534
|
-
const
|
|
535
|
-
if (iconConfig.left)
|
|
1428
|
+
const paddingClasses3 = [];
|
|
1429
|
+
if (iconConfig.left) paddingClasses3.push("pl-10");
|
|
536
1430
|
if (iconConfig.right) {
|
|
537
|
-
|
|
1431
|
+
paddingClasses3.push(inputType === "number" ? "pr-12" : "pr-10");
|
|
1432
|
+
}
|
|
1433
|
+
return paddingClasses3.join(" ");
|
|
1434
|
+
};
|
|
1435
|
+
const SkeletonInput = () => {
|
|
1436
|
+
const iconConfig = getIconConfig(icon);
|
|
1437
|
+
const hasLeftIcon = iconConfig.left;
|
|
1438
|
+
const hasRightIcon = iconConfig.right;
|
|
1439
|
+
if (type === "checkbox") {
|
|
1440
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center p-2 space-x-3 h-full", children: [
|
|
1441
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative inline-flex h-6 w-11 items-center rounded-full bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block h-4 w-4 transform rounded-full bg-white border border-border translate-x-1" }) }),
|
|
1442
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
1443
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "form-label", children: [
|
|
1444
|
+
label,
|
|
1445
|
+
required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
|
|
1446
|
+
] }),
|
|
1447
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: description })
|
|
1448
|
+
] })
|
|
1449
|
+
] });
|
|
1450
|
+
}
|
|
1451
|
+
if (type === "textarea") {
|
|
1452
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1453
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "form-label", children: [
|
|
1454
|
+
label,
|
|
1455
|
+
required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", children: "*" })
|
|
1456
|
+
] }),
|
|
1457
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-secondary-foreground", children: description }),
|
|
1458
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1459
|
+
SkeletonItem,
|
|
1460
|
+
{
|
|
1461
|
+
width: "w-full",
|
|
1462
|
+
height: "h-24",
|
|
1463
|
+
className: `rounded-md`
|
|
1464
|
+
}
|
|
1465
|
+
) }),
|
|
1466
|
+
footerDescription && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-secondary-foreground", children: footerDescription })
|
|
1467
|
+
] });
|
|
538
1468
|
}
|
|
539
|
-
|
|
1469
|
+
if (type === "color") {
|
|
1470
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1471
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "form-label", children: [
|
|
1472
|
+
label,
|
|
1473
|
+
required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", children: "*" })
|
|
1474
|
+
] }),
|
|
1475
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-secondary-foreground", children: description }),
|
|
1476
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-3", children: [
|
|
1477
|
+
/* @__PURE__ */ jsxRuntime.jsx(SkeletonItem, { width: "w-10", height: "h-10", className: "rounded-md" }),
|
|
1478
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonItem, { width: "w-24", height: "h-10", className: "rounded-md" }) })
|
|
1479
|
+
] })
|
|
1480
|
+
] });
|
|
1481
|
+
}
|
|
1482
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1483
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "form-label", children: [
|
|
1484
|
+
label,
|
|
1485
|
+
required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", children: "*" })
|
|
1486
|
+
] }),
|
|
1487
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-secondary-foreground", children: description }),
|
|
1488
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1490
|
+
SkeletonItem,
|
|
1491
|
+
{
|
|
1492
|
+
width: "w-full",
|
|
1493
|
+
height: "h-10",
|
|
1494
|
+
className: `rounded-md ${hasLeftIcon ? "pl-10" : ""} ${hasRightIcon ? "pr-10" : ""}`
|
|
1495
|
+
}
|
|
1496
|
+
),
|
|
1497
|
+
hasLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonItem, { width: "w-5", height: "h-5", className: "rounded-full" }) }),
|
|
1498
|
+
hasRightIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonItem, { width: "w-5", height: "h-5", className: "rounded-full" }) })
|
|
1499
|
+
] }),
|
|
1500
|
+
footerDescription && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-secondary-foreground", children: footerDescription })
|
|
1501
|
+
] });
|
|
540
1502
|
};
|
|
541
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `form-group ${className}`, children: type === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center p-2 space-x-3 h-full", children: [
|
|
1503
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `form-group ${className}`, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(SkeletonInput, {}) : type === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center p-2 space-x-3 h-full", children: [
|
|
542
1504
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
543
1505
|
"input",
|
|
544
1506
|
{
|
|
@@ -643,7 +1605,45 @@ function FormInput({
|
|
|
643
1605
|
required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "form-label-required", children: "*" })
|
|
644
1606
|
] }),
|
|
645
1607
|
description && /* @__PURE__ */ jsxRuntime.jsx("p", { id: `${name}-description`, className: "form-description", children: description }),
|
|
646
|
-
type === "
|
|
1608
|
+
type === "select" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1609
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1610
|
+
SmartSelect,
|
|
1611
|
+
{
|
|
1612
|
+
value: multiSelect ? Array.isArray(value) ? value : value ? String(value).split(",") : [] : String(value),
|
|
1613
|
+
onChange: multiSelect ? (selectedValue) => {
|
|
1614
|
+
const syntheticEvent = {
|
|
1615
|
+
target: {
|
|
1616
|
+
name,
|
|
1617
|
+
value: Array.isArray(selectedValue) ? selectedValue.join(",") : selectedValue
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
onChange(syntheticEvent);
|
|
1621
|
+
} : (selectedValue) => {
|
|
1622
|
+
const syntheticEvent = {
|
|
1623
|
+
target: {
|
|
1624
|
+
name,
|
|
1625
|
+
value: selectedValue
|
|
1626
|
+
}
|
|
1627
|
+
};
|
|
1628
|
+
onChange(syntheticEvent);
|
|
1629
|
+
},
|
|
1630
|
+
options,
|
|
1631
|
+
placeholder: placeholder || "Select an option...",
|
|
1632
|
+
className: `form-input ${error ? "form-input-error" : ""} ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${getInputPaddingClasses(type, getIconConfig(icon))} ${inputClassName}`,
|
|
1633
|
+
multiple: multiSelect,
|
|
1634
|
+
width: selectWidth,
|
|
1635
|
+
searchable,
|
|
1636
|
+
clearable
|
|
1637
|
+
}
|
|
1638
|
+
),
|
|
1639
|
+
shouldShowIcons(type) && (() => {
|
|
1640
|
+
const iconConfig = getIconConfig(icon);
|
|
1641
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1642
|
+
renderIcon(iconConfig.left, "left"),
|
|
1643
|
+
renderIcon(iconConfig.right, "right")
|
|
1644
|
+
] });
|
|
1645
|
+
})()
|
|
1646
|
+
] }) : type === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
647
1647
|
"textarea",
|
|
648
1648
|
{
|
|
649
1649
|
id: name,
|
|
@@ -842,337 +1842,85 @@ function FormInput({
|
|
|
842
1842
|
error && /* @__PURE__ */ jsxRuntime.jsx("div", { id: `${name}-error`, className: "form-error", role: "alert", children: typeof error === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { children: error }) : error })
|
|
843
1843
|
] }) });
|
|
844
1844
|
}
|
|
845
|
-
function
|
|
846
|
-
|
|
847
|
-
onChange,
|
|
848
|
-
disabled = false,
|
|
849
|
-
label,
|
|
1845
|
+
function FormSection({
|
|
1846
|
+
title,
|
|
850
1847
|
description,
|
|
851
|
-
|
|
852
|
-
|
|
1848
|
+
children,
|
|
1849
|
+
className = ""
|
|
853
1850
|
}) {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
sm: { track: "w-8 h-4", thumb: "w-3 h-3", translate: "translate-x-4" },
|
|
861
|
-
md: { track: "w-11 h-6", thumb: "w-5 h-5", translate: "translate-x-5" },
|
|
862
|
-
lg: { track: "w-14 h-8", thumb: "w-7 h-7", translate: "translate-x-6" }
|
|
863
|
-
};
|
|
864
|
-
const currentSize = sizes[size];
|
|
865
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-start ${className}`, children: [
|
|
866
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
867
|
-
"button",
|
|
868
|
-
{
|
|
869
|
-
type: "button",
|
|
870
|
-
role: "switch",
|
|
871
|
-
"aria-checked": checked,
|
|
872
|
-
disabled,
|
|
873
|
-
onClick: toggle,
|
|
874
|
-
className: `
|
|
875
|
-
relative inline-flex flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent
|
|
876
|
-
transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2
|
|
877
|
-
${checked ? "bg-primary" : "bg-muted"}
|
|
878
|
-
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
879
|
-
${currentSize.track}
|
|
880
|
-
`,
|
|
881
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
882
|
-
"span",
|
|
883
|
-
{
|
|
884
|
-
"aria-hidden": "true",
|
|
885
|
-
className: `
|
|
886
|
-
pointer-events-none inline-block transform rounded-full bg-white shadow ring-0
|
|
887
|
-
transition duration-200 ease-in-out
|
|
888
|
-
${checked ? currentSize.translate : "translate-x-0"}
|
|
889
|
-
${currentSize.thumb}
|
|
890
|
-
`
|
|
891
|
-
}
|
|
892
|
-
)
|
|
893
|
-
}
|
|
894
|
-
),
|
|
895
|
-
(label || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-3 text-sm leading-6", children: [
|
|
896
|
-
label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "font-medium text-foreground cursor-pointer", onClick: toggle, children: label }),
|
|
897
|
-
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: description })
|
|
898
|
-
] })
|
|
1851
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `space-y-4 ${className}`, children: [
|
|
1852
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1853
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium ", children: title }),
|
|
1854
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description })
|
|
1855
|
+
] }),
|
|
1856
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children })
|
|
899
1857
|
] });
|
|
900
1858
|
}
|
|
901
|
-
|
|
902
|
-
sm: "max-w-md",
|
|
903
|
-
md: "max-w-2xl",
|
|
904
|
-
lg: "max-w-4xl",
|
|
905
|
-
xl: "max-w-6xl",
|
|
906
|
-
full: "max-w-full mx-4"
|
|
907
|
-
};
|
|
908
|
-
function Modal({
|
|
909
|
-
isOpen,
|
|
910
|
-
onClose,
|
|
1859
|
+
function Grid({
|
|
911
1860
|
children,
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
size = "md",
|
|
916
|
-
className = "",
|
|
917
|
-
footer,
|
|
918
|
-
fullScreen = false,
|
|
919
|
-
noPadding = false,
|
|
920
|
-
footerBg = "gray",
|
|
921
|
-
variant = "default",
|
|
922
|
-
scrollable = true,
|
|
923
|
-
"aria-describedby": ariaDescribedBy,
|
|
924
|
-
customStyles = {}
|
|
1861
|
+
cols = 1,
|
|
1862
|
+
gap = 4,
|
|
1863
|
+
className = ""
|
|
925
1864
|
}) {
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
"input:not([disabled])",
|
|
935
|
-
"select:not([disabled])",
|
|
936
|
-
"textarea:not([disabled])",
|
|
937
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
938
|
-
].join(", ");
|
|
939
|
-
return Array.from(
|
|
940
|
-
modalContentRef.current.querySelectorAll(focusableSelectors)
|
|
941
|
-
);
|
|
942
|
-
};
|
|
943
|
-
React4.useEffect(() => {
|
|
944
|
-
if (!isOpen) {
|
|
945
|
-
hasPerformedInitialFocusRef.current = false;
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
if (!hasPerformedInitialFocusRef.current) {
|
|
949
|
-
previousActiveElementRef.current = document.activeElement;
|
|
950
|
-
}
|
|
951
|
-
let timeoutId = null;
|
|
952
|
-
if (!hasPerformedInitialFocusRef.current) {
|
|
953
|
-
const focusableElements = getFocusableElements();
|
|
954
|
-
const firstFocusable = focusableElements[0];
|
|
955
|
-
timeoutId = setTimeout(() => {
|
|
956
|
-
const activeElement = document.activeElement;
|
|
957
|
-
const isHTMLElement = activeElement instanceof HTMLElement;
|
|
958
|
-
const isUserTyping = activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || isHTMLElement && activeElement.isContentEditable);
|
|
959
|
-
const isFocusInModal = modalContentRef.current?.contains(activeElement);
|
|
960
|
-
if (!isUserTyping && !isFocusInModal) {
|
|
961
|
-
if (firstFocusable) {
|
|
962
|
-
firstFocusable.focus();
|
|
963
|
-
hasPerformedInitialFocusRef.current = true;
|
|
964
|
-
} else if (modalContentRef.current) {
|
|
965
|
-
modalContentRef.current.focus();
|
|
966
|
-
hasPerformedInitialFocusRef.current = true;
|
|
967
|
-
}
|
|
968
|
-
} else if (isFocusInModal) {
|
|
969
|
-
hasPerformedInitialFocusRef.current = true;
|
|
970
|
-
}
|
|
971
|
-
}, 100);
|
|
972
|
-
}
|
|
973
|
-
const handleTab = (event) => {
|
|
974
|
-
if (event.key !== "Tab") return;
|
|
975
|
-
const focusableElements = getFocusableElements();
|
|
976
|
-
if (focusableElements.length === 0) return;
|
|
977
|
-
const firstElement = focusableElements[0];
|
|
978
|
-
const lastElement = focusableElements[focusableElements.length - 1];
|
|
979
|
-
if (event.shiftKey) {
|
|
980
|
-
if (document.activeElement === firstElement) {
|
|
981
|
-
event.preventDefault();
|
|
982
|
-
lastElement.focus();
|
|
983
|
-
}
|
|
984
|
-
} else {
|
|
985
|
-
if (document.activeElement === lastElement) {
|
|
986
|
-
event.preventDefault();
|
|
987
|
-
firstElement.focus();
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
};
|
|
991
|
-
const handleEsc = (event) => {
|
|
992
|
-
if (event.key === "Escape" && !blocking) {
|
|
993
|
-
onClose();
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
document.addEventListener("keydown", handleTab);
|
|
997
|
-
document.addEventListener("keydown", handleEsc);
|
|
998
|
-
document.body.style.overflow = "hidden";
|
|
999
|
-
return () => {
|
|
1000
|
-
if (timeoutId) {
|
|
1001
|
-
clearTimeout(timeoutId);
|
|
1002
|
-
}
|
|
1003
|
-
document.removeEventListener("keydown", handleTab);
|
|
1004
|
-
document.removeEventListener("keydown", handleEsc);
|
|
1005
|
-
document.body.style.overflow = "unset";
|
|
1006
|
-
if (!isOpen && previousActiveElementRef.current) {
|
|
1007
|
-
previousActiveElementRef.current.focus();
|
|
1008
|
-
}
|
|
1009
|
-
};
|
|
1010
|
-
}, [isOpen, onClose, blocking]);
|
|
1011
|
-
const modalRoot = (() => {
|
|
1012
|
-
if (typeof document === "undefined") return null;
|
|
1013
|
-
let root = document.getElementById("modal-root");
|
|
1014
|
-
if (!root) {
|
|
1015
|
-
root = document.createElement("div");
|
|
1016
|
-
root.id = "modal-root";
|
|
1017
|
-
document.body.appendChild(root);
|
|
1018
|
-
}
|
|
1019
|
-
return root;
|
|
1020
|
-
})();
|
|
1021
|
-
if (!modalRoot) {
|
|
1022
|
-
return null;
|
|
1023
|
-
}
|
|
1024
|
-
const backdropVariants = {
|
|
1025
|
-
hidden: { opacity: 0 },
|
|
1026
|
-
visible: { opacity: 1 }
|
|
1865
|
+
const colClasses = {
|
|
1866
|
+
1: "grid-cols-1",
|
|
1867
|
+
2: "grid-cols-1 md:grid-cols-2",
|
|
1868
|
+
3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
|
1869
|
+
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
|
|
1870
|
+
5: "grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5",
|
|
1871
|
+
6: "grid-cols-2 md:grid-cols-3 lg:grid-cols-6",
|
|
1872
|
+
12: "grid-cols-12"
|
|
1027
1873
|
};
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
opacity: 1,
|
|
1036
|
-
scale: 1,
|
|
1037
|
-
y: 0,
|
|
1038
|
-
transition: {
|
|
1039
|
-
duration: 0.2,
|
|
1040
|
-
ease: "easeOut"
|
|
1041
|
-
}
|
|
1042
|
-
},
|
|
1043
|
-
exit: {
|
|
1044
|
-
opacity: 0,
|
|
1045
|
-
scale: 0.9,
|
|
1046
|
-
y: 100,
|
|
1047
|
-
// Slide down much further for reverse effect
|
|
1048
|
-
transition: {
|
|
1049
|
-
duration: 0.3,
|
|
1050
|
-
ease: "easeIn"
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1874
|
+
const gapClasses = {
|
|
1875
|
+
1: "gap-1",
|
|
1876
|
+
2: "gap-2",
|
|
1877
|
+
3: "gap-3",
|
|
1878
|
+
4: "gap-4",
|
|
1879
|
+
6: "gap-6",
|
|
1880
|
+
8: "gap-8"
|
|
1053
1881
|
};
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1882
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid ${colClasses[cols]} ${gapClasses[gap]} ${className}`, children });
|
|
1883
|
+
}
|
|
1884
|
+
var variantClasses3 = {
|
|
1885
|
+
default: "text-foreground hover:text-primary",
|
|
1886
|
+
primary: "text-primary hover:text-primary/80",
|
|
1887
|
+
muted: "text-muted-foreground hover:text-foreground"
|
|
1888
|
+
};
|
|
1889
|
+
var Link = React4.forwardRef(
|
|
1890
|
+
({
|
|
1891
|
+
href,
|
|
1892
|
+
variant = "default",
|
|
1893
|
+
underline = false,
|
|
1894
|
+
external = false,
|
|
1895
|
+
className = "",
|
|
1896
|
+
children,
|
|
1897
|
+
...props
|
|
1898
|
+
}, ref) => {
|
|
1899
|
+
const classes = [
|
|
1900
|
+
"transition-colors",
|
|
1901
|
+
variantClasses3[variant],
|
|
1902
|
+
underline ? "underline underline-offset-4" : "hover:underline hover:underline-offset-4",
|
|
1903
|
+
className
|
|
1904
|
+
].filter(Boolean).join(" ");
|
|
1905
|
+
if (external || href.startsWith("http")) {
|
|
1906
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1907
|
+
"a",
|
|
1059
1908
|
{
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
children
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
"aria-modal": "true",
|
|
1072
|
-
"aria-labelledby": title ? "modal-title-plain" : void 0,
|
|
1073
|
-
"aria-describedby": ariaDescribedBy || "modal-content-plain",
|
|
1074
|
-
tabIndex: -1,
|
|
1075
|
-
className: `w-full flex flex-col overflow-hidden relative z-[1000000] ${customStyles.container || "bg-card shadow-xl"} ${fullScreen ? "h-full rounded-none" : `rounded-lg ${className} ${sizeClasses3[size]} max-h-[90vh]`}`,
|
|
1076
|
-
variants: modalVariants,
|
|
1077
|
-
initial: "hidden",
|
|
1078
|
-
animate: isOpen ? "visible" : "exit",
|
|
1079
|
-
exit: "exit",
|
|
1080
|
-
onClick: (e) => e.stopPropagation(),
|
|
1081
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1082
|
-
"div",
|
|
1083
|
-
{
|
|
1084
|
-
id: "modal-content-plain",
|
|
1085
|
-
className: `flex-1 ${customStyles.content || ""}`,
|
|
1086
|
-
children
|
|
1087
|
-
}
|
|
1088
|
-
)
|
|
1089
|
-
},
|
|
1090
|
-
"modal-content"
|
|
1091
|
-
)
|
|
1092
|
-
},
|
|
1093
|
-
"modal-backdrop"
|
|
1094
|
-
) }),
|
|
1095
|
-
modalRoot
|
|
1096
|
-
);
|
|
1909
|
+
ref,
|
|
1910
|
+
href,
|
|
1911
|
+
className: classes,
|
|
1912
|
+
target: "_blank",
|
|
1913
|
+
rel: "noopener noreferrer",
|
|
1914
|
+
...props,
|
|
1915
|
+
children
|
|
1916
|
+
}
|
|
1917
|
+
);
|
|
1918
|
+
}
|
|
1919
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NextLink__default.default, { ref, href, className: classes, ...props, children });
|
|
1097
1920
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
{
|
|
1102
|
-
className: `modal-backdrop fixed inset-0 w-screen h-screen bg-black/10 flex items-center ${customStyles.backdrop || "justify-center"} z-[999999] m-0 ${fullScreen ? "p-0" : "p-4"}`,
|
|
1103
|
-
variants: backdropVariants,
|
|
1104
|
-
initial: "hidden",
|
|
1105
|
-
animate: isOpen ? "visible" : "hidden",
|
|
1106
|
-
exit: "hidden",
|
|
1107
|
-
onClick: blocking ? void 0 : onClose,
|
|
1108
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1109
|
-
framerMotion.motion.div,
|
|
1110
|
-
{
|
|
1111
|
-
ref: modalContentRef,
|
|
1112
|
-
role: "dialog",
|
|
1113
|
-
"aria-modal": "true",
|
|
1114
|
-
"aria-labelledby": title ? "modal-title" : void 0,
|
|
1115
|
-
"aria-describedby": ariaDescribedBy || "modal-content",
|
|
1116
|
-
tabIndex: -1,
|
|
1117
|
-
className: `bg-card border border-border shadow-xl w-full flex flex-col overflow-hidden relative z-[1000000] ${fullScreen ? "h-full rounded-none" : `rounded-lg ${customStyles.container || className || sizeClasses3[size]} max-h-[90vh]`}`,
|
|
1118
|
-
variants: modalVariants,
|
|
1119
|
-
initial: "hidden",
|
|
1120
|
-
animate: isOpen ? "visible" : "exit",
|
|
1121
|
-
exit: "exit",
|
|
1122
|
-
onClick: (e) => e.stopPropagation(),
|
|
1123
|
-
children: [
|
|
1124
|
-
header ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: header }) : title ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1125
|
-
"div",
|
|
1126
|
-
{
|
|
1127
|
-
className: `px-6 py-4 border-b border-border flex justify-between items-center flex-shrink-0 ${customStyles.header || ""}`,
|
|
1128
|
-
children: [
|
|
1129
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1130
|
-
"h2",
|
|
1131
|
-
{
|
|
1132
|
-
id: "modal-title",
|
|
1133
|
-
className: "text-xl font-semibold text-foreground",
|
|
1134
|
-
children: title
|
|
1135
|
-
}
|
|
1136
|
-
),
|
|
1137
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1138
|
-
"button",
|
|
1139
|
-
{
|
|
1140
|
-
onClick: onClose,
|
|
1141
|
-
className: "p-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-full transition-colors",
|
|
1142
|
-
title: "Close",
|
|
1143
|
-
"aria-label": "Close modal",
|
|
1144
|
-
disabled: blocking,
|
|
1145
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ri.RiCloseLine, { className: "w-5 h-5", "aria-hidden": "true" })
|
|
1146
|
-
}
|
|
1147
|
-
)
|
|
1148
|
-
]
|
|
1149
|
-
}
|
|
1150
|
-
) : null,
|
|
1151
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1152
|
-
"div",
|
|
1153
|
-
{
|
|
1154
|
-
id: "modal-content",
|
|
1155
|
-
className: `bg-background text-foreground flex-1 ${scrollable ? "overflow-y-auto" : ""} ${fullScreen || noPadding ? "p-0" : "px-6 py-4"}`,
|
|
1156
|
-
children
|
|
1157
|
-
}
|
|
1158
|
-
),
|
|
1159
|
-
footer && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1160
|
-
"div",
|
|
1161
|
-
{
|
|
1162
|
-
className: `flex-shrink-0 px-6 py-4 border-t border-border ${footerBg === "white" ? "bg-card" : "bg-muted"} ${customStyles.footer || ""}`,
|
|
1163
|
-
children: footer
|
|
1164
|
-
}
|
|
1165
|
-
)
|
|
1166
|
-
]
|
|
1167
|
-
},
|
|
1168
|
-
"modal-content"
|
|
1169
|
-
)
|
|
1170
|
-
},
|
|
1171
|
-
"modal-backdrop"
|
|
1172
|
-
) }),
|
|
1173
|
-
modalRoot
|
|
1174
|
-
);
|
|
1175
|
-
}
|
|
1921
|
+
);
|
|
1922
|
+
Link.displayName = "Link";
|
|
1923
|
+
var Link_default = Link;
|
|
1176
1924
|
var LoadingSpinner = ({
|
|
1177
1925
|
message = "Initializing...",
|
|
1178
1926
|
className,
|
|
@@ -1231,76 +1979,110 @@ function PageHeader({
|
|
|
1231
1979
|
rightContent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center space-x-2 lg:space-x-3 flex-shrink-0", children: rightContent })
|
|
1232
1980
|
] }) });
|
|
1233
1981
|
}
|
|
1234
|
-
function
|
|
1235
|
-
|
|
1982
|
+
function Switch({
|
|
1983
|
+
checked,
|
|
1984
|
+
onChange,
|
|
1985
|
+
disabled = false,
|
|
1986
|
+
label,
|
|
1236
1987
|
description,
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
}) {
|
|
1240
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `space-y-4 ${className}`, children: [
|
|
1241
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1242
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium ", children: title }),
|
|
1243
|
-
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description })
|
|
1244
|
-
] }),
|
|
1245
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children })
|
|
1246
|
-
] });
|
|
1247
|
-
}
|
|
1248
|
-
function Grid({
|
|
1249
|
-
children,
|
|
1250
|
-
cols = 1,
|
|
1251
|
-
gap = 4,
|
|
1252
|
-
className = ""
|
|
1988
|
+
className = "",
|
|
1989
|
+
size = "md"
|
|
1253
1990
|
}) {
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
|
|
1259
|
-
5: "grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5",
|
|
1260
|
-
6: "grid-cols-2 md:grid-cols-3 lg:grid-cols-6",
|
|
1261
|
-
12: "grid-cols-12"
|
|
1991
|
+
const toggle = () => {
|
|
1992
|
+
if (!disabled) {
|
|
1993
|
+
onChange(!checked);
|
|
1994
|
+
}
|
|
1262
1995
|
};
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
4: "gap-4",
|
|
1268
|
-
6: "gap-6",
|
|
1269
|
-
8: "gap-8"
|
|
1996
|
+
const sizes = {
|
|
1997
|
+
sm: { track: "w-8 h-4", thumb: "w-3 h-3", translate: "translate-x-4" },
|
|
1998
|
+
md: { track: "w-11 h-6", thumb: "w-5 h-5", translate: "translate-x-5" },
|
|
1999
|
+
lg: { track: "w-14 h-8", thumb: "w-7 h-7", translate: "translate-x-6" }
|
|
1270
2000
|
};
|
|
1271
|
-
|
|
2001
|
+
const currentSize = sizes[size];
|
|
2002
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-start ${className}`, children: [
|
|
2003
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2004
|
+
"button",
|
|
2005
|
+
{
|
|
2006
|
+
type: "button",
|
|
2007
|
+
role: "switch",
|
|
2008
|
+
"aria-checked": checked,
|
|
2009
|
+
disabled,
|
|
2010
|
+
onClick: toggle,
|
|
2011
|
+
className: `
|
|
2012
|
+
relative inline-flex flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent
|
|
2013
|
+
transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2
|
|
2014
|
+
${checked ? "bg-primary" : "bg-muted"}
|
|
2015
|
+
${disabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
2016
|
+
${currentSize.track}
|
|
2017
|
+
`,
|
|
2018
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2019
|
+
"span",
|
|
2020
|
+
{
|
|
2021
|
+
"aria-hidden": "true",
|
|
2022
|
+
className: `
|
|
2023
|
+
pointer-events-none inline-block transform rounded-full bg-white shadow ring-0
|
|
2024
|
+
transition duration-200 ease-in-out
|
|
2025
|
+
${checked ? currentSize.translate : "translate-x-0"}
|
|
2026
|
+
${currentSize.thumb}
|
|
2027
|
+
`
|
|
2028
|
+
}
|
|
2029
|
+
)
|
|
2030
|
+
}
|
|
2031
|
+
),
|
|
2032
|
+
(label || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-3 text-sm leading-6", children: [
|
|
2033
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "font-medium text-foreground cursor-pointer", onClick: toggle, children: label }),
|
|
2034
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: description })
|
|
2035
|
+
] })
|
|
2036
|
+
] });
|
|
1272
2037
|
}
|
|
1273
|
-
|
|
2038
|
+
var variantClasses4 = {
|
|
2039
|
+
default: "text-foreground",
|
|
2040
|
+
muted: "text-muted-foreground",
|
|
2041
|
+
bold: "font-semibold"
|
|
2042
|
+
};
|
|
2043
|
+
var sizeClasses4 = {
|
|
2044
|
+
xs: "text-xs",
|
|
2045
|
+
sm: "text-sm",
|
|
2046
|
+
base: "text-base",
|
|
2047
|
+
lg: "text-lg",
|
|
2048
|
+
xl: "text-xl",
|
|
2049
|
+
"2xl": "text-2xl",
|
|
2050
|
+
"3xl": "text-3xl"
|
|
2051
|
+
};
|
|
2052
|
+
function Typography({
|
|
2053
|
+
as: Element = "p",
|
|
2054
|
+
variant = "default",
|
|
2055
|
+
size = "base",
|
|
1274
2056
|
children,
|
|
1275
|
-
span = 1,
|
|
1276
2057
|
className = ""
|
|
1277
2058
|
}) {
|
|
1278
|
-
|
|
2059
|
+
const classes = `${variantClasses4[variant]} ${sizeClasses4[size]} ${className}`;
|
|
2060
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Element, { className: classes, children });
|
|
1279
2061
|
}
|
|
1280
2062
|
|
|
1281
|
-
|
|
2063
|
+
// src/index.ts
|
|
2064
|
+
var VERSION = "0.1.3";
|
|
2065
|
+
|
|
1282
2066
|
exports.Badge = Badge;
|
|
1283
2067
|
exports.Button = Button_default;
|
|
1284
2068
|
exports.Card = Card;
|
|
1285
|
-
exports.
|
|
1286
|
-
exports.
|
|
2069
|
+
exports.ConfirmDialog = ConfirmDialog_default;
|
|
2070
|
+
exports.Container = Container;
|
|
2071
|
+
exports.EmptyState = EmptyState_default;
|
|
1287
2072
|
exports.FormInput = FormInput;
|
|
1288
2073
|
exports.FormSection = FormSection;
|
|
1289
|
-
exports.GrayBadge = GrayBadge;
|
|
1290
2074
|
exports.Grid = Grid;
|
|
1291
|
-
exports.GridItem = GridItem;
|
|
1292
|
-
exports.HeaderCard = HeaderCard;
|
|
1293
|
-
exports.InfoBadge = InfoBadge;
|
|
1294
2075
|
exports.Link = Link_default;
|
|
1295
2076
|
exports.LoadingSpinner = LoadingSpinner_default;
|
|
1296
2077
|
exports.Modal = Modal;
|
|
1297
2078
|
exports.PageHeader = PageHeader;
|
|
1298
|
-
exports.
|
|
1299
|
-
exports.
|
|
1300
|
-
exports.
|
|
1301
|
-
exports.
|
|
1302
|
-
exports.SuccessBadge = SuccessBadge;
|
|
2079
|
+
exports.Skeleton = Skeleton;
|
|
2080
|
+
exports.SkeletonItem = SkeletonItem;
|
|
2081
|
+
exports.SmartDropdown = SmartDropdown;
|
|
2082
|
+
exports.SmartSelect = SmartSelect;
|
|
1303
2083
|
exports.Switch = Switch;
|
|
1304
|
-
exports.
|
|
2084
|
+
exports.Typography = Typography;
|
|
2085
|
+
exports.VERSION = VERSION;
|
|
2086
|
+
exports.useConfirmDialog = useConfirmDialog;
|
|
1305
2087
|
//# sourceMappingURL=index.js.map
|
|
1306
2088
|
//# sourceMappingURL=index.js.map
|