@mirror-physics/fractal-ui 0.2.0-next.76 → 0.2.0-next.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,162 +1,11 @@
1
- // src/components/Button/Button.tsx
2
- import * as React from "react";
3
-
4
- // src/utils/cn.ts
5
- import { clsx } from "clsx";
6
- function cn(...inputs) {
7
- return clsx(inputs);
8
- }
9
-
10
- // src/components/Button/Button.tsx
11
- import { jsxs } from "react/jsx-runtime";
12
- var colorPalette = {
13
- blue: {
14
- 0: "var(--blue-0)",
15
- 50: "var(--blue-50)",
16
- 100: "var(--blue-100)",
17
- 200: "var(--blue-200)",
18
- 500: "var(--blue-500)",
19
- 600: "var(--blue-600)",
20
- 700: "var(--blue-700)"
21
- },
22
- pink: {
23
- 0: "var(--pink-0)",
24
- 50: "var(--pink-50)",
25
- 100: "var(--pink-100)",
26
- 200: "var(--pink-200)",
27
- 500: "var(--pink-500)",
28
- 600: "var(--pink-600)",
29
- 700: "var(--pink-700)"
30
- },
31
- orange: {
32
- 0: "var(--orange-0)",
33
- 50: "var(--orange-50)",
34
- 100: "var(--orange-100)",
35
- 200: "var(--orange-200)",
36
- 500: "var(--orange-500)",
37
- 600: "var(--orange-600)",
38
- 700: "var(--orange-700)"
39
- },
40
- green: {
41
- 0: "var(--green-0)",
42
- 50: "var(--green-50)",
43
- 100: "var(--green-100)",
44
- 200: "var(--green-200)",
45
- 500: "var(--green-500)",
46
- 600: "var(--green-600)",
47
- 700: "var(--green-700)"
48
- }
49
- };
50
- function getButtonStyles(buttonType, isHovered, isActive, disabled, color, hasIconOnly) {
51
- const palette = colorPalette[color];
52
- const base = {
53
- borderRadius: hasIconOnly ? "var(--radius-lg, 8px)" : "var(--radius-full, 9999px)",
54
- cursor: disabled ? "not-allowed" : "pointer",
55
- transition: "background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease"
56
- };
57
- if (hasIconOnly) {
58
- base.justifyContent = "center";
59
- }
60
- if (disabled) {
61
- if (buttonType === "ghost") {
62
- return { ...base, backgroundColor: "transparent", border: "1px solid transparent", color: "var(--fg-disabled)" };
63
- }
64
- return { ...base, backgroundColor: "transparent", border: "1px solid var(--fg-disabled)", color: "var(--fg-disabled)" };
65
- }
66
- switch (buttonType) {
67
- // Primary with text: dark pill. Icon-only: color palette (Synapse style).
68
- case "primary":
69
- if (hasIconOnly) {
70
- return {
71
- ...base,
72
- backgroundColor: isActive ? palette[700] : isHovered ? palette[500] : palette[600],
73
- border: "1px solid transparent",
74
- color: "var(--fg-inverse)"
75
- };
76
- }
77
- return {
78
- ...base,
79
- backgroundColor: "var(--fg-primary)",
80
- border: "1px solid var(--fg-primary)",
81
- color: "var(--fg-inverse)",
82
- ...isHovered || isActive ? { opacity: 0.85 } : {}
83
- };
84
- // Secondary: neutral. Rest=canvas, hover=surface-1 (darken), pressed=surface-2. Subtle border, dark text.
85
- case "secondary":
86
- return {
87
- ...base,
88
- backgroundColor: isActive ? "var(--bg-surface-2)" : isHovered ? "var(--bg-surface-1)" : "var(--bg-canvas)",
89
- border: "1px solid var(--border-subtle)",
90
- color: "var(--fg-primary)"
91
- };
92
- // Ghost: no border. Rest=transparent, hover/press=surface-1.
93
- case "ghost":
94
- return {
95
- ...base,
96
- backgroundColor: isHovered || isActive ? "var(--bg-surface-1)" : "transparent",
97
- border: "1px solid transparent",
98
- color: "var(--fg-primary)"
99
- };
100
- // Danger: low-intensity destructive action. Text stays steady; hover deepens the light red surface.
101
- case "danger":
102
- return {
103
- ...base,
104
- backgroundColor: isHovered || isActive ? "var(--danger-button-surface-hover)" : "var(--danger-button-surface)",
105
- border: "1px solid transparent",
106
- color: "var(--danger-button-fg)"
107
- };
108
- default:
109
- return base;
110
- }
111
- }
112
- var Button = React.forwardRef(
113
- ({ className, buttonType = "primary", buttonSize = "md", controlSize, color = "blue", icon, hasIconOnly, iconPosition = "left", style, disabled, children, ...props }, ref) => {
114
- const [isHovered, setIsHovered] = React.useState(false);
115
- const [isActive, setIsActive] = React.useState(false);
116
- const typeStyles = getButtonStyles(buttonType, isHovered, isActive, !!disabled, color, hasIconOnly);
117
- const hasIconAndText = icon && children && !hasIconOnly;
118
- const finalStyles = hasIconAndText ? { ...typeStyles, gap: "var(--space-2, 8px)", ...style } : { ...typeStyles, ...style };
119
- return /* @__PURE__ */ jsxs(
120
- "button",
121
- {
122
- ref,
123
- type: "button",
124
- "data-control-size": controlSize ?? buttonSize,
125
- "data-icon-only": hasIconOnly || void 0,
126
- className: cn("fractal-control", "fractal-button", `fractal-button--${buttonType}`, className),
127
- style: finalStyles,
128
- disabled,
129
- onMouseEnter: (e) => {
130
- setIsHovered(true);
131
- props.onMouseEnter?.(e);
132
- },
133
- onMouseLeave: (e) => {
134
- setIsHovered(false);
135
- setIsActive(false);
136
- props.onMouseLeave?.(e);
137
- },
138
- onMouseDown: (e) => {
139
- setIsActive(true);
140
- props.onMouseDown?.(e);
141
- },
142
- onMouseUp: (e) => {
143
- setIsActive(false);
144
- props.onMouseUp?.(e);
145
- },
146
- ...props,
147
- children: [
148
- iconPosition !== "right" && icon,
149
- !hasIconOnly && children,
150
- iconPosition === "right" && icon
151
- ]
152
- }
153
- );
154
- }
155
- );
156
- Button.displayName = "Button";
1
+ import {
2
+ Button,
3
+ ColumnEditor,
4
+ cn
5
+ } from "./chunk-QZX655IA.js";
157
6
 
158
7
  // src/components/CodeBlock/CodeBlock.tsx
159
- import { useEffect, useMemo, useRef, useState as useState2 } from "react";
8
+ import { useEffect, useMemo, useRef, useState } from "react";
160
9
  import CodeMirror from "@uiw/react-codemirror";
161
10
  import { HighlightStyle, foldGutter, foldService, syntaxHighlighting } from "@codemirror/language";
162
11
  import { json } from "@codemirror/lang-json";
@@ -169,7 +18,7 @@ import {
169
18
  } from "@codemirror/view";
170
19
  import { tags } from "@lezer/highlight";
171
20
  import { Check, Copy } from "@mirror-physics/fractal-icons";
