mywhy-ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useRef, useEffect, useState, useCallback } from 'react';
2
+ import React9, { useRef, useEffect, useState, useCallback } from 'react';
3
3
 
4
4
  // src/components/Spinner/Spinner.tsx
5
5
  var sizeClasses = {
@@ -194,6 +194,49 @@ function Select({
194
194
  error && /* @__PURE__ */ jsx("p", { className: "text-sm text-danger-text", children: error })
195
195
  ] });
196
196
  }
197
+ function Switch({
198
+ label,
199
+ description,
200
+ error,
201
+ id,
202
+ className = "",
203
+ checked,
204
+ ...props
205
+ }) {
206
+ const switchId = id ?? (typeof label === "string" ? label.toLowerCase().replace(/\s+/g, "-") : void 0);
207
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-0.5 ${className}`, children: [
208
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-3 cursor-pointer", htmlFor: switchId, children: [
209
+ /* @__PURE__ */ jsx(
210
+ "input",
211
+ {
212
+ id: switchId,
213
+ type: "checkbox",
214
+ role: "switch",
215
+ "aria-checked": checked,
216
+ className: [
217
+ "peer relative w-10 h-6 appearance-none rounded-full transition-colors",
218
+ "bg-surface-gray border border-outline",
219
+ "hover:bg-surface-overlay",
220
+ "focus:outline-none focus:ring-2 focus:ring-brand focus:ring-offset-2",
221
+ "disabled:opacity-50 disabled:cursor-not-allowed",
222
+ "checked:bg-brand checked:border-brand checked:hover:bg-brand-dark",
223
+ "after:content-[''] after:absolute after:top-1 after:left-1",
224
+ "after:w-4 after:h-4 after:bg-white after:rounded-full after:transition-transform",
225
+ "peer-checked:after:translate-x-4",
226
+ error ? "border-danger-border" : ""
227
+ ].join(" "),
228
+ checked,
229
+ ...props
230
+ }
231
+ ),
232
+ (label || description) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
233
+ label && /* @__PURE__ */ jsx("span", { className: "text-base font-medium text-ink leading-tight", children: label }),
234
+ description && /* @__PURE__ */ jsx("span", { className: "text-sm text-ink-light", children: description })
235
+ ] })
236
+ ] }),
237
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-danger-text ml-4", children: error })
238
+ ] });
239
+ }
197
240
  var subtleClasses = {
198
241
  brand: "bg-brand-50 text-brand border-brand-200",
199
242
  success: "bg-success-bg text-success-text border-success-border",
@@ -390,6 +433,419 @@ function Textarea({
390
433
  error && /* @__PURE__ */ jsx("p", { className: "text-sm text-danger-text", children: error })
391
434
  ] });
392
435
  }
436
+ var themeClasses2 = {
437
+ info: "bg-brand-50 border-brand-200 text-brand-900",
438
+ success: "bg-green-50 border-green-200 text-green-900",
439
+ warning: "bg-amber-50 border-amber-200 text-amber-900",
440
+ danger: "bg-red-50 border-red-200 text-red-900"
441
+ };
442
+ var iconColors = {
443
+ info: "text-brand",
444
+ success: "text-success-icon",
445
+ warning: "text-warning-icon",
446
+ danger: "text-danger-icon"
447
+ };
448
+ var closeButtonColors = {
449
+ info: "hover:bg-brand-100 text-brand-600",
450
+ success: "hover:bg-green-100 text-green-600",
451
+ warning: "hover:bg-amber-100 text-amber-600",
452
+ danger: "hover:bg-red-100 text-red-600"
453
+ };
454
+ function Alert({
455
+ theme = "info",
456
+ title,
457
+ icon,
458
+ onClose,
459
+ isDismissible = false,
460
+ children,
461
+ className = "",
462
+ ...props
463
+ }) {
464
+ const [isVisible, setIsVisible] = React9.useState(true);
465
+ const handleClose = () => {
466
+ setIsVisible(false);
467
+ onClose?.();
468
+ };
469
+ if (!isVisible) return null;
470
+ return /* @__PURE__ */ jsxs(
471
+ "div",
472
+ {
473
+ className: `flex gap-3 p-3 rounded-md border ${themeClasses2[theme]} ${className}`,
474
+ role: "alert",
475
+ ...props,
476
+ children: [
477
+ icon && /* @__PURE__ */ jsx("div", { className: `shrink-0 mt-0.5 ${iconColors[theme]}`, children: icon }),
478
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
479
+ title && /* @__PURE__ */ jsx("p", { className: "font-medium", children: title }),
480
+ children && /* @__PURE__ */ jsx("p", { className: title ? "text-sm mt-0.5" : "text-sm", children })
481
+ ] }),
482
+ isDismissible && /* @__PURE__ */ jsx(
483
+ "button",
484
+ {
485
+ onClick: handleClose,
486
+ className: `shrink-0 p-1 rounded transition-colors ${closeButtonColors[theme]}`,
487
+ "aria-label": "Dismiss alert",
488
+ children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
489
+ }
490
+ )
491
+ ]
492
+ }
493
+ );
494
+ }
495
+ function MultiSelect({
496
+ options,
497
+ value = [],
498
+ onChange,
499
+ placeholder = "Select items...",
500
+ label,
501
+ description,
502
+ error,
503
+ disabled = false,
504
+ searchable = true,
505
+ clearable = true,
506
+ size = "md",
507
+ className = "",
508
+ ...props
509
+ }) {
510
+ const [isOpen, setIsOpen] = React9.useState(false);
511
+ const [searchTerm, setSearchTerm] = React9.useState("");
512
+ const containerRef = useRef(null);
513
+ const inputRef = useRef(null);
514
+ const filteredOptions = searchable ? options.filter(
515
+ (opt) => opt.label.toLowerCase().includes(searchTerm.toLowerCase())
516
+ ) : options;
517
+ const handleSelect = (optionValue) => {
518
+ const newValues = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue];
519
+ onChange?.(newValues);
520
+ };
521
+ const handleRemove = (optionValue) => {
522
+ const newValues = value.filter((v) => v !== optionValue);
523
+ onChange?.(newValues);
524
+ };
525
+ const handleClear = () => {
526
+ onChange?.([]);
527
+ setSearchTerm("");
528
+ };
529
+ useEffect(() => {
530
+ const handleClickOutside = (event) => {
531
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
532
+ setIsOpen(false);
533
+ }
534
+ };
535
+ if (isOpen) {
536
+ document.addEventListener("mousedown", handleClickOutside);
537
+ }
538
+ return () => {
539
+ document.removeEventListener("mousedown", handleClickOutside);
540
+ };
541
+ }, [isOpen]);
542
+ const sizeClasses13 = {
543
+ sm: "h-7 px-2 text-sm",
544
+ md: "h-8 px-3 text-base",
545
+ lg: "h-9 px-4 text-base"
546
+ };
547
+ const selectedOptions = options.filter((opt) => value.includes(opt.value));
548
+ return /* @__PURE__ */ jsxs("div", { className, ...props, children: [
549
+ label && /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-ink mb-1", children: label }),
550
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light mb-1.5", children: description }),
551
+ /* @__PURE__ */ jsxs("div", { className: "relative", ref: containerRef, children: [
552
+ /* @__PURE__ */ jsxs(
553
+ "div",
554
+ {
555
+ className: [
556
+ "flex flex-wrap gap-1 items-center border rounded-md transition-colors",
557
+ "focus-within:ring-2 focus-within:ring-brand focus-within:ring-offset-1",
558
+ disabled ? "bg-surface-gray opacity-50 cursor-not-allowed" : "bg-white",
559
+ error ? "border-danger-border" : "border-outline",
560
+ sizeClasses13[size]
561
+ ].join(" "),
562
+ onClick: () => !disabled && setIsOpen(!isOpen),
563
+ children: [
564
+ selectedOptions.map((opt) => /* @__PURE__ */ jsxs(
565
+ "div",
566
+ {
567
+ className: "inline-flex items-center gap-1 bg-brand-50 text-brand px-2 py-0.5 rounded text-xs font-medium",
568
+ children: [
569
+ opt.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: opt.icon }),
570
+ /* @__PURE__ */ jsx("span", { children: opt.label }),
571
+ /* @__PURE__ */ jsx(
572
+ "button",
573
+ {
574
+ onClick: (e) => {
575
+ e.stopPropagation();
576
+ handleRemove(opt.value);
577
+ },
578
+ className: "shrink-0 hover:text-brand-dark",
579
+ children: "\xD7"
580
+ }
581
+ )
582
+ ]
583
+ },
584
+ opt.value
585
+ )),
586
+ /* @__PURE__ */ jsx(
587
+ "input",
588
+ {
589
+ ref: inputRef,
590
+ type: "text",
591
+ placeholder: value.length === 0 ? placeholder : "",
592
+ value: searchTerm,
593
+ onChange: (e) => setSearchTerm(e.target.value),
594
+ onFocus: () => !disabled && setIsOpen(true),
595
+ disabled,
596
+ className: "flex-1 min-w-[40px] bg-transparent border-0 outline-none text-sm"
597
+ }
598
+ ),
599
+ clearable && value.length > 0 && /* @__PURE__ */ jsx(
600
+ "button",
601
+ {
602
+ onClick: (e) => {
603
+ e.stopPropagation();
604
+ handleClear();
605
+ },
606
+ className: "shrink-0 text-ink-light hover:text-ink",
607
+ children: "\u2715"
608
+ }
609
+ )
610
+ ]
611
+ }
612
+ ),
613
+ isOpen && /* @__PURE__ */ jsx("div", { className: "absolute top-full mt-1 left-0 right-0 z-50 bg-white border border-outline rounded-md shadow-lg py-1", children: filteredOptions.length > 0 ? filteredOptions.map((opt) => /* @__PURE__ */ jsxs(
614
+ "button",
615
+ {
616
+ onClick: () => {
617
+ handleSelect(opt.value);
618
+ if (!opt.disabled) {
619
+ inputRef.current?.focus();
620
+ }
621
+ },
622
+ disabled: opt.disabled,
623
+ className: [
624
+ "w-full px-3 py-2 text-left text-sm flex items-center gap-2 transition-colors",
625
+ opt.disabled ? "opacity-50 cursor-not-allowed" : "hover:bg-surface-gray",
626
+ value.includes(opt.value) ? "bg-brand-50" : ""
627
+ ].join(" "),
628
+ children: [
629
+ /* @__PURE__ */ jsx(
630
+ "input",
631
+ {
632
+ type: "checkbox",
633
+ checked: value.includes(opt.value),
634
+ readOnly: true,
635
+ className: "w-4 h-4"
636
+ }
637
+ ),
638
+ opt.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: opt.icon }),
639
+ /* @__PURE__ */ jsx("span", { children: opt.label })
640
+ ]
641
+ },
642
+ opt.value
643
+ )) : /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-ink-light", children: "No options found" }) })
644
+ ] }),
645
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-danger-text mt-1", children: error })
646
+ ] });
647
+ }
648
+ function FormControl({
649
+ label,
650
+ description,
651
+ error,
652
+ required = false,
653
+ helperText,
654
+ children,
655
+ className = "",
656
+ ...props
657
+ }) {
658
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-1.5 ${className}`, ...props, children: [
659
+ (label || description) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
660
+ label && /* @__PURE__ */ jsxs("label", { className: "text-sm font-medium text-ink", children: [
661
+ label,
662
+ required && /* @__PURE__ */ jsx("span", { className: "text-danger-icon ml-1", children: "*" })
663
+ ] }),
664
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light", children: description })
665
+ ] }),
666
+ children,
667
+ error && /* @__PURE__ */ jsxs("p", { className: "text-xs text-danger-text flex items-center gap-1", children: [
668
+ /* @__PURE__ */ jsx("svg", { className: "w-3.5 h-3.5 shrink-0", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }),
669
+ error
670
+ ] }),
671
+ helperText && !error && /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light", children: helperText })
672
+ ] });
673
+ }
674
+ function Tabs({
675
+ tabs,
676
+ activeTab,
677
+ onTabChange,
678
+ variant = "underline",
679
+ className = "",
680
+ tabsClassName = "",
681
+ contentClassName = ""
682
+ }) {
683
+ const [internalActiveTab, setInternalActiveTab] = React9.useState(activeTab || tabs[0]?.value || "");
684
+ const active = activeTab !== void 0 ? activeTab : internalActiveTab;
685
+ const handleTabChange = (value) => {
686
+ setInternalActiveTab(value);
687
+ onTabChange?.(value);
688
+ };
689
+ const baseTabClasses = "px-3 py-2 font-medium text-sm rounded-t-md transition-colors whitespace-nowrap";
690
+ const variantClasses2 = {
691
+ underline: {
692
+ base: "border-b-2 border-transparent text-ink-light hover:text-ink hover:border-outline",
693
+ active: "border-brand text-brand",
694
+ disabled: "opacity-50 cursor-not-allowed"
695
+ },
696
+ soft: {
697
+ base: "text-ink-light hover:text-ink hover:bg-surface-gray",
698
+ active: "bg-brand text-white",
699
+ disabled: "opacity-50 cursor-not-allowed"
700
+ }
701
+ };
702
+ const variantStyle = variantClasses2[variant];
703
+ return /* @__PURE__ */ jsxs("div", { className, children: [
704
+ /* @__PURE__ */ jsx(
705
+ "div",
706
+ {
707
+ className: `flex gap-0 border-b border-outline ${tabsClassName}`,
708
+ role: "tablist",
709
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs(
710
+ "button",
711
+ {
712
+ role: "tab",
713
+ "aria-selected": active === tab.value,
714
+ "aria-disabled": tab.disabled,
715
+ onClick: () => !tab.disabled && handleTabChange(tab.value),
716
+ disabled: tab.disabled,
717
+ className: [
718
+ baseTabClasses,
719
+ active === tab.value ? variantStyle.active : variantStyle.base,
720
+ tab.disabled ? variantStyle.disabled : ""
721
+ ].join(" "),
722
+ children: [
723
+ tab.icon && /* @__PURE__ */ jsx("span", { className: "inline-block mr-1", children: tab.icon }),
724
+ tab.label
725
+ ]
726
+ },
727
+ tab.value
728
+ ))
729
+ }
730
+ ),
731
+ /* @__PURE__ */ jsx("div", { className: contentClassName, role: "tabpanel", children: tabs.find((tab) => tab.value === active)?.content })
732
+ ] });
733
+ }
734
+ function Breadcrumbs({
735
+ items,
736
+ separator = "/",
737
+ className = "",
738
+ ...props
739
+ }) {
740
+ return /* @__PURE__ */ jsx("nav", { className: `flex items-center gap-0 text-sm ${className}`, ...props, children: items.map((item, index) => /* @__PURE__ */ jsxs(React9.Fragment, { children: [
741
+ index > 0 && /* @__PURE__ */ jsx("span", { className: "text-ink-light px-1.5", children: separator }),
742
+ item.href ? /* @__PURE__ */ jsxs(
743
+ "a",
744
+ {
745
+ href: item.href,
746
+ className: [
747
+ "flex items-center gap-1 rounded px-1.5 py-1 transition-colors",
748
+ item.isActive ? "text-ink font-medium" : "text-brand hover:bg-brand-50 cursor-pointer"
749
+ ].join(" "),
750
+ children: [
751
+ item.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: item.icon }),
752
+ item.label
753
+ ]
754
+ }
755
+ ) : /* @__PURE__ */ jsxs(
756
+ "button",
757
+ {
758
+ onClick: item.onClick,
759
+ disabled: !item.onClick && !item.isActive,
760
+ className: [
761
+ "flex items-center gap-1 rounded px-1.5 py-1 transition-colors",
762
+ item.isActive ? "text-ink font-medium cursor-default" : item.onClick ? "text-brand hover:bg-brand-50 cursor-pointer" : "text-ink-light cursor-default"
763
+ ].join(" "),
764
+ children: [
765
+ item.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: item.icon }),
766
+ item.label
767
+ ]
768
+ }
769
+ )
770
+ ] }, index)) });
771
+ }
772
+ function Dropdown({
773
+ items,
774
+ trigger,
775
+ placement = "bottom",
776
+ isOpen: controlledIsOpen,
777
+ onOpenChange,
778
+ className = "",
779
+ triggerClassName = "",
780
+ menuClassName = ""
781
+ }) {
782
+ const [internalIsOpen, setInternalIsOpen] = React9.useState(false);
783
+ const containerRef = useRef(null);
784
+ const menuRef = useRef(null);
785
+ const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
786
+ const toggleOpen = () => {
787
+ const newState = !isOpen;
788
+ setInternalIsOpen(newState);
789
+ onOpenChange?.(newState);
790
+ };
791
+ useEffect(() => {
792
+ const handleClickOutside = (event) => {
793
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
794
+ setInternalIsOpen(false);
795
+ onOpenChange?.(false);
796
+ }
797
+ };
798
+ if (isOpen) {
799
+ document.addEventListener("mousedown", handleClickOutside);
800
+ }
801
+ return () => {
802
+ document.removeEventListener("mousedown", handleClickOutside);
803
+ };
804
+ }, [isOpen, onOpenChange]);
805
+ const placementClasses2 = {
806
+ bottom: "top-full mt-1 left-0",
807
+ top: "bottom-full mb-1 left-0",
808
+ left: "right-full mr-1 top-0",
809
+ right: "left-full ml-1 top-0"
810
+ };
811
+ return /* @__PURE__ */ jsxs("div", { className: `relative inline-block ${className}`, ref: containerRef, children: [
812
+ /* @__PURE__ */ jsx(
813
+ "button",
814
+ {
815
+ onClick: toggleOpen,
816
+ className: `inline-flex items-center gap-1.5 ${triggerClassName}`,
817
+ children: trigger
818
+ }
819
+ ),
820
+ isOpen && /* @__PURE__ */ jsx(
821
+ "div",
822
+ {
823
+ ref: menuRef,
824
+ className: `absolute ${placementClasses2[placement]} z-50 min-w-[160px] bg-surface-default border border-outline rounded-md shadow-lg py-1 ${menuClassName}`,
825
+ children: items.map((item, index) => /* @__PURE__ */ jsxs(
826
+ "button",
827
+ {
828
+ onClick: () => {
829
+ item.onClick?.();
830
+ setInternalIsOpen(false);
831
+ onOpenChange?.(false);
832
+ },
833
+ disabled: item.disabled,
834
+ className: [
835
+ "w-full px-3 py-2 text-left text-sm flex items-center gap-2 transition-colors",
836
+ item.disabled ? "opacity-50 cursor-not-allowed" : item.isDanger ? "text-danger-text hover:bg-danger-bg" : "text-ink hover:bg-surface-gray"
837
+ ].join(" "),
838
+ children: [
839
+ item.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: item.icon }),
840
+ /* @__PURE__ */ jsx("span", { children: item.label })
841
+ ]
842
+ },
843
+ index
844
+ ))
845
+ }
846
+ )
847
+ ] });
848
+ }
393
849
  var sizeClasses7 = {
394
850
  sm: "max-w-sm",
395
851
  md: "max-w-md",
@@ -602,6 +1058,961 @@ function Link({
602
1058
  }
603
1059
  );
604
1060
  }
