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