@mirror-physics/fractal-ui 0.2.0-next.3 → 0.2.0-next.30

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
@@ -32,36 +32,71 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Alert: () => Alert,
34
34
  AlertDescription: () => AlertDescription,
35
+ AlertGhost: () => AlertGhost,
35
36
  AlertTitle: () => AlertTitle,
36
37
  Button: () => Button,
38
+ ButtonGhost: () => ButtonGhost,
37
39
  Card: () => Card,
38
40
  CardContent: () => CardContent,
39
41
  CardDescription: () => CardDescription,
40
42
  CardFooter: () => CardFooter,
43
+ CardGhost: () => CardGhost,
41
44
  CardHeader: () => CardHeader,
42
45
  CardTitle: () => CardTitle,
46
+ Checkbox: () => Checkbox,
47
+ CheckboxGhost: () => CheckboxGhost,
43
48
  Chip: () => Chip,
49
+ ChipGhost: () => ChipGhost,
50
+ ContentSwitcher: () => ContentSwitcher,
51
+ ContentSwitcherGhost: () => ContentSwitcherGhost,
44
52
  DataTable: () => DataTable,
53
+ DataTableGhost: () => DataTableGhost,
45
54
  Disclosure: () => Disclosure,
55
+ DisclosureGhost: () => DisclosureGhost,
46
56
  Dropdown: () => Dropdown,
57
+ DropdownGhost: () => DropdownGhost,
47
58
  FeatureCard: () => FeatureCard,
59
+ FileDropzone: () => FileDropzone,
60
+ FileDropzoneGhost: () => FileDropzoneGhost,
48
61
  FolderCard: () => FolderCard,
62
+ Ghost: () => Ghost,
63
+ GhostLine: () => GhostLine,
49
64
  Input: () => Input,
65
+ InputGhost: () => InputGhost,
50
66
  Label: () => Label,
67
+ LabelGhost: () => LabelGhost,
68
+ LatticeLoader: () => LatticeLoader,
51
69
  Link: () => Link,
70
+ LinkGhost: () => LinkGhost,
52
71
  Modal: () => Modal,
72
+ ModalGhost: () => ModalGhost,
73
+ Pagination: () => Pagination,
74
+ PaginationGhost: () => PaginationGhost,
53
75
  PromptCard: () => PromptCard,
76
+ PromptCardGhost: () => PromptCardGhost,
54
77
  PromptGrid: () => PromptGrid,
78
+ SidePanel: () => SidePanel,
79
+ SidePanelGhost: () => SidePanelGhost,
55
80
  Sidebar: () => Sidebar,
81
+ SidebarAccountMenu: () => SidebarAccountMenu,
56
82
  SidebarBrand: () => SidebarBrand,
57
83
  SidebarFooter: () => SidebarFooter,
84
+ SidebarGhost: () => SidebarGhost,
58
85
  SidebarHeader: () => SidebarHeader,
59
86
  SidebarNav: () => SidebarNav,
60
87
  SidebarNavItem: () => SidebarNavItem,
61
88
  SidebarSection: () => SidebarSection,
62
89
  SortableTable: () => SortableTable,
90
+ SortableTableGhost: () => SortableTableGhost,
63
91
  Tabs: () => Tabs,
92
+ TabsGhost: () => TabsGhost,
93
+ TextButton: () => TextButton,
94
+ TextButtonGhost: () => TextButtonGhost,
95
+ Textarea: () => Textarea,
96
+ TextareaGhost: () => TextareaGhost,
64
97
  Toggle: () => Toggle,
98
+ ToggleGhost: () => ToggleGhost,
99
+ UILoader: () => UILoader,
65
100
  cn: () => cn,
66
101
  useEscapeDismiss: () => useEscapeDismiss
67
102
  });
@@ -119,7 +154,7 @@ var colorPalette = {
119
154
  var sizeConfig = {
120
155
  xs: { height: "28px", padding: "4px 8px", iconOnly: "28px", fontSize: "0.75rem" },
121
156
  sm: { height: "32px", padding: "6px 12px", iconOnly: "32px", fontSize: "0.75rem" },
122
- md: { height: "38px", padding: "8px 16px", iconOnly: "38px", fontSize: "0.875rem" },
157
+ md: { height: "40px", padding: "8px 16px", iconOnly: "40px", fontSize: "0.875rem" },
123
158
  lg: { height: "44px", padding: "10px 20px", iconOnly: "44px", fontSize: "1rem" },
124
159
  xl: { height: "56px", padding: "14px 28px", iconOnly: "56px", fontSize: "1rem" }
125
160
  };
@@ -398,28 +433,32 @@ Label.displayName = "Label";
398
433
 
399
434
  // src/components/Alert/Alert.tsx
400
435
  var React6 = __toESM(require("react"), 1);
436
+ var import_fractal_icons2 = require("@mirror-physics/fractal-icons");
401
437
  var import_jsx_runtime6 = require("react/jsx-runtime");
402
438
  var defaultIcons = {
403
- default: "\u2139",
404
- info: "\u2139",
405
- success: "\u2713",
406
- warning: "\u26A0",
407
- error: "\u2715"
439
+ default: import_fractal_icons2.CircleInfo,
440
+ info: import_fractal_icons2.CircleInfo,
441
+ success: import_fractal_icons2.CircleCheck,
442
+ warning: import_fractal_icons2.Warning,
443
+ error: import_fractal_icons2.CircleClose
408
444
  };
409
445
  var Alert = React6.forwardRef(
410
- ({ className, variant = "default", icon, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
411
- "div",
412
- {
413
- ref,
414
- role: "alert",
415
- className: cn("fractal-alert", `fractal-alert--${variant}`, className),
416
- ...props,
417
- children: [
418
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? defaultIcons[variant] }),
419
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fractal-alert-content", children })
420
- ]
421
- }
422
- )
446
+ ({ className, variant = "default", icon, children, ...props }, ref) => {
447
+ const DefaultIcon = defaultIcons[variant];
448
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
449
+ "div",
450
+ {
451
+ ref,
452
+ role: "alert",
453
+ className: cn("fractal-alert", `fractal-alert--${variant}`, className),
454
+ ...props,
455
+ children: [
456
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DefaultIcon, { size: 18 }) }),
457
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fractal-alert-content", children })
458
+ ]
459
+ }
460
+ );
461
+ }
423
462
  );
424
463
  Alert.displayName = "Alert";
425
464
  var AlertTitle = React6.forwardRef(
@@ -503,27 +542,72 @@ function useEscapeDismiss(priority, handler, enabled = true) {
503
542
  }, [priority, enabled]);
504
543
  }
505
544
 
506
- // src/components/Modal/Modal.tsx
545
+ // src/components/UILoader/UILoader.tsx
546
+ var import_react2 = require("react");
507
547
  var import_jsx_runtime8 = require("react/jsx-runtime");