1061
+ function FileUploader({
1062
+ label,
1063
+ description,
1064
+ error,
1065
+ hint,
1066
+ onFilesChange,
1067
+ maxSize,
1068
+ accept = "*",
1069
+ multiple = false,
1070
+ disabled = false,
1071
+ className = "",
1072
+ ...props
1073
+ }) {
1074
+ const [dragActive, setDragActive] = React9.useState(false);
1075
+ const [files, setFiles] = React9.useState([]);
1076
+ const inputRef = React9.useRef(null);
1077
+ const handleFiles = (fileList) => {
1078
+ if (!fileList) return;
1079
+ let newFiles = Array.from(fileList);
1080
+ if (maxSize) {
1081
+ newFiles = newFiles.filter((file) => file.size <= maxSize);
1082
+ }
1083
+ if (!multiple && newFiles.length > 0) {
1084
+ newFiles = [newFiles[0]];
1085
+ }
1086
+ setFiles(newFiles);
1087
+ onFilesChange?.(newFiles);
1088
+ };
1089
+ const handleChange = (e) => {
1090
+ handleFiles(e.target.files);
1091
+ };
1092
+ const handleDrag = (e) => {
1093
+ e.preventDefault();
1094
+ e.stopPropagation();
1095
+ if (e.type === "dragenter" || e.type === "dragover") {
1096
+ setDragActive(true);
1097
+ } else if (e.type === "dragleave") {
1098
+ setDragActive(false);
1099
+ }
1100
+ };
1101
+ const handleDrop = (e) => {
1102
+ e.preventDefault();
1103
+ e.stopPropagation();
1104
+ setDragActive(false);
1105
+ handleFiles(e.dataTransfer.files);
1106
+ };
1107
+ const handleRemoveFile = (index) => {
1108
+ const newFiles = files.filter((_, i) => i !== index);
1109
+ setFiles(newFiles);
1110
+ onFilesChange?.(newFiles);
1111
+ };
1112
+ const handleClick = () => {
1113
+ inputRef.current?.click();
1114
+ };
1115
+ const formatFileSize = (bytes) => {
1116
+ if (bytes === 0) return "0 Bytes";
1117
+ const k = 1024;
1118
+ const sizes = ["Bytes", "KB", "MB", "GB"];
1119
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1120
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
1121
+ };
1122
+ return /* @__PURE__ */ jsxs("div", { className, children: [
1123
+ label && /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-ink mb-1", children: label }),
1124
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light mb-2", children: description }),
1125
+ /* @__PURE__ */ jsxs(
1126
+ "div",
1127
+ {
1128
+ onDragEnter: handleDrag,
1129
+ onDragLeave: handleDrag,
1130
+ onDragOver: handleDrag,
1131
+ onDrop: handleDrop,
1132
+ onClick: handleClick,
1133
+ className: [
1134
+ "relative px-4 py-6 border-2 border-dashed rounded-md transition-colors cursor-pointer",
1135
+ disabled ? "opacity-50 cursor-not-allowed" : "",
1136
+ dragActive ? "border-brand bg-brand-50" : "border-outline hover:border-brand",
1137
+ error ? "border-danger-border" : ""
1138
+ ].join(" "),
1139
+ children: [
1140
+ /* @__PURE__ */ jsx(
1141
+ "input",
1142
+ {
1143
+ ref: inputRef,
1144
+ type: "file",
1145
+ accept,
1146
+ multiple,
1147
+ onChange: handleChange,
1148
+ disabled,
1149
+ className: "hidden",
1150
+ ...props
1151
+ }
1152
+ ),
1153
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2", children: [
1154
+ /* @__PURE__ */ jsx(
1155
+ "svg",
1156
+ {
1157
+ className: "w-8 h-8 text-brand",
1158
+ fill: "none",
1159
+ stroke: "currentColor",
1160
+ viewBox: "0 0 24 24",
1161
+ children: /* @__PURE__ */ jsx(
1162
+ "path",
1163
+ {
1164
+ strokeLinecap: "round",
1165
+ strokeLinejoin: "round",
1166
+ strokeWidth: 2,
1167
+ d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M9 19l3 3m0 0l3-3m-3 3v-6"
1168
+ }
1169
+ )
1170
+ }
1171
+ ),
1172
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
1173
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-ink", children: "Drag files here or click to upload" }),
1174
+ hint && /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light mt-1", children: hint })
1175
+ ] })
1176
+ ] })
1177
+ ]
1178
+ }
1179
+ ),
1180
+ files.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 space-y-1.5", children: files.map((file, index) => /* @__PURE__ */ jsxs(
1181
+ "div",
1182
+ {
1183
+ className: "flex items-center justify-between p-2 bg-surface-gray rounded border border-outline",
1184
+ children: [
1185
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
1186
+ /* @__PURE__ */ jsxs("svg", { className: "w-4 h-4 text-brand shrink-0", fill: "currentColor", viewBox: "0 0 20 20", children: [
1187
+ /* @__PURE__ */ jsx("path", { d: "M8 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM15 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z" }),
1188
+ /* @__PURE__ */ jsx("path", { d: "M3 4a1 1 0 00-1 1v10a1 1 0 001 1h1.05a2.5 2.5 0 014.9 0H10a1 1 0 001-1V5a1 1 0 00-1-1H3zM14 7a1 1 0 00-1 1v6.05A2.5 2.5 0 0015.95 16H17a1 1 0 001-1v-5a1 1 0 00-.293-.707l-2-2A1 1 0 0015 7h-1z" })
1189
+ ] }),
1190
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
1191
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-ink truncate", children: file.name }),
1192
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light", children: formatFileSize(file.size) })
1193
+ ] })
1194
+ ] }),
1195
+ /* @__PURE__ */ jsx(
1196
+ "button",
1197
+ {
1198
+ onClick: (e) => {
1199
+ e.stopPropagation();
1200
+ handleRemoveFile(index);
1201
+ },
1202
+ className: "p-1 hover:bg-surface-overlay rounded transition-colors",
1203
+ children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 text-danger-text", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z", clipRule: "evenodd" }) })
1204
+ }
1205
+ )
1206
+ ]
1207
+ },
1208
+ `${file.name}-${index}`
1209
+ )) }),
1210
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-danger-text mt-1", children: error })
1211
+ ] });
1212
+ }
1213
+ function DatePicker({
1214
+ value = "",
1215
+ onChange,
1216
+ label,
1217
+ description,
1218
+ error,
1219
+ min,
1220
+ max,
1221
+ placeholder = "Select a date",
1222
+ disabled = false,
1223
+ className = "",
1224
+ ...props
1225
+ }) {
1226
+ const [isOpen, setIsOpen] = React9.useState(false);
1227
+ const containerRef = useRef(null);
1228
+ const handleDateChange = (e) => {
1229
+ onChange?.(e.target.value);
1230
+ };
1231
+ useEffect(() => {
1232
+ const handleClickOutside = (event) => {
1233
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
1234
+ setIsOpen(false);
1235
+ }
1236
+ };
1237
+ if (isOpen) {
1238
+ document.addEventListener("mousedown", handleClickOutside);
1239
+ }
1240
+ return () => {
1241
+ document.removeEventListener("mousedown", handleClickOutside);
1242
+ };
1243
+ }, [isOpen]);
1244
+ const formatDateForDisplay = (dateString) => {
1245
+ if (!dateString) return "";
1246
+ const date = new Date(dateString);
1247
+ return date.toLocaleDateString("en-US", {
1248
+ year: "numeric",
1249
+ month: "long",
1250
+ day: "numeric"
1251
+ });
1252
+ };
1253
+ return /* @__PURE__ */ jsxs("div", { className, ref: containerRef, children: [
1254
+ label && /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-ink mb-1", children: label }),
1255
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light mb-1.5", children: description }),
1256
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1257
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1258
+ /* @__PURE__ */ jsx(
1259
+ "input",
1260
+ {
1261
+ type: "text",
1262
+ value: value ? formatDateForDisplay(value) : "",
1263
+ onChange: handleDateChange,
1264
+ placeholder,
1265
+ disabled,
1266
+ readOnly: true,
1267
+ onClick: () => !disabled && setIsOpen(!isOpen),
1268
+ className: [
1269
+ "w-full px-3 py-2 border rounded-md text-base transition-colors",
1270
+ "focus:outline-none focus:ring-2 focus:ring-brand focus:ring-offset-1",
1271
+ "cursor-pointer",
1272
+ disabled ? "bg-surface-gray opacity-50 cursor-not-allowed" : "bg-white",
1273
+ error ? "border-danger-border" : "border-outline"
1274
+ ].join(" ")
1275
+ }
1276
+ ),
1277
+ /* @__PURE__ */ jsx(
1278
+ "button",
1279
+ {
1280
+ type: "button",
1281
+ onClick: () => !disabled && setIsOpen(!isOpen),
1282
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-ink-light hover:text-ink",
1283
+ children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h18M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
1284
+ }
1285
+ )
1286
+ ] }),
1287
+ isOpen && /* @__PURE__ */ jsx(
1288
+ "input",
1289
+ {
1290
+ type: "date",
1291
+ value,
1292
+ onChange: handleDateChange,
1293
+ min,
1294
+ max,
1295
+ disabled,
1296
+ autoFocus: true,
1297
+ className: "absolute inset-0 opacity-0 w-full h-full cursor-pointer",
1298
+ ...props
1299
+ }
1300
+ )
1301
+ ] }),
1302
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-danger-text mt-1", children: error })
1303
+ ] });
1304
+ }
1305
+ function TimePicker({
1306
+ value = "",
1307
+ onChange,
1308
+ label,
1309
+ description,
1310
+ error,
1311
+ placeholder = "Select a time",
1312
+ format = "24h",
1313
+ disabled = false,
1314
+ className = "",
1315
+ ...props
1316
+ }) {
1317
+ const [isOpen, setIsOpen] = React9.useState(false);
1318
+ const containerRef = useRef(null);
1319
+ const handleTimeChange = (e) => {
1320
+ onChange?.(e.target.value);
1321
+ };
1322
+ useEffect(() => {
1323
+ const handleClickOutside = (event) => {
1324
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
1325
+ setIsOpen(false);
1326
+ }
1327
+ };
1328
+ if (isOpen) {
1329
+ document.addEventListener("mousedown", handleClickOutside);
1330
+ }
1331
+ return () => {
1332
+ document.removeEventListener("mousedown", handleClickOutside);
1333
+ };
1334
+ }, [isOpen]);
1335
+ const formatTimeForDisplay = (timeString) => {
1336
+ if (!timeString) return "";
1337
+ const [hours, minutes] = timeString.split(":");
1338
+ if (format === "12h") {
1339
+ const h = parseInt(hours, 10);
1340
+ const period = h >= 12 ? "PM" : "AM";
1341
+ const displayHours = h > 12 ? h - 12 : h === 0 ? 12 : h;
1342
+ return `${displayHours.toString().padStart(2, "0")}:${minutes} ${period}`;
1343
+ }
1344
+ return `${hours}:${minutes}`;
1345
+ };
1346
+ return /* @__PURE__ */ jsxs("div", { className, ref: containerRef, children: [
1347
+ label && /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-ink mb-1", children: label }),
1348
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-ink-light mb-1.5", children: description }),
1349
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1350
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1351
+ /* @__PURE__ */ jsx(
1352
+ "input",
1353
+ {
1354
+ type: "text",
1355
+ value: value ? formatTimeForDisplay(value) : "",
1356
+ onChange: handleTimeChange,
1357
+ placeholder,
1358
+ disabled,
1359
+ readOnly: true,
1360
+ onClick: () => !disabled && setIsOpen(!isOpen),
1361
+ className: [
1362
+ "w-full px-3 py-2 border rounded-md text-base transition-colors",
1363
+ "focus:outline-none focus:ring-2 focus:ring-brand focus:ring-offset-1",
1364
+ "cursor-pointer",
1365
+ disabled ? "bg-surface-gray opacity-50 cursor-not-allowed" : "bg-white",
1366
+ error ? "border-danger-border" : "border-outline"
1367
+ ].join(" ")
1368
+ }
1369
+ ),
1370
+ /* @__PURE__ */ jsx(
1371
+ "button",
1372
+ {
1373
+ type: "button",
1374
+ onClick: () => !disabled && setIsOpen(!isOpen),
1375
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-ink-light hover:text-ink",
1376
+ children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) })
1377
+ }
1378
+ )
1379
+ ] }),
1380
+ isOpen && /* @__PURE__ */ jsx(
1381
+ "input",
1382
+ {
1383
+ type: "time",
1384
+ value,
1385
+ onChange: handleTimeChange,
1386
+ disabled,
1387
+ autoFocus: true,
1388
+ className: "absolute inset-0 opacity-0 w-full h-full cursor-pointer",
1389
+ ...props
1390
+ }
1391
+ )
1392
+ ] }),
1393
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-danger-text mt-1", children: error })
1394
+ ] });
1395
+ }
1396
+ var sizeClasses8 = {
1397
+ sm: "h-1.5",
1398
+ md: "h-2.5",
1399
+ lg: "h-4"
1400
+ };
1401
+ var themeClasses3 = {
1402
+ brand: "bg-brand",
1403
+ success: "bg-success-icon",
1404
+ warning: "bg-warning-icon",
1405
+ danger: "bg-danger-icon"
1406
+ };
1407
+ function Progress({
1408
+ value,
1409
+ label,
1410
+ size = "md",
1411
+ theme = "brand",
1412
+ showLabel = false,
1413
+ striped = false,
1414
+ animated = false,
1415
+ className = "",
1416
+ ...props
1417
+ }) {
1418
+ const clampedValue = Math.min(Math.max(value, 0), 100);
1419
+ return /* @__PURE__ */ jsxs("div", { className, ...props, children: [
1420
+ (label || showLabel) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1.5", children: [
1421
+ label && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-ink", children: label }),
1422
+ showLabel && /* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-ink-light", children: [
1423
+ clampedValue,
1424
+ "%"
1425
+ ] })
1426
+ ] }),
1427
+ /* @__PURE__ */ jsx("div", { className: `w-full bg-surface-gray rounded-full overflow-hidden ${sizeClasses8[size]}`, children: /* @__PURE__ */ jsx(
1428
+ "div",
1429
+ {
1430
+ className: [
1431
+ `${themeClasses3[theme]} ${sizeClasses8[size]} rounded-full transition-all duration-300`,
1432
+ striped ? "bg-gradient-to-r from-transparent to-white opacity-30" : "",
1433
+ animated ? "animate-pulse" : ""
1434
+ ].join(" "),
1435
+ style: { width: `${clampedValue}%` }
1436
+ }
1437
+ ) })
1438
+ ] });
1439
+ }
1440
+ var sizeClasses9 = {
1441
+ sm: "w-4 h-4",
1442
+ md: "w-5 h-5",
1443
+ lg: "w-6 h-6"
1444
+ };
1445
+ var colorClasses2 = {
1446
+ yellow: "text-yellow-400",
1447
+ brand: "text-brand",
1448
+ danger: "text-danger-icon"
1449
+ };
1450
+ function Rating({
1451
+ value = 0,
1452
+ onChange,
1453
+ count = 5,
1454
+ size = "md",
1455
+ readonly = false,
1456
+ label,
1457
+ color = "yellow",
1458
+ className = "",
1459
+ ...props
1460
+ }) {
1461
+ const [hoverValue, setHoverValue] = React9.useState(0);
1462
+ const displayValue = hoverValue || value;
1463
+ return /* @__PURE__ */ jsxs("div", { className, ...props, children: [
1464
+ label && /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-ink mb-2", children: label }),
1465
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: Array.from({ length: count }, (_, i) => i + 1).map((starValue) => /* @__PURE__ */ jsx(
1466
+ "button",
1467
+ {
1468
+ onClick: () => !readonly && onChange?.(starValue),
1469
+ onMouseEnter: () => !readonly && setHoverValue(starValue),
1470
+ onMouseLeave: () => setHoverValue(0),
1471
+ disabled: readonly,
1472
+ className: `transition-transform hover:scale-110 ${readonly ? "cursor-default" : "cursor-pointer"}`,
1473
+ children: /* @__PURE__ */ jsx(
1474
+ "svg",
1475
+ {
1476
+ className: `${sizeClasses9[size]} ${starValue <= displayValue ? `fill-current ${colorClasses2[color]}` : "text-outline"}`,
1477
+ viewBox: "0 0 20 20",
1478
+ fill: "currentColor",
1479
+ children: /* @__PURE__ */ jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
1480
+ }
1481
+ )
1482
+ },
1483
+ starValue
1484
+ )) }),
1485
+ displayValue > 0 && /* @__PURE__ */ jsxs("p", { className: "text-sm text-ink-light mt-2", children: [
1486
+ displayValue,
1487
+ " / ",
1488
+ count
1489
+ ] })
1490
+ ] });
1491
+ }
1492
+ var themeClasses4 = {
1493
+ brand: "accent-brand",
1494
+ success: "accent-success-icon",
1495
+ danger: "accent-danger-icon"
1496
+ };
1497
+ function Slider({
1498
+ value = 0,
1499
+ onChange,
1500
+ min = 0,
1501
+ max = 100,
1502
+ step = 1,
1503
+ label,
1504
+ showValue = false,
1505
+ theme = "brand",
1506
+ className = "",
1507
+ disabled = false,
1508
+ ...props
1509
+ }) {
1510
+ const handleChange = (e) => {
1511
+ onChange?.(parseFloat(e.target.value));
1512
+ };
1513
+ const percentage = (Number(value) - Number(min)) / (Number(max) - Number(min)) * 100;
1514
+ return /* @__PURE__ */ jsxs("div", { className, children: [
1515
+ (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
1516
+ label && /* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-ink", children: label }),
1517
+ showValue && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-ink-light", children: value })
1518
+ ] }),
1519
+ /* @__PURE__ */ jsx(
1520
+ "input",
1521
+ {
1522
+ type: "range",
1523
+ min,
1524
+ max,
1525
+ step,
1526
+ value,
1527
+ onChange: handleChange,
1528
+ disabled,
1529
+ className: [
1530
+ `w-full h-2 rounded-lg appearance-none cursor-pointer ${themeClasses4[theme]}`,
1531
+ "bg-gradient-to-r from-surface-gray to-surface-gray",
1532
+ "focus:outline-none focus:ring-2 focus:ring-brand focus:ring-offset-2",
1533
+ disabled ? "opacity-50 cursor-not-allowed" : ""
1534
+ ].join(" "),
1535
+ style: {
1536
+ background: disabled ? void 0 : `linear-gradient(to right, var(--color-brand) 0%, var(--color-brand) ${percentage}%, var(--color-surface-gray) ${percentage}%, var(--color-surface-gray) 100%)`
1537
+ },
1538
+ ...props
1539
+ }
1540
+ )
1541
+ ] });
1542
+ }
1543
+ function Sidebar({
1544
+ sections,
1545
+ activeItem,
1546
+ onItemClick,
1547
+ collapsible = false,
1548
+ isCollapsed = false,
1549
+ onCollapsedChange,
1550
+ width = "w-64",
1551
+ className = "",
1552
+ ...props
1553
+ }) {
1554
+ const handleItemClick = (value, onClick) => {
1555
+ onClick?.();
1556
+ onItemClick?.(value);
1557
+ };
1558
+ return /* @__PURE__ */ jsxs(
1559
+ "aside",
1560
+ {
1561
+ className: [
1562
+ `${width} bg-surface-default border-r border-outline transition-all duration-200`,
1563
+ isCollapsed ? "w-16" : "",
1564
+ className
1565
+ ].join(" "),
1566
+ ...props,
1567
+ children: [
1568
+ collapsible && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border-b border-outline", children: [
1569
+ !isCollapsed && /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-ink", children: "Menu" }),
1570
+ /* @__PURE__ */ jsx(
1571
+ "button",
1572
+ {
1573
+ onClick: () => onCollapsedChange?.(!isCollapsed),
1574
+ className: "p-1 hover:bg-surface-gray rounded transition-colors",
1575
+ title: isCollapsed ? "Expand sidebar" : "Collapse sidebar",
1576
+ children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 text-ink", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: isCollapsed ? /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) : /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
1577
+ }
1578
+ )
1579
+ ] }),
1580
+ /* @__PURE__ */ jsx("nav", { className: "py-2", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
1581
+ section.title && !isCollapsed && /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-xs font-semibold text-ink-light uppercase tracking-wide", children: section.title }),
1582
+ section.items.map((item) => /* @__PURE__ */ jsxs(
1583
+ "button",
1584
+ {
1585
+ onClick: () => handleItemClick(item.value, item.onClick),
1586
+ disabled: item.disabled,
1587
+ title: isCollapsed ? typeof item.label === "string" ? item.label : "" : void 0,
1588
+ className: [
1589
+ "w-full px-3 py-2 flex items-center gap-2 text-sm transition-colors",
1590
+ "hover:bg-surface-gray focus:outline-none focus:ring-2 focus:ring-brand focus:ring-offset-0",
1591
+ item.disabled ? "opacity-50 cursor-not-allowed hover:bg-transparent" : "",
1592
+ item.isActive || item.value === activeItem ? "bg-brand-50 text-brand font-medium" : "text-ink hover:text-brand",
1593
+ isCollapsed ? "justify-center" : ""
1594
+ ].join(" "),
1595
+ children: [
1596
+ item.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: item.icon }),
1597
+ !isCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
1598
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: item.label }),
1599
+ item.badge && /* @__PURE__ */ jsx("span", { className: "text-xs px-1.5 py-0.5 bg-brand rounded-full text-white", children: item.badge })
1600
+ ] })
1601
+ ]
1602
+ },
1603
+ item.value
1604
+ ))
1605
+ ] }, sectionIndex)) })
1606
+ ]
1607
+ }
1608
+ );
1609
+ }
1610
+ function Table({
1611
+ columns,
1612
+ data,
1613
+ striped = true,
1614
+ hoverable = true,
1615
+ compact = false,
1616
+ className = "",
1617
+ emptyMessage = "No data"
1618
+ }) {
1619
+ if (data.length === 0) {
1620
+ return /* @__PURE__ */ jsx("div", { className: "text-center py-8 text-ink-faint text-sm", children: emptyMessage });
1621
+ }
1622
+ return /* @__PURE__ */ jsx("div", { className: `overflow-x-auto border border-outline rounded-lg ${className}`, children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
1623
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "bg-surface-gray border-b border-outline", children: columns.map((col) => /* @__PURE__ */ jsx(
1624
+ "th",
1625
+ {
1626
+ style: { width: col.width },
1627
+ className: `
1628
+ ${compact ? "px-3 py-2" : "px-4 py-3"}
1629
+ text-left text-xs font-semibold text-ink-faint uppercase tracking-wide
1630
+ ${col.align === "center" ? "text-center" : col.align === "right" ? "text-right" : "text-left"}
1631
+ `,
1632
+ children: col.label
1633
+ },
1634
+ col.key
1635
+ )) }) }),
1636
+ /* @__PURE__ */ jsx("tbody", { children: data.map((row, rowIdx) => /* @__PURE__ */ jsx(
1637
+ "tr",
1638
+ {
1639
+ className: `
1640
+ border-b border-outline last:border-b-0
1641
+ ${striped && rowIdx % 2 === 1 ? "bg-surface-gray/50" : ""}
1642
+ ${hoverable ? "hover:bg-surface-overlay transition-colors" : ""}
1643
+ `,
1644
+ children: columns.map((col) => /* @__PURE__ */ jsx(
1645
+ "td",
1646
+ {
1647
+ style: { width: col.width },
1648
+ className: `
1649
+ ${compact ? "px-3 py-2" : "px-4 py-3"}
1650
+ text-sm text-ink
1651
+ ${col.align === "center" ? "text-center" : col.align === "right" ? "text-right" : "text-left"}
1652
+ `,
1653
+ children: col.render ? col.render(row[col.key], row) : row[col.key]
1654
+ },
1655
+ `${rowIdx}-${col.key}`
1656
+ ))
1657
+ },
1658
+ rowIdx
1659
+ )) })
1660
+ ] }) });
1661
+ }
1662
+ var ChevronLeftIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "15 18 9 12 15 6" }) });
1663
+ var ChevronRightIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" }) });
1664
+ function Pagination({
1665
+ current,
1666
+ total,
1667
+ onChange,
1668
+ size = "md",
1669
+ showInfo = true,
1670
+ maxVisible = 5,
1671
+ className = ""
1672
+ }) {
1673
+ const sizeClass = size === "sm" ? "text-xs px-2 py-1" : "text-sm px-3 py-2";
1674
+ const getPages = () => {
1675
+ const pages2 = [];
1676
+ const halfVisible = Math.floor(maxVisible / 2);
1677
+ let start = Math.max(1, current - halfVisible);
1678
+ let end = Math.min(total, current + halfVisible);
1679
+ if (start === 1) {
1680
+ end = Math.min(total, maxVisible);
1681
+ } else if (end === total) {
1682
+ start = Math.max(1, total - maxVisible + 1);
1683
+ }
1684
+ if (start > 1) pages2.push(1);
1685
+ if (start > 2) pages2.push("...");
1686
+ for (let i = start; i <= end; i++) {
1687
+ pages2.push(i);
1688
+ }
1689
+ if (end < total - 1) pages2.push("...");
1690
+ if (end < total) pages2.push(total);
1691
+ return pages2;
1692
+ };
1693
+ const pages = getPages();
1694
+ return /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-2 ${className}`, children: [
1695
+ showInfo && /* @__PURE__ */ jsxs("span", { className: "text-xs text-ink-faint", children: [
1696
+ "Page ",
1697
+ current,
1698
+ " of ",
1699
+ total
1700
+ ] }),
1701
+ /* @__PURE__ */ jsx(
1702
+ "button",
1703
+ {
1704
+ onClick: () => onChange(Math.max(1, current - 1)),
1705
+ disabled: current === 1,
1706
+ className: `
1707
+ flex items-center justify-center rounded border border-outline
1708
+ hover:bg-surface-overlay disabled:text-ink-faint disabled:cursor-not-allowed disabled:hover:bg-transparent
1709
+ transition-colors ${sizeClass}
1710
+ `,
1711
+ title: "Previous page",
1712
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, { size: size === "sm" ? 12 : 16 })
1713
+ }
1714
+ ),
1715
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: pages.map(
1716
+ (page, i) => page === "..." ? /* @__PURE__ */ jsx("span", { className: "px-2 text-ink-faint", children: "..." }, `ellipsis-${i}`) : /* @__PURE__ */ jsx(
1717
+ "button",
1718
+ {
1719
+ onClick: () => onChange(page),
1720
+ className: `
1721
+ flex items-center justify-center rounded border
1722
+ transition-colors ${sizeClass}
1723
+ ${current === page ? "bg-brand text-white border-brand" : "border-outline hover:bg-surface-overlay"}
1724
+ `,
1725
+ children: page
1726
+ },
1727
+ page
1728
+ )
1729
+ ) }),
1730
+ /* @__PURE__ */ jsx(
1731
+ "button",
1732
+ {
1733
+ onClick: () => onChange(Math.min(total, current + 1)),
1734
+ disabled: current === total,
1735
+ className: `
1736
+ flex items-center justify-center rounded border border-outline
1737
+ hover:bg-surface-overlay disabled:text-ink-faint disabled:cursor-not-allowed disabled:hover:bg-transparent
1738
+ transition-colors ${sizeClass}
1739
+ `,
1740
+ title: "Next page",
1741
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, { size: size === "sm" ? 12 : 16 })
1742
+ }
1743
+ )
1744
+ ] });
1745
+ }
1746
+ function EmptyState({
1747
+ icon,
1748
+ title,
1749
+ description,
1750
+ action,
1751
+ className = ""
1752
+ }) {
1753
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-col items-center justify-center py-12 px-4 ${className}`, children: [
1754
+ icon && /* @__PURE__ */ jsx("div", { className: "text-4xl mb-4", children: icon }),
1755
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-ink mb-2", children: title }),
1756
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-ink-faint mb-6 text-center max-w-sm", children: description }),
1757
+ action && /* @__PURE__ */ jsx(
1758
+ "button",
1759
+ {
1760
+ onClick: action.onClick,
1761
+ className: "px-4 py-2 bg-brand text-white rounded-md hover:bg-brand-600 transition-colors text-sm font-medium",
1762
+ children: action.label
1763
+ }
1764
+ )
1765
+ ] });
1766
+ }
1767
+ var ChevronUpIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "18 15 12 9 6 15" }) });
1768
+ var ChevronDownIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" }) });
1769
+ var sizeClasses10 = {
1770
+ sm: "text-xs px-2 py-1 h-8",
1771
+ md: "text-sm px-3 py-2 h-10",
1772
+ lg: "text-base px-4 py-2.5 h-12"
1773
+ };
1774
+ function NumberInput({
1775
+ value,
1776
+ onChange,
1777
+ step = 1,
1778
+ min,
1779
+ max,
1780
+ size = "md",
1781
+ disabled = false,
1782
+ placeholder,
1783
+ className = ""
1784
+ }) {
1785
+ const [isEditing, setIsEditing] = useState(false);
1786
+ const handleIncrement = () => {
1787
+ const newValue = value + step;
1788
+ if (max === void 0 || newValue <= max) {
1789
+ onChange(newValue);
1790
+ }
1791
+ };
1792
+ const handleDecrement = () => {
1793
+ const newValue = value - step;
1794
+ if (min === void 0 || newValue >= min) {
1795
+ onChange(newValue);
1796
+ }
1797
+ };
1798
+ const handleInputChange = (e) => {
1799
+ const newValue = parseFloat(e.target.value);
1800
+ if (!isNaN(newValue)) {
1801
+ let val = newValue;
1802
+ if (min !== void 0 && val < min) val = min;
1803
+ if (max !== void 0 && val > max) val = max;
1804
+ onChange(val);
1805
+ }
1806
+ };
1807
+ return /* @__PURE__ */ jsxs("div", { className: `relative inline-flex items-center border border-outline rounded-md bg-surface ${className}`, children: [
1808
+ /* @__PURE__ */ jsx(
1809
+ "input",
1810
+ {
1811
+ type: "number",
1812
+ value,
1813
+ onChange: handleInputChange,
1814
+ onFocus: () => setIsEditing(true),
1815
+ onBlur: () => setIsEditing(false),
1816
+ disabled,
1817
+ placeholder,
1818
+ step,
1819
+ min,
1820
+ max,
1821
+ className: `
1822
+ flex-1 bg-transparent outline-none text-ink disabled:text-ink-faint disabled:cursor-not-allowed
1823
+ ${sizeClasses10[size]}
1824
+ `
1825
+ }
1826
+ ),
1827
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col border-l border-outline", children: [
1828
+ /* @__PURE__ */ jsx(
1829
+ "button",
1830
+ {
1831
+ onClick: handleIncrement,
1832
+ disabled: disabled || max !== void 0 && value >= max,
1833
+ className: "flex-1 px-1 hover:bg-surface-overlay disabled:text-ink-faint disabled:cursor-not-allowed transition-colors",
1834
+ title: "Increment",
1835
+ children: /* @__PURE__ */ jsx(ChevronUpIcon, { size: size === "sm" ? 12 : size === "md" ? 14 : 16 })
1836
+ }
1837
+ ),
1838
+ /* @__PURE__ */ jsx(
1839
+ "button",
1840
+ {
1841
+ onClick: handleDecrement,
1842
+ disabled: disabled || min !== void 0 && value <= min,
1843
+ className: "flex-1 px-1 hover:bg-surface-overlay disabled:text-ink-faint disabled:cursor-not-allowed transition-colors border-t border-outline",
1844
+ title: "Decrement",
1845
+ children: /* @__PURE__ */ jsx(ChevronDownIcon, { size: size === "sm" ? 12 : size === "md" ? 14 : 16 })
1846
+ }
1847
+ )
1848
+ ] })
1849
+ ] });
1850
+ }
1851
+ var CopyIcon = ({ size }) => /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1852
+ /* @__PURE__ */ jsx("path", { d: "M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" }),
1853
+ /* @__PURE__ */ jsx("rect", { x: "8", y: "2", width: "8", height: "4", rx: "1", ry: "1" })
1854
+ ] });
1855
+ var CheckIcon = ({ size, className }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) });
1856
+ function CodeBlock({
1857
+ code,
1858
+ language = "text",
1859
+ copyable = true,
1860
+ numbered = false,
1861
+ maxHeight = "max-h-96",
1862
+ className = ""
1863
+ }) {
1864
+ const [copied, setCopied] = useState(false);
1865
+ const handleCopy = async () => {
1866
+ try {
1867
+ await navigator.clipboard.writeText(code);
1868
+ setCopied(true);
1869
+ setTimeout(() => setCopied(false), 2e3);
1870
+ } catch (err) {
1871
+ console.error("Failed to copy:", err);
1872
+ }
1873
+ };
1874
+ const lines = code.split("\n");
1875
+ return /* @__PURE__ */ jsxs("div", { className: `relative bg-ink rounded-lg overflow-hidden border border-outline ${className}`, children: [
1876
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between bg-surface-gray px-4 py-2 border-b border-outline", children: [
1877
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-ink-faint font-mono uppercase", children: language }),
1878
+ copyable && /* @__PURE__ */ jsx(
1879
+ "button",
1880
+ {
1881
+ onClick: handleCopy,
1882
+ className: "p-1 rounded hover:bg-surface-overlay transition-colors text-ink-faint hover:text-ink",
1883
+ title: "Copy to clipboard",
1884
+ children: copied ? /* @__PURE__ */ jsx("span", { style: { color: "currentColor" }, className: "text-status-online", children: /* @__PURE__ */ jsx(CheckIcon, { size: 14 }) }) : /* @__PURE__ */ jsx(CopyIcon, { size: 14 })
1885
+ }
1886
+ )
1887
+ ] }),
1888
+ /* @__PURE__ */ jsx("div", { className: `overflow-auto ${maxHeight}`, children: /* @__PURE__ */ jsx("pre", { className: "p-4 text-sm font-mono text-sky-100", children: numbered ? /* @__PURE__ */ jsx(Fragment, { children: lines.map((line, i) => /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
1889
+ /* @__PURE__ */ jsx("span", { className: "text-ink-faint select-none", children: String(i + 1).padStart(3, " ") }),
1890
+ /* @__PURE__ */ jsx("span", { children: line })
1891
+ ] }, i)) }) : code }) })
1892
+ ] });
1893
+ }
1894
+ var statusColors = {
1895
+ completed: {
1896
+ dot: "bg-status-online border-status-online",
1897
+ line: "bg-status-online",
1898
+ text: "text-status-online"
1899
+ },
1900
+ pending: {
1901
+ dot: "bg-ink-light border-ink-light",
1902
+ line: "bg-ink-faint",
1903
+ text: "text-ink-faint"
1904
+ },
1905
+ error: {
1906
+ dot: "bg-danger-icon border-danger-icon",
1907
+ line: "bg-danger-icon",
1908
+ text: "text-danger-text"
1909
+ },
1910
+ "in-progress": {
1911
+ dot: "bg-brand border-brand",
1912
+ line: "bg-brand",
1913
+ text: "text-brand"
1914
+ }
1915
+ };
1916
+ function Timeline({
1917
+ items,
1918
+ orientation = "vertical",
1919
+ className = ""
1920
+ }) {
1921
+ if (orientation === "vertical") {
1922
+ return /* @__PURE__ */ jsx("div", { className: `space-y-4 ${className}`, children: items.map((item, index) => {
1923
+ const colors = statusColors[item.status];
1924
+ const isLast = index === items.length - 1;
1925
+ return /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
1926
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
1927
+ /* @__PURE__ */ jsx(
1928
+ "div",
1929
+ {
1930
+ className: `
1931
+ w-4 h-4 rounded-full border-2 flex-shrink-0
1932
+ flex items-center justify-center bg-white
1933
+ ${colors.dot}
1934
+ `,
1935
+ children: item.icon && /* @__PURE__ */ jsx("span", { className: "text-white text-2xs", children: item.icon })
1936
+ }
1937
+ ),
1938
+ !isLast && /* @__PURE__ */ jsx("div", { className: `w-0.5 h-12 ${colors.line}` })
1939
+ ] }),
1940
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 py-1", children: [
1941
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1942
+ /* @__PURE__ */ jsx("h4", { className: `font-semibold text-sm ${colors.text}`, children: item.label }),
1943
+ item.timestamp && /* @__PURE__ */ jsx("span", { className: "text-xs text-ink-faint", children: typeof item.timestamp === "string" ? item.timestamp : new Date(item.timestamp).toLocaleTimeString("en-GB", {
1944
+ hour12: false,
1945
+ hour: "2-digit",
1946
+ minute: "2-digit",
1947
+ second: "2-digit"
1948
+ }) })
1949
+ ] }),
1950
+ item.description && /* @__PURE__ */ jsx("p", { className: "text-sm text-ink-faint mt-1", children: item.description })
1951
+ ] })
1952
+ ] }, item.id);
1953
+ }) });
1954
+ }
1955
+ return /* @__PURE__ */ jsx("div", { className: `flex gap-4 overflow-x-auto pb-2 ${className}`, children: items.map((item, index) => {
1956
+ const colors = statusColors[item.status];
1957
+ index === items.length - 1;
1958
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center flex-shrink-0 gap-2 min-w-fit", children: [
1959
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1960
+ index > 0 && /* @__PURE__ */ jsx("div", { className: `h-0.5 w-6 ${statusColors[items[index - 1].status].line}` }),
1961
+ /* @__PURE__ */ jsx(
1962
+ "div",
1963
+ {
1964
+ className: `
1965
+ w-5 h-5 rounded-full border-2 flex items-center justify-center bg-white
1966
+ ${colors.dot}
1967
+ `,
1968
+ children: item.icon && /* @__PURE__ */ jsx("span", { className: "text-white text-2xs", children: item.icon })
1969
+ }
1970
+ )
1971
+ ] }),
1972
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
1973
+ /* @__PURE__ */ jsx("p", { className: `text-xs font-semibold ${colors.text}`, children: item.label }),
1974
+ item.timestamp && /* @__PURE__ */ jsx("p", { className: "text-2xs text-ink-faint", children: typeof item.timestamp === "string" ? item.timestamp : new Date(item.timestamp).toLocaleTimeString("en-GB", {
1975
+ hour12: false,
1976
+ hour: "2-digit",
1977
+ minute: "2-digit"
1978
+ }) })
1979
+ ] })
1980
+ ] }, item.id);
1981
+ }) });
1982
+ }
1983
+ var sizeClasses11 = {
1984
+ xs: "text-xs px-1.5 py-0.5 min-w-5 h-5",
1985
+ sm: "text-xs px-2 py-1 min-w-6 h-6",
1986
+ md: "text-sm px-2.5 py-1.5 min-w-8 h-8"
1987
+ };
1988
+ var themeClasses5 = {
1989
+ gray: "bg-surface-gray border-outline text-ink",
1990
+ dark: "bg-ink text-white border-ink-faint",
1991
+ brand: "bg-brand border-brand text-white"
1992
+ };
1993
+ function Kbd({
1994
+ keys,
1995
+ size = "sm",
1996
+ theme = "gray",
1997
+ className = ""
1998
+ }) {
1999
+ const keyArray = Array.isArray(keys) ? keys : [keys];
2000
+ return /* @__PURE__ */ jsx("span", { className: `inline-flex items-center gap-1 ${className}`, children: keyArray.map((key, i) => /* @__PURE__ */ jsxs(React9.Fragment, { children: [
2001
+ /* @__PURE__ */ jsx(
2002
+ "kbd",
2003
+ {
2004
+ className: `
2005
+ inline-flex items-center justify-center rounded font-mono font-medium
2006
+ border border-b-2 shadow-sm
2007
+ ${sizeClasses11[size]}
2008
+ ${themeClasses5[theme]}
2009
+ `,
2010
+ children: key
2011
+ }
2012
+ ),
2013
+ i < keyArray.length - 1 && /* @__PURE__ */ jsx("span", { className: "text-ink-faint text-xs", children: "+" })
2014
+ ] }, key)) });
2015
+ }
605
2016
  var statusConfig = {
606
2017
  online: {
607
2018
  label: "Online",
@@ -676,7 +2087,7 @@ function StatusBadge({
676
2087
  }
677
2088
  );
678
2089
  }
679
- var sizeClasses8 = {
2090
+ var sizeClasses12 = {
680
2091
  sm: "text-xs gap-1.5",
681
2092
  md: "text-sm gap-2",
682
2093
  lg: "text-base gap-2"
@@ -695,7 +2106,7 @@ function ConnectionIndicator({
695
2106
  className = ""
696
2107
  }) {
697
2108
  const status = connected ? "online" : "offline";
698
- return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center ${sizeClasses8[size]} ${className}`, children: [
2109
+ return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center ${sizeClasses12[size]} ${className}`, children: [
699
2110
  /* @__PURE__ */ jsx(
700
2111
  StatusBadge,
701
2112
  {
@@ -742,6 +2153,6 @@ function useToast() {
742
2153
  return { toasts, addToast, removeToast };
743
2154
  }
744
2155
 
745
- export { Avatar, Badge, Button, Card, Checkbox, ConnectionIcon, ConnectionIndicator, Dialog, Input, Link, Select, Spinner, StatusBadge, Textarea, Toast, ToastContainer, Tooltip, useDisclosure, useToast };
2156
+ export { Alert, Avatar, Badge, Breadcrumbs, Button, Card, Checkbox, CodeBlock, ConnectionIcon, ConnectionIndicator, DatePicker, Dialog, Dropdown, EmptyState, FileUploader, FormControl, Input, Kbd, Link, MultiSelect, NumberInput, Pagination, Progress, Rating, Select, Sidebar, Slider, Spinner, StatusBadge, Switch, Table, Tabs, Textarea, TimePicker, Timeline, Toast, ToastContainer, Tooltip, useDisclosure, useToast };
746
2157
  //# sourceMappingURL=index.js.map
747
2158
  //# sourceMappingURL=index.js.map