@mirror-physics/fractal-ui 0.2.0-next.6 → 0.2.0-next.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -32,39 +32,77 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Alert: () => Alert,
34
34
  AlertDescription: () => AlertDescription,
35
+ AlertGhost: () => AlertGhost,
35
36
  AlertTitle: () => AlertTitle,
37
+ Breadcrumbs: () => Breadcrumbs,
36
38
  Button: () => Button,
39
+ ButtonGhost: () => ButtonGhost,
37
40
  Card: () => Card,
38
41
  CardContent: () => CardContent,
39
42
  CardDescription: () => CardDescription,
40
43
  CardFooter: () => CardFooter,
44
+ CardGhost: () => CardGhost,
41
45
  CardHeader: () => CardHeader,
42
46
  CardTitle: () => CardTitle,
47
+ Checkbox: () => Checkbox,
48
+ CheckboxGhost: () => CheckboxGhost,
43
49
  Chip: () => Chip,
50
+ ChipGhost: () => ChipGhost,
51
+ CodeBlock: () => CodeBlock,
52
+ ContentSwitcher: () => ContentSwitcher,
53
+ ContentSwitcherGhost: () => ContentSwitcherGhost,
54
+ ConversationGhost: () => ConversationGhost,
44
55
  DataTable: () => DataTable,
56
+ DataTableGhost: () => DataTableGhost,
45
57
  Disclosure: () => Disclosure,
58
+ DisclosureGhost: () => DisclosureGhost,
46
59
  Dropdown: () => Dropdown,
60
+ DropdownGhost: () => DropdownGhost,
47
61
  FeatureCard: () => FeatureCard,
62
+ FileDropzone: () => FileDropzone,
63
+ FileDropzoneGhost: () => FileDropzoneGhost,
48
64
  FolderCard: () => FolderCard,
65
+ Ghost: () => Ghost,
66
+ GhostLine: () => GhostLine,
49
67
  Input: () => Input,
68
+ InputGhost: () => InputGhost,
50
69
  Label: () => Label,
70
+ LabelGhost: () => LabelGhost,
71
+ LatticeLoader: () => LatticeLoader,
51
72
  Link: () => Link,
73
+ LinkGhost: () => LinkGhost,
52
74
  Modal: () => Modal,
53
- PageHeader: () => PageHeader,
75
+ ModalGhost: () => ModalGhost,
76
+ NumberInput: () => NumberInput,
77
+ Pagination: () => Pagination,
78
+ PaginationGhost: () => PaginationGhost,
79
+ PasswordInput: () => PasswordInput,
54
80
  PromptCard: () => PromptCard,
81
+ PromptCardGhost: () => PromptCardGhost,
55
82
  PromptGrid: () => PromptGrid,
56
83
  SidePanel: () => SidePanel,
84
+ SidePanelGhost: () => SidePanelGhost,
57
85
  Sidebar: () => Sidebar,
86
+ SidebarAccountMenu: () => SidebarAccountMenu,
58
87
  SidebarBrand: () => SidebarBrand,
59
88
  SidebarFooter: () => SidebarFooter,
89
+ SidebarGhost: () => SidebarGhost,
60
90
  SidebarHeader: () => SidebarHeader,
61
91
  SidebarNav: () => SidebarNav,
62
92
  SidebarNavItem: () => SidebarNavItem,
63
93
  SidebarSection: () => SidebarSection,
64
94
  SortableTable: () => SortableTable,
95
+ SortableTableGhost: () => SortableTableGhost,
96
+ TableSearch: () => TableSearch,
65
97
  Tabs: () => Tabs,
98
+ TabsGhost: () => TabsGhost,
99
+ TextButton: () => TextButton,
100
+ TextButtonGhost: () => TextButtonGhost,
66
101
  Textarea: () => Textarea,
102
+ TextareaGhost: () => TextareaGhost,
67
103
  Toggle: () => Toggle,
104
+ ToggleGhost: () => ToggleGhost,
105
+ UILoader: () => UILoader,
68
106
  cn: () => cn,
69
107
  useEscapeDismiss: () => useEscapeDismiss
70
108
  });