508
- var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
509
- function Modal({ open, onClose, title, children, danger, warn, footer, noClose, size = "sm", className }) {
510
- useEscapeDismiss(80, onClose, open && !noClose);
548
+ var LEFT = "M0 53C0 51 1.6 49.5 3.6 49.5h16.5c1 0 1.9.4 2.5 1L42.1 69.6c.7.7 1.1 1.6 1.1 2.5v16.2c0 2-1.6 3.5-3.6 3.5H23.1c-1 0-1.9-.4-2.5-1L1.1 71.7C.4 71 0 70.1 0 69.2V53Z";
549
+ var CENTER = "M0 3.5C0 1.6 1.6 0 3.6 0h16.5c1 0 1.9.4 2.5 1L92.5 69.6c.7.7 1 1.6 1 2.5v16.2c0 2-1.6 3.5-3.6 3.5H73.4c-1 0-1.9-.4-2.5-1L1.1 22.2C.4 21.6 0 20.7 0 19.7V3.5Z";
550
+ var RIGHT = "M50.4 3.5C50.4 1.6 52 0 54 0h16.5c1 0 1.9.4 2.5 1l69.8 68.6c.7.7 1.1 1.6 1.1 2.5v16.2c0 2-1.6 3.5-3.6 3.5h-16.5c-1 0-1.9-.4-2.5-1L51.4 22.2c-.7-.6-1-1.5-1-2.5V3.5Z";
551
+ function UILoader({ size = 48, tone = "neutral", className, style, label = "Loading", ariaHidden = false }) {
552
+ const rawId = (0, import_react2.useId)().replace(/[^a-zA-Z0-9_-]/g, "");
553
+ const clipId = `fractal-ui-loader-clip-${rawId}`;
554
+ const gradientId = `fractal-ui-loader-gradient-${rawId}`;
555
+ const height = typeof size === "number" ? `${size}px` : size;
556
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
557
+ "span",
558
+ {
559
+ "aria-hidden": ariaHidden || void 0,
560
+ "aria-label": ariaHidden ? void 0 : label,
561
+ className: cn("fractal-ui-loader", `fractal-ui-loader--${tone}`, className),
562
+ role: ariaHidden ? void 0 : "status",
563
+ style,
564
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
565
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("defs", { children: [
566
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
567
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("stop", { className: "fractal-ui-loader__stop-start", offset: "0" }),
568
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("stop", { className: "fractal-ui-loader__stop-end", offset: "1" })
569
+ ] }),
570
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
571
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("stop", { offset: "0.4", stopColor: "white", stopOpacity: "0" }),
572
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("stop", { offset: "0.5", stopColor: "white", stopOpacity: "0.62" }),
573
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("stop", { offset: "0.6", stopColor: "white", stopOpacity: "0" })
574
+ ] }),
575
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("clipPath", { id: clipId, children: [
576
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: LEFT }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: CENTER }),
578
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: RIGHT })
579
+ ] })
580
+ ] }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: CENTER, fill: `url(#${gradientId})` }),
582
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: RIGHT, fill: `url(#${gradientId})` }),
583
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: LEFT, fill: `url(#${gradientId})` }),
584
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("g", { clipPath: `url(#${clipId})`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("g", { className: "fractal-ui-loader__shine-axis", transform: "translate(72 46) rotate(68.4)", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { className: "fractal-ui-loader__shine", x: "-160", y: "-100", width: "320", height: "200", fill: `url(#${gradientId}-shine)` }) }) })
585
+ ] })
586
+ }
587
+ );
588
+ }
589
+
590
+ // src/components/Modal/Modal.tsx
591
+ var import_jsx_runtime9 = require("react/jsx-runtime");
592
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
593
+ function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", className }) {
594
+ useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
511
595
  if (!open) return null;
512
596
  const sizeClass = `fractal-modal-panel--${size}`;
513
597
  const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
514
598
  return (0, import_react_dom.createPortal)(
515
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
599
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
516
600
  "div",
517
601
  {
518
602
  className: cn("fractal-modal-panel", sizeClass, accentClass, className),
519
603
  onClick: (e) => e.stopPropagation(),
520
604
  children: [
521
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "fractal-modal-title-row", children: [
522
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
523
- !noClose && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: onClose, title: "Close", className: "fractal-modal-close", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {}) })
605
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "fractal-modal-title-row", children: [
606
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
607
+ !noClose && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseIcon, {}) })
524
608
  ] }),
525
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("fractal-modal-body", size === "lg" && "fractal-modal-body--lg"), children }),
526
- footer && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-footer", children: footer })
609
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { "aria-busy": loading || void 0, className: cn("fractal-modal-body", size === "lg" && "fractal-modal-body--lg", loading && "fractal-modal-body--loading"), children: loading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(UILoader, { label: loadingLabel }) : children }),
610
+ footer && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-modal-footer", children: footer })
527
611
  ]
528
612
  }
529
613
  ) }),
@@ -532,17 +616,17 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
532
616
  }
533
617
 
534
618
  // src/components/DataTable/DataTable.tsx
535
- var import_jsx_runtime9 = require("react/jsx-runtime");
619
+ var import_jsx_runtime10 = require("react/jsx-runtime");
536
620
  function DataTable({ columns, data, emptyMessage, header, size = "md", className }) {
537
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: cn("fractal-datatable", `fractal-datatable--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "fractal-datatable-surface", children: [
538
- header && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-datatable-header", children: header }),
539
- data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { className: "fractal-datatable-table", children: [
540
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tr", { className: "fractal-datatable-thead-row", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { className: "fractal-datatable-th", style: { width: col.width }, children: col.header }, col.key)) }) }),
541
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
621
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: cn("fractal-datatable", `fractal-datatable--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "fractal-datatable-surface", children: [
622
+ header && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-datatable-header", children: header }),
623
+ data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { className: "fractal-datatable-table", children: [
624
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { className: "fractal-datatable-thead-row", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "fractal-datatable-th", style: { width: col.width }, children: col.header }, col.key)) }) }),
625
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
542
626
  "tr",
543
627
  {
544
628
  className: "fractal-datatable-row",
545
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "fractal-datatable-td", style: { width: col.width }, children: col.render(row, rowIndex) }, col.key))
629
+ children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "fractal-datatable-td", style: { width: col.width }, children: col.render(row, rowIndex) }, col.key))
546
630
  },
547
631
  rowIndex
548
632
  )) })
@@ -552,8 +636,8 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
552
636
 
553
637
  // src/components/Dropdown/Dropdown.tsx
554
638
  var React7 = __toESM(require("react"), 1);
555
- var import_fractal_icons2 = require("@mirror-physics/fractal-icons");
556
- var import_jsx_runtime10 = require("react/jsx-runtime");
639
+ var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
640
+ var import_jsx_runtime11 = require("react/jsx-runtime");
557
641
  var MARGIN = 4;
