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