@@ -122,7 +160,7 @@ var colorPalette = {
122
160
  var sizeConfig = {
123
161
  xs: { height: "28px", padding: "4px 8px", iconOnly: "28px", fontSize: "0.75rem" },
124
162
  sm: { height: "32px", padding: "6px 12px", iconOnly: "32px", fontSize: "0.75rem" },
125
- md: { height: "38px", padding: "8px 16px", iconOnly: "38px", fontSize: "0.875rem" },
163
+ md: { height: "40px", padding: "8px 16px", iconOnly: "40px", fontSize: "0.875rem" },
126
164
  lg: { height: "44px", padding: "10px 20px", iconOnly: "44px", fontSize: "1rem" },
127
165
  xl: { height: "56px", padding: "14px 28px", iconOnly: "56px", fontSize: "1rem" }
128
166
  };
@@ -237,44 +275,409 @@ var Button = React.forwardRef(
237
275
  );
238
276
  Button.displayName = "Button";
239
277
 
240
- // src/components/Card/Card.tsx
241
- var React2 = __toESM(require("react"), 1);
278
+ // src/components/CodeBlock/CodeBlock.tsx
279
+ var import_react = require("react");
280
+ var import_react_codemirror = __toESM(require("@uiw/react-codemirror"), 1);
281
+ var import_language = require("@codemirror/language");
282
+ var import_lang_json = require("@codemirror/lang-json");
283
+ var import_view = require("@codemirror/view");
284
+ var import_highlight = require("@lezer/highlight");
242
285
  var import_fractal_icons = require("@mirror-physics/fractal-icons");
243
286
  var import_jsx_runtime2 = require("react/jsx-runtime");
287
+ var codeTheme = import_view.EditorView.theme({
288
+ "&": {
289
+ backgroundColor: "transparent",
290
+ color: "var(--fg-primary)",
291
+ fontSize: "0.75rem"
292
+ },
293
+ "&.cm-focused": { outline: "none" },
294
+ ".cm-scroller": {
295
+ fontFamily: "var(--font-mono)",
296
+ lineHeight: "1.55",
297
+ overscrollBehavior: "none"
298
+ },
299
+ ".cm-content": { padding: "10px 0" },
300
+ ".cm-line": {
301
+ padding: "0 12px 0 calc(12px + var(--fractal-code-wrap-indent, 0ch))",
302
+ textIndent: "calc(0px - var(--fractal-code-wrap-indent, 0ch))"
303
+ },
304
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--fg-primary)" },
305
+ ".cm-gutters": {
306
+ backgroundColor: "var(--bg-canvas)",
307
+ borderRight: "1px solid var(--border-subtle)",
308
+ color: "var(--fg-tertiary)"
309
+ },
310
+ ".cm-lineNumbers .cm-gutterElement": { padding: "0 10px 0 4px" },
311
+ ".cm-foldGutter": { width: "14px" },
312
+ ".cm-foldGutter .cm-gutterElement": {
313
+ position: "relative",
314
+ display: "block",
315
+ width: "14px",
316
+ padding: "0"
317
+ },
318
+ ".cm-foldGutter .cm-gutterElement > span": {
319
+ position: "absolute",
320
+ top: "2px",
321
+ left: "0",
322
+ display: "inline-flex",
323
+ width: "14px",
324
+ height: "14px",
325
+ alignItems: "center",
326
+ justifyContent: "center",
327
+ padding: "0",
328
+ color: "var(--fg-tertiary)",
329
+ lineHeight: "14px",
330
+ transition: "color 120ms ease"
331
+ },
332
+ '.cm-foldGutter .cm-gutterElement > span[title="Fold line"]': { transform: "translateY(-3px)" },
333
+ ".cm-foldGutter .cm-gutterElement > span:hover": { color: "var(--fg-secondary)" },
334
+ ".fractal-code-block__escape": { color: "var(--fg-secondary)" },
335
+ ".cm-activeLine, .cm-activeLineGutter": { backgroundColor: "var(--bg-surface-1)" },
336
+ ".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection": {
337
+ backgroundColor: "var(--accent-surface-stroke) !important"
338
+ },
339
+ ".cm-searchMatch": {
340
+ backgroundColor: "var(--warning-surface)",
341
+ outline: "1px solid var(--warning-surface-stroke)"
342
+ },
343
+ ".cm-searchMatch.cm-searchMatch-selected": { backgroundColor: "var(--warning-subtle)" },
344
+ ".cm-panels": { backgroundColor: "var(--bg-surface-1)", color: "var(--fg-primary)" },
345
+ ".cm-tooltip": {
346
+ borderColor: "var(--border-subtle)",
347
+ backgroundColor: "var(--bg-canvas)",
348
+ color: "var(--fg-primary)"
349
+ }
350
+ });
351
+ var fractalHighlightStyle = import_language.HighlightStyle.define([
352
+ { tag: import_highlight.tags.comment, color: "var(--fg-tertiary)", fontStyle: "italic" },
353
+ { tag: [import_highlight.tags.keyword, import_highlight.tags.controlKeyword, import_highlight.tags.operatorKeyword], color: "var(--purple-default)" },
354
+ { tag: [import_highlight.tags.string, import_highlight.tags.special(import_highlight.tags.string)], color: "var(--purple-default)" },
355
+ { tag: [import_highlight.tags.number, import_highlight.tags.bool, import_highlight.tags.null], color: "var(--orange-default)" },
356
+ { tag: [import_highlight.tags.function(import_highlight.tags.variableName), import_highlight.tags.labelName], color: "var(--accent-default)" },
357
+ { tag: [import_highlight.tags.typeName, import_highlight.tags.className, import_highlight.tags.namespace], color: "var(--pink-default)" },
358
+ { tag: [import_highlight.tags.propertyName, import_highlight.tags.attributeName], color: "var(--success-default)" },
359
+ { tag: [import_highlight.tags.operator, import_highlight.tags.punctuation], color: "var(--fg-secondary)" },
360
+ { tag: import_highlight.tags.bracket, color: "var(--accent-default)" },
361
+ { tag: [import_highlight.tags.heading, import_highlight.tags.strong], color: "var(--fg-primary)", fontWeight: "600" },
362
+ { tag: import_highlight.tags.emphasis, fontStyle: "italic" },
363
+ { tag: import_highlight.tags.link, color: "var(--accent-default)", textDecoration: "underline" },
364
+ { tag: import_highlight.tags.invalid, color: "var(--error-default)", textDecoration: "underline wavy" }
365
+ ]);
366
+ var jsonSupport = (0, import_lang_json.json)();
367
+ var JSON_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["json", "jsonl", "ndjson", "geojson"]);
368
+ var JSON_LINES_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["jsonl", "ndjson"]);
369
+ var JSON_LINES_PRETTY_PRINT_THRESHOLD = 160;
370
+ var JSON_PROPERTY_PREFIX = /^(\s*"(?:\\.|[^"\\])*"\s*:\s*)/;
371
+ function countVisualColumns(value) {
372
+ let columns = 0;
373
+ for (const character of value) columns += character === " " ? 2 : 1;
374
+ return columns;
375
+ }
376
+ function getWrappedLineIndent(line) {
377
+ const leadingWhitespace = line.match(/^\s*/)?.[0] ?? "";
378
+ if (JSON_PROPERTY_PREFIX.test(line)) return Math.min(countVisualColumns(leadingWhitespace), 24);
379
+ return Math.min(countVisualColumns(leadingWhitespace) + 2, 12);
380
+ }
381
+ function buildWrappedLineIndentation(view) {
382
+ const decorations = [];
383
+ const decoratedLines = /* @__PURE__ */ new Set();
384
+ for (const visibleRange of view.visibleRanges) {
385
+ let position = visibleRange.from;
386
+ while (position <= visibleRange.to) {
387
+ const line = view.state.doc.lineAt(position);
388
+ if (!decoratedLines.has(line.from)) {
389
+ const indent = getWrappedLineIndent(line.text);
390
+ decorations.push(import_view.Decoration.line({
391
+ attributes: { style: `--fractal-code-wrap-indent: ${indent}ch` }
392
+ }).range(line.from));
393
+ decoratedLines.add(line.from);
394
+ }
395
+ if (line.to >= visibleRange.to) break;
396
+ position = line.to + 1;
397
+ }
398
+ }
399
+ return import_view.Decoration.set(decorations, true);
400
+ }
401
+ var wrappedLineIndentation = import_view.ViewPlugin.fromClass(class {
402
+ constructor(view) {
403
+ this.decorations = buildWrappedLineIndentation(view);
404
+ }
405
+ update(update) {
406
+ this.decorations = buildWrappedLineIndentation(update.view);
407
+ }
408
+ }, {
409
+ decorations: (plugin) => plugin.decorations
410
+ });
411
+ var jsonEscapeMatcher = new import_view.MatchDecorator({
412
+ regexp: /\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})/g,
413
+ decoration: import_view.Decoration.mark({ class: "fractal-code-block__escape" })
414
+ });
415
+ var jsonEscapeHighlighting = import_view.ViewPlugin.fromClass(class {
416
+ constructor(view) {
417
+ this.decorations = jsonEscapeMatcher.createDeco(view);
418
+ }
419
+ update(update) {
420
+ this.decorations = jsonEscapeMatcher.updateDeco(update, this.decorations);
421
+ }
422
+ }, {
423
+ decorations: (plugin) => plugin.decorations
424
+ });
425
+ function formatJsonLinesForDisplay(value) {
426
+ return value.split(/\r?\n/).map((line) => {
427
+ const firstContentIndex = line.search(/\S/);
428
+ if (firstContentIndex < 0 || line.length - firstContentIndex <= JSON_LINES_PRETTY_PRINT_THRESHOLD) return line;
429
+ const indentation = line.slice(0, firstContentIndex);
430
+ try {
431
+ const parsed = JSON.parse(line.slice(firstContentIndex));
432
+ if (parsed === null || typeof parsed !== "object") return line;
433
+ return JSON.stringify(parsed, null, 2).split("\n").map((formattedLine) => `${indentation}${formattedLine}`).join("\n");
434
+ } catch {
435
+ return line;
436
+ }
437
+ }).join("\n");
438
+ }
439
+ function findJsonContainerEnd(document2, start) {
440
+ const openingCharacter = document2[start];
441
+ if (openingCharacter !== "{" && openingCharacter !== "[") return null;
442
+ const closingCharacters = [];
443
+ let isInsideString = false;
444
+ let isEscaped = false;
445
+ for (let index = start; index < document2.length; index += 1) {
446
+ const character = document2[index];
447
+ if (isInsideString) {
448
+ if (isEscaped) {
449
+ isEscaped = false;
450
+ } else if (character === "\\") {
451
+ isEscaped = true;
452
+ } else if (character === '"') {
453
+ isInsideString = false;
454
+ }
455
+ continue;
456
+ }
457
+ if (character === '"') {
458
+ isInsideString = true;
459
+ } else if (character === "{") {
460
+ closingCharacters.push("}");
461
+ } else if (character === "[") {
462
+ closingCharacters.push("]");
463
+ } else if (character === "}" || character === "]") {
464
+ if (closingCharacters.pop() !== character) return null;
465
+ if (closingCharacters.length === 0) return index;
466
+ }
467
+ }
468
+ return null;
469
+ }
470
+ var jsonLinesFoldSupport = import_language.foldService.of((state, lineStart, lineEnd) => {
471
+ const line = state.doc.sliceString(lineStart, lineEnd);
472
+ const firstContentIndex = line.search(/\S/);
473
+ if (firstContentIndex < 0) return null;
474
+ const containerStart = lineStart + firstContentIndex;
475
+ const openingCharacter = line[firstContentIndex];
476
+ if (openingCharacter !== "{" && openingCharacter !== "[") return null;
477
+ const document2 = state.doc.toString();
478
+ const containerEnd = findJsonContainerEnd(document2, containerStart);
479
+ if (containerEnd === null || containerEnd - containerStart < 2) return null;
480
+ try {
481
+ const parsed = JSON.parse(document2.slice(containerStart, containerEnd + 1));
482
+ if (parsed === null || typeof parsed !== "object") return null;
483
+ } catch {
484
+ return null;
485
+ }
486
+ return {
487
+ from: containerStart + 1,
488
+ to: containerEnd
489
+ };
490
+ });
491
+ function resolveLanguage(language, fileName) {
492
+ const normalized = language?.trim().toLowerCase();
493
+ const extension = fileName?.split(/[?#]/, 1)[0].split(".").pop()?.toLowerCase();
494
+ if (normalized && JSON_LANGUAGE_NAMES.has(normalized) || extension && JSON_LANGUAGE_NAMES.has(extension)) {
495
+ const isJsonLines = Boolean(
496
+ normalized && JSON_LINES_LANGUAGE_NAMES.has(normalized) || extension && JSON_LINES_LANGUAGE_NAMES.has(extension)
497
+ );
498
+ return { label: isJsonLines ? "JSONL" : "JSON", support: jsonSupport, isJsonLines };
499
+ }
500
+ if (normalized && !["text", "txt", "plaintext", "plain"].includes(normalized)) {
501
+ return { label: language?.trim(), support: null, isJsonLines: false };
502
+ }
503
+ return { support: null, isJsonLines: false };
504
+ }
505
+ function CodeBlock({
506
+ value,
507
+ language,
508
+ fileName,
509
+ label,
510
+ editable = false,
511
+ onChange,
512
+ lineNumbers = true,
513
+ wrap = true,
514
+ copyable = true,
515
+ ariaLabel,
516
+ height,
517
+ minHeight,
518
+ maxHeight = "28rem",
519
+ placeholder,
520
+ autoFocus,
521
+ className,
522
+ ...props
523
+ }) {
524
+ const resolvedLanguage = (0, import_react.useMemo)(() => resolveLanguage(language, fileName), [fileName, language]);
525
+ const displayValue = (0, import_react.useMemo)(
526
+ () => !editable && resolvedLanguage.isJsonLines ? formatJsonLinesForDisplay(value) : value,
527
+ [editable, resolvedLanguage.isJsonLines, value]
528
+ );
529
+ const [copyStatus, setCopyStatus] = (0, import_react.useState)("idle");
530
+ const copyResetTimer = (0, import_react.useRef)(null);
531
+ (0, import_react.useEffect)(() => () => {
532
+ if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
533
+ }, []);
534
+ const extensions = (0, import_react.useMemo)(() => [
535
+ codeTheme,
536
+ (0, import_language.syntaxHighlighting)(fractalHighlightStyle),
537
+ ...resolvedLanguage.support ? [resolvedLanguage.support] : [],
538
+ ...resolvedLanguage.support ? [jsonEscapeHighlighting] : [],
539
+ ...resolvedLanguage.isJsonLines ? [jsonLinesFoldSupport] : [],
540
+ ...lineNumbers ? [(0, import_language.foldGutter)(), (0, import_view.lineNumbers)()] : [],
541
+ ...wrap ? [import_view.EditorView.lineWrapping, wrappedLineIndentation] : []
542
+ ], [lineNumbers, resolvedLanguage.isJsonLines, resolvedLanguage.support, wrap]);
543
+ const languageLabel = resolvedLanguage.label;
544
+ const toolbarLabel = label ?? fileName ?? languageLabel;
545
+ const surfaceLabel = ariaLabel ?? (fileName ? `${fileName} ${editable ? "editor" : "viewer"}` : `Code ${editable ? "editor" : "viewer"}`);
546
+ const copyCode = async () => {
547
+ try {
548
+ await navigator.clipboard.writeText(value);
549
+ setCopyStatus("copied");
550
+ } catch {
551
+ setCopyStatus("error");
552
+ }
553
+ if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
554
+ copyResetTimer.current = setTimeout(() => setCopyStatus("idle"), 1800);
555
+ };
556
+ const showToolbar = toolbarLabel !== void 0 || copyable || editable;
557
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
558
+ "div",
559
+ {
560
+ className: cn(
561
+ "fractal-code-block",
562
+ editable && "fractal-code-block--editable",
563
+ !lineNumbers && "fractal-code-block--no-line-numbers",
564
+ className
565
+ ),
566
+ ...props,
567
+ children: [
568
+ showToolbar && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fractal-code-block__toolbar", children: [
569
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fractal-code-block__identity", children: [
570
+ toolbarLabel !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fractal-code-block__label", title: typeof toolbarLabel === "string" ? toolbarLabel : void 0, children: toolbarLabel }),
571
+ fileName && languageLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fractal-code-block__language", children: languageLabel }),
572
+ editable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fractal-code-block__mode", children: "Editing" })
573
+ ] }),
574
+ copyable && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
575
+ "button",
576
+ {
577
+ type: "button",
578
+ className: "fractal-code-block__copy",
579
+ "aria-label": copyStatus === "copied" ? "Code copied" : "Copy code",
580
+ onClick: () => void copyCode(),
581
+ children: [
582
+ copyStatus === "copied" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fractal_icons.Check, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fractal_icons.Copy, { size: 14 }),
583
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: copyStatus === "copied" ? "Copied" : copyStatus === "error" ? "Copy failed" : "Copy" })
584
+ ]
585
+ }
586
+ )
587
+ ] }),
588
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fractal-code-block__surface", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
589
+ import_react_codemirror.default,
590
+ {
591
+ "aria-label": surfaceLabel,
592
+ value: displayValue,
593
+ editable,
594
+ readOnly: !editable,
595
+ onChange,
596
+ extensions,
597
+ theme: "none",
598
+ basicSetup: {
599
+ lineNumbers: false,
600
+ foldGutter: false,
601
+ drawSelection: editable,
602
+ highlightActiveLine: editable,
603
+ highlightActiveLineGutter: editable,
604
+ highlightSelectionMatches: editable,
605
+ autocompletion: editable,
606
+ history: editable
607
+ },
608
+ indentWithTab: editable,
609
+ height,
610
+ minHeight,
611
+ maxHeight,
612
+ placeholder,
613
+ autoFocus
614
+ }
615
+ ) }),
616
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fractal-code-block__status", "aria-live": "polite", children: copyStatus === "copied" ? "Code copied to clipboard." : copyStatus === "error" ? "Code could not be copied." : "" })
617
+ ]
618
+ }
619
+ );
620
+ }
621
+
622
+ // src/components/Breadcrumbs/Breadcrumbs.tsx
623
+ var import_fractal_icons2 = require("@mirror-physics/fractal-icons");
624
+ var import_jsx_runtime3 = require("react/jsx-runtime");
625
+ function Breadcrumbs({
626
+ items,
627
+ ariaLabel = "Breadcrumbs",
628
+ separator = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_fractal_icons2.ChevronRight, { "aria-hidden": "true", size: 14 }),
629
+ className,
630
+ ...props
631
+ }) {
632
+ if (items.length === 0) return null;
633
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("nav", { "aria-label": ariaLabel, className: cn("fractal-breadcrumbs", className), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "fractal-breadcrumbs__list", children: items.map((item, index) => {
634
+ const isCurrent = index === items.length - 1;
635
+ const content = isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "aria-current": "page", className: "fractal-breadcrumbs__current", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: "fractal-breadcrumbs__link", href: item.href ?? "#", onClick: item.onClick, children: item.label });
636
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: "fractal-breadcrumbs__item", children: [
637
+ index > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "aria-hidden": "true", className: "fractal-breadcrumbs__separator", children: separator }),
638
+ content
639
+ ] }, index);
640
+ }) }) });
641
+ }
642
+
643
+ // src/components/Card/Card.tsx
644
+ var React2 = __toESM(require("react"), 1);
645
+ var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
646
+ var import_jsx_runtime4 = require("react/jsx-runtime");
244
647
  var Card = React2.forwardRef(
245
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card", className), ...props })
648
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("fractal-card", className), ...props })
246
649
  );
247
650
  Card.displayName = "Card";
248
651
  var CardHeader = React2.forwardRef(
249
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card-header", className), ...props })
652
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("fractal-card-header", className), ...props })
250
653
  );
251
654
  CardHeader.displayName = "CardHeader";
252
655
  var CardTitle = React2.forwardRef(
253
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { ref, className: cn("fractal-card-title", className), ...props })
656
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { ref, className: cn("fractal-card-title", className), ...props })
254
657
  );
255
658
  CardTitle.displayName = "CardTitle";
256
659
  var CardDescription = React2.forwardRef(
257
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { ref, className: cn("fractal-card-description", className), ...props })
660
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { ref, className: cn("fractal-card-description", className), ...props })
258
661
  );
259
662
  CardDescription.displayName = "CardDescription";
260
663
  var CardContent = React2.forwardRef(
261
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card-content", className), ...props })
664
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("fractal-card-content", className), ...props })
262
665
  );
263
666
  CardContent.displayName = "CardContent";
264
667
  var CardFooter = React2.forwardRef(
265
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card-footer", className), ...props })
668
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("fractal-card-footer", className), ...props })
266
669
  );
267
670
  CardFooter.displayName = "CardFooter";
268
671
  var FeatureCard = React2.forwardRef(
269
- ({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
270
- icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fractal-feature-card__icon", children: icon }),
271
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "fractal-feature-card__title", children: title }),
272
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "fractal-feature-card__description", children: description })
672
+ ({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
673
+ icon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "fractal-feature-card__icon", children: icon }),
674
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "fractal-feature-card__title", children: title }),
675
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "fractal-feature-card__description", children: description })
273
676
  ] })
274
677
  );
275
678
  FeatureCard.displayName = "FeatureCard";