558
642
  function Dropdown({
559
643
  items,
@@ -564,13 +648,15 @@ function Dropdown({
564
648
  align = "left",
565
649
  triggerContent,
566
650
  label,
651
+ iconOnly = false,
567
652
  noChevron = false,
568
653
  size = "md",
569
654
  triggerVariant = "outline",
570
655
  className,
571
656
  triggerClassName,
572
657
  panelClassName,
573
- closeOnSelect = true
658
+ closeOnSelect = true,
659
+ disabled = false
574
660
  }) {
575
661
  const [open, setOpen] = React7.useState(false);
576
662
  const triggerRef = React7.useRef(null);
@@ -583,7 +669,7 @@ function Dropdown({
583
669
  const selectableItems = visibleItems.filter((i) => i.kind !== "header");
584
670
  const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
585
671
  const isUp = direction === "up";
586
- const ChevronIcon = isUp ? import_fractal_icons2.ChevronUp : import_fractal_icons2.ChevronDown;
672
+ const ChevronIcon = isUp ? import_fractal_icons3.ChevronUp : import_fractal_icons3.ChevronDown;
587
673
  React7.useLayoutEffect(() => {
588
674
  if (!open || !triggerRef.current || !panelRef.current) return;
589
675
  const triggerRect = triggerRef.current.getBoundingClientRect();
@@ -628,12 +714,13 @@ function Dropdown({
628
714
  document.addEventListener("mousedown", handleClickOutside);
629
715
  return () => document.removeEventListener("mousedown", handleClickOutside);
630
716
  }, [open]);
631
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
632
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
717
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
718
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
633
719
  "button",
634
720
  {
635
721
  ref: triggerRef,
636
722
  type: "button",
723
+ disabled,
637
724
  "aria-haspopup": "listbox",
638
725
  "aria-expanded": open,
639
726
  "aria-label": triggerLabel,
@@ -642,18 +729,19 @@ function Dropdown({
642
729
  "fractal-dropdown-trigger",
643
730
  `fractal-dropdown-trigger--${size}`,
644
731
  `fractal-dropdown-trigger--${triggerVariant}`,
732
+ iconOnly && "fractal-dropdown-trigger--icon-only",
645
733
  triggerClassName
646
734
  ),
647
735
  children: [
648
- triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
649
- selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
650
- selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
736
+ triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
737
+ selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
738
+ selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
651
739
  ] }),
652
- !noChevron && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
740
+ !noChevron && !iconOnly && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
653
741
  ]
654
742
  }
655
743
  ),
656
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
744
+ open && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
657
745
  "div",
658
746
  {
659
747
  ref: panelRef,
@@ -662,21 +750,21 @@ function Dropdown({
662
750
  className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
663
751
  style: panelStyle,
664
752
  children: [
665
- label != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-label", children: label }),
753
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "fractal-dropdown-label", children: label }),
666
754
  visibleItems.map((item, index) => {
667
- const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
668
- const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
755
+ const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
756
+ const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
669
757
  if (item.kind === "header") {
670
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
758
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(React7.Fragment, { children: [
671
759
  topDivider,
672
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
760
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
673
761
  bottomDivider
674
762
  ] }, `header-${index}`);
675
763
  }
676
764
  const isSelected = item.value === selectedValue;
677
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
765
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(React7.Fragment, { children: [
678
766
  topDivider,
679
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
767
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
680
768
  "button",
681
769
  {
682
770
  type: "button",
@@ -688,9 +776,9 @@ function Dropdown({
688
776
  },
689
777
  className: "fractal-dropdown-option",
690
778
  children: [
691
- item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
692
- item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
693
- item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
779
+ item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
780
+ item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
781
+ item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
694
782
  ]
695
783
  }
696
784
  ),
@@ -705,9 +793,9 @@ function Dropdown({
705
793
 
706
794
  // src/components/Link/Link.tsx
707
795
  var React8 = __toESM(require("react"), 1);
708
- var import_jsx_runtime11 = require("react/jsx-runtime");
796
+ var import_jsx_runtime12 = require("react/jsx-runtime");
709
797
  var Link = React8.forwardRef(
710
- ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
798
+ ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
711
799
  "a",
712
800
  {
713
801
  ref,
@@ -720,9 +808,9 @@ Link.displayName = "Link";
720
808
 
721
809
  // src/components/Chip/Chip.tsx
722
810
  var React9 = __toESM(require("react"), 1);
723
- var import_jsx_runtime12 = require("react/jsx-runtime");
811
+ var import_jsx_runtime13 = require("react/jsx-runtime");
724
812
  var Chip = React9.forwardRef(
725
- ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
813
+ ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
726
814
  "span",
727
815
  {
728
816
  ref,
@@ -733,35 +821,69 @@ var Chip = React9.forwardRef(
733
821
  );
734
822
  Chip.displayName = "Chip";
735
823
 
824
+ // src/components/Checkbox/Checkbox.tsx
825
+ var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
826
+ var import_jsx_runtime14 = require("react/jsx-runtime");
827
+ function Checkbox({ checked, onCheckedChange, className, disabled, onClick, onKeyDown, ...props }) {
828
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
829
+ "button",
830
+ {
831
+ ...props,
832
+ className: cn("fractal-checkbox", checked && "fractal-checkbox--checked", className),
833
+ type: "button",
834
+ role: "checkbox",
835
+ "aria-checked": checked,
836
+ disabled,
837
+ onClick: (event) => {
838
+ onClick?.(event);
839
+ if (!event.defaultPrevented) onCheckedChange(!checked);
840
+ },
841
+ onKeyDown: (event) => {
842
+ onKeyDown?.(event);
843
+ if (event.key === " " || event.key === "Enter") event.stopPropagation();
844
+ },
845
+ children: checked ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_fractal_icons4.CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_fractal_icons4.Checkbox, { "aria-hidden": "true", size: 18 })
846
+ }
847
+ );
848
+ }
849
+
736
850
  // src/components/SortableTable/SortableTable.tsx
737
- var import_react2 = require("react");
738
- var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
739
- var import_jsx_runtime13 = require("react/jsx-runtime");
851
+ var import_react3 = require("react");
852
+ var import_fractal_icons5 = require("@mirror-physics/fractal-icons");
853
+ var import_jsx_runtime15 = require("react/jsx-runtime");
740
854
  function SortableTable({
741
855
  columns,
742
856
  data,
743
857
  emptyMessage,
744
858
  header,
745
859
  size = "md",
860
+ embedded = false,
746
861
  className,
862
+ defaultSort,
747
863
  defaultSortKey = void 0,
748
864
  defaultSortDirection = null,
749
865
  sortKey: controlledKey,
750
866
  sortDirection: controlledDirection,
751
867
  onSortChange,
752
- highlightRow
868
+ highlightRow,
869
+ onRowClick,
870
+ rowAction
753
871
  }) {
754
- const [internalKey, setInternalKey] = (0, import_react2.useState)(defaultSortKey ?? null);
755
- const [internalDirection, setInternalDirection] = (0, import_react2.useState)(defaultSortDirection);
872
+ const [internalKey, setInternalKey] = (0, import_react3.useState)(defaultSortKey ?? null);
873
+ const [internalDirection, setInternalDirection] = (0, import_react3.useState)(defaultSortDirection);
756
874
  const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
757
875
  const activeKey = isControlled ? controlledKey : internalKey;
758
876
  const activeDirection = isControlled ? controlledDirection : internalDirection;
759
- const sorted = (0, import_react2.useMemo)(() => {
760
- if (!activeKey || !activeDirection) return data;
761
- const col = columns.find((c) => c.key === activeKey);
877
+ const baselineKey = defaultSort?.key ?? null;
878
+ const baselineDirection = defaultSort?.direction ?? null;
879
+ const effectiveKey = activeKey && activeDirection ? activeKey : baselineKey;
880
+ const effectiveDirection = activeKey && activeDirection ? activeDirection : baselineDirection;
881
+ const sorted = (0, import_react3.useMemo)(() => {
882
+ if (!effectiveKey || !effectiveDirection) return data;
883
+ const col = columns.find((c) => c.key === effectiveKey);
762
884
  if (!col) return data;
763
885
  const accessor = col.sortAccessor ?? ((row) => {
764
- const value = row[activeKey];
886
+ const value = row[effectiveKey];
765
887
  return typeof value === "string" || typeof value === "number" ? value : null;
766
888
  });
767
889
  const copy = [...data];
@@ -772,26 +894,28 @@ function SortableTable({
772
894
  if (av == null) return 1;
773
895
  if (bv == null) return -1;
774
896
  if (typeof av === "number" && typeof bv === "number") {
775
- return activeDirection === "asc" ? av - bv : bv - av;
897
+ return effectiveDirection === "asc" ? av - bv : bv - av;
776
898
  }
777
899
  const as = String(av).toLowerCase();
778
900
  const bs = String(bv).toLowerCase();
779
- if (as < bs) return activeDirection === "asc" ? -1 : 1;
780
- if (as > bs) return activeDirection === "asc" ? 1 : -1;
901
+ if (as < bs) return effectiveDirection === "asc" ? -1 : 1;
902
+ if (as > bs) return effectiveDirection === "asc" ? 1 : -1;
781
903
  return 0;
782
904
  });
783
905
  return copy;
784
- }, [data, columns, activeKey, activeDirection]);
906
+ }, [data, columns, effectiveKey, effectiveDirection]);
785
907
  const handleSortClick = (key) => {
786
908
  let nextDirection;
787
- if (activeKey !== key) {
909
+ if (!activeKey || !activeDirection) {
910
+ nextDirection = baselineKey === key && baselineDirection ? baselineDirection : "asc";
911
+ } else if (activeKey !== key) {
788
912
  nextDirection = "asc";
913
+ } else if (baselineKey === key && baselineDirection) {
914
+ nextDirection = activeDirection === baselineDirection ? baselineDirection === "asc" ? "desc" : "asc" : null;
789
915
  } else if (activeDirection === "asc") {
790
916
  nextDirection = "desc";
791
- } else if (activeDirection === "desc") {
792
- nextDirection = null;
793
917
  } else {
794
- nextDirection = "asc";
918
+ nextDirection = null;
795
919
  }
796
920
  const nextKey = nextDirection === null ? null : key;
797
921
  if (isControlled) {
@@ -802,13 +926,13 @@ function SortableTable({
802
926
  onSortChange?.(nextKey, nextDirection);
803
927
  }
804
928
  };
805
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "fractal-sortable-table-surface", children: [
806
- header && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
807
- sorted.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { className: "fractal-sortable-table-table", children: [
808
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tr", { className: "fractal-sortable-table-thead-row", children: columns.map((col) => {
929
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fractal-sortable-table-surface", children: [
930
+ header && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
931
+ sorted.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("table", { className: "fractal-sortable-table-table", children: [
932
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tr", { className: "fractal-sortable-table-thead-row", children: columns.map((col) => {
809
933
  const isActive = activeKey === col.key && activeDirection !== null;
810
934
  if (!col.sortable) {
811
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
935
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
812
936
  "th",
813
937
  {
814
938
  className: "fractal-sortable-table-th",
@@ -818,12 +942,12 @@ function SortableTable({
818
942
  col.key
819
943
  );
820
944
  }
821
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
945
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
822
946
  "th",
823
947
  {
824
948
  className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
825
949
  style: { width: col.width },
826
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
950
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
827
951
  "button",
828
952
  {
829
953
  type: "button",
@@ -834,8 +958,8 @@ function SortableTable({
834
958
  onClick: () => handleSortClick(col.key),
835
959
  "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
836
960
  children: [
837
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: col.header }),
838
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.ArrowDown, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.ArrowsUpDown, { size: 14 }) })
961
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: col.header }),
962
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_fractal_icons5.ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_fractal_icons5.ArrowDown, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_fractal_icons5.ArrowsUpDown, { size: 14 }) })
839
963
  ]
840
964
  }
841
965
  )
@@ -843,21 +967,42 @@ function SortableTable({
843
967
  col.key
844
968
  );
845
969
  }) }) }),
846
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
970
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
847
971
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
848
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
972
+ const action = rowAction ? {
973
+ label: rowAction.label(row, rowIndex),
974
+ icon: rowAction.icon(row, rowIndex)
975
+ } : null;
976
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
849
977
  "tr",
850
978
  {
851
979
  className: cn(
852
980
  "fractal-sortable-table-row",
853
- highlighted && "fractal-sortable-table-row--highlighted"
981
+ highlighted && "fractal-sortable-table-row--highlighted",
982
+ onRowClick && "fractal-sortable-table-row--interactive"
854
983
  ),
855
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
984
+ onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
985
+ onKeyDown: onRowClick ? (event) => {
986
+ if (event.key === "Enter" || event.key === " ") {
987
+ event.preventDefault();
988
+ onRowClick(row, rowIndex);
989
+ }
990
+ } : void 0,
991
+ "aria-label": action?.label,
992
+ role: onRowClick ? "button" : void 0,
993
+ tabIndex: onRowClick ? 0 : void 0,
994
+ children: columns.map((col, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
856
995
  "td",
857
996
  {
858
- className: "fractal-sortable-table-td",
997
+ className: cn(
998
+ "fractal-sortable-table-td",
999
+ action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1000
+ ),
859
1001
  style: { width: col.width, textAlign: col.align ?? "left" },
860
- children: col.render(row, rowIndex)
1002
+ children: [
1003
+ col.render(row, rowIndex),
1004
+ action && columnIndex === columns.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
1005
+ ]
861
1006
  },
862
1007
  col.key
863
1008
  ))
@@ -870,23 +1015,39 @@ function SortableTable({
870
1015
  }
871
1016
 
872
1017
  // src/components/Tabs/Tabs.tsx
873
- var import_react3 = require("react");
874
- var import_jsx_runtime14 = require("react/jsx-runtime");
1018
+ var import_react4 = require("react");
1019
+ var import_jsx_runtime16 = require("react/jsx-runtime");
875
1020
  function Tabs({
876
1021
  items,
877
1022
  defaultValue,
878
1023
  value: controlledValue,
879
1024
  onValueChange,
880
1025
  className,
881
- ariaLabel
1026
+ ariaLabel,
1027
+ divider = false
882
1028
  }) {
883
- const reactId = (0, import_react3.useId)();
884
- const [internalValue, setInternalValue] = (0, import_react3.useState)(
1029
+ const reactId = (0, import_react4.useId)();
1030
+ const [internalValue, setInternalValue] = (0, import_react4.useState)(
885
1031
  defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
886
1032
  );
887
1033
  const isControlled = controlledValue !== void 0;
888
1034
  const activeId = isControlled ? controlledValue : internalValue;
889
- const tabRefs = (0, import_react3.useRef)({});
1035
+ const tabListRef = (0, import_react4.useRef)(null);
1036
+ const tabRefs = (0, import_react4.useRef)({});
1037
+ const [indicator, setIndicator] = (0, import_react4.useState)(null);
1038
+ (0, import_react4.useLayoutEffect)(() => {
1039
+ const updateIndicator = () => {
1040
+ const activeTab = tabRefs.current[activeId];
1041
+ if (!activeTab) return;
1042
+ setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
1043
+ };
1044
+ updateIndicator();
1045
+ const list = tabListRef.current;
1046
+ if (!list || typeof ResizeObserver === "undefined") return;
1047
+ const observer = new ResizeObserver(updateIndicator);
1048
+ observer.observe(list);
1049
+ return () => observer.disconnect();
1050
+ }, [activeId, items.length]);
890
1051
  const selectTab = (id) => {
891
1052
  if (isControlled) {
892
1053
  onValueChange?.(id);
@@ -896,6 +1057,10 @@ function Tabs({
896
1057
  }
897
1058
  };
898
1059
  const focusable = items.filter((i) => !i.disabled);
1060
+ const indicatorStyle = indicator ? {
1061
+ "--fractal-tabs-indicator-offset": `${indicator.offset}px`,
1062
+ "--fractal-tabs-indicator-width": `${indicator.width}px`
1063
+ } : void 0;
899
1064
  const onKeyDown = (event) => {
900
1065
  const currentIndex = focusable.findIndex((i) => i.id === activeId);
901
1066
  if (currentIndex === -1) return;
@@ -921,41 +1086,52 @@ function Tabs({
921
1086
  selectTab(nextId2);
922
1087
  requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
923
1088
  };
924
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cn("fractal-tabs", className), children: [
925
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "tablist", "aria-label": ariaLabel, className: "fractal-tabs-list", children: items.map((item) => {
926
- const isActive = item.id === activeId;
927
- const tabId = `${reactId}-tab-${item.id}`;
928
- const panelId = `${reactId}-panel-${item.id}`;
929
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
930
- "button",
931
- {
932
- ref: (el) => {
933
- tabRefs.current[item.id] = el;
934
- },
935
- id: tabId,
936
- role: "tab",
937
- type: "button",
938
- "aria-selected": isActive,
939
- "aria-controls": panelId,
940
- tabIndex: isActive ? 0 : -1,
941
- disabled: item.disabled,
942
- className: cn(
943
- "fractal-tabs-trigger",
944
- isActive && "fractal-tabs-trigger--active",
945
- item.disabled && "fractal-tabs-trigger--disabled"
946
- ),
947
- onClick: () => !item.disabled && selectTab(item.id),
948
- onKeyDown,
949
- children: item.label
950
- },
951
- item.id
952
- );
953
- }) }),
1089
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cn("fractal-tabs", divider && "fractal-tabs--divider", className), children: [
1090
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1091
+ "div",
1092
+ {
1093
+ ref: tabListRef,
1094
+ role: "tablist",
1095
+ "aria-label": ariaLabel,
1096
+ className: "fractal-tabs-list",
1097
+ "data-indicator-ready": indicator ? "true" : void 0,
1098
+ style: indicatorStyle,
1099
+ children: items.map((item) => {
1100
+ const isActive = item.id === activeId;
1101
+ const tabId = `${reactId}-tab-${item.id}`;
1102
+ const panelId = `${reactId}-panel-${item.id}`;
1103
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1104
+ "button",
1105
+ {
1106
+ ref: (el) => {
1107
+ tabRefs.current[item.id] = el;
1108
+ },
1109
+ id: tabId,
1110
+ role: "tab",
1111
+ type: "button",
1112
+ "aria-selected": isActive,
1113
+ "aria-controls": panelId,
1114
+ tabIndex: isActive ? 0 : -1,
1115
+ disabled: item.disabled,
1116
+ className: cn(
1117
+ "fractal-tabs-trigger",
1118
+ isActive && "fractal-tabs-trigger--active",
1119
+ item.disabled && "fractal-tabs-trigger--disabled"
1120
+ ),
1121
+ onClick: () => !item.disabled && selectTab(item.id),
1122
+ onKeyDown,
1123
+ children: item.label
1124
+ },
1125
+ item.id
1126
+ );
1127
+ })
1128
+ }
1129
+ ),
954
1130
  items.map((item) => {
955
1131
  const tabId = `${reactId}-tab-${item.id}`;
956
1132
  const panelId = `${reactId}-panel-${item.id}`;
957
1133
  const isActive = item.id === activeId;
958
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1134
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
959
1135
  "div",
960
1136
  {
961
1137
  id: panelId,
@@ -971,10 +1147,94 @@ function Tabs({
971
1147
  ] });
972
1148
  }
973
1149
 
1150
+ // src/components/ContentSwitcher/ContentSwitcher.tsx
1151
+ var React10 = __toESM(require("react"), 1);
1152
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1153
+ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1154
+ const switcherRef = React10.useRef(null);
1155
+ const buttonRefs = React10.useRef([]);
1156
+ const activeIndex = items.findIndex((item) => item.value === value);
1157
+ React10.useLayoutEffect(() => {
1158
+ const switcher = switcherRef.current;
1159
+ const activeButton = buttonRefs.current[activeIndex];
1160
+ if (!switcher || !activeButton) {
1161
+ switcher?.removeAttribute("data-indicator-ready");
1162
+ return;
1163
+ }
1164
+ const updateIndicator = () => {
1165
+ const switcherRect = switcher.getBoundingClientRect();
1166
+ const activeButtonRect = activeButton.getBoundingClientRect();
1167
+ switcher.style.setProperty("--fractal-content-switcher-indicator-x", `${activeButtonRect.left - switcherRect.left - switcher.clientLeft}px`);
1168
+ switcher.style.setProperty("--fractal-content-switcher-indicator-y", `${activeButtonRect.top - switcherRect.top - switcher.clientTop}px`);
1169
+ switcher.style.setProperty("--fractal-content-switcher-indicator-width", `${activeButtonRect.width}px`);
1170
+ switcher.style.setProperty("--fractal-content-switcher-indicator-height", `${activeButtonRect.height}px`);
1171
+ switcher.setAttribute("data-indicator-ready", "true");
1172
+ };
1173
+ updateIndicator();
1174
+ if (typeof ResizeObserver === "undefined") return;
1175
+ const resizeObserver = new ResizeObserver(updateIndicator);
1176
+ resizeObserver.observe(switcher);
1177
+ buttonRefs.current.forEach((button) => {
1178
+ if (button) resizeObserver.observe(button);
1179
+ });
1180
+ return () => resizeObserver.disconnect();
1181
+ }, [activeIndex, items.length]);
1182
+ const moveFocus = (index, direction) => {
1183
+ let nextIndex = index;
1184
+ do {
1185
+ nextIndex = (nextIndex + direction + items.length) % items.length;
1186
+ } while (items[nextIndex]?.disabled && nextIndex !== index);
1187
+ if (!items[nextIndex]?.disabled) {
1188
+ buttonRefs.current[nextIndex]?.focus();
1189
+ onValueChange(items[nextIndex].value);
1190
+ }
1191
+ };
1192
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1193
+ "div",
1194
+ {
1195
+ className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className),
1196
+ role: "group",
1197
+ "aria-label": ariaLabel,
1198
+ ref: switcherRef,
1199
+ children: [
1200
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
1201
+ items.map((item, index) => {
1202
+ const active = item.value === value;
1203
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1204
+ "button",
1205
+ {
1206
+ className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
1207
+ type: "button",
1208
+ "aria-pressed": active,
1209
+ disabled: item.disabled,
1210
+ onClick: () => onValueChange(item.value),
1211
+ onKeyDown: (event) => {
1212
+ if (event.key === "ArrowRight") {
1213
+ event.preventDefault();
1214
+ moveFocus(index, 1);
1215
+ }
1216
+ if (event.key === "ArrowLeft") {
1217
+ event.preventDefault();
1218
+ moveFocus(index, -1);
1219
+ }
1220
+ },
1221
+ ref: (element) => {
1222
+ buttonRefs.current[index] = element;
1223
+ },
1224
+ children: item.label
1225
+ },
1226
+ item.value
1227
+ );
1228
+ })
1229
+ ]
1230
+ }
1231
+ );
1232
+ }
1233
+
974
1234
  // src/components/Disclosure/Disclosure.tsx
975
- var import_react4 = require("react");
976
- var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
977
- var import_jsx_runtime15 = require("react/jsx-runtime");
1235
+ var import_react5 = require("react");
1236
+ var import_fractal_icons6 = require("@mirror-physics/fractal-icons");
1237
+ var import_jsx_runtime18 = require("react/jsx-runtime");
978
1238
  function Disclosure({
979
1239
  title,
980
1240
  meta,
@@ -982,16 +1242,18 @@ function Disclosure({
982
1242
  defaultOpen = false,
983
1243
  open: controlledOpen,
984
1244
  onOpenChange,
1245
+ disabled = false,
985
1246
  className,
986
1247
  variant = "card"
987
1248
  }) {
988
- const reactId = (0, import_react4.useId)();
1249
+ const reactId = (0, import_react5.useId)();
989
1250
  const headerId = `${reactId}-header`;
990
1251
  const panelId = `${reactId}-panel`;
991
- const [internalOpen, setInternalOpen] = (0, import_react4.useState)(defaultOpen);
1252
+ const [internalOpen, setInternalOpen] = (0, import_react5.useState)(defaultOpen);
992
1253
  const isControlled = controlledOpen !== void 0;
993
1254
  const isOpen = isControlled ? controlledOpen : internalOpen;
994
1255
  const toggle = () => {
1256
+ if (disabled) return;
995
1257
  const next = !isOpen;
996
1258
  if (isControlled) {
997
1259
  onOpenChange?.(next);
@@ -1000,17 +1262,18 @@ function Disclosure({
1000
1262
  onOpenChange?.(next);
1001
1263
  }
1002
1264
  };
1003
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1265
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1004
1266
  "div",
1005
1267
  {
1006
1268
  className: cn(
1007
1269
  "fractal-disclosure",
1008
1270
  variant === "card" && "fractal-disclosure--card",
1009
1271
  isOpen && "fractal-disclosure--open",
1272
+ disabled && "fractal-disclosure--disabled",
1010
1273
  className
1011
1274
  ),
1012
1275
  children: [
1013
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1276
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1014
1277
  "button",
1015
1278
  {
1016
1279
  type: "button",
@@ -1018,15 +1281,16 @@ function Disclosure({
1018
1281
  className: "fractal-disclosure-trigger",
1019
1282
  "aria-expanded": isOpen,
1020
1283
  "aria-controls": panelId,
1284
+ disabled,
1021
1285
  onClick: toggle,
1022
1286
  children: [
1023
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_fractal_icons4.ChevronDown, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_fractal_icons4.ChevronRight, { size: 16 }) }),
1024
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1025
- meta && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1287
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_fractal_icons6.ChevronDown, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_fractal_icons6.ChevronRight, { size: 16 }) }),
1288
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1289
+ meta && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1026
1290
  ]
1027
1291
  }
1028
1292
  ),
1029
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1293
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1030
1294
  "div",
1031
1295
  {
1032
1296
  id: panelId,
@@ -1034,7 +1298,7 @@ function Disclosure({
1034
1298
  "aria-labelledby": headerId,
1035
1299
  className: "fractal-disclosure-panel",
1036
1300
  hidden: !isOpen,
1037
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1301
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1038
1302
  }
1039
1303
  )
1040
1304
  ]
@@ -1042,11 +1306,176 @@ function Disclosure({
1042
1306
  );
1043
1307
  }
1044
1308
 
1309
+ // src/components/LatticeLoader/LatticeLoader.tsx
1310
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1311
+ var LATTICE_COUNT = 160;
1312
+ var WAVE_PERIOD = 80;
1313
+ function LatticeLoader({ className, label = "Loading", ...props }) {
1314
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1315
+ "span",
1316
+ {
1317
+ "aria-label": label,
1318
+ className: cn("fractal-lattice-loader", className),
1319
+ role: "progressbar",
1320
+ ...props,
1321
+ children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1322
+ "span",
1323
+ {
1324
+ "aria-hidden": "true",
1325
+ className: "fractal-lattice-loader__cell",
1326
+ style: { "--fractal-lattice-index": index % WAVE_PERIOD }
1327
+ },
1328
+ index
1329
+ ))
1330
+ }
1331
+ );
1332
+ }
1333
+
1334
+ // src/components/Ghost/Ghost.tsx
1335
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1336
+ var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
1337
+ function Ghost({ className, width, height, radius, style, ...props }) {
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1339
+ "div",
1340
+ {
1341
+ "aria-hidden": "true",
1342
+ className: cn("fractal-ghost", className),
1343
+ style: {
1344
+ width: toCssLength(width),
1345
+ height: toCssLength(height),
1346
+ borderRadius: toCssLength(radius),
1347
+ ...style
1348
+ },
1349
+ ...props
1350
+ }
1351
+ );
1352
+ }
1353
+ function GhostLine({ className, size = "md", width = "100%", ...props }) {
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
1355
+ }
1356
+ function ButtonGhost({ className, size = "md", iconOnly = false, width, ...props }) {
1357
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
1358
+ }
1359
+ function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
1360
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
1361
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: "38%" }),
1362
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: index === lines - 1 ? "62%" : "100%" }, index)) })
1363
+ ] });
1364
+ }
1365
+ function DataTableGhost({
1366
+ className,
1367
+ showHeader = true,
1368
+ headers,
1369
+ columns = 4,
1370
+ rows = 5,
1371
+ columnWidths,
1372
+ size = "md",
1373
+ ...props
1374
+ }) {
1375
+ const cells = Array.from({ length: columns }, (_, index) => index);
1376
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { "aria-busy": "true", "aria-label": "Loading table", className: cn("fractal-ghost-table", `fractal-ghost-table--${size}`, className), role: "status", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("table", { className: "fractal-ghost-table__table", children: [
1377
+ (showHeader || headers) && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tr", { className: "fractal-ghost-table__head-row", children: cells.map((index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("th", { style: { width: columnWidths?.[index] }, children: headers?.[index] ?? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { size: "sm", width: index === columns - 1 ? "62%" : "76%" }) }, index)) }) }),
1378
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tr", { className: "fractal-ghost-table__row", children: cells.map((columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { style: { width: columnWidths?.[columnIndex] }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: `${[72, 54, 82, 63, 46][(rowIndex + columnIndex) % 5]}%` }) }, columnIndex)) }, rowIndex)) })
1379
+ ] }) });
1380
+ }
1381
+ function InputGhost({ className, labelWidth = "26%", ...props }) {
1382
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FormFieldGhost, { className, labelWidth, ...props });
1383
+ }
1384
+ function TextareaGhost({ className, labelWidth = "26%", ...props }) {
1385
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
1386
+ }
1387
+ function LabelGhost({ className, width = "26%", ...props }) {
1388
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
1389
+ }
1390
+ function FormFieldGhost({ className, labelWidth = "26%", multiline = false, ...props }) {
1391
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-field", className), ...props, children: [
1392
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LabelGhost, { width: labelWidth }),
1393
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
1394
+ ] });
1395
+ }
1396
+ function AlertGhost({ className, ...props }) {
1397
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
1398
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: "30%" }),
1399
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { size: "sm", width: "78%" })
1400
+ ] });
1401
+ }
1402
+ function CheckboxGhost({ className, ...props }) {
1403
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
1404
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: "fractal-ghost-choice__control" }),
1405
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: "42%" })
1406
+ ] });
1407
+ }
1408
+ var ToggleGhost = CheckboxGhost;
1409
+ function ChipGhost({ className, width = 74, ...props }) {
1410
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
1411
+ }
1412
+ function LinkGhost({ className, width = 96, ...props }) {
1413
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
1414
+ }
1415
+ var TextButtonGhost = LinkGhost;
1416
+ function DropdownGhost({ className, ...props }) {
1417
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropdown", className), ...props, children: [
1418
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: "38%" }),
1419
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: "fractal-ghost-dropdown__chevron" })
1420
+ ] });
1421
+ }
1422
+ function ContentSwitcherGhost({ className, options = 3, ...props }) {
1423
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { "aria-hidden": "true", className: cn("fractal-ghost-switcher", className), ...props, children: Array.from({ length: options }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, {}, index)) });
1424
+ }
1425
+ var TabsGhost = ContentSwitcherGhost;
1426
+ function DisclosureGhost({ className, ...props }) {
1427
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
1428
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: "fractal-ghost-disclosure__icon" }),
1429
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: "42%" })
1430
+ ] });
1431
+ }
1432
+ function PaginationGhost({ className, pages = 5, ...props }) {
1433
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { "aria-hidden": "true", className: cn("fractal-ghost-pagination", className), ...props, children: Array.from({ length: pages }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, {}, index)) });
1434
+ }
1435
+ function FileDropzoneGhost({ className, ...props }) {
1436
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
1437
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: "fractal-ghost-dropzone__icon" }),
1438
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: "26%" }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { size: "sm", width: "46%" })
1440
+ ] });
1441
+ }
1442
+ function PromptCardGhost({ className, ...props }) {
1443
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
1444
+ }
1445
+ function SortableTableGhost(props) {
1446
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DataTableGhost, { ...props });
1447
+ }
1448
+ function SidebarGhost({ className, items = 6, ...props }) {
1449
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
1450
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: "fractal-ghost-sidebar__brand" }),
1451
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-ghost-sidebar__items", children: Array.from({ length: items }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "fractal-ghost-sidebar__item", children: [
1452
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, {}),
1453
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
1454
+ ] }, index)) })
1455
+ ] });
1456
+ }
1457
+ function ModalGhost({ className, title, lines = 3, ...props }) {
1458
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
1459
+ }
1460
+ function SidePanelGhost({ className, title, lines = 5, ...props }) {
1461
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
1462
+ }
1463
+ function SurfaceGhost({ className, title, lines = 3, ...props }) {
1464
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
1465
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "fractal-ghost-surface__header", children: [
1466
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: "42%" }),
1467
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Ghost, { className: "fractal-ghost-surface__close" })
1468
+ ] }),
1469
+ title && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-ghost-surface__title", children: title }),
1470
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GhostLine, { width: index === lines - 1 ? "64%" : "100%" }, index)) })
1471
+ ] });
1472
+ }
1473
+
1045
1474
  // src/components/Sidebar/Sidebar.tsx