172
- import { jsx, jsxs as jsxs2 } from "react/jsx-runtime";
21
+ import { jsx, jsxs } from "react/jsx-runtime";
173
22
  var codeTheme = EditorView.theme({
174
23
  "&": {
175
24
  backgroundColor: "transparent",
@@ -412,7 +261,7 @@ function CodeBlock({
412
261
  () => !editable && resolvedLanguage.isJsonLines ? formatJsonLinesForDisplay(value) : value,
413
262
  [editable, resolvedLanguage.isJsonLines, value]
414
263
  );
415
- const [copyStatus, setCopyStatus] = useState2("idle");
264
+ const [copyStatus, setCopyStatus] = useState("idle");
416
265
  const copyResetTimer = useRef(null);
417
266
  useEffect(() => () => {
418
267
  if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
@@ -440,7 +289,7 @@ function CodeBlock({
440
289
  copyResetTimer.current = setTimeout(() => setCopyStatus("idle"), 1800);
441
290
  };
442
291
  const showToolbar = toolbarLabel !== void 0 || copyable || editable;
443
- return /* @__PURE__ */ jsxs2(
292
+ return /* @__PURE__ */ jsxs(
444
293
  "div",
445
294
  {
446
295
  className: cn(
@@ -451,13 +300,13 @@ function CodeBlock({
451
300
  ),
452
301
  ...props,
453
302
  children: [
454
- showToolbar && /* @__PURE__ */ jsxs2("div", { className: "fractal-code-block__toolbar", children: [
455
- /* @__PURE__ */ jsxs2("div", { className: "fractal-code-block__identity", children: [
303
+ showToolbar && /* @__PURE__ */ jsxs("div", { className: "fractal-code-block__toolbar", children: [
304
+ /* @__PURE__ */ jsxs("div", { className: "fractal-code-block__identity", children: [
456
305
  toolbarLabel !== void 0 && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__label", title: typeof toolbarLabel === "string" ? toolbarLabel : void 0, children: toolbarLabel }),
457
306
  fileName && languageLabel && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__language", children: languageLabel }),
458
307
  editable && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__mode", children: "Editing" })
459
308
  ] }),
460
- copyable && /* @__PURE__ */ jsxs2(
309
+ copyable && /* @__PURE__ */ jsxs(
461
310
  "button",
462
311
  {
463
312
  type: "button",
@@ -507,7 +356,7 @@ function CodeBlock({
507
356
 
508
357
  // src/components/Breadcrumbs/Breadcrumbs.tsx
509
358
  import { ChevronRight } from "@mirror-physics/fractal-icons";
510
- import { jsx as jsx2, jsxs as jsxs3 } from "react/jsx-runtime";
359
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
511
360
  function Breadcrumbs({
512
361
  items,
513
362
  ariaLabel = "Breadcrumbs",
@@ -519,7 +368,7 @@ function Breadcrumbs({
519
368
  return /* @__PURE__ */ jsx2("nav", { "aria-label": ariaLabel, className: cn("fractal-breadcrumbs", className), ...props, children: /* @__PURE__ */ jsx2("ol", { className: "fractal-breadcrumbs__list", children: items.map((item, index) => {
520
369
  const isCurrent = index === items.length - 1;
521
370
  const content = isCurrent ? /* @__PURE__ */ jsx2("span", { "aria-current": "page", className: "fractal-breadcrumbs__current", children: item.label }) : /* @__PURE__ */ jsx2("a", { className: "fractal-breadcrumbs__link", href: item.href ?? "#", onClick: item.onClick, children: item.label });
522
- return /* @__PURE__ */ jsxs3("li", { className: "fractal-breadcrumbs__item", children: [
371
+ return /* @__PURE__ */ jsxs2("li", { className: "fractal-breadcrumbs__item", children: [
523
372
  index > 0 && /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: "fractal-breadcrumbs__separator", children: separator }),
524
373
  content
525
374
  ] }, index);
@@ -527,43 +376,43 @@ function Breadcrumbs({
527
376
  }
528
377
 
529
378
  // src/components/Card/Card.tsx
530
- import * as React2 from "react";
379
+ import * as React from "react";
531
380
  import { Folder as FolderIcon } from "@mirror-physics/fractal-icons";
532
- import { jsx as jsx3, jsxs as jsxs4 } from "react/jsx-runtime";
533
- var Card = React2.forwardRef(
381
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
382
+ var Card = React.forwardRef(
534
383
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, "data-fractal-border-surface": "surface-1", className: cn("fractal-card", className), ...props })
535
384
  );
536
385
  Card.displayName = "Card";
537
- var CardHeader = React2.forwardRef(
386
+ var CardHeader = React.forwardRef(
538
387
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-header", className), ...props })
539
388
  );
540
389
  CardHeader.displayName = "CardHeader";
541
- var CardTitle = React2.forwardRef(
390
+ var CardTitle = React.forwardRef(
542
391
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx3("h3", { ref, className: cn("fractal-card-title", className), ...props })
543
392
  );
544
393
  CardTitle.displayName = "CardTitle";
545
- var CardDescription = React2.forwardRef(
394
+ var CardDescription = React.forwardRef(
546
395
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx3("p", { ref, className: cn("fractal-card-description", className), ...props })
547
396
  );
548
397
  CardDescription.displayName = "CardDescription";
549
- var CardContent = React2.forwardRef(
398
+ var CardContent = React.forwardRef(
550
399
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-content", className), ...props })
551
400
  );
552
401
  CardContent.displayName = "CardContent";
553
- var CardFooter = React2.forwardRef(
402
+ var CardFooter = React.forwardRef(
554
403
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-footer", className), ...props })
555
404
  );
556
405
  CardFooter.displayName = "CardFooter";
557
- var FeatureCard = React2.forwardRef(
558
- ({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ jsxs4("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
406
+ var FeatureCard = React.forwardRef(
407
+ ({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ jsxs3("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
559
408
  icon && /* @__PURE__ */ jsx3("div", { className: "fractal-feature-card__icon", children: icon }),
560
409
  /* @__PURE__ */ jsx3("h3", { className: "fractal-feature-card__title", children: title }),
561
410
  /* @__PURE__ */ jsx3("p", { className: "fractal-feature-card__description", children: description })
562
411
  ] })
563
412
  );
564
413
  FeatureCard.displayName = "FeatureCard";
565
- var FolderCard = React2.forwardRef(
566
- ({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ jsxs4(
414
+ var FolderCard = React.forwardRef(
415
+ ({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ jsxs3(
567
416
  "div",
568
417
  {
569
418
  ref,
@@ -579,11 +428,11 @@ var FolderCard = React2.forwardRef(
579
428
  className: cn("fractal-folder-card", selected && "fractal-folder-card--selected", className),
580
429
  ...props,
581
430
  children: [
582
- /* @__PURE__ */ jsxs4("div", { className: "fractal-folder-card__header", children: [
431
+ /* @__PURE__ */ jsxs3("div", { className: "fractal-folder-card__header", children: [
583
432
  /* @__PURE__ */ jsx3(FolderIcon, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
584
433
  /* @__PURE__ */ jsx3("span", { className: "fractal-folder-card__name", children: name })
585
434
  ] }),
586
- sessionCount !== void 0 && /* @__PURE__ */ jsx3("div", { className: "fractal-folder-card__footer", children: /* @__PURE__ */ jsxs4("span", { className: "fractal-folder-card__sessions", children: [
435
+ sessionCount !== void 0 && /* @__PURE__ */ jsx3("div", { className: "fractal-folder-card__footer", children: /* @__PURE__ */ jsxs3("span", { className: "fractal-folder-card__sessions", children: [
587
436
  sessionCount,
588
437
  " ",
589
438
  sessionCount === 1 ? "session" : "sessions"
@@ -595,10 +444,10 @@ var FolderCard = React2.forwardRef(
595
444
  FolderCard.displayName = "FolderCard";
596
445
 
597
446
  // src/components/PromptCard/PromptCard.tsx
598
- import * as React3 from "react";
599
- import { jsx as jsx4, jsxs as jsxs5 } from "react/jsx-runtime";
447
+ import * as React2 from "react";
448
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
600
449
  var titleToPrompt = (title) => typeof title === "string" || typeof title === "number" ? String(title) : "";
601
- var PromptCard = React3.forwardRef(
450
+ var PromptCard = React2.forwardRef(
602
451
  ({
603
452
  title,
604
453
  icon,
@@ -617,7 +466,7 @@ var PromptCard = React3.forwardRef(
617
466
  onPromptSelect?.(prompt ?? titleToPrompt(title));
618
467
  }
619
468
  };
620
- return /* @__PURE__ */ jsxs5(
469
+ return /* @__PURE__ */ jsxs4(
621
470
  "button",
622
471
  {
623
472
  ref,
@@ -640,7 +489,7 @@ var PromptCard = React3.forwardRef(
640
489
  }
641
490
  );
642
491
  PromptCard.displayName = "PromptCard";
643
- var PromptGrid = React3.forwardRef(
492
+ var PromptGrid = React2.forwardRef(
644
493
  ({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ jsx4(
645
494
  "div",
646
495
  {
@@ -658,9 +507,9 @@ var PromptGrid = React3.forwardRef(
658
507
  PromptGrid.displayName = "PromptGrid";
659
508
 
660
509
  // src/components/Input/Input.tsx
661
- import * as React4 from "react";
510
+ import * as React3 from "react";
662
511
  import { jsx as jsx5 } from "react/jsx-runtime";
663
- var Input = React4.forwardRef(
512
+ var Input = React3.forwardRef(
664
513
  ({ className, type, controlSize = "md", ...props }, ref) => /* @__PURE__ */ jsx5(
665
514
  "input",
666
515
  {
@@ -675,10 +524,10 @@ var Input = React4.forwardRef(
675
524
  Input.displayName = "Input";
676
525
 
677
526
  // src/components/TableSearch/TableSearch.tsx
678
- import * as React5 from "react";
527
+ import * as React4 from "react";
679
528
  import { MagnifyingGlass, MagnifyingGlassLines } from "@mirror-physics/fractal-icons";
680
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
681
- var TableSearch = React5.forwardRef(
529
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
530
+ var TableSearch = React4.forwardRef(
682
531
  ({
683
532
  searchType = "text",
684
533
  controlSize = "md",
@@ -690,7 +539,7 @@ var TableSearch = React5.forwardRef(
690
539
  }, ref) => {
691
540
  const isGlob = searchType === "glob";
692
541
  const SearchIcon = isGlob ? MagnifyingGlassLines : MagnifyingGlass;
693
- return /* @__PURE__ */ jsxs6(
542
+ return /* @__PURE__ */ jsxs5(
694
543
  "div",
695
544
  {
696
545
  className: cn("fractal-table-search", className),
@@ -718,9 +567,9 @@ var TableSearch = React5.forwardRef(
718
567
  TableSearch.displayName = "TableSearch";
719
568
 
720
569
  // src/components/NumberInput/NumberInput.tsx
721
- import * as React6 from "react";
570
+ import * as React5 from "react";
722
571
  import { Minus, Plus } from "@mirror-physics/fractal-icons";
723
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
572
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
724
573
  function NumberInput({
725
574
  unit,
726
575
  controlSize = "md",
@@ -733,7 +582,7 @@ function NumberInput({
733
582
  max,
734
583
  ...props
735
584
  }) {
736
- const inputRef = React6.useRef(null);
585
+ const inputRef = React5.useRef(null);
737
586
  const numericValue = Number(value ?? defaultValue);
738
587
  const characterCount = Math.max(String(value ?? defaultValue ?? "").length, 1);
739
588
  const controlLabel = typeof props["aria-label"] === "string" ? props["aria-label"] : "value";
@@ -747,7 +596,7 @@ function NumberInput({
747
596
  input.dispatchEvent(new Event("input", { bubbles: true }));
748
597
  input.focus();
749
598
  };
750
- return /* @__PURE__ */ jsxs7("div", { "data-control-size": controlSize, className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
599
+ return /* @__PURE__ */ jsxs6("div", { "data-control-size": controlSize, className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
751
600
  /* @__PURE__ */ jsx7(
752
601
  Input,
753
602
  {
@@ -772,7 +621,7 @@ function NumberInput({
772
621
  children: unit
773
622
  }
774
623
  ),
775
- /* @__PURE__ */ jsxs7("div", { className: "fractal-number-input-controls", children: [
624
+ /* @__PURE__ */ jsxs6("div", { className: "fractal-number-input-controls", children: [
776
625
  /* @__PURE__ */ jsx7(
777
626
  "button",
778
627
  {
@@ -800,7 +649,7 @@ function NumberInput({
800
649
  }
801
650
 
802
651
  // src/components/Slider/Slider.tsx
803
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
652
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
804
653
  function Slider(props) {
805
654
  const {
806
655
  min = 0,
@@ -846,18 +695,18 @@ function Slider(props) {
846
695
  if (!(event.key in adjustments)) return null;
847
696
  return value + adjustments[event.key];
848
697
  };
849
- return /* @__PURE__ */ jsxs8(
698
+ return /* @__PURE__ */ jsxs7(
850
699
  "div",
851
700
  {
852
701
  className: cn("fractal-slider", disabled && "fractal-slider--disabled", className),
853
702
  "data-disabled": disabled || void 0,
854
703
  "data-knobs": knobs,
855
704
  children: [
856
- showValues && /* @__PURE__ */ jsxs8("div", { className: "fractal-slider-values", "aria-hidden": "true", children: [
705
+ showValues && /* @__PURE__ */ jsxs7("div", { className: "fractal-slider-values", "aria-hidden": "true", children: [
857
706
  /* @__PURE__ */ jsx8("output", { children: formatValue(firstValue) }),
858
707
  knobs === 2 && /* @__PURE__ */ jsx8("output", { children: formatValue(secondValue) })
859
708
  ] }),
860
- /* @__PURE__ */ jsxs8(
709
+ /* @__PURE__ */ jsxs7(
861
710
  "div",
862
711
  {
863
712
  className: "fractal-slider-control",
@@ -926,10 +775,10 @@ function clamp(value, minimum, maximum) {
926
775
  }
927
776
 
928
777
  // src/components/PasswordInput/PasswordInput.tsx
929
- import * as React7 from "react";
778
+ import * as React6 from "react";
930
779
  import { Eye, EyeSlash } from "@mirror-physics/fractal-icons";
931
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
932
- var PasswordInput = React7.forwardRef(
780
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
781
+ var PasswordInput = React6.forwardRef(
933
782
  ({
934
783
  className,
935
784
  controlSize = "md",
@@ -938,9 +787,9 @@ var PasswordInput = React7.forwardRef(
938
787
  hidePasswordLabel = "Hide password",
939
788
  ...props
940
789
  }, ref) => {
941
- const [passwordVisible, setPasswordVisible] = React7.useState(false);
790
+ const [passwordVisible, setPasswordVisible] = React6.useState(false);
942
791
  const toggleLabel = passwordVisible ? hidePasswordLabel : showPasswordLabel;
943
- return /* @__PURE__ */ jsxs9(
792
+ return /* @__PURE__ */ jsxs8(
944
793
  "div",
945
794
  {
946
795
  className: cn("fractal-password-input", className),
@@ -979,9 +828,9 @@ var PasswordInput = React7.forwardRef(
979
828
  PasswordInput.displayName = "PasswordInput";
980
829
 
981
830
  // src/components/Label/Label.tsx
982
- import * as React8 from "react";
831
+ import * as React7 from "react";
983
832
  import { jsx as jsx10 } from "react/jsx-runtime";
984
- var Label = React8.forwardRef(
833
+ var Label = React7.forwardRef(
985
834
  ({ className, controlSize = "md", ...props }, ref) => /* @__PURE__ */ jsx10(
986
835
  "label",
987
836
  {
@@ -995,9 +844,9 @@ var Label = React8.forwardRef(
995
844
  Label.displayName = "Label";
996
845
 
997
846
  // src/components/Alert/Alert.tsx
998
- import * as React9 from "react";
847
+ import * as React8 from "react";
999
848
  import { CircleCheck, CircleClose, CircleInfo, Warning } from "@mirror-physics/fractal-icons";
1000
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
849
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1001
850
  var defaultIcons = {
1002
851
  default: CircleInfo,
1003
852
  info: CircleInfo,
@@ -1005,10 +854,10 @@ var defaultIcons = {
1005
854
  warning: Warning,
1006
855
  error: CircleClose
1007
856
  };
1008
- var Alert = React9.forwardRef(
857
+ var Alert = React8.forwardRef(
1009
858
  ({ className, variant = "default", icon, children, ...props }, ref) => {
1010
859
  const DefaultIcon = defaultIcons[variant];
1011
- return /* @__PURE__ */ jsxs10(
860
+ return /* @__PURE__ */ jsxs9(
1012
861
  "div",
1013
862
  {
1014
863
  ref,
@@ -1024,20 +873,20 @@ var Alert = React9.forwardRef(
1024
873
  }
1025
874
  );
1026
875
  Alert.displayName = "Alert";
1027
- var AlertTitle = React9.forwardRef(
876
+ var AlertTitle = React8.forwardRef(
1028
877
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx11("h5", { ref, className: cn("fractal-alert-title", className), ...props })
1029
878
  );
1030
879
  AlertTitle.displayName = "AlertTitle";
1031
- var AlertDescription = React9.forwardRef(
880
+ var AlertDescription = React8.forwardRef(
1032
881
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx11("div", { ref, className: cn("fractal-alert-description", className), ...props })
1033
882
  );
1034
883
  AlertDescription.displayName = "AlertDescription";
1035
884
 
1036
885
  // src/components/Toast/Toast.tsx
1037
- import * as React10 from "react";
886
+ import * as React9 from "react";
1038
887
  import { createPortal } from "react-dom";
1039
888
  import { CircleCheck as CircleCheck2, CircleClose as CircleClose2, CircleInfo as CircleInfo2, Close, Warning as Warning2 } from "@mirror-physics/fractal-icons";
1040
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
889
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1041
890
  var defaultIcons2 = {
1042
891
  default: CircleInfo2,
1043
892
  info: CircleInfo2,
@@ -1045,7 +894,7 @@ var defaultIcons2 = {
1045
894
  warning: Warning2,
1046
895
  error: CircleClose2
1047
896
  };
1048
- var Toast = React10.forwardRef(function Toast2({
897
+ var Toast = React9.forwardRef(function Toast2({
1049
898
  action,
1050
899
  children,
1051
900
  className,
@@ -1061,20 +910,20 @@ var Toast = React10.forwardRef(function Toast2({
1061
910
  variant = "default",
1062
911
  ...props
1063
912
  }, ref) {
1064
- const [paused, setPaused] = React10.useState(false);
1065
- const dismissRef = React10.useRef(onDismiss);
913
+ const [paused, setPaused] = React9.useState(false);
914
+ const dismissRef = React9.useRef(onDismiss);
1066
915
  const DefaultIcon = defaultIcons2[variant];
1067
916
  const resolvedDuration = duration === void 0 ? variant === "error" ? null : 5e3 : duration;
1068
- React10.useEffect(() => {
917
+ React9.useEffect(() => {
1069
918
  dismissRef.current = onDismiss;
1070
919
  }, [onDismiss]);
1071
- React10.useEffect(() => {
920
+ React9.useEffect(() => {
1072
921
  if (!dismissRef.current || paused || resolvedDuration === null || resolvedDuration <= 0) return;
1073
922
  const timeout = window.setTimeout(() => dismissRef.current?.(), resolvedDuration);
1074
923
  return () => window.clearTimeout(timeout);
1075
924
  }, [paused, resolvedDuration]);
1076
925
  const announcementRole = role ?? (variant === "error" ? "alert" : "status");
1077
- return /* @__PURE__ */ jsxs11(
926
+ return /* @__PURE__ */ jsxs10(
1078
927
  "div",
1079
928
  {
1080
929
  ref,
@@ -1117,7 +966,7 @@ var Toast = React10.forwardRef(function Toast2({
1117
966
  }
1118
967
  );
1119
968
  });
1120
- var ToastViewport = React10.forwardRef(function ToastViewport2({ children, className, portal = true, position = "top-center", ...props }, ref) {
969
+ var ToastViewport = React9.forwardRef(function ToastViewport2({ children, className, portal = true, position = "top-center", ...props }, ref) {
1121
970
  const viewport = /* @__PURE__ */ jsx12(
1122
971
  "div",
1123
972
  {
@@ -1133,9 +982,9 @@ var ToastViewport = React10.forwardRef(function ToastViewport2({ children, class
1133
982
  });
1134
983
 
1135
984
  // src/components/Toggle/Toggle.tsx
1136
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
985
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1137
986
  function Toggle({ checked, onChange, label, className }) {
1138
- return /* @__PURE__ */ jsxs12(
987
+ return /* @__PURE__ */ jsxs11(
1139
988
  "button",
1140
989
  {
1141
990
  type: "button",
@@ -1152,7 +1001,7 @@ function Toggle({ checked, onChange, label, className }) {
1152
1001
  }
1153
1002
 
1154
1003
  // src/components/Modal/Modal.tsx
1155
- import * as React11 from "react";
1004
+ import * as React10 from "react";
1156
1005
  import { createPortal as createPortal2 } from "react-dom";
1157
1006
 
1158
1007
  // src/hooks/useEscapeDismiss.ts
@@ -1207,7 +1056,7 @@ function useEscapeDismiss(priority, handler, enabled = true) {
1207
1056
 
1208
1057
  // src/components/UILoader/UILoader.tsx
1209
1058
  import { useId } from "react";
1210
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1059
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1211
1060
  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";
1212
1061
  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";
1213
1062
  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";
@@ -1224,18 +1073,18 @@ function UILoader({ size = 48, tone = "neutral", className, style, label = "Load
1224
1073
  className: cn("fractal-ui-loader", `fractal-ui-loader--${tone}`, className),
1225
1074
  role: ariaHidden ? void 0 : "status",
1226
1075
  style,
1227
- children: /* @__PURE__ */ jsxs13("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
1228
- /* @__PURE__ */ jsxs13("defs", { children: [
1229
- /* @__PURE__ */ jsxs13("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
1076
+ children: /* @__PURE__ */ jsxs12("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
1077
+ /* @__PURE__ */ jsxs12("defs", { children: [
1078
+ /* @__PURE__ */ jsxs12("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
1230
1079
  /* @__PURE__ */ jsx14("stop", { className: "fractal-ui-loader__stop-start", offset: "0" }),
1231
1080
  /* @__PURE__ */ jsx14("stop", { className: "fractal-ui-loader__stop-end", offset: "1" })
1232
1081
  ] }),
1233
- /* @__PURE__ */ jsxs13("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
1082
+ /* @__PURE__ */ jsxs12("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
1234
1083
  /* @__PURE__ */ jsx14("stop", { offset: "0.4", stopColor: "white", stopOpacity: "0" }),
1235
1084
  /* @__PURE__ */ jsx14("stop", { offset: "0.5", stopColor: "white", stopOpacity: "0.62" }),
1236
1085
  /* @__PURE__ */ jsx14("stop", { offset: "0.6", stopColor: "white", stopOpacity: "0" })
1237
1086
  ] }),
1238
- /* @__PURE__ */ jsxs13("clipPath", { id: clipId, children: [
1087
+ /* @__PURE__ */ jsxs12("clipPath", { id: clipId, children: [
1239
1088
  /* @__PURE__ */ jsx14("path", { d: LEFT }),
1240
1089
  /* @__PURE__ */ jsx14("path", { d: CENTER }),
1241
1090
  /* @__PURE__ */ jsx14("path", { d: RIGHT })
@@ -1251,25 +1100,25 @@ function UILoader({ size = 48, tone = "neutral", className, style, label = "Load
1251
1100
  }
1252
1101
 
1253
1102
  // src/components/Modal/Modal.tsx
1254
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1103
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
1255
1104
  var CloseIcon = () => /* @__PURE__ */ jsx15("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx15("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1256
1105
  function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
1257
- const [bodyScrolled, setBodyScrolled] = React11.useState(false);
1106
+ const [bodyScrolled, setBodyScrolled] = React10.useState(false);
1258
1107
  useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
1259
- React11.useEffect(() => {
1108
+ React10.useEffect(() => {
1260
1109
  if (open) setBodyScrolled(false);
1261
1110
  }, [open]);
1262
1111
  if (!open) return null;
1263
1112
  const sizeClass = `fractal-modal-panel--${size}`;
1264
1113
  const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
1265
1114
  return createPortal2(
1266
- /* @__PURE__ */ jsx15("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ jsxs14(
1115
+ /* @__PURE__ */ jsx15("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ jsxs13(
1267
1116
  "div",
1268
1117
  {
1269
1118
  className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
1270
1119
  onClick: (e) => e.stopPropagation(),
1271
1120
  children: [
1272
- /* @__PURE__ */ jsxs14(
1121
+ /* @__PURE__ */ jsxs13(
1273
1122
  "div",
1274
1123
  {
1275
1124
  className: cn(
@@ -1305,30 +1154,294 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
1305
1154
  );
1306
1155
  }
1307
1156
 
1157
+ // src/components/TableLayout/TableOverflowMenu.tsx
1158
+ import { useId as useId2, useLayoutEffect, useRef as useRef5, useState as useState5 } from "react";
1159
+ import { createPortal as createPortal3 } from "react-dom";
1160
+ import { Ellipsis } from "@mirror-physics/fractal-icons";
1161
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
1162
+ function TableOverflowMenu({ items, label, disabled, onSelect }) {
1163
+ const id = useId2();
1164
+ const trigger = useRef5(null);
1165
+ const panel = useRef5(null);
1166
+ const initialLast = useRef5(false);
1167
+ const [open, setOpen] = useState5(false);
1168
+ const [position, setPosition] = useState5({ top: 0, left: 0 });
1169
+ const buttons = () => [...panel.current?.querySelectorAll("button:not(:disabled)") ?? []];
1170
+ const close = (restore = true) => {
1171
+ setOpen(false);
1172
+ if (restore) trigger.current?.focus({ preventScroll: true });
1173
+ };
1174
+ useEscapeDismiss(100, () => close(), open);
1175
+ useLayoutEffect(() => {
1176
+ if (!open || !trigger.current || !panel.current) return;
1177
+ const place = () => {
1178
+ const anchor = trigger.current.getBoundingClientRect();
1179
+ const menu = panel.current.getBoundingClientRect();
1180
+ const above = window.innerHeight - anchor.bottom < menu.height + 8 && anchor.top > window.innerHeight - anchor.bottom;
1181
+ setPosition({
1182
+ top: Math.max(8, Math.min(above ? anchor.top - menu.height - 4 : anchor.bottom + 4, window.innerHeight - menu.height - 8)),
1183
+ left: Math.max(8, Math.min(anchor.right - menu.width, window.innerWidth - menu.width - 8))
1184
+ });
1185
+ };
1186
+ place();
1187
+ const enabled = buttons();
1188
+ (initialLast.current ? enabled[enabled.length - 1] : enabled[0])?.focus({ preventScroll: true });
1189
+ if (enabled.length === 0) panel.current.focus({ preventScroll: true });
1190
+ const outside = (event) => {
1191
+ if (!panel.current?.contains(event.target) && !trigger.current?.contains(event.target)) setOpen(false);
1192
+ };
1193
+ const scroll = (event) => {
1194
+ if (!panel.current?.contains(event.target)) setOpen(false);
1195
+ };
1196
+ const observer = new ResizeObserver(place);
1197
+ observer.observe(panel.current);
1198
+ document.addEventListener("pointerdown", outside);
1199
+ window.addEventListener("scroll", scroll, true);
1200
+ window.addEventListener("resize", place);
1201
+ return () => {
1202
+ observer.disconnect();
1203
+ document.removeEventListener("pointerdown", outside);
1204
+ window.removeEventListener("scroll", scroll, true);
1205
+ window.removeEventListener("resize", place);
1206
+ };
1207
+ }, [open]);
1208
+ useLayoutEffect(() => {
1209
+ if (disabled || items.length === 0) setOpen(false);
1210
+ }, [disabled, items.length]);
1211
+ if (items.length === 0) return null;
1212
+ return /* @__PURE__ */ jsxs14("div", { className: "fractal-table-overflow-trigger", children: [
1213
+ /* @__PURE__ */ jsx16(
1214
+ Button,
1215
+ {
1216
+ ref: trigger,
1217
+ buttonType: "ghost",
1218
+ controlSize: "sm",
1219
+ hasIconOnly: true,
1220
+ icon: /* @__PURE__ */ jsx16(Ellipsis, { "aria-hidden": true }),
1221
+ "aria-label": label,
1222
+ "aria-haspopup": "menu",
1223
+ "aria-expanded": open,
1224
+ "aria-controls": open ? id : void 0,
1225
+ disabled,
1226
+ onClick: () => {
1227
+ initialLast.current = false;
1228
+ setOpen(!open);
1229
+ },
1230
+ onKeyDown: (event) => {
1231
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1232
+ event.preventDefault();
1233
+ initialLast.current = event.key === "ArrowUp";
1234
+ setOpen(true);
1235
+ }
1236
+ }
1237
+ }
1238
+ ),
1239
+ open && createPortal3(/* @__PURE__ */ jsx16(
1240
+ "div",
1241
+ {
1242
+ ref: panel,
1243
+ id,
1244
+ role: "menu",
1245
+ tabIndex: -1,
1246
+ "aria-label": label,
1247
+ className: "fractal-table-overflow-menu",
1248
+ style: position,
1249
+ onClick: (event) => event.stopPropagation(),
1250
+ onKeyDown: (event) => {
1251
+ event.stopPropagation();
1252
+ const enabled = buttons(), index = enabled.indexOf(document.activeElement);
1253
+ if (event.key === "Escape") {
1254
+ event.preventDefault();
1255
+ close();
1256
+ } else if (event.key === "Tab") {
1257
+ close();
1258
+ } else if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
1259
+ event.preventDefault();
1260
+ const next = event.key === "Home" ? 0 : event.key === "End" ? enabled.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + enabled.length) % enabled.length;
1261
+ enabled[next]?.focus();
1262
+ } else if (event.key.length === 1 && /\S/.test(event.key)) {
1263
+ const ordered = [...enabled.slice(index + 1), ...enabled.slice(0, index + 1)];
1264
+ ordered.find((button) => button.textContent?.trim().toLocaleLowerCase().startsWith(event.key.toLocaleLowerCase()))?.focus();
1265
+ }
1266
+ },
1267
+ children: items.map((item) => /* @__PURE__ */ jsxs14(
1268
+ "button",
1269
+ {
1270
+ type: "button",
1271
+ role: "menuitem",
1272
+ tabIndex: -1,
1273
+ disabled: item.disabled,
1274
+ onClick: () => {
1275
+ onSelect(item.value);
1276
+ close();
1277
+ },
1278
+ children: [
1279
+ item.icon && /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", children: item.icon }),
1280
+ item.label
1281
+ ]
1282
+ },
1283
+ item.value
1284
+ ))
1285
+ }
1286
+ ), document.body)
1287
+ ] });
1288
+ }
1289
+
1290
+ // src/components/TableLayout/TableLayout.tsx
1291
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef6, useState as useState6 } from "react";
1292
+ import { jsx as jsx17 } from "react/jsx-runtime";
1293
+ var length = (value) => typeof value === "number" ? `${value}px` : value;
1294
+ function columnStyle(column) {
1295
+ return {
1296
+ width: column.width,
1297
+ "--table-column-width": !column.width || column.width.includes("%") ? void 0 : `calc(${column.width} - 1px)`,
1298
+ "--table-column-min": length(column.minWidth),
1299
+ "--table-column-max": length(column.maxWidth)
1300
+ };
1301
+ }
1302
+ function useOverflow() {
1303
+ const ref = useRef6(null);
1304
+ const [overflow, setOverflow] = useState6(false);
1305
+ useLayoutEffect2(() => {
1306
+ const el = ref.current;
1307
+ if (!el) return;
1308
+ const measure = () => setOverflow(el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1);
1309
+ const resize = new ResizeObserver(measure);
1310
+ const observe = () => {
1311
+ resize.disconnect();
1312
+ resize.observe(el);
1313
+ for (const child of el.children) resize.observe(child);
1314
+ measure();
1315
+ };
1316
+ const mutation = new MutationObserver(observe);
1317
+ mutation.observe(el, { childList: true, subtree: true, characterData: true });
1318
+ observe();
1319
+ return () => {
1320
+ resize.disconnect();
1321
+ mutation.disconnect();
1322
+ };
1323
+ }, []);
1324
+ return { ref, overflow };
1325
+ }
1326
+ function TableViewport({ children, maxHeight, label }) {
1327
+ const { ref, overflow } = useOverflow();
1328
+ return /* @__PURE__ */ jsx17("div", { ref, className: "fractal-table-viewport", style: { maxHeight }, tabIndex: overflow ? 0 : void 0, role: overflow ? "region" : void 0, "aria-label": overflow ? `${label}, scrollable table` : void 0, children });
1329
+ }
1330
+ function TableCellContent({ children, label }) {
1331
+ const { ref, overflow } = useOverflow();
1332
+ useLayoutEffect2(() => {
1333
+ const cell = ref.current;
1334
+ if (!cell) return;
1335
+ const wheel = (event) => {
1336
+ if (event.defaultPrevented || event.ctrlKey || !event.cancelable || Math.abs(event.deltaX) <= Math.abs(event.deltaY)) return;
1337
+ const range = cell.scrollWidth - cell.clientWidth;
1338
+ if (range <= 1) return;
1339
+ const rtl = getComputedStyle(cell).direction === "rtl";
1340
+ const left = rtl ? -range : 0, right = rtl ? 0 : range;
1341
+ if (event.deltaX > 0 ? cell.scrollLeft < right - 1 : cell.scrollLeft > left + 1) return;
1342
+ const table = cell.closest(".fractal-table-viewport");
1343
+ if (!table) return;
1344
+ const tableRange = table.scrollWidth - table.clientWidth;
1345
+ const tableRtl = getComputedStyle(table).direction === "rtl";
1346
+ const tableLeft = tableRtl ? -tableRange : 0, tableRight = tableRtl ? 0 : tableRange;
1347
+ if (event.deltaX > 0 ? table.scrollLeft >= tableRight - 1 : table.scrollLeft <= tableLeft + 1) return;
1348
+ const unit = event.deltaMode === 1 ? parseFloat(getComputedStyle(cell).lineHeight) || 16 : event.deltaMode === 2 ? table.clientWidth : 1;
1349
+ event.preventDefault();
1350
+ table.scrollLeft += event.deltaX * unit;
1351
+ };
1352
+ cell.addEventListener("wheel", wheel, { passive: false });
1353
+ return () => cell.removeEventListener("wheel", wheel);
1354
+ }, [ref]);
1355
+ return /* @__PURE__ */ jsx17(
1356
+ "div",
1357
+ {
1358
+ ref,
1359
+ className: "fractal-table-cell-scroll",
1360
+ "data-overflow": overflow || void 0,
1361
+ tabIndex: overflow ? 0 : void 0,
1362
+ role: overflow ? "region" : void 0,
1363
+ "aria-label": overflow ? `${label}, scroll horizontally for full content` : void 0,
1364
+ onKeyDown: (event) => {
1365
+ if (!overflow || event.target !== event.currentTarget) return;
1366
+ if (["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) {
1367
+ event.preventDefault();
1368
+ event.stopPropagation();
1369
+ const el = event.currentTarget;
1370
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") el.scrollBy({ left: event.key === "ArrowLeft" ? -40 : 40 });
1371
+ else el.scrollLeft = event.key === "Home" ? 0 : el.scrollWidth * (getComputedStyle(el).direction === "rtl" ? -1 : 1);
1372
+ } else if (event.key === " " || event.key === "Enter") event.stopPropagation();
1373
+ },
1374
+ children: /* @__PURE__ */ jsx17("div", { className: "fractal-table-cell-content", children })
1375
+ }
1376
+ );
1377
+ }
1378
+
1308
1379
  // src/components/DataTable/DataTable.tsx
1309
- import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1310
- function DataTable({ columns, data, emptyMessage, header, size = "md", className }) {
1311
- return /* @__PURE__ */ jsx16("div", { className: cn("fractal-datatable", `fractal-datatable--${size}`, className), children: /* @__PURE__ */ jsxs15("div", { className: "fractal-datatable-surface", children: [
1312
- header && /* @__PURE__ */ jsx16("div", { className: "fractal-datatable-header", children: header }),
1313
- data.length === 0 ? /* @__PURE__ */ jsx16("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsxs15("table", { className: "fractal-datatable-table", children: [
1314
- /* @__PURE__ */ jsx16("thead", { children: /* @__PURE__ */ jsx16("tr", { className: "fractal-datatable-thead-row", children: columns.map((col) => /* @__PURE__ */ jsx16("th", { className: "fractal-datatable-th", style: { width: col.width }, children: col.header }, col.key)) }) }),
1315
- /* @__PURE__ */ jsx16("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsx16(
1380
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1381
+ function DataTable({ columns, data, emptyMessage, header, size = "md", className, overflowMenu, layout = "fill", stickyHeader = false, stickyFirstColumn = false, maxHeight, "aria-label": ariaLabel = "Data table" }) {
1382
+ return /* @__PURE__ */ jsx18("div", { className: cn("fractal-table-layout", "fractal-datatable", `fractal-datatable--${size}`, className), "data-overflow-menu": Boolean(overflowMenu), "data-table-layout": layout, "data-sticky-first": stickyFirstColumn, "data-sticky-header": stickyHeader, children: /* @__PURE__ */ jsxs15("div", { className: "fractal-datatable-surface", children: [
1383
+ header && /* @__PURE__ */ jsx18("div", { className: "fractal-datatable-header", children: header }),
1384
+ data.length === 0 ? /* @__PURE__ */ jsx18("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsx18(TableViewport, { maxHeight, label: ariaLabel, children: /* @__PURE__ */ jsxs15("table", { "aria-label": ariaLabel, className: "fractal-datatable-table", children: [
1385
+ /* @__PURE__ */ jsx18("thead", { children: /* @__PURE__ */ jsxs15("tr", { className: "fractal-datatable-thead-row", children: [
1386
+ columns.map((col, columnIndex) => /* @__PURE__ */ jsx18("th", { scope: "col", className: "fractal-datatable-th", style: columnStyle(col), "data-pinned-column": columnIndex === 0 ? "data" : void 0, children: /* @__PURE__ */ jsx18(TableCellContent, { label: `${col.header} column`, children: col.header }) }, col.key)),
1387
+ overflowMenu && /* @__PURE__ */ jsx18("th", { scope: "col", "aria-label": "Row actions", className: "fractal-datatable-th fractal-table-overflow-cell", "data-pinned-column": "overflow" })
1388
+ ] }) }),
1389
+ /* @__PURE__ */ jsx18("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsxs15(
1316
1390
  "tr",
1317
1391
  {
1318
1392
  className: "fractal-datatable-row",
1319
- children: columns.map((col) => /* @__PURE__ */ jsx16("td", { className: "fractal-datatable-td", style: { width: col.width }, children: col.render(row, rowIndex) }, col.key))
1393
+ children: [
1394
+ columns.map((col, columnIndex) => /* @__PURE__ */ jsx18("td", { className: "fractal-datatable-td", style: columnStyle(col), "data-pinned-column": columnIndex === 0 ? "data" : void 0, children: /* @__PURE__ */ jsx18(TableCellContent, { label: `${col.header || "Value"}, row ${rowIndex + 1}`, children: col.render(row, rowIndex) }) }, col.key)),
1395
+ overflowMenu && /* @__PURE__ */ jsx18("td", { className: "fractal-datatable-td fractal-table-overflow-cell", "data-pinned-column": "overflow", children: /* @__PURE__ */ jsx18(TableOverflowMenu, { items: overflowMenu.items(row, rowIndex), label: overflowMenu.getLabel?.(row, rowIndex) ?? `Actions for row ${rowIndex + 1}`, disabled: overflowMenu.isDisabled?.(row, rowIndex), onSelect: (value) => overflowMenu.onSelect(value, row, rowIndex) }) })
1396
+ ]
1320
1397
  },
1321
1398
  rowIndex
1322
1399
  )) })
1323
- ] })
1400
+ ] }) })
1324
1401
  ] }) });
1325
1402
  }
1326
1403
 
1327
1404
  // src/components/Dropdown/Dropdown.tsx
1328
- import * as React12 from "react";
1405
+ import * as React11 from "react";
1329
1406
  import { ChevronDown, ChevronLeft, ChevronRight as ChevronRight2, ChevronUp } from "@mirror-physics/fractal-icons";
1330
- import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1331
- var MARGIN = 4;
1407
+
1408
+ // src/components/Dropdown/position.ts
1409
+ function positionDropdown(trigger, panel, bounds, direction, align) {
1410
+ const gap = 4;
1411
+ const width = Math.min(panel.width, Math.max(0, bounds.right - bounds.left));
1412
+ let maxHeight = Math.max(0, bounds.bottom - bounds.top);
1413
+ let left;
1414
+ let top;
1415
+ if (direction === "left" || direction === "right") {
1416
+ const after = bounds.right - trigger.right - gap;
1417
+ const before = trigger.left - bounds.left - gap;
1418
+ let placeRight = direction === "right";
1419
+ if (width > (placeRight ? after : before) && (placeRight ? before > after : after > before)) {
1420
+ placeRight = !placeRight;
1421
+ }
1422
+ left = placeRight ? trigger.right + gap : trigger.left - width - gap;
1423
+ top = trigger.top;
1424
+ } else {
1425
+ const below = Math.max(0, bounds.bottom - trigger.bottom - gap);
1426
+ const above = Math.max(0, trigger.top - bounds.top - gap);
1427
+ let placeAbove = direction === "up";
1428
+ if (panel.height > (placeAbove ? above : below) && (placeAbove ? below > above : above > below)) {
1429
+ placeAbove = !placeAbove;
1430
+ }
1431
+ maxHeight = Math.min(maxHeight, placeAbove ? above : below);
1432
+ top = placeAbove ? trigger.top - Math.min(panel.height, maxHeight) - gap : trigger.bottom + gap;
1433
+ left = align === "right" ? trigger.right - width : trigger.left;
1434
+ }
1435
+ const height = Math.min(panel.height, maxHeight);
1436
+ return {
1437
+ left: Math.max(bounds.left, Math.min(left, bounds.right - width)),
1438
+ top: Math.max(bounds.top, Math.min(top, bounds.bottom - height)),
1439
+ maxHeight
1440
+ };
1441
+ }
1442
+
1443
+ // src/components/Dropdown/Dropdown.tsx
1444
+ import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
1332
1445
  function Dropdown({
1333
1446
  items,
1334
1447
  selectedValue,
@@ -1336,6 +1449,8 @@ function Dropdown({
1336
1449
  triggerLabel = "Options",
1337
1450
  direction = "down",
1338
1451
  align = "left",
1452
+ maxHeight = 320,
1453
+ collisionPadding = 8,
1339
1454
  triggerOrientation = "horizontal",
1340
1455
  triggerContent,
1341
1456
  label,
@@ -1352,71 +1467,100 @@ function Dropdown({
1352
1467
  disabled = false
1353
1468
  }) {
1354
1469
  const size = controlSize ?? sizeAlias;
1355
- const [open, setOpen] = React12.useState(false);
1356
- const triggerRef = React12.useRef(null);
1357
- const panelRef = React12.useRef(null);
1358
- const [panelStyle, setPanelStyle] = React12.useState({});
1470
+ const [open, setOpen] = React11.useState(false);
1471
+ const rootRef = React11.useRef(null);
1472
+ const menuId = React11.useId();
1473
+ const focusOnOpen = React11.useRef(false);
1474
+ const triggerRef = React11.useRef(null);
1475
+ const panelRef = React11.useRef(null);
1476
+ const [panelStyle, setPanelStyle] = React11.useState({});
1359
1477
  const visibleItems = items.filter(
1360
1478
  (item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
1361
1479
  );
1362
- if (visibleItems.length === 0) return null;
1363
1480
  const selectableItems = visibleItems.filter((i) => i.kind !== "header");
1364
1481
  const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
1365
- const isUp = direction === "up";
1366
- const isHorizontalDirection = direction === "left" || direction === "right";
1367
1482
  const ChevronIcon = direction === "up" ? ChevronUp : direction === "left" ? ChevronLeft : direction === "right" ? ChevronRight2 : ChevronDown;
1368
- React12.useLayoutEffect(() => {
1369
- if (!open || !triggerRef.current || !panelRef.current) return;
1370
- const triggerRect = triggerRef.current.getBoundingClientRect();
1371
- const panelRect = panelRef.current.getBoundingClientRect();
1372
- const vw = window.innerWidth;
1373
- const vh = window.innerHeight;
1374
- let top;
1375
- let left;
1376
- let right;
1377
- if (isHorizontalDirection) {
1378
- const spaceRight = vw - triggerRect.right - MARGIN;
1379
- const spaceLeft = triggerRect.left - MARGIN;
1380
- let placeRight = direction === "right";
1381
- if (placeRight && panelRect.width > spaceRight && spaceLeft > spaceRight) {
1382
- placeRight = false;
1383
- } else if (!placeRight && panelRect.width > spaceLeft && spaceRight > spaceLeft) {
1384
- placeRight = true;
1385
- }
1386
- left = placeRight ? triggerRect.width + MARGIN : -(panelRect.width + MARGIN);
1387
- top = 0;
1388
- const panelBottom = triggerRect.top + panelRect.height;
1389
- if (panelBottom > vh - MARGIN) top -= panelBottom - (vh - MARGIN);
1390
- if (triggerRect.top + top < MARGIN) top += MARGIN - (triggerRect.top + top);
1391
- } else {
1392
- const spaceBelow = vh - triggerRect.bottom - MARGIN;
1393
- const spaceAbove = triggerRect.top - MARGIN;
1394
- let placeAbove = isUp;
1395
- if (placeAbove && panelRect.height > spaceAbove && spaceBelow > spaceAbove) {
1396
- placeAbove = false;
1397
- } else if (!placeAbove && panelRect.height > spaceBelow && spaceAbove > spaceBelow) {
1398
- placeAbove = true;
1399
- }
1400
- top = placeAbove ? -(panelRect.height + MARGIN) : triggerRect.height + MARGIN;
1401
- if (align === "right") {
1402
- right = 0;
1403
- const panelLeft = triggerRect.right - panelRect.width;
1404
- if (panelLeft < 0) {
1405
- right = void 0;
1406
- left = 0;
1483
+ useEscapeDismiss(100, () => {
1484
+ setOpen(false);
1485
+ triggerRef.current?.focus();
1486
+ }, open);
1487
+ React11.useLayoutEffect(() => {
1488
+ const root = rootRef.current;
1489
+ const trigger = triggerRef.current;
1490
+ const panel = panelRef.current;
1491
+ if (!open || !root || !trigger || !panel) return;
1492
+ const updatePosition = () => {
1493
+ const viewport = window.visualViewport;
1494
+ const bounds = {
1495
+ left: viewport?.offsetLeft ?? 0,
1496
+ top: viewport?.offsetTop ?? 0,
1497
+ right: (viewport?.offsetLeft ?? 0) + (viewport?.width ?? document.documentElement.clientWidth),
1498
+ bottom: (viewport?.offsetTop ?? 0) + (viewport?.height ?? document.documentElement.clientHeight)
1499
+ };
1500
+ for (let ancestor = root.parentElement; ancestor; ancestor = ancestor.parentElement) {
1501
+ const style = getComputedStyle(ancestor);
1502
+ const rect = ancestor.getBoundingClientRect();
1503
+ if (/(auto|scroll|hidden|clip)/.test(style.overflowX)) {
1504
+ bounds.left = Math.max(bounds.left, rect.left + ancestor.clientLeft);
1505
+ bounds.right = Math.min(bounds.right, rect.left + ancestor.clientLeft + ancestor.clientWidth);
1407
1506
  }
1408
- } else {
1409
- left = 0;
1410
- const panelRight = triggerRect.left + panelRect.width;
1411
- if (panelRight > vw) {
1412
- left = void 0;
1413
- right = 0;
1507
+ if (/(auto|scroll|hidden|clip)/.test(style.overflowY)) {
1508
+ bounds.top = Math.max(bounds.top, rect.top + ancestor.clientTop);
1509
+ bounds.bottom = Math.min(bounds.bottom, rect.top + ancestor.clientTop + ancestor.clientHeight);
1414
1510
  }
1415
1511
  }
1512
+ const padding = Math.max(0, collisionPadding);
1513
+ bounds.left += padding;
1514
+ bounds.right = Math.max(bounds.left, bounds.right - padding);
1515
+ bounds.top += padding;
1516
+ bounds.bottom = Math.max(bounds.top, bounds.bottom - padding);
1517
+ const triggerRect = trigger.getBoundingClientRect();
1518
+ const rootRect = root.getBoundingClientRect();
1519
+ const availableWidth = bounds.right - bounds.left;
1520
+ const heightLimit = Math.max(0, maxHeight);
1521
+ panel.style.maxWidth = `${availableWidth}px`;
1522
+ panel.style.minWidth = `${Math.min(triggerRect.width, availableWidth)}px`;
1523
+ const panelRect = panel.getBoundingClientRect();
1524
+ const desiredHeight = Math.min(heightLimit, panel.scrollHeight + panel.offsetHeight - panel.clientHeight);
1525
+ const position = positionDropdown(triggerRect, { width: panelRect.width, height: desiredHeight }, bounds, direction, align);
1526
+ const nextStyle = {
1527
+ left: position.left - rootRect.left - root.clientLeft + root.scrollLeft,
1528
+ top: position.top - rootRect.top - root.clientTop + root.scrollTop,
1529
+ minWidth: Math.min(triggerRect.width, availableWidth),
1530
+ maxWidth: availableWidth,
1531
+ maxHeight: Math.min(heightLimit, position.maxHeight)
1532
+ };
1533
+ for (const key of Object.keys(nextStyle)) {
1534
+ panel.style[key] = `${nextStyle[key]}px`;
1535
+ }
1536
+ setPanelStyle((previous) => Object.entries(nextStyle).every(([key, value]) => previous[key] === value) ? previous : nextStyle);
1537
+ };
1538
+ updatePosition();
1539
+ if (focusOnOpen.current) {
1540
+ focusOnOpen.current = false;
1541
+ const option = panel.querySelector('[aria-selected="true"]') ?? panel.querySelector('[role="option"]');
1542
+ option?.focus({ preventScroll: true });
1543
+ option?.scrollIntoView({ block: "nearest" });
1544
+ }
1545
+ const resize = new ResizeObserver(updatePosition);
1546
+ resize.observe(root);
1547
+ resize.observe(panel);
1548
+ for (let ancestor = root.parentElement; ancestor; ancestor = ancestor.parentElement) {
1549
+ resize.observe(ancestor);
1416
1550
  }
1417
- setPanelStyle({ top, left, right });
1418
- }, [open, direction, isHorizontalDirection, isUp, align]);
1419
- React12.useEffect(() => {
1551
+ window.addEventListener("resize", updatePosition);
1552
+ window.addEventListener("scroll", updatePosition, true);
1553
+ window.visualViewport?.addEventListener("resize", updatePosition);
1554
+ window.visualViewport?.addEventListener("scroll", updatePosition);
1555
+ return () => {
1556
+ resize.disconnect();
1557
+ window.removeEventListener("resize", updatePosition);
1558
+ window.removeEventListener("scroll", updatePosition, true);
1559
+ window.visualViewport?.removeEventListener("resize", updatePosition);
1560
+ window.visualViewport?.removeEventListener("scroll", updatePosition);
1561
+ };
1562
+ }, [open, direction, align, maxHeight, collisionPadding, items, label]);
1563
+ React11.useEffect(() => {
1420
1564
  if (!open) return;
1421
1565
  const handleClickOutside = (e) => {
1422
1566
  const target = e.target;
@@ -1426,7 +1570,8 @@ function Dropdown({
1426
1570
  document.addEventListener("mousedown", handleClickOutside);
1427
1571
  return () => document.removeEventListener("mousedown", handleClickOutside);
1428
1572
  }, [open]);
1429
- return /* @__PURE__ */ jsxs16("div", { "data-control-size": size, className: cn("fractal-dropdown", className), children: [
1573
+ if (visibleItems.length === 0) return null;
1574
+ return /* @__PURE__ */ jsxs16("div", { ref: rootRef, "data-control-size": size, className: cn("fractal-dropdown", className), children: [
1430
1575
  /* @__PURE__ */ jsxs16(
1431
1576
  "button",
1432
1577
  {
@@ -1437,6 +1582,20 @@ function Dropdown({
1437
1582
  disabled,
1438
1583
  "aria-haspopup": "listbox",
1439
1584
  "aria-expanded": open,
1585
+ "aria-controls": open ? menuId : void 0,
1586
+ onKeyDown: (event) => {
1587
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1588
+ event.preventDefault();
1589
+ if (open) {
1590
+ const option = panelRef.current?.querySelector('[aria-selected="true"]') ?? panelRef.current?.querySelector('[role="option"]');
1591
+ option?.focus({ preventScroll: true });
1592
+ option?.scrollIntoView({ block: "nearest" });
1593
+ } else {
1594
+ focusOnOpen.current = true;
1595
+ setOpen(true);
1596
+ }
1597
+ }
1598
+ },
1440
1599
  "aria-label": triggerLabel,
1441
1600
  onClick: () => setOpen((o) => !o),
1442
1601
  className: cn(
@@ -1450,10 +1609,10 @@ function Dropdown({
1450
1609
  ),
1451
1610
  children: [
1452
1611
  triggerContent != null ? triggerContent : /* @__PURE__ */ jsxs16(Fragment2, { children: [
1453
- selected.icon != null && /* @__PURE__ */ jsx17("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
1454
- selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ jsx17("span", { className: "fractal-dropdown-selected-text", children: selected.description })
1612
+ selected.icon != null && /* @__PURE__ */ jsx19("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
1613
+ selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ jsx19("span", { className: "fractal-dropdown-selected-text", children: selected.description })
1455
1614
  ] }),
1456
- !noChevron && !iconOnly && /* @__PURE__ */ jsx17("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ jsx17(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
1615
+ !noChevron && !iconOnly && /* @__PURE__ */ jsx19("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ jsx19(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
1457
1616
  ]
1458
1617
  }
1459
1618
  ),
@@ -1461,24 +1620,34 @@ function Dropdown({
1461
1620
  "div",
1462
1621
  {
1463
1622
  ref: panelRef,
1623
+ id: menuId,
1624
+ onKeyDown: (event) => {
1625
+ if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
1626
+ event.preventDefault();
1627
+ const options = Array.from(panelRef.current?.querySelectorAll('[role="option"]') ?? []);
1628
+ const current = options.indexOf(document.activeElement);
1629
+ const index = event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : (current + (event.key === "ArrowDown" ? 1 : -1) + options.length) % options.length;
1630
+ options[index]?.focus({ preventScroll: true });
1631
+ options[index]?.scrollIntoView({ block: "nearest" });
1632
+ },
1464
1633
  role: "listbox",
1465
1634
  "aria-label": triggerLabel,
1466
1635
  className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
1467
1636
  style: panelStyle,
1468
1637
  children: [
1469
- label != null && /* @__PURE__ */ jsx17("div", { className: "fractal-dropdown-label", children: label }),
1638
+ label != null && /* @__PURE__ */ jsx19("div", { className: "fractal-dropdown-label", children: label }),
1470
1639
  visibleItems.map((item, index) => {
1471
- const topDivider = item.border === "top" ? /* @__PURE__ */ jsx17("div", { className: "fractal-dropdown-separator" }) : null;
1472
- const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ jsx17("div", { className: "fractal-dropdown-separator" }) : null;
1640
+ const topDivider = item.border === "top" ? /* @__PURE__ */ jsx19("div", { className: "fractal-dropdown-separator" }) : null;
1641
+ const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ jsx19("div", { className: "fractal-dropdown-separator" }) : null;
1473
1642
  if (item.kind === "header") {
1474
- return /* @__PURE__ */ jsxs16(React12.Fragment, { children: [
1643
+ return /* @__PURE__ */ jsxs16(React11.Fragment, { children: [
1475
1644
  topDivider,
1476
- /* @__PURE__ */ jsx17("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
1645
+ /* @__PURE__ */ jsx19("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
1477
1646
  bottomDivider
1478
1647
  ] }, `header-${index}`);
1479
1648
  }
1480
1649
  const isSelected = item.value === selectedValue;
1481
- return /* @__PURE__ */ jsxs16(React12.Fragment, { children: [
1650
+ return /* @__PURE__ */ jsxs16(React11.Fragment, { children: [
1482
1651
  topDivider,
1483
1652
  /* @__PURE__ */ jsxs16(
1484
1653
  "button",
@@ -1488,13 +1657,16 @@ function Dropdown({
1488
1657
  "aria-selected": isSelected,
1489
1658
  onClick: () => {
1490
1659
  onSelect(item.value);
1491
- if (closeOnSelect) setOpen(false);
1660
+ if (closeOnSelect) {
1661
+ setOpen(false);
1662
+ triggerRef.current?.focus();
1663
+ }
1492
1664
  },
1493
1665
  className: "fractal-dropdown-option",
1494
1666
  children: [
1495
- item.icon != null && /* @__PURE__ */ jsx17("span", { className: "fractal-dropdown-icon", children: item.icon }),
1496
- item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ jsx17("span", { className: "fractal-dropdown-option-text", children: item.description }),
1497
- item.trailing != null && /* @__PURE__ */ jsx17("span", { className: "fractal-dropdown-trailing", children: item.trailing })
1667
+ item.icon != null && /* @__PURE__ */ jsx19("span", { className: "fractal-dropdown-icon", children: item.icon }),
1668
+ item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ jsx19("span", { className: "fractal-dropdown-option-text", children: item.description }),
1669
+ item.trailing != null && /* @__PURE__ */ jsx19("span", { className: "fractal-dropdown-trailing", children: item.trailing })
1498
1670
  ]
1499
1671
  }
1500
1672
  ),
@@ -1508,10 +1680,10 @@ function Dropdown({
1508
1680
  }
1509
1681
 
1510
1682
  // src/components/Link/Link.tsx
1511
- import * as React13 from "react";
1512
- import { jsx as jsx18 } from "react/jsx-runtime";
1513
- var Link = React13.forwardRef(
1514
- ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ jsx18(
1683
+ import * as React12 from "react";
1684
+ import { jsx as jsx20 } from "react/jsx-runtime";
1685
+ var Link = React12.forwardRef(
1686
+ ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ jsx20(
1515
1687
  "a",
1516
1688
  {
1517
1689
  ref,
@@ -1523,14 +1695,13 @@ var Link = React13.forwardRef(
1523
1695
  Link.displayName = "Link";
1524
1696
 
1525
1697
  // src/components/Chip/Chip.tsx
1526
- import * as React14 from "react";
1527
- import { jsx as jsx19 } from "react/jsx-runtime";
1528
- var Chip = React14.forwardRef(
1529
- ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ jsx19(
1698
+ import * as React13 from "react";
1699
+ import { jsx as jsx21 } from "react/jsx-runtime";
1700
+ var Chip = React13.forwardRef(
1701
+ ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ jsx21(
1530
1702
  "span",
1531
1703
  {
1532
1704
  ref,
1533
- "data-fractal-border-surface": tone === "neutral" ? "surface-2" : void 0,
1534
1705
  className: cn("fractal-chip", `fractal-chip--${tone}`, className),
1535
1706
  ...props
1536
1707
  }
@@ -1540,7 +1711,7 @@ Chip.displayName = "Chip";
1540
1711
 
1541
1712
  // src/components/Checkbox/Checkbox.tsx
1542
1713
  import { Checkbox as CheckboxIcon, CheckboxChecked, Minus as Minus2 } from "@mirror-physics/fractal-icons";
1543
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
1714
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
1544
1715
  function Checkbox({
1545
1716
  checked,
1546
1717
  indeterminate = false,
@@ -1551,7 +1722,7 @@ function Checkbox({
1551
1722
  onKeyDown,
1552
1723
  ...props
1553
1724
  }) {
1554
- return /* @__PURE__ */ jsx20(
1725
+ return /* @__PURE__ */ jsx22(
1555
1726
  "button",
1556
1727
  {
1557
1728
  ...props,
@@ -1574,15 +1745,15 @@ function Checkbox({
1574
1745
  if (event.key === " " || event.key === "Enter") event.stopPropagation();
1575
1746
  },
1576
1747
  children: indeterminate ? /* @__PURE__ */ jsxs17("span", { className: "fractal-checkbox__indeterminate-icon", "aria-hidden": "true", children: [
1577
- /* @__PURE__ */ jsx20(CheckboxIcon, { size: 18 }),
1578
- /* @__PURE__ */ jsx20(Minus2, { className: "fractal-checkbox__indeterminate-mark", size: 12 })
1579
- ] }) : checked ? /* @__PURE__ */ jsx20(CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ jsx20(CheckboxIcon, { "aria-hidden": "true", size: 18 })
1748
+ /* @__PURE__ */ jsx22(CheckboxIcon, { size: 18 }),
1749
+ /* @__PURE__ */ jsx22(Minus2, { className: "fractal-checkbox__indeterminate-mark", size: 12 })
1750
+ ] }) : checked ? /* @__PURE__ */ jsx22(CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ jsx22(CheckboxIcon, { "aria-hidden": "true", size: 18 })
1580
1751
  }
1581
1752
  );
1582
1753
  }
1583
1754
 
1584
1755
  // src/components/Radio/Radio.tsx
1585
- import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
1756
+ import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
1586
1757
  function Radio({
1587
1758
  checked,
1588
1759
  className,
@@ -1593,7 +1764,7 @@ function Radio({
1593
1764
  ...props
1594
1765
  }) {
1595
1766
  return /* @__PURE__ */ jsxs18("label", { className: cn("fractal-radio", disabled && "fractal-radio--disabled", className), children: [
1596
- /* @__PURE__ */ jsx21(
1767
+ /* @__PURE__ */ jsx23(
1597
1768
  "input",
1598
1769
  {
1599
1770
  ...props,
@@ -1604,18 +1775,18 @@ function Radio({
1604
1775
  type: "radio"
1605
1776
  }
1606
1777
  ),
1607
- /* @__PURE__ */ jsx21("span", { "aria-hidden": "true", className: "fractal-radio__control", children: /* @__PURE__ */ jsx21("span", { className: "fractal-radio__dot" }) }),
1778
+ /* @__PURE__ */ jsx23("span", { "aria-hidden": "true", className: "fractal-radio__control", children: /* @__PURE__ */ jsx23("span", { className: "fractal-radio__dot" }) }),
1608
1779
  /* @__PURE__ */ jsxs18("span", { className: "fractal-radio__content", children: [
1609
- /* @__PURE__ */ jsx21("span", { className: "fractal-radio__label", children: label }),
1610
- description && /* @__PURE__ */ jsx21("span", { className: "fractal-radio__description", children: description })
1780
+ /* @__PURE__ */ jsx23("span", { className: "fractal-radio__label", children: label }),
1781
+ description && /* @__PURE__ */ jsx23("span", { className: "fractal-radio__description", children: description })
1611
1782
  ] })
1612
1783
  ] });
1613
1784
  }
1614
1785
 
1615
1786
  // src/components/SortableTable/SortableTable.tsx
1616
- import { useMemo as useMemo2, useState as useState7 } from "react";
1787
+ import { useMemo as useMemo2, useState as useState8 } from "react";
1617
1788
  import { ArrowUp, ArrowDown, ArrowsUpDown } from "@mirror-physics/fractal-icons";
1618
- import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
1789
+ import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
1619
1790
  function SortableTable({
1620
1791
  columns,
1621
1792
  data,
@@ -1624,6 +1795,11 @@ function SortableTable({
1624
1795
  header,
1625
1796
  size = "md",
1626
1797
  embedded = false,
1798
+ layout = "fill",
1799
+ stickyHeader = false,
1800
+ stickyFirstColumn = false,
1801
+ maxHeight,
1802
+ overflowMenu,
1627
1803
  className,
1628
1804
  defaultSort,
1629
1805
  defaultSortKey = void 0,
@@ -1640,8 +1816,8 @@ function SortableTable({
1640
1816
  onRowDoubleClick,
1641
1817
  rowAction
1642
1818
  }) {
1643
- const [internalKey, setInternalKey] = useState7(defaultSortKey ?? null);
1644
- const [internalDirection, setInternalDirection] = useState7(defaultSortDirection);
1819
+ const [internalKey, setInternalKey] = useState8(defaultSortKey ?? null);
1820
+ const [internalDirection, setInternalDirection] = useState8(defaultSortDirection);
1645
1821
  const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
1646
1822
  const activeKey = isControlled ? controlledKey : internalKey;
1647
1823
  const activeDirection = isControlled ? controlledDirection : internalDirection;
@@ -1710,16 +1886,17 @@ function SortableTable({
1710
1886
  onSortChange?.(nextKey, nextDirection);
1711
1887
  }
1712
1888
  };
1713
- return /* @__PURE__ */ jsx22("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), children: /* @__PURE__ */ jsxs19("div", { className: "fractal-sortable-table-surface", children: [
1714
- header && /* @__PURE__ */ jsx22("div", { className: "fractal-sortable-table-header", children: header }),
1715
- visibleRows.length === 0 ? /* @__PURE__ */ jsx22("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsxs19("table", { "aria-label": ariaLabel, className: "fractal-sortable-table-table", children: [
1716
- /* @__PURE__ */ jsx22("thead", { children: /* @__PURE__ */ jsxs19("tr", { className: "fractal-sortable-table-thead-row", children: [
1717
- selection && /* @__PURE__ */ jsx22(
1889
+ return /* @__PURE__ */ jsx24("div", { className: cn("fractal-table-layout", "fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), "data-overflow-menu": Boolean(overflowMenu), "data-table-layout": layout, "data-sticky-first": stickyFirstColumn, "data-sticky-header": stickyHeader, "data-table-selection": Boolean(selection), children: /* @__PURE__ */ jsxs19("div", { className: "fractal-sortable-table-surface", children: [
1890
+ header && /* @__PURE__ */ jsx24("div", { className: "fractal-sortable-table-header", children: header }),
1891
+ visibleRows.length === 0 ? /* @__PURE__ */ jsx24("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsx24(TableViewport, { maxHeight, label: ariaLabel || "Data table", children: /* @__PURE__ */ jsxs19("table", { "aria-label": ariaLabel, className: "fractal-sortable-table-table", children: [
1892
+ /* @__PURE__ */ jsx24("thead", { children: /* @__PURE__ */ jsxs19("tr", { className: "fractal-sortable-table-thead-row", children: [
1893
+ selection && /* @__PURE__ */ jsx24(
1718
1894
  "th",
1719
1895
  {
1720
1896
  className: "fractal-sortable-table-th fractal-sortable-table-selection-cell",
1897
+ "data-pinned-column": "selection",
1721
1898
  scope: "col",
1722
- children: /* @__PURE__ */ jsx22(
1899
+ children: /* @__PURE__ */ jsx24(
1723
1900
  Checkbox,
1724
1901
  {
1725
1902
  "aria-label": selection.selectAllLabel ?? "Select all rows",
@@ -1742,27 +1919,29 @@ function SortableTable({
1742
1919
  )
1743
1920
  }
1744
1921
  ),
1745
- columns.map((col) => {
1922
+ columns.map((col, columnIndex) => {
1746
1923
  const isActive = activeKey === col.key && activeDirection !== null;
1747
1924
  if (!col.sortable) {
1748
- return /* @__PURE__ */ jsx22(
1925
+ return /* @__PURE__ */ jsx24(
1749
1926
  "th",
1750
1927
  {
1751
1928
  className: "fractal-sortable-table-th",
1752
1929
  scope: "col",
1753
- style: { width: col.width },
1754
- children: col.header
1930
+ style: columnStyle(col),
1931
+ "data-pinned-column": columnIndex === 0 ? "data" : void 0,
1932
+ children: /* @__PURE__ */ jsx24(TableCellContent, { label: `${col.header} column`, children: col.header })
1755
1933
  },
1756
1934
  col.key
1757
1935
  );
1758
1936
  }
1759
- return /* @__PURE__ */ jsx22(
1937
+ return /* @__PURE__ */ jsx24(
1760
1938
  "th",
1761
1939
  {
1762
1940
  className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
1763
1941
  scope: "col",
1764
- style: { width: col.width },
1765
- children: /* @__PURE__ */ jsxs19(
1942
+ style: columnStyle(col),
1943
+ "data-pinned-column": columnIndex === 0 ? "data" : void 0,
1944
+ children: /* @__PURE__ */ jsx24(TableCellContent, { label: `${col.header} column`, children: /* @__PURE__ */ jsxs19(
1766
1945
  "button",
1767
1946
  {
1768
1947
  type: "button",
@@ -1773,17 +1952,18 @@ function SortableTable({
1773
1952
  onClick: () => handleSortClick(col.key),
1774
1953
  "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
1775
1954
  children: [
1776
- /* @__PURE__ */ jsx22("span", { children: col.header }),
1777
- /* @__PURE__ */ jsx22("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ jsx22(ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ jsx22(ArrowDown, { size: 14 }) : /* @__PURE__ */ jsx22(ArrowsUpDown, { size: 14 }) })
1955
+ /* @__PURE__ */ jsx24("span", { children: col.header }),
1956
+ /* @__PURE__ */ jsx24("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ jsx24(ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ jsx24(ArrowDown, { size: 14 }) : /* @__PURE__ */ jsx24(ArrowsUpDown, { size: 14 }) })
1778
1957
  ]
1779
1958
  }
1780
- )
1959
+ ) })
1781
1960
  },
1782
1961
  col.key
1783
1962
  );
1784
- })
1963
+ }),
1964
+ overflowMenu && /* @__PURE__ */ jsx24("th", { scope: "col", "aria-label": "Row actions", className: "fractal-sortable-table-th fractal-table-overflow-cell", "data-pinned-column": "overflow" })
1785
1965
  ] }) }),
1786
- /* @__PURE__ */ jsx22("tbody", { children: visibleRows.map((row, rowIndex) => {
1966
+ /* @__PURE__ */ jsx24("tbody", { children: visibleRows.map((row, rowIndex) => {
1787
1967
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
1788
1968
  const disabled = isRowDisabled?.(row) ?? false;
1789
1969
  const selectionDisabled = disabled || (isRowSelectionDisabled?.(row) ?? false);
@@ -1816,7 +1996,7 @@ function SortableTable({
1816
1996
  role: interactive ? "button" : void 0,
1817
1997
  tabIndex: interactive ? 0 : void 0,
1818
1998
  children: [
1819
- selection && /* @__PURE__ */ jsx22("td", { className: "fractal-sortable-table-td fractal-sortable-table-selection-cell", children: /* @__PURE__ */ jsx22(
1999
+ selection && /* @__PURE__ */ jsx24("td", { className: "fractal-sortable-table-td fractal-sortable-table-selection-cell", "data-pinned-column": "selection", children: /* @__PURE__ */ jsx24(
1820
2000
  Checkbox,
1821
2001
  {
1822
2002
  "aria-label": selection.getRowLabel(row),
@@ -1835,26 +2015,39 @@ function SortableTable({
1835
2015
  "fractal-sortable-table-td",
1836
2016
  action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1837
2017
  ),
1838
- style: { width: col.width, textAlign: col.align ?? "left" },
2018
+ style: { ...columnStyle(col), textAlign: col.align ?? "left" },
2019
+ "data-column-align": col.align,
2020
+ "data-pinned-column": columnIndex === 0 ? "data" : void 0,
1839
2021
  children: [
1840
- col.render(row, rowIndex),
1841
- action && columnIndex === columns.length - 1 && /* @__PURE__ */ jsx22("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ jsx22("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
2022
+ /* @__PURE__ */ jsx24(TableCellContent, { label: `${col.header || "Value"}, row ${rowIndex + 1}`, children: col.render(row, rowIndex) }),
2023
+ action && columnIndex === columns.length - 1 && /* @__PURE__ */ jsx24("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ jsx24("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
1842
2024
  ]
1843
2025
  },
1844
2026
  col.key
1845
- ))
2027
+ )),
2028
+ overflowMenu && /* @__PURE__ */ jsx24(
2029
+ "td",
2030
+ {
2031
+ className: "fractal-sortable-table-td fractal-table-overflow-cell",
2032
+ "data-pinned-column": "overflow",
2033
+ onClick: (event) => event.stopPropagation(),
2034
+ onDoubleClick: (event) => event.stopPropagation(),
2035
+ onKeyDown: (event) => event.stopPropagation(),
2036
+ children: /* @__PURE__ */ jsx24(TableOverflowMenu, { items: overflowMenu.items(row, rowIndex), label: overflowMenu.getLabel?.(row, rowIndex) ?? `Actions for row ${rowIndex + 1}`, disabled: disabled || overflowMenu.isDisabled?.(row, rowIndex), onSelect: (value) => overflowMenu.onSelect(value, row, rowIndex) })
2037
+ }
2038
+ )
1846
2039
  ]
1847
2040
  },
1848
2041
  rowIndex
1849
2042
  );
1850
2043
  }) })
1851
- ] })
2044
+ ] }) })
1852
2045
  ] }) });
1853
2046
  }
1854
2047
 
1855
2048
  // src/components/Tabs/Tabs.tsx
1856
- import { useId as useId2, useLayoutEffect as useLayoutEffect2, useRef as useRef6, useState as useState8 } from "react";
1857
- import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
2049
+ import { useId as useId4, useLayoutEffect as useLayoutEffect4, useRef as useRef8, useState as useState9 } from "react";
2050
+ import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
1858
2051
  function Tabs({
1859
2052
  items,
1860
2053
  defaultValue,
@@ -1865,16 +2058,16 @@ function Tabs({
1865
2058
  divider = false,
1866
2059
  variant = "line"
1867
2060
  }) {
1868
- const reactId = useId2();
1869
- const [internalValue, setInternalValue] = useState8(
2061
+ const reactId = useId4();
2062
+ const [internalValue, setInternalValue] = useState9(
1870
2063
  defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
1871
2064
  );
1872
2065
  const isControlled = controlledValue !== void 0;
1873
2066
  const activeId = isControlled ? controlledValue : internalValue;
1874
- const tabListRef = useRef6(null);
1875
- const tabRefs = useRef6({});
1876
- const [indicator, setIndicator] = useState8(null);
1877
- useLayoutEffect2(() => {
2067
+ const tabListRef = useRef8(null);
2068
+ const tabRefs = useRef8({});
2069
+ const [indicator, setIndicator] = useState9(null);
2070
+ useLayoutEffect4(() => {
1878
2071
  const updateIndicator = () => {
1879
2072
  const activeTab = tabRefs.current[activeId];
1880
2073
  if (!activeTab) return;
@@ -1926,7 +2119,7 @@ function Tabs({
1926
2119
  requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
1927
2120
  };
1928
2121
  return /* @__PURE__ */ jsxs20("div", { className: cn("fractal-tabs", `fractal-tabs--${variant}`, divider && "fractal-tabs--divider", className), children: [
1929
- /* @__PURE__ */ jsx23(
2122
+ /* @__PURE__ */ jsx25(
1930
2123
  "div",
1931
2124
  {
1932
2125
  ref: tabListRef,
@@ -1939,7 +2132,7 @@ function Tabs({
1939
2132
  const isActive = item.id === activeId;
1940
2133
  const tabId = `${reactId}-tab-${item.id}`;
1941
2134
  const panelId = `${reactId}-panel-${item.id}`;
1942
- return /* @__PURE__ */ jsx23(
2135
+ return /* @__PURE__ */ jsx25(
1943
2136
  "button",
1944
2137
  {
1945
2138
  ref: (el) => {
@@ -1970,7 +2163,7 @@ function Tabs({
1970
2163
  const tabId = `${reactId}-tab-${item.id}`;
1971
2164
  const panelId = `${reactId}-panel-${item.id}`;
1972
2165
  const isActive = item.id === activeId;
1973
- return /* @__PURE__ */ jsx23(
2166
+ return /* @__PURE__ */ jsx25(
1974
2167
  "div",
1975
2168
  {
1976
2169
  id: panelId,
@@ -1987,14 +2180,14 @@ function Tabs({
1987
2180
  }
1988
2181
 
1989
2182
  // src/components/ContentSwitcher/ContentSwitcher.tsx
1990
- import * as React15 from "react";
1991
- import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
2183
+ import * as React14 from "react";
2184
+ import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
1992
2185
  function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1993
- const switcherRef = React15.useRef(null);
1994
- const buttonRefs = React15.useRef([]);
1995
- const indicatorMotionReadyRef = React15.useRef(false);
2186
+ const switcherRef = React14.useRef(null);
2187
+ const buttonRefs = React14.useRef([]);
2188
+ const indicatorMotionReadyRef = React14.useRef(false);
1996
2189
  const activeIndex = items.findIndex((item) => item.value === value);
1997
- React15.useLayoutEffect(() => {
2190
+ React14.useLayoutEffect(() => {
1998
2191
  const switcher = switcherRef.current;
1999
2192
  const activeButton = buttonRefs.current[activeIndex];
2000
2193
  let motionFrame = 0;
@@ -2054,10 +2247,10 @@ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = f
2054
2247
  "aria-label": ariaLabel,
2055
2248
  ref: switcherRef,
2056
2249
  children: [
2057
- /* @__PURE__ */ jsx24("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
2250
+ /* @__PURE__ */ jsx26("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
2058
2251
  items.map((item, index) => {
2059
2252
  const active = item.value === value;
2060
- return /* @__PURE__ */ jsx24(
2253
+ return /* @__PURE__ */ jsx26(
2061
2254
  "button",
2062
2255
  {
2063
2256
  className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
@@ -2089,9 +2282,9 @@ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = f
2089
2282
  }
2090
2283
 
2091
2284
  // src/components/Disclosure/Disclosure.tsx
2092
- import { useId as useId3, useState as useState9 } from "react";
2285
+ import { useId as useId5, useState as useState10 } from "react";
2093
2286
  import { ChevronRight as ChevronRight3, ChevronDown as ChevronDown2 } from "@mirror-physics/fractal-icons";
2094
- import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
2287
+ import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
2095
2288
  function Disclosure({
2096
2289
  title,
2097
2290
  meta,
@@ -2103,10 +2296,10 @@ function Disclosure({
2103
2296
  className,
2104
2297
  variant = "card"
2105
2298
  }) {
2106
- const reactId = useId3();
2299
+ const reactId = useId5();
2107
2300
  const headerId = `${reactId}-header`;
2108
2301
  const panelId = `${reactId}-panel`;
2109
- const [internalOpen, setInternalOpen] = useState9(defaultOpen);
2302
+ const [internalOpen, setInternalOpen] = useState10(defaultOpen);
2110
2303
  const isControlled = controlledOpen !== void 0;
2111
2304
  const isOpen = isControlled ? controlledOpen : internalOpen;
2112
2305
  const toggle = () => {
@@ -2141,13 +2334,13 @@ function Disclosure({
2141
2334
  disabled,
2142
2335
  onClick: toggle,
2143
2336
  children: [
2144
- /* @__PURE__ */ jsx25("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ jsx25(ChevronDown2, { size: 16 }) : /* @__PURE__ */ jsx25(ChevronRight3, { size: 16 }) }),
2145
- /* @__PURE__ */ jsx25("span", { className: "fractal-disclosure-title", children: title }),
2146
- meta && /* @__PURE__ */ jsx25("span", { className: "fractal-disclosure-meta", children: meta })
2337
+ /* @__PURE__ */ jsx27("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ jsx27(ChevronDown2, { size: 16 }) : /* @__PURE__ */ jsx27(ChevronRight3, { size: 16 }) }),
2338
+ /* @__PURE__ */ jsx27("span", { className: "fractal-disclosure-title", children: title }),
2339
+ meta && /* @__PURE__ */ jsx27("span", { className: "fractal-disclosure-meta", children: meta })
2147
2340
  ]
2148
2341
  }
2149
2342
  ),
2150
- /* @__PURE__ */ jsx25(
2343
+ /* @__PURE__ */ jsx27(
2151
2344
  "div",
2152
2345
  {
2153
2346
  id: panelId,
@@ -2155,7 +2348,7 @@ function Disclosure({
2155
2348
  "aria-labelledby": headerId,
2156
2349
  className: "fractal-disclosure-panel",
2157
2350
  hidden: !isOpen,
2158
- children: /* @__PURE__ */ jsx25("div", { className: "fractal-disclosure-panel-inner", children })
2351
+ children: /* @__PURE__ */ jsx27("div", { className: "fractal-disclosure-panel-inner", children })
2159
2352
  }
2160
2353
  )
2161
2354
  ]
@@ -2164,18 +2357,18 @@ function Disclosure({
2164
2357
  }
2165
2358
 
2166
2359
  // src/components/LatticeLoader/LatticeLoader.tsx
2167
- import { jsx as jsx26 } from "react/jsx-runtime";
2360
+ import { jsx as jsx28 } from "react/jsx-runtime";
2168
2361
  var LATTICE_COUNT = 160;
2169
2362
  var WAVE_PERIOD = 80;
2170
2363
  function LatticeLoader({ className, label = "Loading", ...props }) {
2171
- return /* @__PURE__ */ jsx26(
2364
+ return /* @__PURE__ */ jsx28(
2172
2365
  "span",
2173
2366
  {
2174
2367
  "aria-label": label,
2175
2368
  className: cn("fractal-lattice-loader", className),
2176
2369
  role: "progressbar",
2177
2370
  ...props,
2178
- children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ jsx26(
2371
+ children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ jsx28(
2179
2372
  "span",
2180
2373
  {
2181
2374
  "aria-hidden": "true",
@@ -2189,10 +2382,10 @@ function LatticeLoader({ className, label = "Loading", ...props }) {
2189
2382
  }
2190
2383
 
2191
2384
  // src/components/Ghost/Ghost.tsx
2192
- import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
2385
+ import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
2193
2386
  var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
2194
2387
  function Ghost({ className, width, height, radius, style, ...props }) {
2195
- return /* @__PURE__ */ jsx27(
2388
+ return /* @__PURE__ */ jsx29(
2196
2389
  "div",
2197
2390
  {
2198
2391
  "aria-hidden": "true",
@@ -2208,15 +2401,15 @@ function Ghost({ className, width, height, radius, style, ...props }) {
2208
2401
  );
2209
2402
  }
2210
2403
  function GhostLine({ className, size = "md", width = "100%", ...props }) {
2211
- return /* @__PURE__ */ jsx27(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
2404
+ return /* @__PURE__ */ jsx29(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
2212
2405
  }
2213
2406
  function ButtonGhost({ className, size = "md", controlSize, iconOnly = false, width, ...props }) {
2214
- return /* @__PURE__ */ jsx27(Ghost, { "data-control-size": controlSize ?? size, className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
2407
+ return /* @__PURE__ */ jsx29(Ghost, { "data-control-size": controlSize ?? size, className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
2215
2408
  }
2216
2409
  function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
2217
2410
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
2218
- showHeader && /* @__PURE__ */ jsx27(GhostLine, { width: "38%" }),
2219
- /* @__PURE__ */ jsx27("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx27(GhostLine, { width: index === lines - 1 ? "62%" : "100%" }, index)) })
2411
+ showHeader && /* @__PURE__ */ jsx29(GhostLine, { width: "38%" }),
2412
+ /* @__PURE__ */ jsx29("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx29(GhostLine, { width: index === lines - 1 ? "62%" : "100%" }, index)) })
2220
2413
  ] });
2221
2414
  }
2222
2415
  function DataTableGhost({
@@ -2230,74 +2423,74 @@ function DataTableGhost({
2230
2423
  ...props
2231
2424
  }) {
2232
2425
  const cells = Array.from({ length: columns }, (_, index) => index);
2233
- return /* @__PURE__ */ jsx27("div", { "aria-busy": "true", "aria-label": "Loading table", className: cn("fractal-ghost-table", `fractal-ghost-table--${size}`, className), role: "status", ...props, children: /* @__PURE__ */ jsxs23("table", { className: "fractal-ghost-table__table", children: [
2234
- (showHeader || headers) && /* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsx27("tr", { className: "fractal-ghost-table__head-row", children: cells.map((index) => /* @__PURE__ */ jsx27("th", { style: { width: columnWidths?.[index] }, children: headers?.[index] ?? /* @__PURE__ */ jsx27(GhostLine, { size: "sm", width: index === columns - 1 ? "62%" : "76%" }) }, index)) }) }),
2235
- /* @__PURE__ */ jsx27("tbody", { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ jsx27("tr", { className: "fractal-ghost-table__row", children: cells.map((columnIndex) => /* @__PURE__ */ jsx27("td", { style: { width: columnWidths?.[columnIndex] }, children: /* @__PURE__ */ jsx27(GhostLine, { width: `${[72, 54, 82, 63, 46][(rowIndex + columnIndex) % 5]}%` }) }, columnIndex)) }, rowIndex)) })
2426
+ return /* @__PURE__ */ jsx29("div", { "aria-busy": "true", "aria-label": "Loading table", className: cn("fractal-ghost-table", `fractal-ghost-table--${size}`, className), role: "status", ...props, children: /* @__PURE__ */ jsxs23("table", { className: "fractal-ghost-table__table", children: [
2427
+ (showHeader || headers) && /* @__PURE__ */ jsx29("thead", { children: /* @__PURE__ */ jsx29("tr", { className: "fractal-ghost-table__head-row", children: cells.map((index) => /* @__PURE__ */ jsx29("th", { style: { width: columnWidths?.[index] }, children: headers?.[index] ?? /* @__PURE__ */ jsx29(GhostLine, { size: "sm", width: index === columns - 1 ? "62%" : "76%" }) }, index)) }) }),
2428
+ /* @__PURE__ */ jsx29("tbody", { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ jsx29("tr", { className: "fractal-ghost-table__row", children: cells.map((columnIndex) => /* @__PURE__ */ jsx29("td", { style: { width: columnWidths?.[columnIndex] }, children: /* @__PURE__ */ jsx29(GhostLine, { width: `${[72, 54, 82, 63, 46][(rowIndex + columnIndex) % 5]}%` }) }, columnIndex)) }, rowIndex)) })
2236
2429
  ] }) });
2237
2430
  }
2238
2431
  function InputGhost({ className, labelWidth = "26%", ...props }) {
2239
- return /* @__PURE__ */ jsx27(FormFieldGhost, { className, labelWidth, ...props });
2432
+ return /* @__PURE__ */ jsx29(FormFieldGhost, { className, labelWidth, ...props });
2240
2433
  }
2241
2434
  function TextareaGhost({ className, labelWidth = "26%", ...props }) {
2242
- return /* @__PURE__ */ jsx27(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
2435
+ return /* @__PURE__ */ jsx29(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
2243
2436
  }
2244
2437
  function LabelGhost({ className, width = "26%", ...props }) {
2245
- return /* @__PURE__ */ jsx27(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
2438
+ return /* @__PURE__ */ jsx29(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
2246
2439
  }
2247
2440
  function FormFieldGhost({ className, labelWidth = "26%", multiline = false, controlSize = "md", ...props }) {
2248
2441
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", "data-control-size": controlSize, className: cn("fractal-ghost-field", className), ...props, children: [
2249
- /* @__PURE__ */ jsx27(LabelGhost, { width: labelWidth }),
2250
- /* @__PURE__ */ jsx27(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
2442
+ /* @__PURE__ */ jsx29(LabelGhost, { width: labelWidth }),
2443
+ /* @__PURE__ */ jsx29(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
2251
2444
  ] });
2252
2445
  }
2253
2446
  function AlertGhost({ className, ...props }) {
2254
2447
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
2255
- /* @__PURE__ */ jsx27(GhostLine, { width: "30%" }),
2256
- /* @__PURE__ */ jsx27(GhostLine, { size: "sm", width: "78%" })
2448
+ /* @__PURE__ */ jsx29(GhostLine, { width: "30%" }),
2449
+ /* @__PURE__ */ jsx29(GhostLine, { size: "sm", width: "78%" })
2257
2450
  ] });
2258
2451
  }
2259
2452
  function CheckboxGhost({ className, ...props }) {
2260
2453
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
2261
- /* @__PURE__ */ jsx27(Ghost, { className: "fractal-ghost-choice__control" }),
2262
- /* @__PURE__ */ jsx27(GhostLine, { width: "42%" })
2454
+ /* @__PURE__ */ jsx29(Ghost, { className: "fractal-ghost-choice__control" }),
2455
+ /* @__PURE__ */ jsx29(GhostLine, { width: "42%" })
2263
2456
  ] });
2264
2457
  }
2265
2458
  var ToggleGhost = CheckboxGhost;
2266
2459
  function ChipGhost({ className, width = 74, ...props }) {
2267
- return /* @__PURE__ */ jsx27(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
2460
+ return /* @__PURE__ */ jsx29(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
2268
2461
  }
2269
2462
  function LinkGhost({ className, width = 96, ...props }) {
2270
- return /* @__PURE__ */ jsx27(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
2463
+ return /* @__PURE__ */ jsx29(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
2271
2464
  }
2272
2465
  var TextButtonGhost = LinkGhost;
2273
2466
  function DropdownGhost({ className, controlSize = "md", ...props }) {
2274
2467
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", "data-control-size": controlSize, className: cn("fractal-ghost-dropdown", className), ...props, children: [
2275
- /* @__PURE__ */ jsx27(GhostLine, { width: "38%" }),
2276
- /* @__PURE__ */ jsx27(Ghost, { className: "fractal-ghost-dropdown__chevron" })
2468
+ /* @__PURE__ */ jsx29(GhostLine, { width: "38%" }),
2469
+ /* @__PURE__ */ jsx29(Ghost, { className: "fractal-ghost-dropdown__chevron" })
2277
2470
  ] });
2278
2471
  }
2279
2472
  function ContentSwitcherGhost({ className, options = 3, ...props }) {
2280
- return /* @__PURE__ */ jsx27("div", { "aria-hidden": "true", className: cn("fractal-ghost-switcher", className), ...props, children: Array.from({ length: options }, (_, index) => /* @__PURE__ */ jsx27(Ghost, {}, index)) });
2473
+ return /* @__PURE__ */ jsx29("div", { "aria-hidden": "true", className: cn("fractal-ghost-switcher", className), ...props, children: Array.from({ length: options }, (_, index) => /* @__PURE__ */ jsx29(Ghost, {}, index)) });
2281
2474
  }
2282
2475
  var TabsGhost = ContentSwitcherGhost;
2283
2476
  function DisclosureGhost({ className, ...props }) {
2284
2477
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
2285
- /* @__PURE__ */ jsx27(Ghost, { className: "fractal-ghost-disclosure__icon" }),
2286
- /* @__PURE__ */ jsx27(GhostLine, { width: "42%" })
2478
+ /* @__PURE__ */ jsx29(Ghost, { className: "fractal-ghost-disclosure__icon" }),
2479
+ /* @__PURE__ */ jsx29(GhostLine, { width: "42%" })
2287
2480
  ] });
2288
2481
  }
2289
2482
  function PaginationGhost({ className, pages = 5, ...props }) {
2290
- return /* @__PURE__ */ jsx27("div", { "aria-hidden": "true", className: cn("fractal-ghost-pagination", className), ...props, children: Array.from({ length: pages }, (_, index) => /* @__PURE__ */ jsx27(Ghost, {}, index)) });
2483
+ return /* @__PURE__ */ jsx29("div", { "aria-hidden": "true", className: cn("fractal-ghost-pagination", className), ...props, children: Array.from({ length: pages }, (_, index) => /* @__PURE__ */ jsx29(Ghost, {}, index)) });
2291
2484
  }
2292
2485
  function FileDropzoneGhost({ className, ...props }) {
2293
2486
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
2294
- /* @__PURE__ */ jsx27(Ghost, { className: "fractal-ghost-dropzone__icon" }),
2295
- /* @__PURE__ */ jsx27(GhostLine, { width: "26%" }),
2296
- /* @__PURE__ */ jsx27(GhostLine, { size: "sm", width: "46%" })
2487
+ /* @__PURE__ */ jsx29(Ghost, { className: "fractal-ghost-dropzone__icon" }),
2488
+ /* @__PURE__ */ jsx29(GhostLine, { width: "26%" }),
2489
+ /* @__PURE__ */ jsx29(GhostLine, { size: "sm", width: "46%" })
2297
2490
  ] });
2298
2491
  }
2299
2492
  function PromptCardGhost({ className, ...props }) {
2300
- return /* @__PURE__ */ jsx27(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
2493
+ return /* @__PURE__ */ jsx29(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
2301
2494
  }
2302
2495
  function ConversationGhost({
2303
2496
  className,
@@ -2313,54 +2506,54 @@ function ConversationGhost({
2313
2506
  role: "status",
2314
2507
  ...props,
2315
2508
  children: [
2316
- /* @__PURE__ */ jsx27("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--user", children: /* @__PURE__ */ jsxs23("div", { className: "fractal-ghost-conversation__bubble", children: [
2317
- /* @__PURE__ */ jsx27(GhostLine, { width: "100%" }),
2318
- /* @__PURE__ */ jsx27(GhostLine, { width: "86%" }),
2319
- /* @__PURE__ */ jsx27(GhostLine, { width: "64%" })
2509
+ /* @__PURE__ */ jsx29("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--user", children: /* @__PURE__ */ jsxs23("div", { className: "fractal-ghost-conversation__bubble", children: [
2510
+ /* @__PURE__ */ jsx29(GhostLine, { width: "100%" }),
2511
+ /* @__PURE__ */ jsx29(GhostLine, { width: "86%" }),
2512
+ /* @__PURE__ */ jsx29(GhostLine, { width: "64%" })
2320
2513
  ] }) }),
2321
2514
  /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--assistant", children: [
2322
- /* @__PURE__ */ jsx27(GhostLine, { width: "92%" }),
2323
- /* @__PURE__ */ jsx27(GhostLine, { width: "78%" }),
2324
- /* @__PURE__ */ jsx27(GhostLine, { width: "58%" })
2515
+ /* @__PURE__ */ jsx29(GhostLine, { width: "92%" }),
2516
+ /* @__PURE__ */ jsx29(GhostLine, { width: "78%" }),
2517
+ /* @__PURE__ */ jsx29(GhostLine, { width: "58%" })
2325
2518
  ] })
2326
2519
  ]
2327
2520
  }
2328
2521
  );
2329
2522
  }
2330
2523
  function SortableTableGhost(props) {
2331
- return /* @__PURE__ */ jsx27(DataTableGhost, { ...props });
2524
+ return /* @__PURE__ */ jsx29(DataTableGhost, { ...props });
2332
2525
  }
2333
2526
  function SidebarGhost({ className, items = 6, ...props }) {
2334
2527
  return /* @__PURE__ */ jsxs23("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
2335
- /* @__PURE__ */ jsx27(Ghost, { className: "fractal-ghost-sidebar__brand" }),
2336
- /* @__PURE__ */ jsx27("div", { className: "fractal-ghost-sidebar__items", children: Array.from({ length: items }, (_, index) => /* @__PURE__ */ jsxs23("div", { className: "fractal-ghost-sidebar__item", children: [
2337
- /* @__PURE__ */ jsx27(Ghost, {}),
2338
- /* @__PURE__ */ jsx27(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
2528
+ /* @__PURE__ */ jsx29(Ghost, { className: "fractal-ghost-sidebar__brand" }),
2529
+ /* @__PURE__ */ jsx29("div", { className: "fractal-ghost-sidebar__items", children: Array.from({ length: items }, (_, index) => /* @__PURE__ */ jsxs23("div", { className: "fractal-ghost-sidebar__item", children: [
2530
+ /* @__PURE__ */ jsx29(Ghost, {}),
2531
+ /* @__PURE__ */ jsx29(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
2339
2532
  ] }, index)) })
2340
2533
  ] });
2341
2534
  }
2342
2535
  function ModalGhost({ className, title, lines = 3, ...props }) {
2343
- return /* @__PURE__ */ jsx27(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
2536
+ return /* @__PURE__ */ jsx29(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
2344
2537
  }
2345
2538
  function SidePanelGhost({ className, title, lines = 5, ...props }) {
2346
- return /* @__PURE__ */ jsx27(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
2539
+ return /* @__PURE__ */ jsx29(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
2347
2540
  }
2348
2541
  function SurfaceGhost({ className, title, lines = 3, ...props }) {
2349
2542
  return /* @__PURE__ */ jsxs23("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
2350
2543
  /* @__PURE__ */ jsxs23("div", { className: "fractal-ghost-surface__header", children: [
2351
- /* @__PURE__ */ jsx27(GhostLine, { width: "42%" }),
2352
- /* @__PURE__ */ jsx27(Ghost, { className: "fractal-ghost-surface__close" })
2544
+ /* @__PURE__ */ jsx29(GhostLine, { width: "42%" }),
2545
+ /* @__PURE__ */ jsx29(Ghost, { className: "fractal-ghost-surface__close" })
2353
2546
  ] }),
2354
- title && /* @__PURE__ */ jsx27("div", { className: "fractal-ghost-surface__title", children: title }),
2355
- /* @__PURE__ */ jsx27("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx27(GhostLine, { width: index === lines - 1 ? "64%" : "100%" }, index)) })
2547
+ title && /* @__PURE__ */ jsx29("div", { className: "fractal-ghost-surface__title", children: title }),
2548
+ /* @__PURE__ */ jsx29("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx29(GhostLine, { width: index === lines - 1 ? "64%" : "100%" }, index)) })
2356
2549
  ] });
2357
2550
  }
2358
2551
 
2359
2552
  // src/components/Sidebar/Sidebar.tsx
2360
- import * as React16 from "react";
2361
- import { Fragment as Fragment3, jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
2362
- var Sidebar = React16.forwardRef(
2363
- ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ jsx28(
2553
+ import * as React15 from "react";
2554
+ import { Fragment as Fragment3, jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
2555
+ var Sidebar = React15.forwardRef(
2556
+ ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ jsx30(
2364
2557
  "aside",
2365
2558
  {
2366
2559
  ref,
@@ -2372,12 +2565,12 @@ var Sidebar = React16.forwardRef(
2372
2565
  )
2373
2566
  );
2374
2567
  Sidebar.displayName = "Sidebar";
2375
- var SidebarHeader = React16.forwardRef(
2376
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx28("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
2568
+ var SidebarHeader = React15.forwardRef(
2569
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx30("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
2377
2570
  );
2378
2571
  SidebarHeader.displayName = "SidebarHeader";
2379
- var SidebarBrand = React16.forwardRef(
2380
- ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ jsx28("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
2572
+ var SidebarBrand = React15.forwardRef(
2573
+ ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ jsx30("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
2381
2574
  );
2382
2575
  SidebarBrand.displayName = "SidebarBrand";
2383
2576
  function SidebarAccountMenu({
@@ -2388,7 +2581,7 @@ function SidebarAccountMenu({
2388
2581
  icon,
2389
2582
  className
2390
2583
  }) {
2391
- return /* @__PURE__ */ jsx28(
2584
+ return /* @__PURE__ */ jsx30(
2392
2585
  Dropdown,
2393
2586
  {
2394
2587
  align: "left",
@@ -2399,23 +2592,23 @@ function SidebarAccountMenu({
2399
2592
  selectedValue: "",
2400
2593
  triggerClassName: "fractal-sidebar__account-trigger",
2401
2594
  triggerContent: /* @__PURE__ */ jsxs24(Fragment3, { children: [
2402
- icon && /* @__PURE__ */ jsx28("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
2403
- /* @__PURE__ */ jsx28("span", { className: "fractal-sidebar__account-name", children: name })
2595
+ icon && /* @__PURE__ */ jsx30("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
2596
+ /* @__PURE__ */ jsx30("span", { className: "fractal-sidebar__account-name", children: name })
2404
2597
  ] }),
2405
2598
  triggerLabel,
2406
2599
  triggerVariant: "tertiary"
2407
2600
  }
2408
2601
  );
2409
2602
  }
2410
- var SidebarNav = React16.forwardRef(
2411
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx28("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
2603
+ var SidebarNav = React15.forwardRef(
2604
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx30("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
2412
2605
  );
2413
2606
  SidebarNav.displayName = "SidebarNav";
2414
- var SidebarSection = React16.forwardRef(
2415
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx28("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
2607
+ var SidebarSection = React15.forwardRef(
2608
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx30("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
2416
2609
  );
2417
2610
  SidebarSection.displayName = "SidebarSection";
2418
- var SidebarNavItem = React16.forwardRef(
2611
+ var SidebarNavItem = React15.forwardRef(
2419
2612
  ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ jsxs24(
2420
2613
  "button",
2421
2614
  {
@@ -2426,28 +2619,60 @@ var SidebarNavItem = React16.forwardRef(
2426
2619
  "aria-current": active ? "page" : void 0,
2427
2620
  ...props,
2428
2621
  children: [
2429
- icon && /* @__PURE__ */ jsx28("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
2430
- /* @__PURE__ */ jsx28("span", { className: "fractal-sidebar__nav-item-label", children }),
2431
- endAdornment && /* @__PURE__ */ jsx28("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
2622
+ icon && /* @__PURE__ */ jsx30("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
2623
+ /* @__PURE__ */ jsx30("span", { className: "fractal-sidebar__nav-item-label", children }),
2624
+ endAdornment && /* @__PURE__ */ jsx30("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
2432
2625
  ]
2433
2626
  }
2434
2627
  )
2435
2628
  );
2436
2629
  SidebarNavItem.displayName = "SidebarNavItem";
2437
- var SidebarFooter = React16.forwardRef(
2438
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx28("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
2630
+ var SidebarFooter = React15.forwardRef(
2631
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx30("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
2439
2632
  );
2440
2633
  SidebarFooter.displayName = "SidebarFooter";
2441
2634
 
2442
2635
  // src/components/SidePanel/SidePanel.tsx
2443
- import { createPortal as createPortal3 } from "react-dom";
2636
+ import * as React16 from "react";
2637
+ import { createPortal as createPortal4 } from "react-dom";
2444
2638
  import { Close as Close2 } from "@mirror-physics/fractal-icons";
2445
- import { jsx as jsx29, jsxs as jsxs25 } from "react/jsx-runtime";
2639
+ import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
2446
2640
  function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
2447
2641
  useEscapeDismiss(80, onClose, open);
2642
+ const bodyRef = React16.useRef(null);
2643
+ const [scrollEdges, setScrollEdges] = React16.useState({ above: false, below: false });
2644
+ React16.useLayoutEffect(() => {
2645
+ const body = bodyRef.current;
2646
+ if (!open || !body) return;
2647
+ const measure = () => {
2648
+ const maxScroll = Math.max(0, body.scrollHeight - body.clientHeight);
2649
+ const top = Math.max(0, Math.min(body.scrollTop, maxScroll));
2650
+ const above = maxScroll > 1 && top > 0;
2651
+ const below = maxScroll - top > 1;
2652
+ setScrollEdges((previous) => previous.above === above && previous.below === below ? previous : { above, below });
2653
+ };
2654
+ const resize = new ResizeObserver(measure);
2655
+ const observeContent = () => {
2656
+ resize.disconnect();
2657
+ resize.observe(body);
2658
+ for (const child of body.children) resize.observe(child);
2659
+ measure();
2660
+ };
2661
+ const mutations = new MutationObserver(observeContent);
2662
+ mutations.observe(body, { childList: true, subtree: true, characterData: true, attributes: true });
2663
+ body.addEventListener("scroll", measure, { passive: true });
2664
+ body.addEventListener("load", measure, true);
2665
+ observeContent();
2666
+ return () => {
2667
+ resize.disconnect();
2668
+ mutations.disconnect();
2669
+ body.removeEventListener("scroll", measure);
2670
+ body.removeEventListener("load", measure, true);
2671
+ };
2672
+ }, [open, loading]);
2448
2673
  if (!open) return null;
2449
- return createPortal3(
2450
- /* @__PURE__ */ jsx29("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ jsxs25(
2674
+ return createPortal4(
2675
+ /* @__PURE__ */ jsx31("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ jsxs25(
2451
2676
  "aside",
2452
2677
  {
2453
2678
  className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
@@ -2456,15 +2681,15 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
2456
2681
  role: "dialog",
2457
2682
  onMouseDown: (event) => event.stopPropagation(),
2458
2683
  children: [
2459
- /* @__PURE__ */ jsxs25("header", { className: "fractal-side-panel__header", children: [
2684
+ /* @__PURE__ */ jsxs25("header", { className: "fractal-side-panel__header", "data-scroll-divider": scrollEdges.above, children: [
2460
2685
  /* @__PURE__ */ jsxs25("div", { className: "fractal-side-panel__heading", children: [
2461
- typeof title === "string" ? /* @__PURE__ */ jsx29("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ jsx29("div", { className: "fractal-side-panel__title", children: title }),
2462
- description && /* @__PURE__ */ jsx29("p", { className: "fractal-side-panel__description", children: description })
2686
+ typeof title === "string" ? /* @__PURE__ */ jsx31("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ jsx31("div", { className: "fractal-side-panel__title", children: title }),
2687
+ description && /* @__PURE__ */ jsx31("p", { className: "fractal-side-panel__description", children: description })
2463
2688
  ] }),
2464
- /* @__PURE__ */ jsx29("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx29(Close2, { size: 18 }) })
2689
+ /* @__PURE__ */ jsx31("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx31(Close2, { size: 18 }) })
2465
2690
  ] }),
2466
- /* @__PURE__ */ jsx29("div", { "aria-busy": loading || void 0, className: cn("fractal-side-panel__body", loading && "fractal-side-panel__body--loading"), children: loading ? /* @__PURE__ */ jsx29(UILoader, { label: loadingLabel }) : children }),
2467
- footer && /* @__PURE__ */ jsx29("footer", { className: "fractal-side-panel__footer", children: footer })
2691
+ /* @__PURE__ */ jsx31("div", { ref: bodyRef, "aria-busy": loading || void 0, className: cn("fractal-side-panel__body", loading && "fractal-side-panel__body--loading"), children: loading ? /* @__PURE__ */ jsx31(UILoader, { label: loadingLabel }) : children }),
2692
+ footer && /* @__PURE__ */ jsx31("footer", { className: "fractal-side-panel__footer", "data-scroll-divider": scrollEdges.below, children: footer })
2468
2693
  ]
2469
2694
  }
2470
2695
  ) }),
@@ -2474,15 +2699,15 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
2474
2699
 
2475
2700
  // src/components/Textarea/Textarea.tsx
2476
2701
  import * as React17 from "react";
2477
- import { jsx as jsx30 } from "react/jsx-runtime";
2702
+ import { jsx as jsx32 } from "react/jsx-runtime";
2478
2703
  var Textarea = React17.forwardRef(
2479
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx30("textarea", { ref, className: cn("fractal-textarea", className), ...props })
2704
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx32("textarea", { ref, className: cn("fractal-textarea", className), ...props })
2480
2705
  );
2481
2706
  Textarea.displayName = "Textarea";
2482
2707
 
2483
2708
  // src/components/TextButton/TextButton.tsx
2484
2709
  import * as React18 from "react";
2485
- import { jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
2710
+ import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
2486
2711
  var TextButton = React18.forwardRef(
2487
2712
  ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ jsxs26(
2488
2713
  "button",
@@ -2492,9 +2717,9 @@ var TextButton = React18.forwardRef(
2492
2717
  type: "button",
2493
2718
  ...props,
2494
2719
  children: [
2495
- icon && iconPosition === "start" && /* @__PURE__ */ jsx31("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
2496
- /* @__PURE__ */ jsx31("span", { children }),
2497
- icon && iconPosition === "end" && /* @__PURE__ */ jsx31("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
2720
+ icon && iconPosition === "start" && /* @__PURE__ */ jsx33("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
2721
+ /* @__PURE__ */ jsx33("span", { children }),
2722
+ icon && iconPosition === "end" && /* @__PURE__ */ jsx33("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
2498
2723
  ]
2499
2724
  }
2500
2725
  )
@@ -2504,7 +2729,7 @@ TextButton.displayName = "TextButton";
2504
2729
  // src/components/FileDropzone/FileDropzone.tsx
2505
2730
  import * as React19 from "react";
2506
2731
  import { Close as Close3, FileArrowUp } from "@mirror-physics/fractal-icons";
2507
- import { jsx as jsx32, jsxs as jsxs27 } from "react/jsx-runtime";
2732
+ import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
2508
2733
  function FileDropzone({
2509
2734
  files,
2510
2735
  onFilesChange,
@@ -2525,7 +2750,7 @@ function FileDropzone({
2525
2750
  onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
2526
2751
  };
2527
2752
  return /* @__PURE__ */ jsxs27("div", { className: cn("fractal-file-dropzone", className), children: [
2528
- /* @__PURE__ */ jsx32(
2753
+ /* @__PURE__ */ jsx34(
2529
2754
  "input",
2530
2755
  {
2531
2756
  ref: inputRef,
@@ -2564,18 +2789,18 @@ function FileDropzone({
2564
2789
  addFiles(event.dataTransfer.files);
2565
2790
  },
2566
2791
  children: [
2567
- /* @__PURE__ */ jsx32(FileArrowUp, { "aria-hidden": "true", size: 20 }),
2792
+ /* @__PURE__ */ jsx34(FileArrowUp, { "aria-hidden": "true", size: 20 }),
2568
2793
  /* @__PURE__ */ jsxs27("span", { className: "fractal-file-dropzone__copy", children: [
2569
- /* @__PURE__ */ jsx32("span", { className: "fractal-file-dropzone__title", children: title }),
2570
- description && /* @__PURE__ */ jsx32("span", { className: "fractal-file-dropzone__description", children: description })
2794
+ /* @__PURE__ */ jsx34("span", { className: "fractal-file-dropzone__title", children: title }),
2795
+ description && /* @__PURE__ */ jsx34("span", { className: "fractal-file-dropzone__description", children: description })
2571
2796
  ] })
2572
2797
  ]
2573
2798
  }
2574
2799
  ),
2575
- files.length > 0 && /* @__PURE__ */ jsx32("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ jsxs27("li", { className: "fractal-file-dropzone__file", children: [
2576
- /* @__PURE__ */ jsx32("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
2577
- /* @__PURE__ */ jsx32("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
2578
- /* @__PURE__ */ jsx32(
2800
+ files.length > 0 && /* @__PURE__ */ jsx34("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ jsxs27("li", { className: "fractal-file-dropzone__file", children: [
2801
+ /* @__PURE__ */ jsx34("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
2802
+ /* @__PURE__ */ jsx34("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
2803
+ /* @__PURE__ */ jsx34(
2579
2804
  "button",
2580
2805
  {
2581
2806
  className: "fractal-file-dropzone__remove",
@@ -2583,7 +2808,7 @@ function FileDropzone({
2583
2808
  "aria-label": `Remove ${file.name}`,
2584
2809
  disabled,
2585
2810
  onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
2586
- children: /* @__PURE__ */ jsx32(Close3, { "aria-hidden": "true", size: 14 })
2811
+ children: /* @__PURE__ */ jsx34(Close3, { "aria-hidden": "true", size: 14 })
2587
2812
  }
2588
2813
  )
2589
2814
  ] }, `${file.name}-${file.size}-${index}`)) })
@@ -2597,7 +2822,7 @@ function formatFileSize(bytes) {
2597
2822
 
2598
2823
  // src/components/Pagination/Pagination.tsx
2599
2824
  import { ArrowLeft, ArrowRight } from "@mirror-physics/fractal-icons";
2600
- import { jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
2825
+ import { jsx as jsx35, jsxs as jsxs28 } from "react/jsx-runtime";
2601
2826
  function Pagination({
2602
2827
  page,
2603
2828
  pageSize,
@@ -2614,9 +2839,9 @@ function Pagination({
2614
2839
  const end = Math.min(currentPage * pageSize, totalItems);
2615
2840
  const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
2616
2841
  return /* @__PURE__ */ jsxs28("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
2617
- /* @__PURE__ */ jsx33("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
2842
+ /* @__PURE__ */ jsx35("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
2618
2843
  /* @__PURE__ */ jsxs28("div", { className: "fractal-pagination__controls", children: [
2619
- canChangePageSize && /* @__PURE__ */ jsx33(
2844
+ canChangePageSize && /* @__PURE__ */ jsx35(
2620
2845
  Dropdown,
2621
2846
  {
2622
2847
  align: "right",
@@ -2633,7 +2858,7 @@ function Pagination({
2633
2858
  triggerVariant: "tertiary"
2634
2859
  }
2635
2860
  ),
2636
- /* @__PURE__ */ jsx33(
2861
+ /* @__PURE__ */ jsx35(
2637
2862
  "button",
2638
2863
  {
2639
2864
  className: "fractal-pagination__button",
@@ -2642,7 +2867,7 @@ function Pagination({
2642
2867
  title: "Previous page",
2643
2868
  disabled: currentPage === 1 || totalItems === 0,
2644
2869
  onClick: () => onPageChange(currentPage - 1),
2645
- children: /* @__PURE__ */ jsx33(ArrowLeft, { "aria-hidden": "true", size: 16 })
2870
+ children: /* @__PURE__ */ jsx35(ArrowLeft, { "aria-hidden": "true", size: 16 })
2646
2871
  }
2647
2872
  ),
2648
2873
  /* @__PURE__ */ jsxs28("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
@@ -2650,7 +2875,7 @@ function Pagination({
2650
2875
  " of ",
2651
2876
  totalPages
2652
2877
  ] }),
2653
- /* @__PURE__ */ jsx33(
2878
+ /* @__PURE__ */ jsx35(
2654
2879
  "button",
2655
2880
  {
2656
2881
  className: "fractal-pagination__button",
@@ -2659,7 +2884,7 @@ function Pagination({
2659
2884
  title: "Next page",
2660
2885
  disabled: currentPage === totalPages || totalItems === 0,
2661
2886
  onClick: () => onPageChange(currentPage + 1),
2662
- children: /* @__PURE__ */ jsx33(ArrowRight, { "aria-hidden": "true", size: 16 })
2887
+ children: /* @__PURE__ */ jsx35(ArrowRight, { "aria-hidden": "true", size: 16 })
2663
2888
  }
2664
2889
  )
2665
2890
  ] })
@@ -2685,6 +2910,7 @@ export {
2685
2910
  Chip,
2686
2911
  ChipGhost,
2687
2912
  CodeBlock,
2913
+ ColumnEditor,
2688
2914
  ContentSwitcher,
2689
2915
  ContentSwitcherGhost,
2690
2916
  ConversationGhost,