276
679
  var FolderCard = React2.forwardRef(
277
- ({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
680
+ ({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
278
681
  "div",
279
682
  {
280
683
  ref,
@@ -290,11 +693,11 @@ var FolderCard = React2.forwardRef(
290
693
  className: cn("fractal-folder-card", selected && "fractal-folder-card--selected", className),
291
694
  ...props,
292
695
  children: [
293
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fractal-folder-card__header", children: [
294
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fractal_icons.Folder, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
295
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fractal-folder-card__name", children: name })
696
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "fractal-folder-card__header", children: [
697
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fractal_icons3.Folder, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
698
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "fractal-folder-card__name", children: name })
296
699
  ] }),
297
- sessionCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fractal-folder-card__footer", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "fractal-folder-card__sessions", children: [
700
+ sessionCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "fractal-folder-card__footer", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "fractal-folder-card__sessions", children: [
298
701
  sessionCount,
299
702
  " ",
300
703
  sessionCount === 1 ? "session" : "sessions"
@@ -307,7 +710,7 @@ FolderCard.displayName = "FolderCard";
307
710
 
308
711
  // src/components/PromptCard/PromptCard.tsx
309
712
  var React3 = __toESM(require("react"), 1);
310
- var import_jsx_runtime3 = require("react/jsx-runtime");
713
+ var import_jsx_runtime5 = require("react/jsx-runtime");
311
714
  var titleToPrompt = (title) => typeof title === "string" || typeof title === "number" ? String(title) : "";
312
715
  var PromptCard = React3.forwardRef(
313
716
  ({
@@ -328,7 +731,7 @@ var PromptCard = React3.forwardRef(
328
731
  onPromptSelect?.(prompt ?? titleToPrompt(title));
329
732
  }
330
733
  };
331
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
734
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
332
735
  "button",
333
736
  {
334
737
  ref,
@@ -343,8 +746,8 @@ var PromptCard = React3.forwardRef(
343
746
  onClick: handleClick,
344
747
  ...props,
345
748
  children: [
346
- icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fractal-prompt-card__icon", "aria-hidden": "true", children: icon }),
347
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fractal-prompt-card__title", children: title })
749
+ icon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fractal-prompt-card__icon", "aria-hidden": "true", children: icon }),
750
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fractal-prompt-card__title", children: title })
348
751
  ]
349
752
  }
350
753
  );
@@ -352,7 +755,7 @@ var PromptCard = React3.forwardRef(
352
755
  );
353
756
  PromptCard.displayName = "PromptCard";
354
757
  var PromptGrid = React3.forwardRef(
355
- ({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
758
+ ({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
356
759
  "div",
357
760
  {
358
761
  ref,
@@ -370,9 +773,9 @@ PromptGrid.displayName = "PromptGrid";
370
773
 
371
774
  // src/components/Input/Input.tsx
372
775
  var React4 = __toESM(require("react"), 1);
373
- var import_jsx_runtime4 = require("react/jsx-runtime");
776
+ var import_jsx_runtime6 = require("react/jsx-runtime");
374
777
  var Input = React4.forwardRef(
375
- ({ className, type, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
778
+ ({ className, type, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
376
779
  "input",
377
780
  {
378
781
  type,
@@ -384,11 +787,181 @@ var Input = React4.forwardRef(
384
787
  );
385
788
  Input.displayName = "Input";
386
789
 
387
- // src/components/Label/Label.tsx
790
+ // src/components/TableSearch/TableSearch.tsx
388
791
  var React5 = __toESM(require("react"), 1);
389
- var import_jsx_runtime5 = require("react/jsx-runtime");
390
- var Label = React5.forwardRef(
391
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
792
+ var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
793
+ var import_jsx_runtime7 = require("react/jsx-runtime");
794
+ var TableSearch = React5.forwardRef(
795
+ ({
796
+ searchType = "text",
797
+ className,
798
+ inputClassName,
799
+ placeholder,
800
+ title,
801
+ ...props
802
+ }, ref) => {
803
+ const isGlob = searchType === "glob";
804
+ const SearchIcon = isGlob ? import_fractal_icons4.MagnifyingGlassLines : import_fractal_icons4.MagnifyingGlass;
805
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
806
+ "div",
807
+ {
808
+ className: cn("fractal-table-search", className),
809
+ "data-search-type": searchType,
810
+ children: [
811
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchIcon, { className: "fractal-table-search__icon", size: 17, "aria-hidden": "true" }),
812
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
813
+ Input,
814
+ {
815
+ ...props,
816
+ ref,
817
+ type: "search",
818
+ className: cn("fractal-table-search__input", inputClassName),
819
+ placeholder: placeholder ?? (isGlob ? "Glob search \u2014 use *, ?, or [a-z]" : "Search"),
820
+ title: title ?? (isGlob ? "Glob pattern: *, **, ?, [abc], [a-z], and [!abc]" : void 0)
821
+ }
822
+ )
823
+ ]
824
+ }
825
+ );
826
+ }
827
+ );
828
+ TableSearch.displayName = "TableSearch";
829
+
830
+ // src/components/NumberInput/NumberInput.tsx
831
+ var React6 = __toESM(require("react"), 1);
832
+ var import_fractal_icons5 = require("@mirror-physics/fractal-icons");
833
+ var import_jsx_runtime8 = require("react/jsx-runtime");
834
+ function NumberInput({
835
+ unit,
836
+ className,
837
+ value,
838
+ defaultValue,
839
+ disabled,
840
+ readOnly,
841
+ min,
842
+ max,
843
+ ...props
844
+ }) {
845
+ const inputRef = React6.useRef(null);
846
+ const numericValue = Number(value ?? defaultValue);
847
+ const characterCount = Math.max(String(value ?? defaultValue ?? "").length, 1);
848
+ const controlLabel = typeof props["aria-label"] === "string" ? props["aria-label"] : "value";
849
+ const decrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && min !== void 0 && numericValue <= Number(min);
850
+ const incrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && max !== void 0 && numericValue >= Number(max);
851
+ const changeByStep = (direction) => {
852
+ const input = inputRef.current;
853
+ if (!input) return;
854
+ if (direction === -1) input.stepDown();
855
+ else input.stepUp();
856
+ input.dispatchEvent(new Event("input", { bubbles: true }));
857
+ input.focus();
858
+ };
859
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
860
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
861
+ Input,
862
+ {
863
+ ref: inputRef,
864
+ type: "number",
865
+ value,
866
+ defaultValue,
867
+ disabled,
868
+ readOnly,
869
+ min,
870
+ max,
871
+ ...props
872
+ }
873
+ ),
874
+ unit && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
875
+ "span",
876
+ {
877
+ className: "fractal-number-input-unit",
878
+ style: { left: `calc(var(--space-3, 12px) + ${characterCount}ch)` },
879
+ "aria-hidden": "true",
880
+ children: unit
881
+ }
882
+ ),
883
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "fractal-number-input-controls", children: [
884
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
885
+ "button",
886
+ {
887
+ type: "button",
888
+ className: "fractal-number-input-step",
889
+ "aria-label": `Decrease ${controlLabel}`,
890
+ disabled: decrementDisabled,
891
+ onClick: () => changeByStep(-1),
892
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_fractal_icons5.Minus, { "aria-hidden": "true", size: 16 })
893
+ }
894
+ ),
895
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
896
+ "button",
897
+ {
898
+ type: "button",
899
+ className: "fractal-number-input-step",
900
+ "aria-label": `Increase ${controlLabel}`,
901
+ disabled: incrementDisabled,
902
+ onClick: () => changeByStep(1),
903
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_fractal_icons5.Plus, { "aria-hidden": "true", size: 16 })
904
+ }
905
+ )
906
+ ] })
907
+ ] });
908
+ }
909
+
910
+ // src/components/PasswordInput/PasswordInput.tsx
911
+ var React7 = __toESM(require("react"), 1);
912
+ var import_fractal_icons6 = require("@mirror-physics/fractal-icons");
913
+ var import_jsx_runtime9 = require("react/jsx-runtime");
914
+ var PasswordInput = React7.forwardRef(
915
+ ({
916
+ className,
917
+ disabled,
918
+ showPasswordLabel = "Show password",
919
+ hidePasswordLabel = "Hide password",
920
+ ...props
921
+ }, ref) => {
922
+ const [passwordVisible, setPasswordVisible] = React7.useState(false);
923
+ const toggleLabel = passwordVisible ? hidePasswordLabel : showPasswordLabel;
924
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
925
+ "div",
926
+ {
927
+ className: cn("fractal-password-input", className),
928
+ "data-password-visible": passwordVisible ? "" : void 0,
929
+ children: [
930
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
931
+ Input,
932
+ {
933
+ ...props,
934
+ ref,
935
+ className: "fractal-password-input-field",
936
+ disabled,
937
+ type: passwordVisible ? "text" : "password"
938
+ }
939
+ ),
940
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
941
+ "button",
942
+ {
943
+ type: "button",
944
+ className: "fractal-password-input-toggle",
945
+ "aria-label": toggleLabel,
946
+ "aria-pressed": passwordVisible,
947
+ disabled,
948
+ title: toggleLabel,
949
+ onClick: () => setPasswordVisible((visible) => !visible),
950
+ children: passwordVisible ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_fractal_icons6.EyeSlash, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_fractal_icons6.Eye, { "aria-hidden": "true", size: 18 })
951
+ }
952
+ )
953
+ ]
954
+ }
955
+ );
956
+ }
957
+ );
958
+ PasswordInput.displayName = "PasswordInput";
959
+
960
+ // src/components/Label/Label.tsx
961
+ var React8 = __toESM(require("react"), 1);
962
+ var import_jsx_runtime10 = require("react/jsx-runtime");
963
+ var Label = React8.forwardRef(
964
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
392
965
  "label",
393
966
  {
394
967
  ref,
@@ -400,44 +973,48 @@ var Label = React5.forwardRef(
400
973
  Label.displayName = "Label";
401
974
 
402
975
  // src/components/Alert/Alert.tsx
403
- var React6 = __toESM(require("react"), 1);
404
- var import_jsx_runtime6 = require("react/jsx-runtime");
976
+ var React9 = __toESM(require("react"), 1);
977
+ var import_fractal_icons7 = require("@mirror-physics/fractal-icons");
978
+ var import_jsx_runtime11 = require("react/jsx-runtime");
405
979
  var defaultIcons = {
406
- default: "\u2139",
407
- info: "\u2139",
408
- success: "\u2713",
409
- warning: "\u26A0",
410
- error: "\u2715"
980
+ default: import_fractal_icons7.CircleInfo,
981
+ info: import_fractal_icons7.CircleInfo,
982
+ success: import_fractal_icons7.CircleCheck,
983
+ warning: import_fractal_icons7.Warning,
984
+ error: import_fractal_icons7.CircleClose
411
985
  };
412
- var Alert = React6.forwardRef(
413
- ({ className, variant = "default", icon, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
414
- "div",
415
- {
416
- ref,
417
- role: "alert",
418
- className: cn("fractal-alert", `fractal-alert--${variant}`, className),
419
- ...props,
420
- children: [
421
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? defaultIcons[variant] }),
422
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fractal-alert-content", children })
423
- ]
424
- }
425
- )
986
+ var Alert = React9.forwardRef(
987
+ ({ className, variant = "default", icon, children, ...props }, ref) => {
988
+ const DefaultIcon = defaultIcons[variant];
989
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
990
+ "div",
991
+ {
992
+ ref,
993
+ role: "alert",
994
+ className: cn("fractal-alert", `fractal-alert--${variant}`, className),
995
+ ...props,
996
+ children: [
997
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DefaultIcon, { size: 18 }) }),
998
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "fractal-alert-content", children })
999
+ ]
1000
+ }
1001
+ );
1002
+ }
426
1003
  );
427
1004
  Alert.displayName = "Alert";
428
- var AlertTitle = React6.forwardRef(
429
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h5", { ref, className: cn("fractal-alert-title", className), ...props })
1005
+ var AlertTitle = React9.forwardRef(
1006
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h5", { ref, className: cn("fractal-alert-title", className), ...props })
430
1007
  );
431
1008
  AlertTitle.displayName = "AlertTitle";
432
- var AlertDescription = React6.forwardRef(
433
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref, className: cn("fractal-alert-description", className), ...props })
1009
+ var AlertDescription = React9.forwardRef(
1010
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { ref, className: cn("fractal-alert-description", className), ...props })
434
1011
  );
435
1012
  AlertDescription.displayName = "AlertDescription";
436
1013
 
437
1014
  // src/components/Toggle/Toggle.tsx
438
- var import_jsx_runtime7 = require("react/jsx-runtime");
1015
+ var import_jsx_runtime12 = require("react/jsx-runtime");
439
1016
  function Toggle({ checked, onChange, label, className }) {
440
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1017
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
441
1018
  "button",
442
1019
  {
443
1020
  type: "button",
@@ -446,8 +1023,8 @@ function Toggle({ checked, onChange, label, className }) {
446
1023
  className: cn("fractal-toggle", className),
447
1024
  onClick: () => onChange(!checked),
448
1025
  children: [
449
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn("fractal-toggle-track", checked && "fractal-toggle-track--checked"), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn("fractal-toggle-thumb", checked && "fractal-toggle-thumb--checked") }) }),
450
- label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fractal-toggle-label", children: label })
1026
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: cn("fractal-toggle-track", checked && "fractal-toggle-track--checked"), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: cn("fractal-toggle-thumb", checked && "fractal-toggle-thumb--checked") }) }),
1027
+ label && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "fractal-toggle-label", children: label })
451
1028
  ]