1046
- var React10 = __toESM(require("react"), 1);
1047
- var import_jsx_runtime16 = require("react/jsx-runtime");
1048
- var Sidebar = React10.forwardRef(
1049
- ({ className, width, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1475
+ var React11 = __toESM(require("react"), 1);
1476
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1477
+ var Sidebar = React11.forwardRef(
1478
+ ({ className, width, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1050
1479
  "aside",
1051
1480
  {
1052
1481
  ref,
@@ -1057,24 +1486,47 @@ var Sidebar = React10.forwardRef(
1057
1486
  )
1058
1487
  );
1059
1488
  Sidebar.displayName = "Sidebar";
1060
- var SidebarHeader = React10.forwardRef(
1061
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1489
+ var SidebarHeader = React11.forwardRef(
1490
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1062
1491
  );
1063
1492
  SidebarHeader.displayName = "SidebarHeader";
1064
- var SidebarBrand = React10.forwardRef(
1065
- ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1493
+ var SidebarBrand = React11.forwardRef(
1494
+ ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1066
1495
  );
1067
1496
  SidebarBrand.displayName = "SidebarBrand";
1068
- var SidebarNav = React10.forwardRef(
1069
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1497
+ function SidebarAccountMenu({
1498
+ name,
1499
+ items,
1500
+ onSelect,
1501
+ triggerLabel = "Account menu",
1502
+ className
1503
+ }) {
1504
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1505
+ Dropdown,
1506
+ {
1507
+ align: "left",
1508
+ className: cn("fractal-sidebar__account", className),
1509
+ items,
1510
+ onSelect,
1511
+ panelClassName: "fractal-sidebar__account-panel",
1512
+ selectedValue: "",
1513
+ triggerClassName: "fractal-sidebar__account-trigger",
1514
+ triggerContent: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "fractal-sidebar__account-name", children: name }),
1515
+ triggerLabel,
1516
+ triggerVariant: "tertiary"
1517
+ }
1518
+ );
1519
+ }
1520
+ var SidebarNav = React11.forwardRef(
1521
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1070
1522
  );
1071
1523
  SidebarNav.displayName = "SidebarNav";
1072
- var SidebarSection = React10.forwardRef(
1073
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1524
+ var SidebarSection = React11.forwardRef(
1525
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1074
1526
  );
1075
1527
  SidebarSection.displayName = "SidebarSection";
1076
- var SidebarNavItem = React10.forwardRef(
1077
- ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1528
+ var SidebarNavItem = React11.forwardRef(
1529
+ ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1078
1530
  "button",
1079
1531
  {
1080
1532
  ref,
@@ -1084,52 +1536,314 @@ var SidebarNavItem = React10.forwardRef(
1084
1536
  "aria-current": active ? "page" : void 0,
1085
1537
  ...props,
1086
1538
  children: [
1087
- icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1088
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1089
- endAdornment && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1539
+ icon && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1540
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1541
+ endAdornment && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1090
1542
  ]
1091
1543
  }
1092
1544
  )
1093
1545
  );
1094
1546
  SidebarNavItem.displayName = "SidebarNavItem";
1095
- var SidebarFooter = React10.forwardRef(
1096
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1547
+ var SidebarFooter = React11.forwardRef(
1548
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1097
1549
  );
1098
1550
  SidebarFooter.displayName = "SidebarFooter";
1551
+
1552
+ // src/components/SidePanel/SidePanel.tsx
1553
+ var import_react_dom2 = require("react-dom");
1554
+ var import_fractal_icons7 = require("@mirror-physics/fractal-icons");
1555
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1556
+ function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
1557
+ useEscapeDismiss(80, onClose, open);
1558
+ if (!open) return null;
1559
+ return (0, import_react_dom2.createPortal)(
1560
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1561
+ "aside",
1562
+ {
1563
+ className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
1564
+ "aria-modal": "true",
1565
+ "aria-label": typeof title === "string" ? title : "Side panel",
1566
+ role: "dialog",
1567
+ onMouseDown: (event) => event.stopPropagation(),
1568
+ children: [
1569
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("header", { className: "fractal-side-panel__header", children: [
1570
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "fractal-side-panel__heading", children: [
1571
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { className: "fractal-side-panel__title", children: title }),
1572
+ description && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "fractal-side-panel__description", children: description })
1573
+ ] }),
1574
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_fractal_icons7.Close, { size: 18 }) })
1575
+ ] }),
1576
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "aria-busy": loading || void 0, className: cn("fractal-side-panel__body", loading && "fractal-side-panel__body--loading"), children: loading ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(UILoader, { label: loadingLabel }) : children }),
1577
+ footer && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
1578
+ ]
1579
+ }
1580
+ ) }),
1581
+ document.body
1582
+ );
1583
+ }
1584
+
1585
+ // src/components/Textarea/Textarea.tsx
1586
+ var React12 = __toESM(require("react"), 1);
1587
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1588
+ var Textarea = React12.forwardRef(
1589
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
1590
+ );
1591
+ Textarea.displayName = "Textarea";
1592
+
1593
+ // src/components/TextButton/TextButton.tsx
1594
+ var React13 = __toESM(require("react"), 1);
1595
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1596
+ var TextButton = React13.forwardRef(
1597
+ ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1598
+ "button",
1599
+ {
1600
+ ref,
1601
+ className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
1602
+ type: "button",
1603
+ ...props,
1604
+ children: [
1605
+ icon && iconPosition === "start" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
1606
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children }),
1607
+ icon && iconPosition === "end" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
1608
+ ]
1609
+ }
1610
+ )
1611
+ );
1612
+ TextButton.displayName = "TextButton";
1613
+
1614
+ // src/components/FileDropzone/FileDropzone.tsx
1615
+ var React14 = __toESM(require("react"), 1);
1616
+ var import_fractal_icons8 = require("@mirror-physics/fractal-icons");
1617
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1618
+ function FileDropzone({
1619
+ files,
1620
+ onFilesChange,
1621
+ accept,
1622
+ multiple = true,
1623
+ disabled = false,
1624
+ title = "Drop files here or click to browse",
1625
+ description = "Files stay attached to this record.",
1626
+ className
1627
+ }) {
1628
+ const inputId = React14.useId();
1629
+ const inputRef = React14.useRef(null);
1630
+ const [isDragging, setIsDragging] = React14.useState(false);
1631
+ const addFiles = (nextFiles) => {
1632
+ if (disabled) return;
1633
+ const additions = Array.from(nextFiles);
1634
+ if (additions.length === 0) return;
1635
+ onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
1636
+ };
1637
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("fractal-file-dropzone", className), children: [
1638
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1639
+ "input",
1640
+ {
1641
+ ref: inputRef,
1642
+ id: inputId,
1643
+ className: "fractal-file-dropzone__input",
1644
+ type: "file",
1645
+ accept,
1646
+ multiple,
1647
+ disabled,
1648
+ onChange: (event) => {
1649
+ if (event.target.files) addFiles(event.target.files);
1650
+ event.target.value = "";
1651
+ }
1652
+ }
1653
+ ),
1654
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1655
+ "button",
1656
+ {
1657
+ className: "fractal-file-dropzone__target",
1658
+ "data-dragging": isDragging || void 0,
1659
+ type: "button",
1660
+ disabled,
1661
+ onClick: () => inputRef.current?.click(),
1662
+ onDragEnter: (event) => {
1663
+ event.preventDefault();
1664
+ if (!disabled) setIsDragging(true);
1665
+ },
1666
+ onDragOver: (event) => event.preventDefault(),
1667
+ onDragLeave: (event) => {
1668
+ event.preventDefault();
1669
+ setIsDragging(false);
1670
+ },
1671
+ onDrop: (event) => {
1672
+ event.preventDefault();
1673
+ setIsDragging(false);
1674
+ addFiles(event.dataTransfer.files);
1675
+ },
1676
+ children: [
1677
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_fractal_icons8.FileArrowUp, { "aria-hidden": "true", size: 20 }),
1678
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "fractal-file-dropzone__copy", children: [
1679
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "fractal-file-dropzone__title", children: title }),
1680
+ description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "fractal-file-dropzone__description", children: description })
1681
+ ] })
1682
+ ]
1683
+ }
1684
+ ),
1685
+ files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("li", { className: "fractal-file-dropzone__file", children: [
1686
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
1687
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
1688
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1689
+ "button",
1690
+ {
1691
+ className: "fractal-file-dropzone__remove",
1692
+ type: "button",
1693
+ "aria-label": `Remove ${file.name}`,
1694
+ disabled,
1695
+ onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
1696
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_fractal_icons8.Close, { "aria-hidden": "true", size: 14 })
1697
+ }
1698
+ )
1699
+ ] }, `${file.name}-${file.size}-${index}`)) })
1700
+ ] });
1701
+ }
1702
+ function formatFileSize(bytes) {
1703
+ if (bytes < 1024) return `${bytes} B`;
1704
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
1705
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1706
+ }
1707
+
1708
+ // src/components/Pagination/Pagination.tsx
1709
+ var import_fractal_icons9 = require("@mirror-physics/fractal-icons");
1710
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1711
+ function Pagination({
1712
+ page,
1713
+ pageSize,
1714
+ totalItems,
1715
+ onPageChange,
1716
+ pageSizeOptions,
1717
+ onPageSizeChange,
1718
+ ariaLabel = "Pagination",
1719
+ className
1720
+ }) {
1721
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
1722
+ const currentPage = Math.min(Math.max(page, 1), totalPages);
1723
+ const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
1724
+ const end = Math.min(currentPage * pageSize, totalItems);
1725
+ const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
1726
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
1727
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
1728
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "fractal-pagination__controls", children: [
1729
+ canChangePageSize && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1730
+ Dropdown,
1731
+ {
1732
+ align: "right",
1733
+ className: "fractal-pagination__page-size",
1734
+ direction: "up",
1735
+ items: pageSizeOptions.map((option) => ({
1736
+ value: String(option),
1737
+ description: `${option} per page`
1738
+ })),
1739
+ onSelect: (value) => onPageSizeChange(Number(value)),
1740
+ selectedValue: String(pageSize),
1741
+ size: "sm",
1742
+ triggerLabel: "Results per page",
1743
+ triggerVariant: "tertiary"
1744
+ }
1745
+ ),
1746
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1747
+ "button",
1748
+ {
1749
+ className: "fractal-pagination__button",
1750
+ type: "button",
1751
+ "aria-label": "Previous page",
1752
+ title: "Previous page",
1753
+ disabled: currentPage === 1 || totalItems === 0,
1754
+ onClick: () => onPageChange(currentPage - 1),
1755
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_fractal_icons9.ArrowLeft, { "aria-hidden": "true", size: 16 })
1756
+ }
1757
+ ),
1758
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
1759
+ currentPage,
1760
+ " of ",
1761
+ totalPages
1762
+ ] }),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1764
+ "button",
1765
+ {
1766
+ className: "fractal-pagination__button",
1767
+ type: "button",
1768
+ "aria-label": "Next page",
1769
+ title: "Next page",
1770
+ disabled: currentPage === totalPages || totalItems === 0,
1771
+ onClick: () => onPageChange(currentPage + 1),
1772
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_fractal_icons9.ArrowRight, { "aria-hidden": "true", size: 16 })
1773
+ }
1774
+ )
1775
+ ] })
1776
+ ] });
1777
+ }
1099
1778
  // Annotate the CommonJS export names for ESM import in node:
