@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.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/Button.tsx
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
- function SimpleCard({
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
- subtitle,
363
- description,
364
- icon,
365
- iconColor,
366
- iconSize,
367
- actionButton,
368
- children,
354
+ header,
355
+ blocking = false,
356
+ size = "md",
369
357
  className = "",
370
- ...props
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
- return /* @__PURE__ */ jsxRuntime.jsx(
373
- Card,
374
- {
375
- title,
376
- subtitle,
377
- description,
378
- icon,
379
- iconColor,
380
- iconSize,
381
- actionButton,
382
- className,
383
- ...props,
384
- children
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
- function ClickableCard({
409
- onClick,
410
- children,
411
- className = "",
412
- ...props
413
- }) {
414
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { onClick, clickable: true, hover: true, className, ...props, children });
415
- }
416
- function AccordionCard({
417
- accordion = true,
418
- children,
419
- className = "",
420
- ...props
421
- }) {
422
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { accordion, className, ...props, children });
423
- }
424
- var variantClasses3 = {
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
- return /* @__PURE__ */ jsxRuntime.jsx(NextLink__default.default, { ref, href, className: classes, ...props, children });
460
- }
461
- );
462
- Link.displayName = "Link";
463
- var Link_default = Link;
464
- function FormInput({
465
- label,
466
- name,
467
- type = "text",
468
- value,
469
- onChange,
470
- placeholder,
471
- required = false,
472
- disabled = false,
473
- error,
474
- className = "",
475
- inputClassName = "",
476
- min,
477
- max,
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 paddingClasses2 = [];
535
- if (iconConfig.left) paddingClasses2.push("pl-10");
1428
+ const paddingClasses3 = [];
1429
+ if (iconConfig.left) paddingClasses3.push("pl-10");
536
1430
  if (iconConfig.right) {
537
- paddingClasses2.push(inputType === "number" ? "pr-12" : "pr-10");
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
- return paddingClasses2.join(" ");
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 === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
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 Switch({
846
- checked,
847
- onChange,
848
- disabled = false,
849
- label,
1845
+ function FormSection({
1846
+ title,
850
1847
  description,
851
- className = "",
852
- size = "md"
1848
+ children,
1849
+ className = ""
853
1850
  }) {
854
- const toggle = () => {
855
- if (!disabled) {
856
- onChange(!checked);
857
- }
858
- };
859
- const sizes = {
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
- var sizeClasses3 = {
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
- title,
913
- header,
914
- blocking = false,
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 modalContentRef = React4.useRef(null);
927
- const previousActiveElementRef = React4.useRef(null);
928
- const hasPerformedInitialFocusRef = React4.useRef(false);
929
- const getFocusableElements = () => {
930
- if (!modalContentRef.current) return [];
931
- const focusableSelectors = [
932
- "button:not([disabled])",
933
- "a[href]",
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 modalVariants = {
1029
- hidden: {
1030
- opacity: 0,
1031
- scale: 0.95,
1032
- y: 20
1033
- },
1034
- visible: {
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
- if (!isOpen) return null;
1055
- if (variant === "plain") {
1056
- return reactDom.createPortal(
1057
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsx(
1058
- framerMotion.motion.div,
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
- 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"}`,
1061
- variants: backdropVariants,
1062
- initial: "hidden",
1063
- animate: isOpen ? "visible" : "hidden",
1064
- exit: "hidden",
1065
- onClick: blocking ? void 0 : onClose,
1066
- children: /* @__PURE__ */ jsxRuntime.jsx(
1067
- framerMotion.motion.div,
1068
- {
1069
- ref: modalContentRef,
1070
- role: "dialog",
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
- return reactDom.createPortal(
1099
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: /* @__PURE__ */ jsxRuntime.jsx(
1100
- framerMotion.motion.div,
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 FormSection({
1235
- title,
1982
+ function Switch({
1983
+ checked,
1984
+ onChange,
1985
+ disabled = false,
1986
+ label,
1236
1987
  description,
1237
- children,
1238
- className = ""
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 colClasses = {
1255
- 1: "grid-cols-1",
1256
- 2: "grid-cols-1 md:grid-cols-2",
1257
- 3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
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 gapClasses = {
1264
- 1: "gap-1",
1265
- 2: "gap-2",
1266
- 3: "gap-3",
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
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid ${colClasses[cols]} ${gapClasses[gap]} ${className}`, children });
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
- function GridItem({
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
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `col-span-${span} ${className}`, children });
2059
+ const classes = `${variantClasses4[variant]} ${sizeClasses4[size]} ${className}`;
2060
+ return /* @__PURE__ */ jsxRuntime.jsx(Element, { className: classes, children });
1279
2061
  }
1280
2062
 
1281
- exports.AccordionCard = AccordionCard;
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.ClickableCard = ClickableCard;
1286
- exports.ErrorBadge = ErrorBadge;
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.PrimaryBadge = PrimaryBadge;
1299
- exports.SimpleCard = SimpleCard;
1300
- exports.StatusBadge = StatusBadge;
1301
- exports.StatusCard = StatusCard;
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.WarningBadge = WarningBadge;
2084
+ exports.Typography = Typography;
2085
+ exports.VERSION = VERSION;
2086
+ exports.useConfirmDialog = useConfirmDialog;
1305
2087
  //# sourceMappingURL=index.js.map
1306
2088
  //# sourceMappingURL=index.js.map