452
1029
  }
453
1030
  );
@@ -457,7 +1034,7 @@ function Toggle({ checked, onChange, label, className }) {
457
1034
  var import_react_dom = require("react-dom");
458
1035
 
459
1036
  // src/hooks/useEscapeDismiss.ts
460
- var import_react = require("react");
1037
+ var import_react2 = require("react");
461
1038
  var nextId = 0;
462
1039
  var stack = [];
463
1040
  function insertSorted(entry) {
@@ -490,9 +1067,9 @@ function ensureGlobalListener() {
490
1067
  );
491
1068
  }
492
1069
  function useEscapeDismiss(priority, handler, enabled = true) {
493
- const handlerRef = (0, import_react.useRef)(handler);
1070
+ const handlerRef = (0, import_react2.useRef)(handler);
494
1071
  handlerRef.current = handler;
495
- (0, import_react.useEffect)(() => {
1072
+ (0, import_react2.useEffect)(() => {
496
1073
  if (!enabled) return;
497
1074
  ensureGlobalListener();
498
1075
  const id = nextId++;
@@ -506,27 +1083,84 @@ function useEscapeDismiss(priority, handler, enabled = true) {
506
1083
  }, [priority, enabled]);
507
1084
  }
508
1085
 
1086
+ // src/components/UILoader/UILoader.tsx
1087
+ var import_react3 = require("react");
1088
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1089
+ 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";
1090
+ 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";
1091
+ 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";
1092
+ function UILoader({ size = 48, tone = "neutral", className, style, label = "Loading", ariaHidden = false }) {
1093
+ const rawId = (0, import_react3.useId)().replace(/[^a-zA-Z0-9_-]/g, "");
1094
+ const clipId = `fractal-ui-loader-clip-${rawId}`;
1095
+ const gradientId = `fractal-ui-loader-gradient-${rawId}`;
1096
+ const height = typeof size === "number" ? `${size}px` : size;
1097
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1098
+ "span",
1099
+ {
1100
+ "aria-hidden": ariaHidden || void 0,
1101
+ "aria-label": ariaHidden ? void 0 : label,
1102
+ className: cn("fractal-ui-loader", `fractal-ui-loader--${tone}`, className),
1103
+ role: ariaHidden ? void 0 : "status",
1104
+ style,
1105
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
1106
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("defs", { children: [
1107
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
1108
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { className: "fractal-ui-loader__stop-start", offset: "0" }),
1109
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { className: "fractal-ui-loader__stop-end", offset: "1" })
1110
+ ] }),
1111
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
1112
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { offset: "0.4", stopColor: "white", stopOpacity: "0" }),
1113
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { offset: "0.5", stopColor: "white", stopOpacity: "0.62" }),
1114
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { offset: "0.6", stopColor: "white", stopOpacity: "0" })
1115
+ ] }),
1116
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("clipPath", { id: clipId, children: [
1117
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: LEFT }),
1118
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: CENTER }),
1119
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: RIGHT })
1120
+ ] })
1121
+ ] }),
1122
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: CENTER, fill: `url(#${gradientId})` }),
1123
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: RIGHT, fill: `url(#${gradientId})` }),
1124
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: LEFT, fill: `url(#${gradientId})` }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("g", { clipPath: `url(#${clipId})`, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("g", { className: "fractal-ui-loader__shine-axis", transform: "translate(72 46) rotate(68.4)", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { className: "fractal-ui-loader__shine", x: "-160", y: "-100", width: "320", height: "200", fill: `url(#${gradientId}-shine)` }) }) })
1126
+ ] })
1127
+ }
1128
+ );
1129
+ }
1130
+
509
1131
  // src/components/Modal/Modal.tsx
510
- var import_jsx_runtime8 = require("react/jsx-runtime");
511
- var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
512
- function Modal({ open, onClose, title, children, danger, warn, footer, noClose, size = "sm", className }) {
513
- useEscapeDismiss(80, onClose, open && !noClose);
1132
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1133
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1134
+ function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
1135
+ useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
514
1136
  if (!open) return null;
515
1137
  const sizeClass = `fractal-modal-panel--${size}`;
516
1138
  const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
517
1139
  return (0, import_react_dom.createPortal)(
518
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1140
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
519
1141
  "div",
520
1142
  {
521
- className: cn("fractal-modal-panel", sizeClass, accentClass, className),
1143
+ className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
522
1144
  onClick: (e) => e.stopPropagation(),
523
1145
  children: [
524
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "fractal-modal-title-row", children: [
525
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
526
- !noClose && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: onClose, title: "Close", className: "fractal-modal-close", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {}) })
1146
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "fractal-modal-title-row", children: [
1147
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
1148
+ !noClose && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CloseIcon, {}) })
527
1149
  ] }),
528
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("fractal-modal-body", size === "lg" && "fractal-modal-body--lg"), children }),
529
- footer && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-footer", children: footer })
1150
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1151
+ "div",
1152
+ {
1153
+ "aria-busy": loading || void 0,
1154
+ className: cn(
1155
+ "fractal-modal-body",
1156
+ size === "lg" && "fractal-modal-body--lg",
1157
+ loading && "fractal-modal-body--loading",
1158
+ scrollable && "fractal-modal-body--scrollable"
1159
+ ),
1160
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UILoader, { label: loadingLabel }) : children
1161
+ }
1162
+ ),
1163
+ footer && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("fractal-modal-footer", scrollable && "fractal-modal-footer--divided"), children: footer })
530
1164
  ]
531
1165
  }
532
1166
  ) }),
@@ -535,17 +1169,17 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
535
1169
  }
536
1170
 
537
1171
  // src/components/DataTable/DataTable.tsx
538
- var import_jsx_runtime9 = require("react/jsx-runtime");
1172
+ var import_jsx_runtime15 = require("react/jsx-runtime");
539
1173
  function DataTable({ columns, data, emptyMessage, header, size = "md", className }) {
540
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: cn("fractal-datatable", `fractal-datatable--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "fractal-datatable-surface", children: [
541
- header && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-datatable-header", children: header }),
542
- data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { className: "fractal-datatable-table", children: [
543
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tr", { className: "fractal-datatable-thead-row", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { className: "fractal-datatable-th", style: { width: col.width }, children: col.header }, col.key)) }) }),
544
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1174
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn("fractal-datatable", `fractal-datatable--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fractal-datatable-surface", children: [
1175
+ header && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-datatable-header", children: header }),
1176
+ data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("table", { className: "fractal-datatable-table", children: [
1177
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tr", { className: "fractal-datatable-thead-row", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { className: "fractal-datatable-th", style: { width: col.width }, children: col.header }, col.key)) }) }),
1178
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
545
1179
  "tr",
546
1180
  {
547
1181
  className: "fractal-datatable-row",
548
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "fractal-datatable-td", style: { width: col.width }, children: col.render(row, rowIndex) }, col.key))
1182
+ children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "fractal-datatable-td", style: { width: col.width }, children: col.render(row, rowIndex) }, col.key))
549
1183
  },
550
1184
  rowIndex
551
1185
  )) })
@@ -554,9 +1188,9 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
554
1188
  }
555
1189
 
556
1190
  // src/components/Dropdown/Dropdown.tsx
557
- var React7 = __toESM(require("react"), 1);
558
- var import_fractal_icons2 = require("@mirror-physics/fractal-icons");
559
- var import_jsx_runtime10 = require("react/jsx-runtime");
1191
+ var React10 = __toESM(require("react"), 1);
1192
+ var import_fractal_icons8 = require("@mirror-physics/fractal-icons");
1193
+ var import_jsx_runtime16 = require("react/jsx-runtime");
560
1194
  var MARGIN = 4;