1100
1779
  0 && (module.exports = {
1101
1780
  Alert,
1102
1781
  AlertDescription,
1782
+ AlertGhost,
1103
1783
  AlertTitle,
1104
1784
  Button,
1785
+ ButtonGhost,
1105
1786
  Card,
1106
1787
  CardContent,
1107
1788
  CardDescription,
1108
1789
  CardFooter,
1790
+ CardGhost,
1109
1791
  CardHeader,
1110
1792
  CardTitle,
1793
+ Checkbox,
1794
+ CheckboxGhost,
1111
1795
  Chip,
1796
+ ChipGhost,
1797
+ ContentSwitcher,
1798
+ ContentSwitcherGhost,
1112
1799
  DataTable,
1800
+ DataTableGhost,
1113
1801
  Disclosure,
1802
+ DisclosureGhost,
1114
1803
  Dropdown,
1804
+ DropdownGhost,
1115
1805
  FeatureCard,
1806
+ FileDropzone,
1807
+ FileDropzoneGhost,
1116
1808
  FolderCard,
1809
+ Ghost,
1810
+ GhostLine,
1117
1811
  Input,
1812
+ InputGhost,
1118
1813
  Label,
1814
+ LabelGhost,
1815
+ LatticeLoader,
1119
1816
  Link,
1817
+ LinkGhost,
1120
1818
  Modal,
1819
+ ModalGhost,
1820
+ Pagination,
1821
+ PaginationGhost,
1121
1822
  PromptCard,
1823
+ PromptCardGhost,
1122
1824
  PromptGrid,
1825
+ SidePanel,
1826
+ SidePanelGhost,
1123
1827
  Sidebar,
1828
+ SidebarAccountMenu,
1124
1829
  SidebarBrand,
1125
1830
  SidebarFooter,
1831
+ SidebarGhost,
1126
1832
  SidebarHeader,
1127
1833
  SidebarNav,
1128
1834
  SidebarNavItem,
1129
1835
  SidebarSection,
1130
1836
  SortableTable,
1837
+ SortableTableGhost,
1131
1838
  Tabs,
1839
+ TabsGhost,
1840
+ TextButton,
1841
+ TextButtonGhost,
1842
+ Textarea,
1843
+ TextareaGhost,
1132
1844
  Toggle,
1845
+ ToggleGhost,
1846
+ UILoader,
1133
1847
  cn,
1134
1848
  useEscapeDismiss
1135
1849
  });