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

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,87 @@ 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
+ rowAction
757
1462
  }) {
758
- const [internalKey, setInternalKey] = (0, import_react2.useState)(defaultSortKey ?? null);
759
- const [internalDirection, setInternalDirection] = (0, import_react2.useState)(defaultSortDirection);
1463
+ const [internalKey, setInternalKey] = (0, import_react4.useState)(defaultSortKey ?? null);
1464
+ const [internalDirection, setInternalDirection] = (0, import_react4.useState)(defaultSortDirection);
760
1465
  const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
761
1466
  const activeKey = isControlled ? controlledKey : internalKey;
762
1467
  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);
1468
+ const baselineKey = defaultSort?.key ?? null;
1469
+ const baselineDirection = defaultSort?.direction ?? null;
1470
+ const effectiveKey = activeKey && activeDirection ? activeKey : baselineKey;
1471
+ const effectiveDirection = activeKey && activeDirection ? activeDirection : baselineDirection;
1472
+ const sorted = (0, import_react4.useMemo)(() => {
1473
+ if (!effectiveKey || !effectiveDirection) return data;
1474
+ const col = columns.find((c) => c.key === effectiveKey);
766
1475
  if (!col) return data;
767
1476
  const accessor = col.sortAccessor ?? ((row) => {
768
- const value = row[activeKey];
1477
+ const value = row[effectiveKey];
769
1478
  return typeof value === "string" || typeof value === "number" ? value : null;
770
1479
  });
771
1480
  const copy = [...data];
@@ -776,26 +1485,36 @@ function SortableTable({
776
1485
  if (av == null) return 1;
777
1486
  if (bv == null) return -1;
778
1487
  if (typeof av === "number" && typeof bv === "number") {
779
- return activeDirection === "asc" ? av - bv : bv - av;
1488
+ return effectiveDirection === "asc" ? av - bv : bv - av;
780
1489
  }
781
1490
  const as = String(av).toLowerCase();
782
1491
  const bs = String(bv).toLowerCase();
783
- if (as < bs) return activeDirection === "asc" ? -1 : 1;
784
- if (as > bs) return activeDirection === "asc" ? 1 : -1;
1492
+ if (as < bs) return effectiveDirection === "asc" ? -1 : 1;
1493
+ if (as > bs) return effectiveDirection === "asc" ? 1 : -1;
785
1494
  return 0;
786
1495
  });
787
1496
  return copy;
788
- }, [data, columns, activeKey, activeDirection]);
1497
+ }, [data, columns, effectiveKey, effectiveDirection]);
1498
+ const visibleRows = (0, import_react4.useMemo)(() => {
1499
+ if (!pagination) return sorted;
1500
+ const pageSize = Math.max(1, pagination.pageSize);
1501
+ const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));
1502
+ const page = Math.min(Math.max(1, pagination.page), totalPages);
1503
+ const startIndex = (page - 1) * pageSize;
1504
+ return sorted.slice(startIndex, startIndex + pageSize);
1505
+ }, [pagination, sorted]);
789
1506
  const handleSortClick = (key) => {
790
1507
  let nextDirection;
791
- if (activeKey !== key) {
1508
+ if (!activeKey || !activeDirection) {
1509
+ nextDirection = baselineKey === key && baselineDirection ? baselineDirection : "asc";
1510
+ } else if (activeKey !== key) {
792
1511
  nextDirection = "asc";
1512
+ } else if (baselineKey === key && baselineDirection) {
1513
+ nextDirection = activeDirection === baselineDirection ? baselineDirection === "asc" ? "desc" : "asc" : null;
793
1514
  } else if (activeDirection === "asc") {
794
1515
  nextDirection = "desc";
795
- } else if (activeDirection === "desc") {
796
- nextDirection = null;
797
1516
  } else {
798
- nextDirection = "asc";
1517
+ nextDirection = null;
799
1518
  }
800
1519
  const nextKey = nextDirection === null ? null : key;
801
1520
  if (isControlled) {
@@ -806,13 +1525,13 @@ function SortableTable({
806
1525
  onSortChange?.(nextKey, nextDirection);
807
1526
  }
808
1527
  };
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) => {
1528
+ 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: [
1529
+ header && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
1530
+ 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: [
1531
+ /* @__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
1532
  const isActive = activeKey === col.key && activeDirection !== null;
814
1533
  if (!col.sortable) {
815
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1534
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
816
1535
  "th",
817
1536
  {
818
1537
  className: "fractal-sortable-table-th",
@@ -822,12 +1541,12 @@ function SortableTable({
822
1541
  col.key
823
1542
  );
824
1543
  }
825
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1544
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
826
1545
  "th",
827
1546
  {
828
1547
  className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
829
1548
  style: { width: col.width },
830
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1549
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
831
1550
  "button",
832
1551
  {
833
1552
  type: "button",
@@ -838,8 +1557,8 @@ function SortableTable({
838
1557
  onClick: () => handleSortClick(col.key),
839
1558
  "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
840
1559
  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 }) })
1560
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: col.header }),
1561
+ /* @__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
1562
  ]
844
1563
  }
845
1564
  )
@@ -847,9 +1566,13 @@ function SortableTable({
847
1566
  col.key
848
1567
  );
849
1568
  }) }) }),
850
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
1569
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { children: visibleRows.map((row, rowIndex) => {
851
1570
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
852
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1571
+ const action = rowAction ? {
1572
+ label: rowAction.label(row, rowIndex),
1573
+ icon: rowAction.icon(row, rowIndex)
1574
+ } : null;
1575
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
853
1576
  "tr",
854
1577
  {
855
1578
  className: cn(
@@ -864,14 +1587,21 @@ function SortableTable({
864
1587
  onRowClick(row, rowIndex);
865
1588
  }
866
1589
  } : void 0,
1590
+ "aria-label": action?.label,
867
1591
  role: onRowClick ? "button" : void 0,
868
1592
  tabIndex: onRowClick ? 0 : void 0,
869
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1593
+ children: columns.map((col, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
870
1594
  "td",
871
1595
  {
872
- className: "fractal-sortable-table-td",
1596
+ className: cn(
1597
+ "fractal-sortable-table-td",
1598
+ action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1599
+ ),
873
1600
  style: { width: col.width, textAlign: col.align ?? "left" },
874
- children: col.render(row, rowIndex)
1601
+ children: [
1602
+ col.render(row, rowIndex),
1603
+ 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 }) })
1604
+ ]
875
1605
  },
876
1606
  col.key
877
1607
  ))
@@ -884,23 +1614,40 @@ function SortableTable({
884
1614
  }
885
1615
 
886
1616
  // src/components/Tabs/Tabs.tsx
887
- var import_react3 = require("react");
888
- var import_jsx_runtime14 = require("react/jsx-runtime");
1617
+ var import_react5 = require("react");
1618
+ var import_jsx_runtime21 = require("react/jsx-runtime");
889
1619
  function Tabs({
890
1620
  items,
891
1621
  defaultValue,
892
1622
  value: controlledValue,
893
1623
  onValueChange,
894
1624
  className,
895
- ariaLabel
1625
+ ariaLabel,
1626
+ divider = false,
1627
+ variant = "line"
896
1628
  }) {
897
- const reactId = (0, import_react3.useId)();
898
- const [internalValue, setInternalValue] = (0, import_react3.useState)(
1629
+ const reactId = (0, import_react5.useId)();
1630
+ const [internalValue, setInternalValue] = (0, import_react5.useState)(
899
1631
  defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
900
1632
  );
901
1633
  const isControlled = controlledValue !== void 0;
902
1634
  const activeId = isControlled ? controlledValue : internalValue;
903
- const tabRefs = (0, import_react3.useRef)({});
1635
+ const tabListRef = (0, import_react5.useRef)(null);
1636
+ const tabRefs = (0, import_react5.useRef)({});
1637
+ const [indicator, setIndicator] = (0, import_react5.useState)(null);
1638
+ (0, import_react5.useLayoutEffect)(() => {
1639
+ const updateIndicator = () => {
1640
+ const activeTab = tabRefs.current[activeId];
1641
+ if (!activeTab) return;
1642
+ setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
1643
+ };
1644
+ updateIndicator();
1645
+ const list = tabListRef.current;
1646
+ if (!list || typeof ResizeObserver === "undefined") return;
1647
+ const observer = new ResizeObserver(updateIndicator);
1648
+ observer.observe(list);
1649
+ return () => observer.disconnect();
1650
+ }, [activeId, items.length]);
904
1651
  const selectTab = (id) => {
905
1652
  if (isControlled) {
906
1653
  onValueChange?.(id);
@@ -910,6 +1657,10 @@ function Tabs({
910
1657
  }
911
1658
  };
912
1659
  const focusable = items.filter((i) => !i.disabled);
1660
+ const indicatorStyle = indicator ? {
1661
+ "--fractal-tabs-indicator-offset": `${indicator.offset}px`,
1662
+ "--fractal-tabs-indicator-width": `${indicator.width}px`
1663
+ } : void 0;
913
1664
  const onKeyDown = (event) => {
914
1665
  const currentIndex = focusable.findIndex((i) => i.id === activeId);
915
1666
  if (currentIndex === -1) return;
@@ -935,41 +1686,52 @@ function Tabs({
935
1686
  selectTab(nextId2);
936
1687
  requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
937
1688
  };
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
- }) }),
1689
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: cn("fractal-tabs", `fractal-tabs--${variant}`, divider && "fractal-tabs--divider", className), children: [
1690
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1691
+ "div",
1692
+ {
1693
+ ref: tabListRef,
1694
+ role: "tablist",
1695
+ "aria-label": ariaLabel,
1696
+ className: "fractal-tabs-list",
1697
+ "data-indicator-ready": indicator ? "true" : void 0,
1698
+ style: indicatorStyle,
1699
+ children: items.map((item) => {
1700
+ const isActive = item.id === activeId;
1701
+ const tabId = `${reactId}-tab-${item.id}`;
1702
+ const panelId = `${reactId}-panel-${item.id}`;
1703
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1704
+ "button",
1705
+ {
1706
+ ref: (el) => {
1707
+ tabRefs.current[item.id] = el;
1708
+ },
1709
+ id: tabId,
1710
+ role: "tab",
1711
+ type: "button",
1712
+ "aria-selected": isActive,
1713
+ "aria-controls": panelId,
1714
+ tabIndex: isActive ? 0 : -1,
1715
+ disabled: item.disabled,
1716
+ className: cn(
1717
+ "fractal-tabs-trigger",
1718
+ isActive && "fractal-tabs-trigger--active",
1719
+ item.disabled && "fractal-tabs-trigger--disabled"
1720
+ ),
1721
+ onClick: () => !item.disabled && selectTab(item.id),
1722
+ onKeyDown,
1723
+ children: item.label
1724
+ },
1725
+ item.id
1726
+ );
1727
+ })
1728
+ }
1729
+ ),
968
1730
  items.map((item) => {
969
1731
  const tabId = `${reactId}-tab-${item.id}`;
970
1732
  const panelId = `${reactId}-panel-${item.id}`;
971
1733
  const isActive = item.id === activeId;
972
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1734
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
973
1735
  "div",
974
1736
  {
975
1737
  id: panelId,
@@ -985,10 +1747,112 @@ function Tabs({
985
1747
  ] });
986
1748
  }
987
1749
 
1750
+ // src/components/ContentSwitcher/ContentSwitcher.tsx
1751
+ var React13 = __toESM(require("react"), 1);
1752
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1753
+ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1754
+ const switcherRef = React13.useRef(null);
1755
+ const buttonRefs = React13.useRef([]);
1756
+ const indicatorMotionReadyRef = React13.useRef(false);
1757
+ const activeIndex = items.findIndex((item) => item.value === value);
1758
+ React13.useLayoutEffect(() => {
1759
+ const switcher = switcherRef.current;
1760
+ const activeButton = buttonRefs.current[activeIndex];
1761
+ let motionFrame = 0;
1762
+ if (!switcher || !activeButton) {
1763
+ switcher?.removeAttribute("data-indicator-ready");
1764
+ switcher?.removeAttribute("data-indicator-animate");
1765
+ indicatorMotionReadyRef.current = false;
1766
+ return;
1767
+ }
1768
+ const updateIndicator = () => {
1769
+ const switcherRect = switcher.getBoundingClientRect();
1770
+ const activeButtonRect = activeButton.getBoundingClientRect();
1771
+ switcher.style.setProperty("--fractal-content-switcher-indicator-x", `${activeButtonRect.left - switcherRect.left - switcher.clientLeft}px`);
1772
+ switcher.style.setProperty("--fractal-content-switcher-indicator-y", `${activeButtonRect.top - switcherRect.top - switcher.clientTop}px`);
1773
+ switcher.style.setProperty("--fractal-content-switcher-indicator-width", `${activeButtonRect.width}px`);
1774
+ switcher.style.setProperty("--fractal-content-switcher-indicator-height", `${activeButtonRect.height}px`);
1775
+ switcher.setAttribute("data-indicator-ready", "true");
1776
+ if (!indicatorMotionReadyRef.current && motionFrame === 0) {
1777
+ motionFrame = window.requestAnimationFrame(() => {
1778
+ indicatorMotionReadyRef.current = true;
1779
+ switcher.setAttribute("data-indicator-animate", "true");
1780
+ motionFrame = 0;
1781
+ });
1782
+ }
1783
+ };
1784
+ updateIndicator();
1785
+ if (typeof ResizeObserver === "undefined") {
1786
+ return () => {
1787
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1788
+ };
1789
+ }
1790
+ const resizeObserver = new ResizeObserver(updateIndicator);
1791
+ resizeObserver.observe(switcher);
1792
+ buttonRefs.current.forEach((button) => {
1793
+ if (button) resizeObserver.observe(button);
1794
+ });
1795
+ return () => {
1796
+ resizeObserver.disconnect();
1797
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1798
+ };
1799
+ }, [activeIndex, items.length]);
1800
+ const moveFocus = (index, direction) => {
1801
+ let nextIndex = index;
1802
+ do {
1803
+ nextIndex = (nextIndex + direction + items.length) % items.length;
1804
+ } while (items[nextIndex]?.disabled && nextIndex !== index);
1805
+ if (!items[nextIndex]?.disabled) {
1806
+ buttonRefs.current[nextIndex]?.focus();
1807
+ onValueChange(items[nextIndex].value);
1808
+ }
1809
+ };
1810
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1811
+ "div",
1812
+ {
1813
+ className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className),
1814
+ role: "group",
1815
+ "aria-label": ariaLabel,
1816
+ ref: switcherRef,
1817
+ children: [
1818
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
1819
+ items.map((item, index) => {
1820
+ const active = item.value === value;
1821
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1822
+ "button",
1823
+ {
1824
+ className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
1825
+ type: "button",
1826
+ "aria-pressed": active,
1827
+ disabled: item.disabled,
1828
+ onClick: () => onValueChange(item.value),
1829
+ onKeyDown: (event) => {
1830
+ if (event.key === "ArrowRight") {
1831
+ event.preventDefault();
1832
+ moveFocus(index, 1);
1833
+ }
1834
+ if (event.key === "ArrowLeft") {
1835
+ event.preventDefault();
1836
+ moveFocus(index, -1);
1837
+ }
1838
+ },
1839
+ ref: (element) => {
1840
+ buttonRefs.current[index] = element;
1841
+ },
1842
+ children: item.label
1843
+ },
1844
+ item.value
1845
+ );
1846
+ })
1847
+ ]
1848
+ }
1849
+ );
1850
+ }
1851
+
988
1852
  // 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");
1853
+ var import_react6 = require("react");
1854
+ var import_fractal_icons11 = require("@mirror-physics/fractal-icons");
1855
+ var import_jsx_runtime23 = require("react/jsx-runtime");
992
1856
  function Disclosure({
993
1857
  title,
994
1858
  meta,
@@ -996,16 +1860,18 @@ function Disclosure({
996
1860
  defaultOpen = false,
997
1861
  open: controlledOpen,
998
1862
  onOpenChange,
1863
+ disabled = false,
999
1864
  className,
1000
1865
  variant = "card"
1001
1866
  }) {
1002
- const reactId = (0, import_react4.useId)();
1867
+ const reactId = (0, import_react6.useId)();
1003
1868
  const headerId = `${reactId}-header`;
1004
1869
  const panelId = `${reactId}-panel`;
1005
- const [internalOpen, setInternalOpen] = (0, import_react4.useState)(defaultOpen);
1870
+ const [internalOpen, setInternalOpen] = (0, import_react6.useState)(defaultOpen);
1006
1871
  const isControlled = controlledOpen !== void 0;
1007
1872
  const isOpen = isControlled ? controlledOpen : internalOpen;
1008
1873
  const toggle = () => {
1874
+ if (disabled) return;
1009
1875
  const next = !isOpen;
1010
1876
  if (isControlled) {
1011
1877
  onOpenChange?.(next);
@@ -1014,17 +1880,18 @@ function Disclosure({
1014
1880
  onOpenChange?.(next);
1015
1881
  }
1016
1882
  };
1017
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1883
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1018
1884
  "div",
1019
1885
  {
1020
1886
  className: cn(
1021
1887
  "fractal-disclosure",
1022
1888
  variant === "card" && "fractal-disclosure--card",
1023
1889
  isOpen && "fractal-disclosure--open",
1890
+ disabled && "fractal-disclosure--disabled",
1024
1891
  className
1025
1892
  ),
1026
1893
  children: [
1027
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1894
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1028
1895
  "button",
1029
1896
  {
1030
1897
  type: "button",
@@ -1032,15 +1899,16 @@ function Disclosure({
1032
1899
  className: "fractal-disclosure-trigger",
1033
1900
  "aria-expanded": isOpen,
1034
1901
  "aria-controls": panelId,
1902
+ disabled,
1035
1903
  onClick: toggle,
1036
1904
  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 })
1905
+ /* @__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 }) }),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1907
+ meta && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1040
1908
  ]
1041
1909
  }
1042
1910
  ),
1043
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1911
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1044
1912
  "div",
1045
1913
  {
1046
1914
  id: panelId,
@@ -1048,7 +1916,7 @@ function Disclosure({
1048
1916
  "aria-labelledby": headerId,
1049
1917
  className: "fractal-disclosure-panel",
1050
1918
  hidden: !isOpen,
1051
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1919
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1052
1920
  }
1053
1921
  )
1054
1922
  ]
@@ -1056,39 +1924,260 @@ function Disclosure({
1056
1924
  );
1057
1925
  }
1058
1926
 
1927
+ // src/components/LatticeLoader/LatticeLoader.tsx
1928
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1929
+ var LATTICE_COUNT = 160;
1930
+ var WAVE_PERIOD = 80;
1931
+ function LatticeLoader({ className, label = "Loading", ...props }) {
1932
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1933
+ "span",
1934
+ {
1935
+ "aria-label": label,
1936
+ className: cn("fractal-lattice-loader", className),
1937
+ role: "progressbar",
1938
+ ...props,
1939
+ children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1940
+ "span",
1941
+ {
1942
+ "aria-hidden": "true",
1943
+ className: "fractal-lattice-loader__cell",
1944
+ style: { "--fractal-lattice-index": index % WAVE_PERIOD }
1945
+ },
1946
+ index
1947
+ ))
1948
+ }
1949
+ );
1950
+ }
1951
+
1952
+ // src/components/Ghost/Ghost.tsx
1953
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1954
+ var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
1955
+ function Ghost({ className, width, height, radius, style, ...props }) {
1956
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1957
+ "div",
1958
+ {
1959
+ "aria-hidden": "true",
1960
+ className: cn("fractal-ghost", className),
1961
+ style: {
1962
+ width: toCssLength(width),
1963
+ height: toCssLength(height),
1964
+ borderRadius: toCssLength(radius),
1965
+ ...style
1966
+ },
1967
+ ...props
1968
+ }
1969
+ );
1970
+ }
1971
+ function GhostLine({ className, size = "md", width = "100%", ...props }) {
1972
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
1973
+ }
1974
+ function ButtonGhost({ className, size = "md", iconOnly = false, width, ...props }) {
1975
+ 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 });
1976
+ }
1977
+ function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
1978
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
1979
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "38%" }),
1980
+ /* @__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)) })
1981
+ ] });
1982
+ }
1983
+ function DataTableGhost({
1984
+ className,
1985
+ showHeader = true,
1986
+ headers,
1987
+ columns = 4,
1988
+ rows = 5,
1989
+ columnWidths,
1990
+ size = "md",
1991
+ ...props
1992
+ }) {
1993
+ const cells = Array.from({ length: columns }, (_, index) => index);
1994
+ 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: [
1995
+ (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)) }) }),
1996
+ /* @__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)) })
1997
+ ] }) });
1998
+ }
1999
+ function InputGhost({ className, labelWidth = "26%", ...props }) {
2000
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FormFieldGhost, { className, labelWidth, ...props });
2001
+ }
2002
+ function TextareaGhost({ className, labelWidth = "26%", ...props }) {
2003
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
2004
+ }
2005
+ function LabelGhost({ className, width = "26%", ...props }) {
2006
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
2007
+ }
2008
+ function FormFieldGhost({ className, labelWidth = "26%", multiline = false, ...props }) {
2009
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-field", className), ...props, children: [
2010
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LabelGhost, { width: labelWidth }),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
2012
+ ] });
2013
+ }
2014
+ function AlertGhost({ className, ...props }) {
2015
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "30%" }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { size: "sm", width: "78%" })
2018
+ ] });
2019
+ }
2020
+ function CheckboxGhost({ className, ...props }) {
2021
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
2022
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-choice__control" }),
2023
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" })
2024
+ ] });
2025
+ }
2026
+ var ToggleGhost = CheckboxGhost;
2027
+ function ChipGhost({ className, width = 74, ...props }) {
2028
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
2029
+ }
2030
+ function LinkGhost({ className, width = 96, ...props }) {
2031
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
2032
+ }
2033
+ var TextButtonGhost = LinkGhost;
2034
+ function DropdownGhost({ className, ...props }) {
2035
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropdown", className), ...props, children: [
2036
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "38%" }),
2037
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-dropdown__chevron" })
2038
+ ] });
2039
+ }
2040
+ function ContentSwitcherGhost({ className, options = 3, ...props }) {
2041
+ 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)) });
2042
+ }
2043
+ var TabsGhost = ContentSwitcherGhost;
2044
+ function DisclosureGhost({ className, ...props }) {
2045
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
2046
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-disclosure__icon" }),
2047
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" })
2048
+ ] });
2049
+ }
2050
+ function PaginationGhost({ className, pages = 5, ...props }) {
2051
+ 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)) });
2052
+ }
2053
+ function FileDropzoneGhost({ className, ...props }) {
2054
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
2055
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-dropzone__icon" }),
2056
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "26%" }),
2057
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { size: "sm", width: "46%" })
2058
+ ] });
2059
+ }
2060
+ function PromptCardGhost({ className, ...props }) {
2061
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
2062
+ }
2063
+ function ConversationGhost({
2064
+ className,
2065
+ "aria-label": ariaLabel = "Loading conversation",
2066
+ ...props
2067
+ }) {
2068
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2069
+ "div",
2070
+ {
2071
+ "aria-busy": "true",
2072
+ "aria-label": ariaLabel,
2073
+ className: cn("fractal-ghost-conversation", className),
2074
+ role: "status",
2075
+ ...props,
2076
+ children: [
2077
+ /* @__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: [
2078
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "100%" }),
2079
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "86%" }),
2080
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "64%" })
2081
+ ] }) }),
2082
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--assistant", children: [
2083
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "92%" }),
2084
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "78%" }),
2085
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "58%" })
2086
+ ] })
2087
+ ]
2088
+ }
2089
+ );
2090
+ }
2091
+ function SortableTableGhost(props) {
2092
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DataTableGhost, { ...props });
2093
+ }
2094
+ function SidebarGhost({ className, items = 6, ...props }) {
2095
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
2096
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-sidebar__brand" }),
2097
+ /* @__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: [
2098
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, {}),
2099
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
2100
+ ] }, index)) })
2101
+ ] });
2102
+ }
2103
+ function ModalGhost({ className, title, lines = 3, ...props }) {
2104
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
2105
+ }
2106
+ function SidePanelGhost({ className, title, lines = 5, ...props }) {
2107
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
2108
+ }
2109
+ function SurfaceGhost({ className, title, lines = 3, ...props }) {
2110
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
2111
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fractal-ghost-surface__header", children: [
2112
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" }),
2113
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-surface__close" })
2114
+ ] }),
2115
+ title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "fractal-ghost-surface__title", children: title }),
2116
+ /* @__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)) })
2117
+ ] });
2118
+ }
2119
+
1059
2120
  // 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)(
2121
+ var React14 = __toESM(require("react"), 1);
2122
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2123
+ var Sidebar = React14.forwardRef(
2124
+ ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1064
2125
  "aside",
1065
2126
  {
1066
2127
  ref,
1067
2128
  className: cn("fractal-sidebar", className),
2129
+ "data-compact": compact || void 0,
1068
2130
  style: { ...style, ...width ? { "--fractal-sidebar-width": width } : {} },
1069
2131
  ...props
1070
2132
  }
1071
2133
  )
1072
2134
  );
1073
2135
  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 })
2136
+ var SidebarHeader = React14.forwardRef(
2137
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1076
2138
  );
1077
2139
  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 })
2140
+ var SidebarBrand = React14.forwardRef(
2141
+ ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1080
2142
  );
1081
2143
  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 })
2144
+ function SidebarAccountMenu({
2145
+ name,
2146
+ items,
2147
+ onSelect,
2148
+ triggerLabel = "Account menu",
2149
+ icon,
2150
+ className
2151
+ }) {
2152
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2153
+ Dropdown,
2154
+ {
2155
+ align: "left",
2156
+ className: cn("fractal-sidebar__account", className),
2157
+ items,
2158
+ onSelect,
2159
+ panelClassName: "fractal-sidebar__account-panel",
2160
+ selectedValue: "",
2161
+ triggerClassName: "fractal-sidebar__account-trigger",
2162
+ triggerContent: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
2163
+ icon && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
2164
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__account-name", children: name })
2165
+ ] }),
2166
+ triggerLabel,
2167
+ triggerVariant: "tertiary"
2168
+ }
2169
+ );
2170
+ }
2171
+ var SidebarNav = React14.forwardRef(
2172
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1084
2173
  );
1085
2174
  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 })
2175
+ var SidebarSection = React14.forwardRef(
2176
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1088
2177
  );
1089
2178
  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)(
2179
+ var SidebarNavItem = React14.forwardRef(
2180
+ ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1092
2181
  "button",
1093
2182
  {
1094
2183
  ref,
@@ -1098,39 +2187,28 @@ var SidebarNavItem = React10.forwardRef(
1098
2187
  "aria-current": active ? "page" : void 0,
1099
2188
  ...props,
1100
2189
  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 })
2190
+ icon && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
2191
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
2192
+ endAdornment && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1104
2193
  ]
1105
2194
  }
1106
2195
  )
1107
2196
  );
1108
2197
  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 })
2198
+ var SidebarFooter = React14.forwardRef(
2199
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1111
2200
  );
1112
2201
  SidebarFooter.displayName = "SidebarFooter";
1113
2202
 
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
2203
  // src/components/SidePanel/SidePanel.tsx
1126
2204
  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 }) {
2205
+ var import_fractal_icons12 = require("@mirror-physics/fractal-icons");
2206
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2207
+ function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
1130
2208
  useEscapeDismiss(80, onClose, open);
1131
2209
  if (!open) return null;
1132
2210
  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)(
2211
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1134
2212
  "aside",
1135
2213
  {
1136
2214
  className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
@@ -1139,15 +2217,15 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
1139
2217
  role: "dialog",
1140
2218
  onMouseDown: (event) => event.stopPropagation(),
1141
2219
  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 })
2220
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("header", { className: "fractal-side-panel__header", children: [
2221
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "fractal-side-panel__heading", children: [
2222
+ 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 }),
2223
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "fractal-side-panel__description", children: description })
1146
2224
  ] }),
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 }) })
2225
+ /* @__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
2226
  ] }),
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 })
2227
+ /* @__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 }),
2228
+ footer && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
1151
2229
  ]
1152
2230
  }
1153
2231
  ) }),
@@ -1156,49 +2234,273 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
1156
2234
  }
1157
2235
 
1158
2236
  // 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 })
2237
+ var React15 = __toESM(require("react"), 1);
2238
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2239
+ var Textarea = React15.forwardRef(
2240
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
1163
2241
  );
1164
2242
  Textarea.displayName = "Textarea";
2243
+
2244
+ // src/components/TextButton/TextButton.tsx
2245
+ var React16 = __toESM(require("react"), 1);
2246
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2247
+ var TextButton = React16.forwardRef(
2248
+ ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2249
+ "button",
2250
+ {
2251
+ ref,
2252
+ className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
2253
+ type: "button",
2254
+ ...props,
2255
+ children: [
2256
+ icon && iconPosition === "start" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
2257
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children }),
2258
+ icon && iconPosition === "end" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
2259
+ ]
2260
+ }
2261
+ )
2262
+ );
2263
+ TextButton.displayName = "TextButton";
2264
+
2265
+ // src/components/FileDropzone/FileDropzone.tsx
2266
+ var React17 = __toESM(require("react"), 1);
2267
+ var import_fractal_icons13 = require("@mirror-physics/fractal-icons");
2268
+ var import_jsx_runtime30 = require("react/jsx-runtime");
2269
+ function FileDropzone({
2270
+ files,
2271
+ onFilesChange,
2272
+ accept,
2273
+ multiple = true,
2274
+ disabled = false,
2275
+ title = "Drop files here or click to browse",
2276
+ description = "Files stay attached to this record.",
2277
+ className
2278
+ }) {
2279
+ const inputId = React17.useId();
2280
+ const inputRef = React17.useRef(null);
2281
+ const [isDragging, setIsDragging] = React17.useState(false);
2282
+ const addFiles = (nextFiles) => {
2283
+ if (disabled) return;
2284
+ const additions = Array.from(nextFiles);
2285
+ if (additions.length === 0) return;
2286
+ onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
2287
+ };
2288
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: cn("fractal-file-dropzone", className), children: [
2289
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2290
+ "input",
2291
+ {
2292
+ ref: inputRef,
2293
+ id: inputId,
2294
+ className: "fractal-file-dropzone__input",
2295
+ type: "file",
2296
+ accept,
2297
+ multiple,
2298
+ disabled,
2299
+ onChange: (event) => {
2300
+ if (event.target.files) addFiles(event.target.files);
2301
+ event.target.value = "";
2302
+ }
2303
+ }
2304
+ ),
2305
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
2306
+ "button",
2307
+ {
2308
+ className: "fractal-file-dropzone__target",
2309
+ "data-dragging": isDragging || void 0,
2310
+ type: "button",
2311
+ disabled,
2312
+ onClick: () => inputRef.current?.click(),
2313
+ onDragEnter: (event) => {
2314
+ event.preventDefault();
2315
+ if (!disabled) setIsDragging(true);
2316
+ },
2317
+ onDragOver: (event) => event.preventDefault(),
2318
+ onDragLeave: (event) => {
2319
+ event.preventDefault();
2320
+ setIsDragging(false);
2321
+ },
2322
+ onDrop: (event) => {
2323
+ event.preventDefault();
2324
+ setIsDragging(false);
2325
+ addFiles(event.dataTransfer.files);
2326
+ },
2327
+ children: [
2328
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_fractal_icons13.FileArrowUp, { "aria-hidden": "true", size: 20 }),
2329
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "fractal-file-dropzone__copy", children: [
2330
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__title", children: title }),
2331
+ description && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__description", children: description })
2332
+ ] })
2333
+ ]
2334
+ }
2335
+ ),
2336
+ 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: [
2337
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
2338
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
2339
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2340
+ "button",
2341
+ {
2342
+ className: "fractal-file-dropzone__remove",
2343
+ type: "button",
2344
+ "aria-label": `Remove ${file.name}`,
2345
+ disabled,
2346
+ onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
2347
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_fractal_icons13.Close, { "aria-hidden": "true", size: 14 })
2348
+ }
2349
+ )
2350
+ ] }, `${file.name}-${file.size}-${index}`)) })
2351
+ ] });
2352
+ }
2353
+ function formatFileSize(bytes) {
2354
+ if (bytes < 1024) return `${bytes} B`;
2355
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
2356
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2357
+ }
2358
+
2359
+ // src/components/Pagination/Pagination.tsx
2360
+ var import_fractal_icons14 = require("@mirror-physics/fractal-icons");
2361
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2362
+ function Pagination({
2363
+ page,
2364
+ pageSize,
2365
+ totalItems,
2366
+ onPageChange,
2367
+ pageSizeOptions,
2368
+ onPageSizeChange,
2369
+ ariaLabel = "Pagination",
2370
+ className
2371
+ }) {
2372
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
2373
+ const currentPage = Math.min(Math.max(page, 1), totalPages);
2374
+ const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
2375
+ const end = Math.min(currentPage * pageSize, totalItems);
2376
+ const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
2377
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
2378
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
2379
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "fractal-pagination__controls", children: [
2380
+ canChangePageSize && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2381
+ Dropdown,
2382
+ {
2383
+ align: "right",
2384
+ className: "fractal-pagination__page-size",
2385
+ direction: "up",
2386
+ items: pageSizeOptions.map((option) => ({
2387
+ value: String(option),
2388
+ description: `${option} per page`
2389
+ })),
2390
+ onSelect: (value) => onPageSizeChange(Number(value)),
2391
+ selectedValue: String(pageSize),
2392
+ size: "sm",
2393
+ triggerLabel: "Results per page",
2394
+ triggerVariant: "tertiary"
2395
+ }
2396
+ ),
2397
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2398
+ "button",
2399
+ {
2400
+ className: "fractal-pagination__button",
2401
+ type: "button",
2402
+ "aria-label": "Previous page",
2403
+ title: "Previous page",
2404
+ disabled: currentPage === 1 || totalItems === 0,
2405
+ onClick: () => onPageChange(currentPage - 1),
2406
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fractal_icons14.ArrowLeft, { "aria-hidden": "true", size: 16 })
2407
+ }
2408
+ ),
2409
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
2410
+ currentPage,
2411
+ " of ",
2412
+ totalPages
2413
+ ] }),
2414
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2415
+ "button",
2416
+ {
2417
+ className: "fractal-pagination__button",
2418
+ type: "button",
2419
+ "aria-label": "Next page",
2420
+ title: "Next page",
2421
+ disabled: currentPage === totalPages || totalItems === 0,
2422
+ onClick: () => onPageChange(currentPage + 1),
2423
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fractal_icons14.ArrowRight, { "aria-hidden": "true", size: 16 })
2424
+ }
2425
+ )
2426
+ ] })
2427
+ ] });
2428
+ }
1165
2429
  // Annotate the CommonJS export names for ESM import in node:
1166
2430
  0 && (module.exports = {
1167
2431
  Alert,
1168
2432
  AlertDescription,
2433
+ AlertGhost,
1169
2434
  AlertTitle,
2435
+ Breadcrumbs,
1170
2436
  Button,
2437
+ ButtonGhost,
1171
2438
  Card,
1172
2439
  CardContent,
1173
2440
  CardDescription,
1174
2441
  CardFooter,
2442
+ CardGhost,
1175
2443
  CardHeader,
1176
2444
  CardTitle,
2445
+ Checkbox,
2446
+ CheckboxGhost,
1177
2447
  Chip,
2448
+ ChipGhost,
2449
+ CodeBlock,
2450
+ ContentSwitcher,
2451
+ ContentSwitcherGhost,
2452
+ ConversationGhost,
1178
2453
  DataTable,
2454
+ DataTableGhost,
1179
2455
  Disclosure,
2456
+ DisclosureGhost,
1180
2457
  Dropdown,
2458
+ DropdownGhost,
1181
2459
  FeatureCard,
2460
+ FileDropzone,
2461
+ FileDropzoneGhost,
1182
2462
  FolderCard,
2463
+ Ghost,
2464
+ GhostLine,
1183
2465
  Input,
2466
+ InputGhost,
1184
2467
  Label,
2468
+ LabelGhost,
2469
+ LatticeLoader,
1185
2470
  Link,
2471
+ LinkGhost,
1186
2472
  Modal,
1187
- PageHeader,
2473
+ ModalGhost,
2474
+ NumberInput,
2475
+ Pagination,
2476
+ PaginationGhost,
2477
+ PasswordInput,
1188
2478
  PromptCard,
2479
+ PromptCardGhost,
1189
2480
  PromptGrid,
1190
2481
  SidePanel,
2482
+ SidePanelGhost,
1191
2483
  Sidebar,
2484
+ SidebarAccountMenu,
1192
2485
  SidebarBrand,
1193
2486
  SidebarFooter,
2487
+ SidebarGhost,
1194
2488
  SidebarHeader,
1195
2489
  SidebarNav,
1196
2490
  SidebarNavItem,
1197
2491
  SidebarSection,
1198
2492
  SortableTable,
2493
+ SortableTableGhost,
2494
+ TableSearch,
1199
2495
  Tabs,
2496
+ TabsGhost,
2497
+ TextButton,
2498
+ TextButtonGhost,
1200
2499
  Textarea,
2500
+ TextareaGhost,
1201
2501
  Toggle,
2502
+ ToggleGhost,
2503
+ UILoader,
1202
2504
  cn,
1203
2505
  useEscapeDismiss
1204
2506
  });