561
1195
  function Dropdown({
562
1196
  items,
@@ -565,20 +1199,23 @@ function Dropdown({
565
1199
  triggerLabel = "Options",
566
1200
  direction = "down",
567
1201
  align = "left",
1202
+ triggerOrientation = "horizontal",
568
1203
  triggerContent,
569
1204
  label,
1205
+ iconOnly = false,
570
1206
  noChevron = false,
571
1207
  size = "md",
572
1208
  triggerVariant = "outline",
573
1209
  className,
574
1210
  triggerClassName,
575
1211
  panelClassName,
576
- closeOnSelect = true
1212
+ closeOnSelect = true,
1213
+ disabled = false
577
1214
  }) {
578
- const [open, setOpen] = React7.useState(false);
579
- const triggerRef = React7.useRef(null);
580
- const panelRef = React7.useRef(null);
581
- const [panelStyle, setPanelStyle] = React7.useState({});
1215
+ const [open, setOpen] = React10.useState(false);
1216
+ const triggerRef = React10.useRef(null);
1217
+ const panelRef = React10.useRef(null);
1218
+ const [panelStyle, setPanelStyle] = React10.useState({});
582
1219
  const visibleItems = items.filter(
583
1220
  (item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
584
1221
  );
@@ -586,42 +1223,60 @@ function Dropdown({
586
1223
  const selectableItems = visibleItems.filter((i) => i.kind !== "header");
587
1224
  const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
588
1225
  const isUp = direction === "up";
589
- const ChevronIcon = isUp ? import_fractal_icons2.ChevronUp : import_fractal_icons2.ChevronDown;
590
- React7.useLayoutEffect(() => {
1226
+ const isHorizontalDirection = direction === "left" || direction === "right";
1227
+ const ChevronIcon = direction === "up" ? import_fractal_icons8.ChevronUp : direction === "left" ? import_fractal_icons8.ChevronLeft : direction === "right" ? import_fractal_icons8.ChevronRight : import_fractal_icons8.ChevronDown;
1228
+ React10.useLayoutEffect(() => {
591
1229
  if (!open || !triggerRef.current || !panelRef.current) return;
592
1230
  const triggerRect = triggerRef.current.getBoundingClientRect();
593
1231
  const panelRect = panelRef.current.getBoundingClientRect();
594
1232
  const vw = window.innerWidth;
595
1233
  const vh = window.innerHeight;
596
- const spaceBelow = vh - triggerRect.bottom - MARGIN;
597
- const spaceAbove = triggerRect.top - MARGIN;
598
- let placeAbove = isUp;
599
- if (placeAbove && panelRect.height > spaceAbove && spaceBelow > spaceAbove) {
600
- placeAbove = false;
601
- } else if (!placeAbove && panelRect.height > spaceBelow && spaceAbove > spaceBelow) {
602
- placeAbove = true;
603
- }
604
- const top = placeAbove ? -(panelRect.height + MARGIN) : triggerRect.height + MARGIN;
1234
+ let top;
605
1235
  let left;
606
1236
  let right;
607
- if (align === "right") {
608
- right = 0;
609
- const panelLeft = triggerRect.right - panelRect.width;
610
- if (panelLeft < 0) {
611
- right = void 0;
612
- left = 0;
1237
+ if (isHorizontalDirection) {
1238
+ const spaceRight = vw - triggerRect.right - MARGIN;
1239
+ const spaceLeft = triggerRect.left - MARGIN;
1240
+ let placeRight = direction === "right";
1241
+ if (placeRight && panelRect.width > spaceRight && spaceLeft > spaceRight) {
1242
+ placeRight = false;
1243
+ } else if (!placeRight && panelRect.width > spaceLeft && spaceRight > spaceLeft) {
1244
+ placeRight = true;
613
1245
  }
1246
+ left = placeRight ? triggerRect.width + MARGIN : -(panelRect.width + MARGIN);
1247
+ top = 0;
1248
+ const panelBottom = triggerRect.top + panelRect.height;
1249
+ if (panelBottom > vh - MARGIN) top -= panelBottom - (vh - MARGIN);
1250
+ if (triggerRect.top + top < MARGIN) top += MARGIN - (triggerRect.top + top);
614
1251
  } else {
615
- left = 0;
616
- const panelRight = triggerRect.left + panelRect.width;
617
- if (panelRight > vw) {
618
- left = void 0;
1252
+ const spaceBelow = vh - triggerRect.bottom - MARGIN;
1253
+ const spaceAbove = triggerRect.top - MARGIN;
1254
+ let placeAbove = isUp;
1255
+ if (placeAbove && panelRect.height > spaceAbove && spaceBelow > spaceAbove) {
1256
+ placeAbove = false;
1257
+ } else if (!placeAbove && panelRect.height > spaceBelow && spaceAbove > spaceBelow) {
1258
+ placeAbove = true;
1259
+ }
1260
+ top = placeAbove ? -(panelRect.height + MARGIN) : triggerRect.height + MARGIN;
1261
+ if (align === "right") {
619
1262
  right = 0;
1263
+ const panelLeft = triggerRect.right - panelRect.width;
1264
+ if (panelLeft < 0) {
1265
+ right = void 0;
1266
+ left = 0;
1267
+ }
1268
+ } else {
1269
+ left = 0;
1270
+ const panelRight = triggerRect.left + panelRect.width;
1271
+ if (panelRight > vw) {
1272
+ left = void 0;
1273
+ right = 0;
1274
+ }
620
1275
  }
621
1276
  }
622
1277
  setPanelStyle({ top, left, right });
623
- }, [open, isUp, align]);
624
- React7.useEffect(() => {
1278
+ }, [open, direction, isHorizontalDirection, isUp, align]);
1279
+ React10.useEffect(() => {
625
1280
  if (!open) return;
626
1281
  const handleClickOutside = (e) => {
627
1282
  const target = e.target;
@@ -631,12 +1286,13 @@ function Dropdown({
631
1286
  document.addEventListener("mousedown", handleClickOutside);
632
1287
  return () => document.removeEventListener("mousedown", handleClickOutside);
633
1288
  }, [open]);
634
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
635
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1289
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
636
1291
  "button",
637
1292
  {
638
1293
  ref: triggerRef,
639
1294
  type: "button",
1295
+ disabled,
640
1296
  "aria-haspopup": "listbox",
641
1297
  "aria-expanded": open,
642
1298
  "aria-label": triggerLabel,
@@ -645,18 +1301,20 @@ function Dropdown({
645
1301
  "fractal-dropdown-trigger",
646
1302
  `fractal-dropdown-trigger--${size}`,
647
1303
  `fractal-dropdown-trigger--${triggerVariant}`,
1304
+ `fractal-dropdown-trigger--${triggerOrientation}`,
1305
+ iconOnly && "fractal-dropdown-trigger--icon-only",
648
1306
  triggerClassName
649
1307
  ),
650
1308
  children: [
651
- triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
652
- selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
653
- selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
1309
+ triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1310
+ selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
1311
+ selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
654
1312
  ] }),
655
- !noChevron && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
1313
+ !noChevron && !iconOnly && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
656
1314
  ]
657
1315
  }
658
1316
  ),
659
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1317
+ open && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
660
1318
  "div",
661
1319
  {
662
1320
  ref: panelRef,
@@ -665,21 +1323,21 @@ function Dropdown({
665
1323
  className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
666
1324
  style: panelStyle,
667
1325
  children: [
668
- label != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-label", children: label }),
1326
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-label", children: label }),
669
1327
  visibleItems.map((item, index) => {
670
- const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
671
- const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
1328
+ const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
1329
+ const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
672
1330
  if (item.kind === "header") {
673
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
1331
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React10.Fragment, { children: [
674
1332
  topDivider,
675
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
1333
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
676
1334
  bottomDivider
677
1335
  ] }, `header-${index}`);
678
1336
  }
679
1337
  const isSelected = item.value === selectedValue;
680
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React10.Fragment, { children: [
681
1339
  topDivider,
682
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1340
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
683
1341
  "button",
684
1342
  {
685
1343
  type: "button",
@@ -691,9 +1349,9 @@ function Dropdown({
691
1349
  },
692
1350
  className: "fractal-dropdown-option",
693
1351
  children: [
694
- item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
695
- item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
696
- item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
1352
+ item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
1353
+ item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
1354
+ item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
697
1355
  ]
698
1356
  }
699
1357
  ),
@@ -707,10 +1365,10 @@ function Dropdown({
707
1365
  }
708
1366
 
709
1367
  // src/components/Link/Link.tsx
710
- var React8 = __toESM(require("react"), 1);
711
- var import_jsx_runtime11 = require("react/jsx-runtime");
712
- var Link = React8.forwardRef(
713
- ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1368
+ var React11 = __toESM(require("react"), 1);
1369
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1370
+ var Link = React11.forwardRef(
1371
+ ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
714
1372
  "a",
715
1373
  {
716
1374
  ref,
@@ -722,10 +1380,10 @@ var Link = React8.forwardRef(
722
1380
  Link.displayName = "Link";
723
1381
 
724
1382
  // src/components/Chip/Chip.tsx
725
- var React9 = __toESM(require("react"), 1);
726
- var import_jsx_runtime12 = require("react/jsx-runtime");
727
- var Chip = React9.forwardRef(
728
- ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1383
+ var React12 = __toESM(require("react"), 1);
1384
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1385
+ var Chip = React12.forwardRef(
1386
+ ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
729
1387
  "span",
730
1388
  {
731
1389
  ref,
@@ -736,36 +1394,88 @@ var Chip = React9.forwardRef(
736
1394
  );
737
1395
  Chip.displayName = "Chip";
738
1396
 
1397
+ // src/components/Checkbox/Checkbox.tsx
1398
+ var import_fractal_icons9 = require("@mirror-physics/fractal-icons");
1399
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1400
+ function Checkbox({
1401
+ checked,
1402
+ indeterminate = false,
1403
+ onCheckedChange,
1404
+ className,
1405
+ disabled,
1406
+ onClick,
1407
+ onKeyDown,
1408
+ ...props
1409
+ }) {
1410
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1411
+ "button",
1412
+ {
1413
+ ...props,
1414
+ className: cn(
1415
+ "fractal-checkbox",
1416
+ (checked || indeterminate) && "fractal-checkbox--checked",
1417
+ indeterminate && "fractal-checkbox--indeterminate",
1418
+ className
1419
+ ),
1420
+ type: "button",
1421
+ role: "checkbox",
1422
+ "aria-checked": indeterminate ? "mixed" : checked,
1423
+ disabled,
1424
+ onClick: (event) => {
1425
+ onClick?.(event);
1426
+ if (!event.defaultPrevented) onCheckedChange(indeterminate || !checked);
1427
+ },
1428
+ onKeyDown: (event) => {
1429
+ onKeyDown?.(event);
1430
+ if (event.key === " " || event.key === "Enter") event.stopPropagation();
1431
+ },
1432
+ children: indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "fractal-checkbox__indeterminate-icon", "aria-hidden": "true", children: [
1433
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fractal_icons9.Checkbox, { size: 18 }),
1434
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fractal_icons9.Minus, { className: "fractal-checkbox__indeterminate-mark", size: 12 })
1435
+ ] }) : checked ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fractal_icons9.CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fractal_icons9.Checkbox, { "aria-hidden": "true", size: 18 })
1436
+ }
1437
+ );
1438
+ }
1439
+
739
1440
  // src/components/SortableTable/SortableTable.tsx
740
- var import_react2 = require("react");
741
- var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
742
- var import_jsx_runtime13 = require("react/jsx-runtime");
1441
+ var import_react4 = require("react");
1442
+ var import_fractal_icons10 = require("@mirror-physics/fractal-icons");
1443
+ var import_jsx_runtime20 = require("react/jsx-runtime");
743
1444
  function SortableTable({
744
1445
  columns,
745
1446
  data,
746
1447
  emptyMessage,
747
1448
  header,
748
1449
  size = "md",
1450
+ embedded = false,
749
1451
  className,
1452
+ defaultSort,
750
1453
  defaultSortKey = void 0,
751
1454
  defaultSortDirection = null,
752
1455
  sortKey: controlledKey,
753
1456
  sortDirection: controlledDirection,
754
1457
  onSortChange,
1458
+ pagination,
755
1459
  highlightRow,
756
- onRowClick
1460
+ onRowClick,
1461
+ onRowDoubleClick,
1462
+ rowAction
757
1463
  }) {
758
- const [internalKey, setInternalKey] = (0, import_react2.useState)(defaultSortKey ?? null);
759
- const [internalDirection, setInternalDirection] = (0, import_react2.useState)(defaultSortDirection);
1464
+ const [internalKey, setInternalKey] = (0, import_react4.useState)(defaultSortKey ?? null);
1465
+ const [internalDirection, setInternalDirection] = (0, import_react4.useState)(defaultSortDirection);
760
1466
  const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
761
1467
  const activeKey = isControlled ? controlledKey : internalKey;
762
1468
  const activeDirection = isControlled ? controlledDirection : internalDirection;
763
- const sorted = (0, import_react2.useMemo)(() => {
764
- if (!activeKey || !activeDirection) return data;
765
- const col = columns.find((c) => c.key === activeKey);
1469
+ const baselineKey = defaultSort?.key ?? null;
1470
+ const baselineDirection = defaultSort?.direction ?? null;
1471
+ const effectiveKey = activeKey && activeDirection ? activeKey : baselineKey;
1472
+ const effectiveDirection = activeKey && activeDirection ? activeDirection : baselineDirection;
1473
+ const sorted = (0, import_react4.useMemo)(() => {
1474
+ if (!effectiveKey || !effectiveDirection) return data;
1475
+ const col = columns.find((c) => c.key === effectiveKey);
766
1476
  if (!col) return data;
767
1477
  const accessor = col.sortAccessor ?? ((row) => {
768
- const value = row[activeKey];
1478
+ const value = row[effectiveKey];
769
1479
  return typeof value === "string" || typeof value === "number" ? value : null;
770
1480
  });
771
1481
  const copy = [...data];
@@ -776,26 +1486,36 @@ function SortableTable({
776
1486
  if (av == null) return 1;
777
1487
  if (bv == null) return -1;
778
1488
  if (typeof av === "number" && typeof bv === "number") {
779
- return activeDirection === "asc" ? av - bv : bv - av;
1489
+ return effectiveDirection === "asc" ? av - bv : bv - av;
780
1490
  }
781
1491
  const as = String(av).toLowerCase();
782
1492
  const bs = String(bv).toLowerCase();
783
- if (as < bs) return activeDirection === "asc" ? -1 : 1;
784
- if (as > bs) return activeDirection === "asc" ? 1 : -1;
1493
+ if (as < bs) return effectiveDirection === "asc" ? -1 : 1;
1494
+ if (as > bs) return effectiveDirection === "asc" ? 1 : -1;
785
1495
  return 0;
786
1496
  });
787
1497
  return copy;
788
- }, [data, columns, activeKey, activeDirection]);
1498
+ }, [data, columns, effectiveKey, effectiveDirection]);
1499
+ const visibleRows = (0, import_react4.useMemo)(() => {
1500
+ if (!pagination) return sorted;
1501
+ const pageSize = Math.max(1, pagination.pageSize);
1502
+ const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));
1503
+ const page = Math.min(Math.max(1, pagination.page), totalPages);
1504
+ const startIndex = (page - 1) * pageSize;
1505
+ return sorted.slice(startIndex, startIndex + pageSize);
1506
+ }, [pagination, sorted]);
789
1507
  const handleSortClick = (key) => {
790
1508
  let nextDirection;
791
- if (activeKey !== key) {
1509
+ if (!activeKey || !activeDirection) {
1510
+ nextDirection = baselineKey === key && baselineDirection ? baselineDirection : "asc";
1511
+ } else if (activeKey !== key) {
792
1512
  nextDirection = "asc";
1513
+ } else if (baselineKey === key && baselineDirection) {
1514
+ nextDirection = activeDirection === baselineDirection ? baselineDirection === "asc" ? "desc" : "asc" : null;
793
1515
  } else if (activeDirection === "asc") {
794
1516
  nextDirection = "desc";
795
- } else if (activeDirection === "desc") {
796
- nextDirection = null;
797
1517
  } else {
798
- nextDirection = "asc";
1518
+ nextDirection = null;
799
1519
  }
800
1520
  const nextKey = nextDirection === null ? null : key;
801
1521
  if (isControlled) {
@@ -806,13 +1526,13 @@ function SortableTable({
806
1526
  onSortChange?.(nextKey, nextDirection);
807
1527
  }
808
1528
  };
809
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "fractal-sortable-table-surface", children: [
810
- header && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
811
- sorted.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { className: "fractal-sortable-table-table", children: [
812
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tr", { className: "fractal-sortable-table-thead-row", children: columns.map((col) => {
1529
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "fractal-sortable-table-surface", children: [
1530
+ header && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
1531
+ visibleRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("table", { className: "fractal-sortable-table-table", children: [
1532
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tr", { className: "fractal-sortable-table-thead-row", children: columns.map((col) => {
813
1533
  const isActive = activeKey === col.key && activeDirection !== null;
814
1534
  if (!col.sortable) {
815
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1535
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
816
1536
  "th",
817
1537
  {
818
1538
  className: "fractal-sortable-table-th",
@@ -822,12 +1542,12 @@ function SortableTable({
822
1542
  col.key
823
1543
  );
824
1544
  }
825
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1545
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
826
1546
  "th",
827
1547
  {
828
1548
  className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
829
1549
  style: { width: col.width },
830
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1550
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
831
1551
  "button",
832
1552
  {
833
1553
  type: "button",
@@ -838,8 +1558,8 @@ function SortableTable({
838
1558
  onClick: () => handleSortClick(col.key),
839
1559
  "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
840
1560
  children: [
841
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: col.header }),
842
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.ArrowDown, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.ArrowsUpDown, { size: 14 }) })
1561
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: col.header }),
1562
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_fractal_icons10.ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_fractal_icons10.ArrowDown, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_fractal_icons10.ArrowsUpDown, { size: 14 }) })
843
1563
  ]
844
1564
  }
845
1565
  )
@@ -847,31 +1567,45 @@ function SortableTable({
847
1567
  col.key
848
1568
  );
849
1569
  }) }) }),
850
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
1570
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { children: visibleRows.map((row, rowIndex) => {
851
1571
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
852
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1572
+ const interactive = Boolean(onRowClick || onRowDoubleClick);
1573
+ const action = rowAction ? {
1574
+ label: rowAction.label(row, rowIndex),
1575
+ icon: rowAction.icon(row, rowIndex)
1576
+ } : null;
1577
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
853
1578
  "tr",
854
1579
  {
855
1580
  className: cn(
856
1581
  "fractal-sortable-table-row",
857
1582
  highlighted && "fractal-sortable-table-row--highlighted",
858
- onRowClick && "fractal-sortable-table-row--interactive"
1583
+ interactive && "fractal-sortable-table-row--interactive"
859
1584
  ),
860
1585
  onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
861
- onKeyDown: onRowClick ? (event) => {
1586
+ onDoubleClick: onRowDoubleClick ? () => onRowDoubleClick(row, rowIndex) : void 0,
1587
+ onKeyDown: interactive ? (event) => {
862
1588
  if (event.key === "Enter" || event.key === " ") {
863
1589
  event.preventDefault();
864
- onRowClick(row, rowIndex);
1590
+ const activateRow = onRowClick ?? onRowDoubleClick;
1591
+ activateRow?.(row, rowIndex);
865
1592
  }
866
1593
  } : void 0,
867
- role: onRowClick ? "button" : void 0,
868
- tabIndex: onRowClick ? 0 : void 0,
869
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1594
+ "aria-label": action?.label,
1595
+ role: interactive ? "button" : void 0,
1596
+ tabIndex: interactive ? 0 : void 0,
1597
+ children: columns.map((col, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
870
1598
  "td",
871
1599
  {
872
- className: "fractal-sortable-table-td",
1600
+ className: cn(
1601
+ "fractal-sortable-table-td",
1602
+ action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1603
+ ),
873
1604
  style: { width: col.width, textAlign: col.align ?? "left" },
874
- children: col.render(row, rowIndex)
1605
+ children: [
1606
+ col.render(row, rowIndex),
1607
+ action && columnIndex === columns.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
1608
+ ]
875
1609
  },
876
1610
  col.key
877
1611
  ))
@@ -884,23 +1618,40 @@ function SortableTable({
884
1618
  }
885
1619
 
886
1620
  // src/components/Tabs/Tabs.tsx
887
- var import_react3 = require("react");
888
- var import_jsx_runtime14 = require("react/jsx-runtime");
1621
+ var import_react5 = require("react");
1622
+ var import_jsx_runtime21 = require("react/jsx-runtime");
889
1623
  function Tabs({
890
1624
  items,
891
1625
  defaultValue,
892
1626
  value: controlledValue,
893
1627
  onValueChange,
894
1628
  className,
895
- ariaLabel
1629
+ ariaLabel,
1630
+ divider = false,
1631
+ variant = "line"
896
1632
  }) {
897
- const reactId = (0, import_react3.useId)();
898
- const [internalValue, setInternalValue] = (0, import_react3.useState)(
1633
+ const reactId = (0, import_react5.useId)();
1634
+ const [internalValue, setInternalValue] = (0, import_react5.useState)(
899
1635
  defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
900
1636
  );
901
1637
  const isControlled = controlledValue !== void 0;
902
1638
  const activeId = isControlled ? controlledValue : internalValue;
903
- const tabRefs = (0, import_react3.useRef)({});
1639
+ const tabListRef = (0, import_react5.useRef)(null);
1640
+ const tabRefs = (0, import_react5.useRef)({});
1641
+ const [indicator, setIndicator] = (0, import_react5.useState)(null);
1642
+ (0, import_react5.useLayoutEffect)(() => {
1643
+ const updateIndicator = () => {
1644
+ const activeTab = tabRefs.current[activeId];
1645
+ if (!activeTab) return;
1646
+ setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
1647
+ };
1648
+ updateIndicator();
1649
+ const list = tabListRef.current;
1650
+ if (!list || typeof ResizeObserver === "undefined") return;
1651
+ const observer = new ResizeObserver(updateIndicator);
1652
+ observer.observe(list);
1653
+ return () => observer.disconnect();
1654
+ }, [activeId, items.length]);
904
1655
  const selectTab = (id) => {
905
1656
  if (isControlled) {
906
1657
  onValueChange?.(id);
@@ -910,6 +1661,10 @@ function Tabs({
910
1661
  }
911
1662
  };
912
1663
  const focusable = items.filter((i) => !i.disabled);
1664
+ const indicatorStyle = indicator ? {
1665
+ "--fractal-tabs-indicator-offset": `${indicator.offset}px`,
1666
+ "--fractal-tabs-indicator-width": `${indicator.width}px`
1667
+ } : void 0;
913
1668
  const onKeyDown = (event) => {
914
1669
  const currentIndex = focusable.findIndex((i) => i.id === activeId);
915
1670
  if (currentIndex === -1) return;
@@ -935,41 +1690,52 @@ function Tabs({
935
1690
  selectTab(nextId2);
936
1691
  requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
937
1692
  };
938
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cn("fractal-tabs", className), children: [
939
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "tablist", "aria-label": ariaLabel, className: "fractal-tabs-list", children: items.map((item) => {
940
- const isActive = item.id === activeId;
941
- const tabId = `${reactId}-tab-${item.id}`;
942
- const panelId = `${reactId}-panel-${item.id}`;
943
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
944
- "button",
945
- {
946
- ref: (el) => {
947
- tabRefs.current[item.id] = el;
948
- },
949
- id: tabId,
950
- role: "tab",
951
- type: "button",
952
- "aria-selected": isActive,
953
- "aria-controls": panelId,
954
- tabIndex: isActive ? 0 : -1,
955
- disabled: item.disabled,
956
- className: cn(
957
- "fractal-tabs-trigger",
958
- isActive && "fractal-tabs-trigger--active",
959
- item.disabled && "fractal-tabs-trigger--disabled"
960
- ),
961
- onClick: () => !item.disabled && selectTab(item.id),
962
- onKeyDown,
963
- children: item.label
964
- },
965
- item.id
966
- );
967
- }) }),
1693
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: cn("fractal-tabs", `fractal-tabs--${variant}`, divider && "fractal-tabs--divider", className), children: [
1694
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1695
+ "div",
1696
+ {
1697
+ ref: tabListRef,
1698
+ role: "tablist",
1699
+ "aria-label": ariaLabel,
1700
+ className: "fractal-tabs-list",
1701
+ "data-indicator-ready": indicator ? "true" : void 0,
1702
+ style: indicatorStyle,
1703
+ children: items.map((item) => {
1704
+ const isActive = item.id === activeId;
1705
+ const tabId = `${reactId}-tab-${item.id}`;
1706
+ const panelId = `${reactId}-panel-${item.id}`;
1707
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1708
+ "button",
1709
+ {
1710
+ ref: (el) => {
1711
+ tabRefs.current[item.id] = el;
1712
+ },
1713
+ id: tabId,
1714
+ role: "tab",
1715
+ type: "button",
1716
+ "aria-selected": isActive,
1717
+ "aria-controls": panelId,
1718
+ tabIndex: isActive ? 0 : -1,
1719
+ disabled: item.disabled,
1720
+ className: cn(
1721
+ "fractal-tabs-trigger",
1722
+ isActive && "fractal-tabs-trigger--active",
1723
+ item.disabled && "fractal-tabs-trigger--disabled"
1724
+ ),
1725
+ onClick: () => !item.disabled && selectTab(item.id),
1726
+ onKeyDown,
1727
+ children: item.label
1728
+ },
1729
+ item.id
1730
+ );
1731
+ })
1732
+ }
1733
+ ),
968
1734
  items.map((item) => {
969
1735
  const tabId = `${reactId}-tab-${item.id}`;
970
1736
  const panelId = `${reactId}-panel-${item.id}`;
971
1737
  const isActive = item.id === activeId;
972
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1738
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
973
1739
  "div",
974
1740
  {
975
1741
  id: panelId,
@@ -985,10 +1751,112 @@ function Tabs({
985
1751
  ] });
986
1752
  }
987
1753
 
1754
+ // src/components/ContentSwitcher/ContentSwitcher.tsx
1755
+ var React13 = __toESM(require("react"), 1);
1756
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1757
+ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1758
+ const switcherRef = React13.useRef(null);
1759
+ const buttonRefs = React13.useRef([]);
1760
+ const indicatorMotionReadyRef = React13.useRef(false);
1761
+ const activeIndex = items.findIndex((item) => item.value === value);
1762
+ React13.useLayoutEffect(() => {
1763
+ const switcher = switcherRef.current;
1764
+ const activeButton = buttonRefs.current[activeIndex];
1765
+ let motionFrame = 0;
1766
+ if (!switcher || !activeButton) {
1767
+ switcher?.removeAttribute("data-indicator-ready");
1768
+ switcher?.removeAttribute("data-indicator-animate");
1769
+ indicatorMotionReadyRef.current = false;
1770
+ return;
1771
+ }
1772
+ const updateIndicator = () => {
1773
+ const switcherRect = switcher.getBoundingClientRect();
1774
+ const activeButtonRect = activeButton.getBoundingClientRect();
1775
+ switcher.style.setProperty("--fractal-content-switcher-indicator-x", `${activeButtonRect.left - switcherRect.left - switcher.clientLeft}px`);
1776
+ switcher.style.setProperty("--fractal-content-switcher-indicator-y", `${activeButtonRect.top - switcherRect.top - switcher.clientTop}px`);
1777
+ switcher.style.setProperty("--fractal-content-switcher-indicator-width", `${activeButtonRect.width}px`);
1778
+ switcher.style.setProperty("--fractal-content-switcher-indicator-height", `${activeButtonRect.height}px`);
1779
+ switcher.setAttribute("data-indicator-ready", "true");
1780
+ if (!indicatorMotionReadyRef.current && motionFrame === 0) {
1781
+ motionFrame = window.requestAnimationFrame(() => {
1782
+ indicatorMotionReadyRef.current = true;
1783
+ switcher.setAttribute("data-indicator-animate", "true");
1784
+ motionFrame = 0;
1785
+ });
1786
+ }
1787
+ };
1788
+ updateIndicator();
1789
+ if (typeof ResizeObserver === "undefined") {
1790
+ return () => {
1791
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1792
+ };
1793
+ }
1794
+ const resizeObserver = new ResizeObserver(updateIndicator);
1795
+ resizeObserver.observe(switcher);
1796
+ buttonRefs.current.forEach((button) => {
1797
+ if (button) resizeObserver.observe(button);
1798
+ });
1799
+ return () => {
1800
+ resizeObserver.disconnect();
1801
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1802
+ };
1803
+ }, [activeIndex, items.length]);
1804
+ const moveFocus = (index, direction) => {
1805
+ let nextIndex = index;
1806
+ do {
1807
+ nextIndex = (nextIndex + direction + items.length) % items.length;
1808
+ } while (items[nextIndex]?.disabled && nextIndex !== index);
1809
+ if (!items[nextIndex]?.disabled) {
1810
+ buttonRefs.current[nextIndex]?.focus();
1811
+ onValueChange(items[nextIndex].value);
1812
+ }
1813
+ };
1814
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1815
+ "div",
1816
+ {
1817
+ className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className),
1818
+ role: "group",
1819
+ "aria-label": ariaLabel,
1820
+ ref: switcherRef,
1821
+ children: [
1822
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
1823
+ items.map((item, index) => {
1824
+ const active = item.value === value;
1825
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1826
+ "button",
1827
+ {
1828
+ className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
1829
+ type: "button",
1830
+ "aria-pressed": active,
1831
+ disabled: item.disabled,
1832
+ onClick: () => onValueChange(item.value),
1833
+ onKeyDown: (event) => {
1834
+ if (event.key === "ArrowRight") {
1835
+ event.preventDefault();
1836
+ moveFocus(index, 1);
1837
+ }
1838
+ if (event.key === "ArrowLeft") {
1839
+ event.preventDefault();
1840
+ moveFocus(index, -1);
1841
+ }
1842
+ },
1843
+ ref: (element) => {
1844
+ buttonRefs.current[index] = element;
1845
+ },
1846
+ children: item.label
1847
+ },
1848
+ item.value
1849
+ );
1850
+ })
1851
+ ]
1852
+ }
1853
+ );
1854
+ }
1855
+
988
1856
  // src/components/Disclosure/Disclosure.tsx
989
- var import_react4 = require("react");
990
- var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
991
- var import_jsx_runtime15 = require("react/jsx-runtime");
1857
+ var import_react6 = require("react");
1858
+ var import_fractal_icons11 = require("@mirror-physics/fractal-icons");
1859
+ var import_jsx_runtime23 = require("react/jsx-runtime");
992
1860
  function Disclosure({
993
1861
  title,
994
1862
  meta,
@@ -996,16 +1864,18 @@ function Disclosure({
996
1864
  defaultOpen = false,
997
1865
  open: controlledOpen,
998
1866
  onOpenChange,
1867
+ disabled = false,
999
1868
  className,
1000
1869
  variant = "card"
1001
1870
  }) {
1002
- const reactId = (0, import_react4.useId)();
1871
+ const reactId = (0, import_react6.useId)();
1003
1872
  const headerId = `${reactId}-header`;
1004
1873
  const panelId = `${reactId}-panel`;
1005
- const [internalOpen, setInternalOpen] = (0, import_react4.useState)(defaultOpen);
1874
+ const [internalOpen, setInternalOpen] = (0, import_react6.useState)(defaultOpen);
1006
1875
  const isControlled = controlledOpen !== void 0;
1007
1876
  const isOpen = isControlled ? controlledOpen : internalOpen;
1008
1877
  const toggle = () => {
1878
+ if (disabled) return;
1009
1879
  const next = !isOpen;
1010
1880
  if (isControlled) {
1011
1881
  onOpenChange?.(next);
@@ -1014,17 +1884,18 @@ function Disclosure({
1014
1884
  onOpenChange?.(next);
1015
1885
  }
1016
1886
  };
1017
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1887
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1018
1888
  "div",
1019
1889
  {
1020
1890
  className: cn(
1021
1891
  "fractal-disclosure",
1022
1892
  variant === "card" && "fractal-disclosure--card",
1023
1893
  isOpen && "fractal-disclosure--open",
1894
+ disabled && "fractal-disclosure--disabled",
1024
1895
  className
1025
1896
  ),
1026
1897
  children: [
1027
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1898
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1028
1899
  "button",
1029
1900
  {
1030
1901
  type: "button",
@@ -1032,15 +1903,16 @@ function Disclosure({
1032
1903
  className: "fractal-disclosure-trigger",
1033
1904
  "aria-expanded": isOpen,
1034
1905
  "aria-controls": panelId,
1906
+ disabled,
1035
1907
  onClick: toggle,
1036
1908
  children: [
1037
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_fractal_icons4.ChevronDown, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_fractal_icons4.ChevronRight, { size: 16 }) }),
1038
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1039
- meta && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1909
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fractal_icons11.ChevronDown, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fractal_icons11.ChevronRight, { size: 16 }) }),
1910
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1911
+ meta && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1040
1912
  ]
1041
1913
  }
1042
1914
  ),
1043
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1915
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1044
1916
  "div",
1045
1917
  {
1046
1918
  id: panelId,
@@ -1048,7 +1920,7 @@ function Disclosure({
1048
1920
  "aria-labelledby": headerId,
1049
1921
  className: "fractal-disclosure-panel",
1050
1922
  hidden: !isOpen,
1051
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1923
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1052
1924
  }
1053
1925
  )
1054
1926
  ]
@@ -1056,39 +1928,260 @@ function Disclosure({
1056
1928
  );
1057
1929
  }
1058
1930
 
1931
+ // src/components/LatticeLoader/LatticeLoader.tsx
1932
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1933
+ var LATTICE_COUNT = 160;
1934
+ var WAVE_PERIOD = 80;
1935
+ function LatticeLoader({ className, label = "Loading", ...props }) {
1936
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1937
+ "span",
1938
+ {
1939
+ "aria-label": label,
1940
+ className: cn("fractal-lattice-loader", className),
1941
+ role: "progressbar",
1942
+ ...props,
1943
+ children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1944
+ "span",
1945
+ {
1946
+ "aria-hidden": "true",
1947
+ className: "fractal-lattice-loader__cell",
1948
+ style: { "--fractal-lattice-index": index % WAVE_PERIOD }
1949
+ },
1950
+ index
1951
+ ))
1952
+ }
1953
+ );
1954
+ }
1955
+
1956
+ // src/components/Ghost/Ghost.tsx
1957
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1958
+ var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
1959
+ function Ghost({ className, width, height, radius, style, ...props }) {
1960
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1961
+ "div",
1962
+ {
1963
+ "aria-hidden": "true",
1964
+ className: cn("fractal-ghost", className),
1965
+ style: {
1966
+ width: toCssLength(width),
1967
+ height: toCssLength(height),
1968
+ borderRadius: toCssLength(radius),
1969
+ ...style
1970
+ },
1971
+ ...props
1972
+ }
1973
+ );
1974
+ }
1975
+ function GhostLine({ className, size = "md", width = "100%", ...props }) {
1976
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
1977
+ }
1978
+ function ButtonGhost({ className, size = "md", iconOnly = false, width, ...props }) {
1979
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
1980
+ }
1981
+ function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
1982
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
1983
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "38%" }),
1984
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: index === lines - 1 ? "62%" : "100%" }, index)) })
1985
+ ] });
1986
+ }
1987
+ function DataTableGhost({
1988
+ className,
1989
+ showHeader = true,
1990
+ headers,
1991
+ columns = 4,
1992
+ rows = 5,
1993
+ columnWidths,
1994
+ size = "md",
1995
+ ...props
1996
+ }) {
1997
+ const cells = Array.from({ length: columns }, (_, index) => index);
1998
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "aria-busy": "true", "aria-label": "Loading table", className: cn("fractal-ghost-table", `fractal-ghost-table--${size}`, className), role: "status", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("table", { className: "fractal-ghost-table__table", children: [
1999
+ (showHeader || headers) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("tr", { className: "fractal-ghost-table__head-row", children: cells.map((index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { style: { width: columnWidths?.[index] }, children: headers?.[index] ?? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { size: "sm", width: index === columns - 1 ? "62%" : "76%" }) }, index)) }) }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("tbody", { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("tr", { className: "fractal-ghost-table__row", children: cells.map((columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { style: { width: columnWidths?.[columnIndex] }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: `${[72, 54, 82, 63, 46][(rowIndex + columnIndex) % 5]}%` }) }, columnIndex)) }, rowIndex)) })
2001
+ ] }) });
2002
+ }
2003
+ function InputGhost({ className, labelWidth = "26%", ...props }) {
2004
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FormFieldGhost, { className, labelWidth, ...props });
2005
+ }
2006
+ function TextareaGhost({ className, labelWidth = "26%", ...props }) {
2007
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
2008
+ }
2009
+ function LabelGhost({ className, width = "26%", ...props }) {
2010
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
2011
+ }
2012
+ function FormFieldGhost({ className, labelWidth = "26%", multiline = false, ...props }) {
2013
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-field", className), ...props, children: [
2014
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LabelGhost, { width: labelWidth }),
2015
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
2016
+ ] });
2017
+ }
2018
+ function AlertGhost({ className, ...props }) {
2019
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
2020
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "30%" }),
2021
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { size: "sm", width: "78%" })
2022
+ ] });
2023
+ }
2024
+ function CheckboxGhost({ className, ...props }) {
2025
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
2026
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-choice__control" }),
2027
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" })
2028
+ ] });
2029
+ }
2030
+ var ToggleGhost = CheckboxGhost;
2031
+ function ChipGhost({ className, width = 74, ...props }) {
2032
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
2033
+ }
2034
+ function LinkGhost({ className, width = 96, ...props }) {
2035
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
2036
+ }
2037
+ var TextButtonGhost = LinkGhost;
2038
+ function DropdownGhost({ className, ...props }) {
2039
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropdown", className), ...props, children: [
2040
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "38%" }),
2041
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-dropdown__chevron" })
2042
+ ] });
2043
+ }
2044
+ function ContentSwitcherGhost({ className, options = 3, ...props }) {
2045
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "aria-hidden": "true", className: cn("fractal-ghost-switcher", className), ...props, children: Array.from({ length: options }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, {}, index)) });
2046
+ }
2047
+ var TabsGhost = ContentSwitcherGhost;
2048
+ function DisclosureGhost({ className, ...props }) {
2049
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
2050
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-disclosure__icon" }),
2051
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" })
2052
+ ] });
2053
+ }
2054
+ function PaginationGhost({ className, pages = 5, ...props }) {
2055
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "aria-hidden": "true", className: cn("fractal-ghost-pagination", className), ...props, children: Array.from({ length: pages }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, {}, index)) });
2056
+ }
2057
+ function FileDropzoneGhost({ className, ...props }) {
2058
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
2059
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-dropzone__icon" }),
2060
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "26%" }),
2061
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { size: "sm", width: "46%" })
2062
+ ] });
2063
+ }
2064
+ function PromptCardGhost({ className, ...props }) {
2065
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
2066
+ }
2067
+ function ConversationGhost({
2068
+ className,
2069
+ "aria-label": ariaLabel = "Loading conversation",
2070
+ ...props
2071
+ }) {
2072
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2073
+ "div",
2074
+ {
2075
+ "aria-busy": "true",
2076
+ "aria-label": ariaLabel,
2077
+ className: cn("fractal-ghost-conversation", className),
2078
+ role: "status",
2079
+ ...props,
2080
+ children: [
2081
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--user", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fractal-ghost-conversation__bubble", children: [
2082
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "100%" }),
2083
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "86%" }),
2084
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "64%" })
2085
+ ] }) }),
2086
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--assistant", children: [
2087
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "92%" }),
2088
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "78%" }),
2089
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "58%" })
2090
+ ] })
2091
+ ]
2092
+ }
2093
+ );
2094
+ }
2095
+ function SortableTableGhost(props) {
2096
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DataTableGhost, { ...props });
2097
+ }
2098
+ function SidebarGhost({ className, items = 6, ...props }) {
2099
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
2100
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-sidebar__brand" }),
2101
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "fractal-ghost-sidebar__items", children: Array.from({ length: items }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fractal-ghost-sidebar__item", children: [
2102
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, {}),
2103
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
2104
+ ] }, index)) })
2105
+ ] });
2106
+ }
2107
+ function ModalGhost({ className, title, lines = 3, ...props }) {
2108
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
2109
+ }
2110
+ function SidePanelGhost({ className, title, lines = 5, ...props }) {
2111
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
2112
+ }
2113
+ function SurfaceGhost({ className, title, lines = 3, ...props }) {
2114
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
2115
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fractal-ghost-surface__header", children: [
2116
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-surface__close" })
2118
+ ] }),
2119
+ title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "fractal-ghost-surface__title", children: title }),
2120
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: index === lines - 1 ? "64%" : "100%" }, index)) })
2121
+ ] });
2122
+ }
2123
+
1059
2124
  // src/components/Sidebar/Sidebar.tsx
1060
- var React10 = __toESM(require("react"), 1);
1061
- var import_jsx_runtime16 = require("react/jsx-runtime");
1062
- var Sidebar = React10.forwardRef(
1063
- ({ className, width, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2125
+ var React14 = __toESM(require("react"), 1);
2126
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2127
+ var Sidebar = React14.forwardRef(
2128
+ ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1064
2129
  "aside",
1065
2130
  {
1066
2131
  ref,
1067
2132
  className: cn("fractal-sidebar", className),
2133
+ "data-compact": compact || void 0,
1068
2134
  style: { ...style, ...width ? { "--fractal-sidebar-width": width } : {} },
1069
2135
  ...props
1070
2136
  }
1071
2137
  )
1072
2138
  );
1073
2139
  Sidebar.displayName = "Sidebar";
1074
- var SidebarHeader = React10.forwardRef(
1075
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
2140
+ var SidebarHeader = React14.forwardRef(
2141
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1076
2142
  );
1077
2143
  SidebarHeader.displayName = "SidebarHeader";
1078
- var SidebarBrand = React10.forwardRef(
1079
- ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
2144
+ var SidebarBrand = React14.forwardRef(
2145
+ ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1080
2146
  );
1081
2147
  SidebarBrand.displayName = "SidebarBrand";
1082
- var SidebarNav = React10.forwardRef(
1083
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
2148
+ function SidebarAccountMenu({
2149
+ name,
2150
+ items,
2151
+ onSelect,
2152
+ triggerLabel = "Account menu",
2153
+ icon,
2154
+ className
2155
+ }) {
2156
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2157
+ Dropdown,
2158
+ {
2159
+ align: "left",
2160
+ className: cn("fractal-sidebar__account", className),
2161
+ items,
2162
+ onSelect,
2163
+ panelClassName: "fractal-sidebar__account-panel",
2164
+ selectedValue: "",
2165
+ triggerClassName: "fractal-sidebar__account-trigger",
2166
+ triggerContent: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
2167
+ icon && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
2168
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__account-name", children: name })
2169
+ ] }),
2170
+ triggerLabel,
2171
+ triggerVariant: "tertiary"
2172
+ }
2173
+ );
2174
+ }
2175
+ var SidebarNav = React14.forwardRef(
2176
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1084
2177
  );
1085
2178
  SidebarNav.displayName = "SidebarNav";
1086
- var SidebarSection = React10.forwardRef(
1087
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
2179
+ var SidebarSection = React14.forwardRef(
2180
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1088
2181
  );
1089
2182
  SidebarSection.displayName = "SidebarSection";
1090
- var SidebarNavItem = React10.forwardRef(
1091
- ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2183
+ var SidebarNavItem = React14.forwardRef(
2184
+ ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1092
2185
  "button",
1093
2186
  {
1094
2187
  ref,
@@ -1098,39 +2191,28 @@ var SidebarNavItem = React10.forwardRef(
1098
2191
  "aria-current": active ? "page" : void 0,
1099
2192
  ...props,
1100
2193
  children: [
1101
- icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1102
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1103
- endAdornment && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
2194
+ icon && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
2195
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
2196
+ endAdornment && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1104
2197
  ]
1105
2198
  }
1106
2199
  )
1107
2200
  );
1108
2201
  SidebarNavItem.displayName = "SidebarNavItem";
1109
- var SidebarFooter = React10.forwardRef(
1110
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
2202
+ var SidebarFooter = React14.forwardRef(
2203
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1111
2204
  );
1112
2205
  SidebarFooter.displayName = "SidebarFooter";
1113
2206
 
1114
- // src/components/PageHeader/PageHeader.tsx
1115
- var React11 = __toESM(require("react"), 1);
1116
- var import_jsx_runtime17 = require("react/jsx-runtime");
1117
- var PageHeader = React11.forwardRef(
1118
- ({ title, actions, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref, className: cn("fractal-page-header", className), ...props, children: [
1119
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-page-header__content", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h1", { className: "fractal-page-header__title", children: title }) }),
1120
- actions && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-page-header__actions", children: actions })
1121
- ] })
1122
- );
1123
- PageHeader.displayName = "PageHeader";
1124
-
1125
2207
  // src/components/SidePanel/SidePanel.tsx
1126
2208
  var import_react_dom2 = require("react-dom");
1127
- var import_fractal_icons5 = require("@mirror-physics/fractal-icons");
1128
- var import_jsx_runtime18 = require("react/jsx-runtime");
1129
- function SidePanel({ open, onClose, title, description, children, footer, size = "md", className }) {
2209
+ var import_fractal_icons12 = require("@mirror-physics/fractal-icons");
2210
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2211
+ function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
1130
2212
  useEscapeDismiss(80, onClose, open);
1131
2213
  if (!open) return null;
1132
2214
  return (0, import_react_dom2.createPortal)(
1133
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2215
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1134
2216
  "aside",
1135
2217
  {
1136
2218
  className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
@@ -1139,15 +2221,15 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
1139
2221
  role: "dialog",
1140
2222
  onMouseDown: (event) => event.stopPropagation(),
1141
2223
  children: [
1142
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("header", { className: "fractal-side-panel__header", children: [
1143
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "fractal-side-panel__heading", children: [
1144
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { className: "fractal-side-panel__title", children: title }),
1145
- description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "fractal-side-panel__description", children: description })
2224
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("header", { className: "fractal-side-panel__header", children: [
2225
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "fractal-side-panel__heading", children: [
2226
+ typeof title === "string" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "fractal-side-panel__title", children: title }),
2227
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "fractal-side-panel__description", children: description })
1146
2228
  ] }),
1147
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_fractal_icons5.Close, { size: 18 }) })
2229
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fractal_icons12.Close, { size: 18 }) })
1148
2230
  ] }),
1149
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fractal-side-panel__body", children }),
1150
- footer && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
2231
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { "aria-busy": loading || void 0, className: cn("fractal-side-panel__body", loading && "fractal-side-panel__body--loading"), children: loading ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UILoader, { label: loadingLabel }) : children }),
2232
+ footer && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
1151
2233
  ]
1152
2234
  }
1153
2235
  ) }),
@@ -1156,49 +2238,273 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
1156
2238
  }
1157
2239
 
1158
2240
  // src/components/Textarea/Textarea.tsx
1159
- var React12 = __toESM(require("react"), 1);
1160
- var import_jsx_runtime19 = require("react/jsx-runtime");
1161
- var Textarea = React12.forwardRef(
1162
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
2241
+ var React15 = __toESM(require("react"), 1);
2242
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2243
+ var Textarea = React15.forwardRef(
2244
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
1163
2245
  );
1164
2246
  Textarea.displayName = "Textarea";
2247
+
2248
+ // src/components/TextButton/TextButton.tsx
2249
+ var React16 = __toESM(require("react"), 1);
2250
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2251
+ var TextButton = React16.forwardRef(
2252
+ ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2253
+ "button",
2254
+ {
2255
+ ref,
2256
+ className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
2257
+ type: "button",
2258
+ ...props,
2259
+ children: [
2260
+ icon && iconPosition === "start" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
2261
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children }),
2262
+ icon && iconPosition === "end" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
2263
+ ]
2264
+ }
2265
+ )
2266
+ );
2267
+ TextButton.displayName = "TextButton";
2268
+
2269
+ // src/components/FileDropzone/FileDropzone.tsx
2270
+ var React17 = __toESM(require("react"), 1);
2271
+ var import_fractal_icons13 = require("@mirror-physics/fractal-icons");
2272
+ var import_jsx_runtime30 = require("react/jsx-runtime");
2273
+ function FileDropzone({
2274
+ files,
2275
+ onFilesChange,
2276
+ accept,
2277
+ multiple = true,
2278
+ disabled = false,
2279
+ title = "Drop files here or click to browse",
2280
+ description = "Files stay attached to this record.",
2281
+ className
2282
+ }) {
2283
+ const inputId = React17.useId();
2284
+ const inputRef = React17.useRef(null);
2285
+ const [isDragging, setIsDragging] = React17.useState(false);
2286
+ const addFiles = (nextFiles) => {
2287
+ if (disabled) return;
2288
+ const additions = Array.from(nextFiles);
2289
+ if (additions.length === 0) return;
2290
+ onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
2291
+ };
2292
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: cn("fractal-file-dropzone", className), children: [
2293
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2294
+ "input",
2295
+ {
2296
+ ref: inputRef,
2297
+ id: inputId,
2298
+ className: "fractal-file-dropzone__input",
2299
+ type: "file",
2300
+ accept,
2301
+ multiple,
2302
+ disabled,
2303
+ onChange: (event) => {
2304
+ if (event.target.files) addFiles(event.target.files);
2305
+ event.target.value = "";
2306
+ }
2307
+ }
2308
+ ),
2309
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
2310
+ "button",
2311
+ {
2312
+ className: "fractal-file-dropzone__target",
2313
+ "data-dragging": isDragging || void 0,
2314
+ type: "button",
2315
+ disabled,
2316
+ onClick: () => inputRef.current?.click(),
2317
+ onDragEnter: (event) => {
2318
+ event.preventDefault();
2319
+ if (!disabled) setIsDragging(true);
2320
+ },
2321
+ onDragOver: (event) => event.preventDefault(),
2322
+ onDragLeave: (event) => {
2323
+ event.preventDefault();
2324
+ setIsDragging(false);
2325
+ },
2326
+ onDrop: (event) => {
2327
+ event.preventDefault();
2328
+ setIsDragging(false);
2329
+ addFiles(event.dataTransfer.files);
2330
+ },
2331
+ children: [
2332
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_fractal_icons13.FileArrowUp, { "aria-hidden": "true", size: 20 }),
2333
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "fractal-file-dropzone__copy", children: [
2334
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__title", children: title }),
2335
+ description && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__description", children: description })
2336
+ ] })
2337
+ ]
2338
+ }
2339
+ ),
2340
+ files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("li", { className: "fractal-file-dropzone__file", children: [
2341
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
2342
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
2343
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2344
+ "button",
2345
+ {
2346
+ className: "fractal-file-dropzone__remove",
2347
+ type: "button",
2348
+ "aria-label": `Remove ${file.name}`,
2349
+ disabled,
2350
+ onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
2351
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_fractal_icons13.Close, { "aria-hidden": "true", size: 14 })
2352
+ }
2353
+ )
2354
+ ] }, `${file.name}-${file.size}-${index}`)) })
2355
+ ] });
2356
+ }
2357
+ function formatFileSize(bytes) {
2358
+ if (bytes < 1024) return `${bytes} B`;
2359
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
2360
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2361
+ }
2362
+
2363
+ // src/components/Pagination/Pagination.tsx
2364
+ var import_fractal_icons14 = require("@mirror-physics/fractal-icons");
2365
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2366
+ function Pagination({
2367
+ page,
2368
+ pageSize,
2369
+ totalItems,
2370
+ onPageChange,
2371
+ pageSizeOptions,
2372
+ onPageSizeChange,
2373
+ ariaLabel = "Pagination",
2374
+ className
2375
+ }) {
2376
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
2377
+ const currentPage = Math.min(Math.max(page, 1), totalPages);
2378
+ const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
2379
+ const end = Math.min(currentPage * pageSize, totalItems);
2380
+ const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
2381
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
2382
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
2383
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "fractal-pagination__controls", children: [
2384
+ canChangePageSize && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2385
+ Dropdown,
2386
+ {
2387
+ align: "right",
2388
+ className: "fractal-pagination__page-size",
2389
+ direction: "up",
2390
+ items: pageSizeOptions.map((option) => ({
2391
+ value: String(option),
2392
+ description: `${option} per page`
2393
+ })),
2394
+ onSelect: (value) => onPageSizeChange(Number(value)),
2395
+ selectedValue: String(pageSize),
2396
+ size: "sm",
2397
+ triggerLabel: "Results per page",
2398
+ triggerVariant: "tertiary"
2399
+ }
2400
+ ),
2401
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2402
+ "button",
2403
+ {
2404
+ className: "fractal-pagination__button",
2405
+ type: "button",
2406
+ "aria-label": "Previous page",
2407
+ title: "Previous page",
2408
+ disabled: currentPage === 1 || totalItems === 0,
2409
+ onClick: () => onPageChange(currentPage - 1),
2410
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fractal_icons14.ArrowLeft, { "aria-hidden": "true", size: 16 })
2411
+ }
2412
+ ),
2413
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
2414
+ currentPage,
2415
+ " of ",
2416
+ totalPages
2417
+ ] }),
2418
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2419
+ "button",
2420
+ {
2421
+ className: "fractal-pagination__button",
2422
+ type: "button",
2423
+ "aria-label": "Next page",
2424
+ title: "Next page",
2425
+ disabled: currentPage === totalPages || totalItems === 0,
2426
+ onClick: () => onPageChange(currentPage + 1),
2427
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fractal_icons14.ArrowRight, { "aria-hidden": "true", size: 16 })
2428
+ }
2429
+ )
2430
+ ] })
2431
+ ] });
2432
+ }
1165
2433
  // Annotate the CommonJS export names for ESM import in node:
1166
2434
  0 && (module.exports = {
1167
2435
  Alert,
1168
2436
  AlertDescription,
2437
+ AlertGhost,
1169
2438
  AlertTitle,
2439
+ Breadcrumbs,
1170
2440
  Button,
2441
+ ButtonGhost,
1171
2442
  Card,
1172
2443
  CardContent,
1173
2444
  CardDescription,
1174
2445
  CardFooter,
2446
+ CardGhost,
1175
2447
  CardHeader,
1176
2448
  CardTitle,
2449
+ Checkbox,
2450
+ CheckboxGhost,
1177
2451
  Chip,
2452
+ ChipGhost,
2453
+ CodeBlock,
2454
+ ContentSwitcher,
2455
+ ContentSwitcherGhost,
2456
+ ConversationGhost,
1178
2457
  DataTable,
2458
+ DataTableGhost,
1179
2459
  Disclosure,
2460
+ DisclosureGhost,
1180
2461
  Dropdown,
2462
+ DropdownGhost,
1181
2463
  FeatureCard,
2464
+ FileDropzone,
2465
+ FileDropzoneGhost,
1182
2466
  FolderCard,
2467
+ Ghost,
2468
+ GhostLine,
1183
2469
  Input,
2470
+ InputGhost,
1184
2471
  Label,
2472
+ LabelGhost,
2473
+ LatticeLoader,
1185
2474
  Link,
2475
+ LinkGhost,
1186
2476
  Modal,
1187
- PageHeader,
2477
+ ModalGhost,
2478
+ NumberInput,
2479
+ Pagination,
2480
+ PaginationGhost,
2481
+ PasswordInput,
1188
2482
  PromptCard,
2483
+ PromptCardGhost,
1189
2484
  PromptGrid,
1190
2485
  SidePanel,
2486
+ SidePanelGhost,
1191
2487
  Sidebar,
2488
+ SidebarAccountMenu,
1192
2489
  SidebarBrand,
1193
2490
  SidebarFooter,
2491
+ SidebarGhost,
1194
2492
  SidebarHeader,
1195
2493
  SidebarNav,
1196
2494
  SidebarNavItem,
1197
2495
  SidebarSection,
1198
2496
  SortableTable,
2497
+ SortableTableGhost,
2498
+ TableSearch,
1199
2499
  Tabs,
2500
+ TabsGhost,
2501
+ TextButton,
2502
+ TextButtonGhost,
1200
2503
  Textarea,
2504
+ TextareaGhost,
1201
2505
  Toggle,
2506
+ ToggleGhost,
2507
+ UILoader,
1202
2508
  cn,
1203
2509
  useEscapeDismiss
1204
2510
  });