@mirror-physics/fractal-ui 0.2.0-next.7 → 0.2.0-next.71

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,38 +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,
75
+ ModalGhost: () => ModalGhost,
76
+ NumberInput: () => NumberInput,
77
+ Pagination: () => Pagination,
78
+ PaginationGhost: () => PaginationGhost,
79
+ PasswordInput: () => PasswordInput,
53
80
  PromptCard: () => PromptCard,
81
+ PromptCardGhost: () => PromptCardGhost,
54
82
  PromptGrid: () => PromptGrid,
55
83
  SidePanel: () => SidePanel,
84
+ SidePanelGhost: () => SidePanelGhost,
56
85
  Sidebar: () => Sidebar,
86
+ SidebarAccountMenu: () => SidebarAccountMenu,
57
87
  SidebarBrand: () => SidebarBrand,
58
88
  SidebarFooter: () => SidebarFooter,
89
+ SidebarGhost: () => SidebarGhost,
59
90
  SidebarHeader: () => SidebarHeader,
60
91
  SidebarNav: () => SidebarNav,
61
92
  SidebarNavItem: () => SidebarNavItem,
62
93
  SidebarSection: () => SidebarSection,
63
94
  SortableTable: () => SortableTable,
95
+ SortableTableGhost: () => SortableTableGhost,
96
+ TableSearch: () => TableSearch,
64
97
  Tabs: () => Tabs,
98
+ TabsGhost: () => TabsGhost,
99
+ TextButton: () => TextButton,
100
+ TextButtonGhost: () => TextButtonGhost,
65
101
  Textarea: () => Textarea,
102
+ TextareaGhost: () => TextareaGhost,
66
103
  Toggle: () => Toggle,
104
+ ToggleGhost: () => ToggleGhost,
105
+ UILoader: () => UILoader,
67
106
  cn: () => cn,
68
107
  useEscapeDismiss: () => useEscapeDismiss
69
108
  });
@@ -236,44 +275,409 @@ var Button = React.forwardRef(
236
275
  );
237
276
  Button.displayName = "Button";
238
277
 
239
- // src/components/Card/Card.tsx
240
- 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");
241
285
  var import_fractal_icons = require("@mirror-physics/fractal-icons");
242
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");
243
647
  var Card = React2.forwardRef(
244
- ({ 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 })
245
649
  );
246
650
  Card.displayName = "Card";
247
651
  var CardHeader = React2.forwardRef(
248
- ({ 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 })
249
653
  );
250
654
  CardHeader.displayName = "CardHeader";
251
655
  var CardTitle = React2.forwardRef(
252
- ({ 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 })
253
657
  );
254
658
  CardTitle.displayName = "CardTitle";
255
659
  var CardDescription = React2.forwardRef(
256
- ({ 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 })
257
661
  );
258
662
  CardDescription.displayName = "CardDescription";
259
663
  var CardContent = React2.forwardRef(
260
- ({ 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 })
261
665
  );
262
666
  CardContent.displayName = "CardContent";
263
667
  var CardFooter = React2.forwardRef(
264
- ({ 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 })
265
669
  );
266
670
  CardFooter.displayName = "CardFooter";
267
671
  var FeatureCard = React2.forwardRef(
268
- ({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
269
- icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fractal-feature-card__icon", children: icon }),
270
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "fractal-feature-card__title", children: title }),
271
- /* @__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 })
272
676
  ] })
273
677
  );
274
678
  FeatureCard.displayName = "FeatureCard";
275
679
  var FolderCard = React2.forwardRef(
276
- ({ 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)(
277
681
  "div",
278
682
  {
279
683
  ref,
@@ -289,11 +693,11 @@ var FolderCard = React2.forwardRef(
289
693
  className: cn("fractal-folder-card", selected && "fractal-folder-card--selected", className),
290
694
  ...props,
291
695
  children: [
292
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fractal-folder-card__header", children: [
293
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fractal_icons.Folder, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
294
- /* @__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 })
295
699
  ] }),
296
- 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: [
297
701
  sessionCount,
298
702
  " ",
299
703
  sessionCount === 1 ? "session" : "sessions"
@@ -306,7 +710,7 @@ FolderCard.displayName = "FolderCard";
306
710
 
307
711
  // src/components/PromptCard/PromptCard.tsx
308
712
  var React3 = __toESM(require("react"), 1);
309
- var import_jsx_runtime3 = require("react/jsx-runtime");
713
+ var import_jsx_runtime5 = require("react/jsx-runtime");
310
714
  var titleToPrompt = (title) => typeof title === "string" || typeof title === "number" ? String(title) : "";
311
715
  var PromptCard = React3.forwardRef(
312
716
  ({
@@ -327,7 +731,7 @@ var PromptCard = React3.forwardRef(
327
731
  onPromptSelect?.(prompt ?? titleToPrompt(title));
328
732
  }
329
733
  };
330
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
734
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
331
735
  "button",
332
736
  {
333
737
  ref,
@@ -342,8 +746,8 @@ var PromptCard = React3.forwardRef(
342
746
  onClick: handleClick,
343
747
  ...props,
344
748
  children: [
345
- icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fractal-prompt-card__icon", "aria-hidden": "true", children: icon }),
346
- /* @__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 })
347
751
  ]
348
752
  }
349
753
  );
@@ -351,7 +755,7 @@ var PromptCard = React3.forwardRef(
351
755
  );
352
756
  PromptCard.displayName = "PromptCard";
353
757
  var PromptGrid = React3.forwardRef(
354
- ({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
758
+ ({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
355
759
  "div",
356
760
  {
357
761
  ref,
@@ -369,9 +773,9 @@ PromptGrid.displayName = "PromptGrid";
369
773
 
370
774
  // src/components/Input/Input.tsx
371
775
  var React4 = __toESM(require("react"), 1);
372
- var import_jsx_runtime4 = require("react/jsx-runtime");
776
+ var import_jsx_runtime6 = require("react/jsx-runtime");
373
777
  var Input = React4.forwardRef(
374
- ({ className, type, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
778
+ ({ className, type, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
375
779
  "input",
376
780
  {
377
781
  type,
@@ -383,11 +787,181 @@ var Input = React4.forwardRef(
383
787
  );
384
788
  Input.displayName = "Input";
385
789
 
386
- // src/components/Label/Label.tsx
790
+ // src/components/TableSearch/TableSearch.tsx
387
791
  var React5 = __toESM(require("react"), 1);
388
- var import_jsx_runtime5 = require("react/jsx-runtime");
389
- var Label = React5.forwardRef(
390
- ({ 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)(
391
965
  "label",
392
966
  {
393
967
  ref,
@@ -399,44 +973,48 @@ var Label = React5.forwardRef(
399
973
  Label.displayName = "Label";
400
974
 
401
975
  // src/components/Alert/Alert.tsx
402
- var React6 = __toESM(require("react"), 1);
403
- 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");
404
979
  var defaultIcons = {
405
- default: "\u2139",
406
- info: "\u2139",
407
- success: "\u2713",
408
- warning: "\u26A0",
409
- 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
410
985
  };
411
- var Alert = React6.forwardRef(
412
- ({ className, variant = "default", icon, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
413
- "div",
414
- {
415
- ref,
416
- role: "alert",
417
- className: cn("fractal-alert", `fractal-alert--${variant}`, className),
418
- ...props,
419
- children: [
420
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? defaultIcons[variant] }),
421
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fractal-alert-content", children })
422
- ]
423
- }
424
- )
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
+ }
425
1003
  );
426
1004
  Alert.displayName = "Alert";
427
- var AlertTitle = React6.forwardRef(
428
- ({ 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 })
429
1007
  );
430
1008
  AlertTitle.displayName = "AlertTitle";
431
- var AlertDescription = React6.forwardRef(
432
- ({ 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 })
433
1011
  );
434
1012
  AlertDescription.displayName = "AlertDescription";
435
1013
 
436
1014
  // src/components/Toggle/Toggle.tsx
437
- var import_jsx_runtime7 = require("react/jsx-runtime");
1015
+ var import_jsx_runtime12 = require("react/jsx-runtime");
438
1016
  function Toggle({ checked, onChange, label, className }) {
439
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1017
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
440
1018
  "button",
441
1019
  {
442
1020
  type: "button",
@@ -445,18 +1023,19 @@ function Toggle({ checked, onChange, label, className }) {
445
1023
  className: cn("fractal-toggle", className),
446
1024
  onClick: () => onChange(!checked),
447
1025
  children: [
448
- /* @__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") }) }),
449
- 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 })
450
1028
  ]
451
1029
  }
452
1030
  );
453
1031
  }
454
1032
 
455
1033
  // src/components/Modal/Modal.tsx
1034
+ var React10 = __toESM(require("react"), 1);
456
1035
  var import_react_dom = require("react-dom");
457
1036
 
458
1037
  // src/hooks/useEscapeDismiss.ts
459
- var import_react = require("react");
1038
+ var import_react2 = require("react");
460
1039
  var nextId = 0;
461
1040
  var stack = [];
462
1041
  function insertSorted(entry) {
@@ -489,9 +1068,9 @@ function ensureGlobalListener() {
489
1068
  );
490
1069
  }
491
1070
  function useEscapeDismiss(priority, handler, enabled = true) {
492
- const handlerRef = (0, import_react.useRef)(handler);
1071
+ const handlerRef = (0, import_react2.useRef)(handler);
493
1072
  handlerRef.current = handler;
494
- (0, import_react.useEffect)(() => {
1073
+ (0, import_react2.useEffect)(() => {
495
1074
  if (!enabled) return;
496
1075
  ensureGlobalListener();
497
1076
  const id = nextId++;
@@ -505,27 +1084,99 @@ function useEscapeDismiss(priority, handler, enabled = true) {
505
1084
  }, [priority, enabled]);
506
1085
  }
507
1086
 
1087
+ // src/components/UILoader/UILoader.tsx
1088
+ var import_react3 = require("react");
1089
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1090
+ 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";
1091
+ 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";
1092
+ 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";
1093
+ function UILoader({ size = 48, tone = "neutral", className, style, label = "Loading", ariaHidden = false }) {
1094
+ const rawId = (0, import_react3.useId)().replace(/[^a-zA-Z0-9_-]/g, "");
1095
+ const clipId = `fractal-ui-loader-clip-${rawId}`;
1096
+ const gradientId = `fractal-ui-loader-gradient-${rawId}`;
1097
+ const height = typeof size === "number" ? `${size}px` : size;
1098
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1099
+ "span",
1100
+ {
1101
+ "aria-hidden": ariaHidden || void 0,
1102
+ "aria-label": ariaHidden ? void 0 : label,
1103
+ className: cn("fractal-ui-loader", `fractal-ui-loader--${tone}`, className),
1104
+ role: ariaHidden ? void 0 : "status",
1105
+ style,
1106
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
1107
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("defs", { children: [
1108
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
1109
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { className: "fractal-ui-loader__stop-start", offset: "0" }),
1110
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { className: "fractal-ui-loader__stop-end", offset: "1" })
1111
+ ] }),
1112
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
1113
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { offset: "0.4", stopColor: "white", stopOpacity: "0" }),
1114
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { offset: "0.5", stopColor: "white", stopOpacity: "0.62" }),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("stop", { offset: "0.6", stopColor: "white", stopOpacity: "0" })
1116
+ ] }),
1117
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("clipPath", { id: clipId, children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: LEFT }),
1119
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: CENTER }),
1120
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: RIGHT })
1121
+ ] })
1122
+ ] }),
1123
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: CENTER, fill: `url(#${gradientId})` }),
1124
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: RIGHT, fill: `url(#${gradientId})` }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: LEFT, fill: `url(#${gradientId})` }),
1126
+ /* @__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)` }) }) })
1127
+ ] })
1128
+ }
1129
+ );
1130
+ }
1131
+
508
1132
  // src/components/Modal/Modal.tsx
509
- var import_jsx_runtime8 = require("react/jsx-runtime");
510
- 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" }) });
511
- function Modal({ open, onClose, title, children, danger, warn, footer, noClose, size = "sm", className }) {
512
- useEscapeDismiss(80, onClose, open && !noClose);
1133
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1134
+ 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" }) });
1135
+ function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
1136
+ const [bodyScrolled, setBodyScrolled] = React10.useState(false);
1137
+ useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
1138
+ React10.useEffect(() => {
1139
+ if (open) setBodyScrolled(false);
1140
+ }, [open]);
513
1141
  if (!open) return null;
514
1142
  const sizeClass = `fractal-modal-panel--${size}`;
515
1143
  const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
516
1144
  return (0, import_react_dom.createPortal)(
517
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1145
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
518
1146
  "div",
519
1147
  {
520
- className: cn("fractal-modal-panel", sizeClass, accentClass, className),
1148
+ className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
521
1149
  onClick: (e) => e.stopPropagation(),
522
1150
  children: [
523
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "fractal-modal-title-row", children: [
524
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
525
- !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, {}) })
526
- ] }),
527
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("fractal-modal-body", size === "lg" && "fractal-modal-body--lg"), children }),
528
- footer && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-footer", children: footer })
1151
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1152
+ "div",
1153
+ {
1154
+ className: cn(
1155
+ "fractal-modal-title-row",
1156
+ scrollable && "fractal-modal-title-row--scrollable",
1157
+ scrollable && bodyScrolled && "fractal-modal-title-row--scrolled"
1158
+ ),
1159
+ children: [
1160
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
1161
+ !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, {}) })
1162
+ ]
1163
+ }
1164
+ ),
1165
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1166
+ "div",
1167
+ {
1168
+ "aria-busy": loading || void 0,
1169
+ className: cn(
1170
+ "fractal-modal-body",
1171
+ size === "lg" && "fractal-modal-body--lg",
1172
+ loading && "fractal-modal-body--loading",
1173
+ scrollable && "fractal-modal-body--scrollable"
1174
+ ),
1175
+ onScroll: scrollable ? (event) => setBodyScrolled(event.currentTarget.scrollTop > 0) : void 0,
1176
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UILoader, { label: loadingLabel }) : children
1177
+ }
1178
+ ),
1179
+ footer && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("fractal-modal-footer", scrollable && "fractal-modal-footer--divided"), children: footer })
529
1180
  ]
530
1181
  }
531
1182
  ) }),
@@ -534,17 +1185,17 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
534
1185
  }
535
1186
 
536
1187
  // src/components/DataTable/DataTable.tsx
537
- var import_jsx_runtime9 = require("react/jsx-runtime");
1188
+ var import_jsx_runtime15 = require("react/jsx-runtime");
538
1189
  function DataTable({ columns, data, emptyMessage, header, size = "md", className }) {
539
- 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: [
540
- header && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-datatable-header", children: header }),
541
- 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: [
542
- /* @__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)) }) }),
543
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1190
+ 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: [
1191
+ header && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-datatable-header", children: header }),
1192
+ 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: [
1193
+ /* @__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)) }) }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
544
1195
  "tr",
545
1196
  {
546
1197
  className: "fractal-datatable-row",
547
- 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))
1198
+ 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))
548
1199
  },
549
1200
  rowIndex
550
1201
  )) })
@@ -553,9 +1204,9 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
553
1204
  }
554
1205
 
555
1206
  // src/components/Dropdown/Dropdown.tsx
556
- var React7 = __toESM(require("react"), 1);
557
- var import_fractal_icons2 = require("@mirror-physics/fractal-icons");
558
- var import_jsx_runtime10 = require("react/jsx-runtime");
1207
+ var React11 = __toESM(require("react"), 1);
1208
+ var import_fractal_icons8 = require("@mirror-physics/fractal-icons");
1209
+ var import_jsx_runtime16 = require("react/jsx-runtime");
559
1210
  var MARGIN = 4;
560
1211
  function Dropdown({
561
1212
  items,
@@ -564,20 +1215,23 @@ function Dropdown({
564
1215
  triggerLabel = "Options",
565
1216
  direction = "down",
566
1217
  align = "left",
1218
+ triggerOrientation = "horizontal",
567
1219
  triggerContent,
568
1220
  label,
1221
+ iconOnly = false,
569
1222
  noChevron = false,
570
1223
  size = "md",
571
1224
  triggerVariant = "outline",
572
1225
  className,
573
1226
  triggerClassName,
574
1227
  panelClassName,
575
- closeOnSelect = true
1228
+ closeOnSelect = true,
1229
+ disabled = false
576
1230
  }) {
577
- const [open, setOpen] = React7.useState(false);
578
- const triggerRef = React7.useRef(null);
579
- const panelRef = React7.useRef(null);
580
- const [panelStyle, setPanelStyle] = React7.useState({});
1231
+ const [open, setOpen] = React11.useState(false);
1232
+ const triggerRef = React11.useRef(null);
1233
+ const panelRef = React11.useRef(null);
1234
+ const [panelStyle, setPanelStyle] = React11.useState({});
581
1235
  const visibleItems = items.filter(
582
1236
  (item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
583
1237
  );
@@ -585,42 +1239,60 @@ function Dropdown({
585
1239
  const selectableItems = visibleItems.filter((i) => i.kind !== "header");
586
1240
  const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
587
1241
  const isUp = direction === "up";
588
- const ChevronIcon = isUp ? import_fractal_icons2.ChevronUp : import_fractal_icons2.ChevronDown;
589
- React7.useLayoutEffect(() => {
1242
+ const isHorizontalDirection = direction === "left" || direction === "right";
1243
+ const ChevronIcon = direction === "up" ? import_fractal_icons8.ChevronUp : direction === "left" ? import_fractal_icons8.ChevronLeft : direction === "right" ? import_fractal_icons8.ChevronRight : import_fractal_icons8.ChevronDown;
1244
+ React11.useLayoutEffect(() => {
590
1245
  if (!open || !triggerRef.current || !panelRef.current) return;
591
1246
  const triggerRect = triggerRef.current.getBoundingClientRect();
592
1247
  const panelRect = panelRef.current.getBoundingClientRect();
593
1248
  const vw = window.innerWidth;
594
1249
  const vh = window.innerHeight;
595
- const spaceBelow = vh - triggerRect.bottom - MARGIN;
596
- const spaceAbove = triggerRect.top - MARGIN;
597
- let placeAbove = isUp;
598
- if (placeAbove && panelRect.height > spaceAbove && spaceBelow > spaceAbove) {
599
- placeAbove = false;
600
- } else if (!placeAbove && panelRect.height > spaceBelow && spaceAbove > spaceBelow) {
601
- placeAbove = true;
602
- }
603
- const top = placeAbove ? -(panelRect.height + MARGIN) : triggerRect.height + MARGIN;
1250
+ let top;
604
1251
  let left;
605
1252
  let right;
606
- if (align === "right") {
607
- right = 0;
608
- const panelLeft = triggerRect.right - panelRect.width;
609
- if (panelLeft < 0) {
610
- right = void 0;
611
- left = 0;
1253
+ if (isHorizontalDirection) {
1254
+ const spaceRight = vw - triggerRect.right - MARGIN;
1255
+ const spaceLeft = triggerRect.left - MARGIN;
1256
+ let placeRight = direction === "right";
1257
+ if (placeRight && panelRect.width > spaceRight && spaceLeft > spaceRight) {
1258
+ placeRight = false;
1259
+ } else if (!placeRight && panelRect.width > spaceLeft && spaceRight > spaceLeft) {
1260
+ placeRight = true;
612
1261
  }
1262
+ left = placeRight ? triggerRect.width + MARGIN : -(panelRect.width + MARGIN);
1263
+ top = 0;
1264
+ const panelBottom = triggerRect.top + panelRect.height;
1265
+ if (panelBottom > vh - MARGIN) top -= panelBottom - (vh - MARGIN);
1266
+ if (triggerRect.top + top < MARGIN) top += MARGIN - (triggerRect.top + top);
613
1267
  } else {
614
- left = 0;
615
- const panelRight = triggerRect.left + panelRect.width;
616
- if (panelRight > vw) {
617
- left = void 0;
1268
+ const spaceBelow = vh - triggerRect.bottom - MARGIN;
1269
+ const spaceAbove = triggerRect.top - MARGIN;
1270
+ let placeAbove = isUp;
1271
+ if (placeAbove && panelRect.height > spaceAbove && spaceBelow > spaceAbove) {
1272
+ placeAbove = false;
1273
+ } else if (!placeAbove && panelRect.height > spaceBelow && spaceAbove > spaceBelow) {
1274
+ placeAbove = true;
1275
+ }
1276
+ top = placeAbove ? -(panelRect.height + MARGIN) : triggerRect.height + MARGIN;
1277
+ if (align === "right") {
618
1278
  right = 0;
1279
+ const panelLeft = triggerRect.right - panelRect.width;
1280
+ if (panelLeft < 0) {
1281
+ right = void 0;
1282
+ left = 0;
1283
+ }
1284
+ } else {
1285
+ left = 0;
1286
+ const panelRight = triggerRect.left + panelRect.width;
1287
+ if (panelRight > vw) {
1288
+ left = void 0;
1289
+ right = 0;
1290
+ }
619
1291
  }
620
1292
  }
621
1293
  setPanelStyle({ top, left, right });
622
- }, [open, isUp, align]);
623
- React7.useEffect(() => {
1294
+ }, [open, direction, isHorizontalDirection, isUp, align]);
1295
+ React11.useEffect(() => {
624
1296
  if (!open) return;
625
1297
  const handleClickOutside = (e) => {
626
1298
  const target = e.target;
@@ -630,12 +1302,13 @@ function Dropdown({
630
1302
  document.addEventListener("mousedown", handleClickOutside);
631
1303
  return () => document.removeEventListener("mousedown", handleClickOutside);
632
1304
  }, [open]);
633
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
634
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1305
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
1306
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
635
1307
  "button",
636
1308
  {
637
1309
  ref: triggerRef,
638
1310
  type: "button",
1311
+ disabled,
639
1312
  "aria-haspopup": "listbox",
640
1313
  "aria-expanded": open,
641
1314
  "aria-label": triggerLabel,
@@ -644,18 +1317,20 @@ function Dropdown({
644
1317
  "fractal-dropdown-trigger",
645
1318
  `fractal-dropdown-trigger--${size}`,
646
1319
  `fractal-dropdown-trigger--${triggerVariant}`,
1320
+ `fractal-dropdown-trigger--${triggerOrientation}`,
1321
+ iconOnly && "fractal-dropdown-trigger--icon-only",
647
1322
  triggerClassName
648
1323
  ),
649
1324
  children: [
650
- triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
651
- selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
652
- selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
1325
+ triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1326
+ selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
1327
+ selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
653
1328
  ] }),
654
- !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 }) })
1329
+ !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 }) })
655
1330
  ]
656
1331
  }
657
1332
  ),
658
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1333
+ open && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
659
1334
  "div",
660
1335
  {
661
1336
  ref: panelRef,
@@ -664,21 +1339,21 @@ function Dropdown({
664
1339
  className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
665
1340
  style: panelStyle,
666
1341
  children: [
667
- label != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-label", children: label }),
1342
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-label", children: label }),
668
1343
  visibleItems.map((item, index) => {
669
- const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
670
- const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
1344
+ const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
1345
+ const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
671
1346
  if (item.kind === "header") {
672
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
1347
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React11.Fragment, { children: [
673
1348
  topDivider,
674
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
675
1350
  bottomDivider
676
1351
  ] }, `header-${index}`);
677
1352
  }
678
1353
  const isSelected = item.value === selectedValue;
679
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React11.Fragment, { children: [
680
1355
  topDivider,
681
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1356
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
682
1357
  "button",
683
1358
  {
684
1359
  type: "button",
@@ -690,9 +1365,9 @@ function Dropdown({
690
1365
  },
691
1366
  className: "fractal-dropdown-option",
692
1367
  children: [
693
- item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
694
- item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
695
- item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
1368
+ item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
1369
+ item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
1370
+ item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
696
1371
  ]
697
1372
  }
698
1373
  ),
@@ -706,10 +1381,10 @@ function Dropdown({
706
1381
  }
707
1382
 
708
1383
  // src/components/Link/Link.tsx
709
- var React8 = __toESM(require("react"), 1);
710
- var import_jsx_runtime11 = require("react/jsx-runtime");
711
- var Link = React8.forwardRef(
712
- ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1384
+ var React12 = __toESM(require("react"), 1);
1385
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1386
+ var Link = React12.forwardRef(
1387
+ ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
713
1388
  "a",
714
1389
  {
715
1390
  ref,
@@ -721,10 +1396,10 @@ var Link = React8.forwardRef(
721
1396
  Link.displayName = "Link";
722
1397
 
723
1398
  // src/components/Chip/Chip.tsx
724
- var React9 = __toESM(require("react"), 1);
725
- var import_jsx_runtime12 = require("react/jsx-runtime");
726
- var Chip = React9.forwardRef(
727
- ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1399
+ var React13 = __toESM(require("react"), 1);
1400
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1401
+ var Chip = React13.forwardRef(
1402
+ ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
728
1403
  "span",
729
1404
  {
730
1405
  ref,
@@ -735,36 +1410,92 @@ var Chip = React9.forwardRef(
735
1410
  );
736
1411
  Chip.displayName = "Chip";
737
1412
 
1413
+ // src/components/Checkbox/Checkbox.tsx
1414
+ var import_fractal_icons9 = require("@mirror-physics/fractal-icons");
1415
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1416
+ function Checkbox({
1417
+ checked,
1418
+ indeterminate = false,
1419
+ onCheckedChange,
1420
+ className,
1421
+ disabled,
1422
+ onClick,
1423
+ onKeyDown,
1424
+ ...props
1425
+ }) {
1426
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1427
+ "button",
1428
+ {
1429
+ ...props,
1430
+ className: cn(
1431
+ "fractal-checkbox",
1432
+ (checked || indeterminate) && "fractal-checkbox--checked",
1433
+ indeterminate && "fractal-checkbox--indeterminate",
1434
+ className
1435
+ ),
1436
+ type: "button",
1437
+ role: "checkbox",
1438
+ "aria-checked": indeterminate ? "mixed" : checked,
1439
+ disabled,
1440
+ onClick: (event) => {
1441
+ onClick?.(event);
1442
+ if (!event.defaultPrevented) onCheckedChange(indeterminate || !checked);
1443
+ },
1444
+ onKeyDown: (event) => {
1445
+ onKeyDown?.(event);
1446
+ if (event.key === " " || event.key === "Enter") event.stopPropagation();
1447
+ },
1448
+ children: indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "fractal-checkbox__indeterminate-icon", "aria-hidden": "true", children: [
1449
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fractal_icons9.Checkbox, { size: 18 }),
1450
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fractal_icons9.Minus, { className: "fractal-checkbox__indeterminate-mark", size: 12 })
1451
+ ] }) : 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 })
1452
+ }
1453
+ );
1454
+ }
1455
+
738
1456
  // src/components/SortableTable/SortableTable.tsx
739
- var import_react2 = require("react");
740
- var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
741
- var import_jsx_runtime13 = require("react/jsx-runtime");
1457
+ var import_react4 = require("react");
1458
+ var import_fractal_icons10 = require("@mirror-physics/fractal-icons");
1459
+ var import_jsx_runtime20 = require("react/jsx-runtime");
742
1460
  function SortableTable({
743
1461
  columns,
744
1462
  data,
1463
+ "aria-label": ariaLabel,
745
1464
  emptyMessage,
746
1465
  header,
747
1466
  size = "md",
1467
+ embedded = false,
748
1468
  className,
1469
+ defaultSort,
749
1470
  defaultSortKey = void 0,
750
1471
  defaultSortDirection = null,
751
1472
  sortKey: controlledKey,
752
1473
  sortDirection: controlledDirection,
753
1474
  onSortChange,
1475
+ pagination,
754
1476
  highlightRow,
755
- onRowClick
1477
+ selection,
1478
+ isRowDisabled,
1479
+ isRowSelectionDisabled,
1480
+ onRowClick,
1481
+ onRowDoubleClick,
1482
+ rowAction
756
1483
  }) {
757
- const [internalKey, setInternalKey] = (0, import_react2.useState)(defaultSortKey ?? null);
758
- const [internalDirection, setInternalDirection] = (0, import_react2.useState)(defaultSortDirection);
1484
+ const [internalKey, setInternalKey] = (0, import_react4.useState)(defaultSortKey ?? null);
1485
+ const [internalDirection, setInternalDirection] = (0, import_react4.useState)(defaultSortDirection);
759
1486
  const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
760
1487
  const activeKey = isControlled ? controlledKey : internalKey;
761
1488
  const activeDirection = isControlled ? controlledDirection : internalDirection;
762
- const sorted = (0, import_react2.useMemo)(() => {
763
- if (!activeKey || !activeDirection) return data;
764
- const col = columns.find((c) => c.key === activeKey);
1489
+ const baselineKey = defaultSort?.key ?? null;
1490
+ const baselineDirection = defaultSort?.direction ?? null;
1491
+ const effectiveKey = activeKey && activeDirection ? activeKey : baselineKey;
1492
+ const effectiveDirection = activeKey && activeDirection ? activeDirection : baselineDirection;
1493
+ const sorted = (0, import_react4.useMemo)(() => {
1494
+ if (!effectiveKey || !effectiveDirection) return data;
1495
+ const col = columns.find((c) => c.key === effectiveKey);
765
1496
  if (!col) return data;
766
1497
  const accessor = col.sortAccessor ?? ((row) => {
767
- const value = row[activeKey];
1498
+ const value = row[effectiveKey];
768
1499
  return typeof value === "string" || typeof value === "number" ? value : null;
769
1500
  });
770
1501
  const copy = [...data];
@@ -775,26 +1506,41 @@ function SortableTable({
775
1506
  if (av == null) return 1;
776
1507
  if (bv == null) return -1;
777
1508
  if (typeof av === "number" && typeof bv === "number") {
778
- return activeDirection === "asc" ? av - bv : bv - av;
1509
+ return effectiveDirection === "asc" ? av - bv : bv - av;
779
1510
  }
780
1511
  const as = String(av).toLowerCase();
781
1512
  const bs = String(bv).toLowerCase();
782
- if (as < bs) return activeDirection === "asc" ? -1 : 1;
783
- if (as > bs) return activeDirection === "asc" ? 1 : -1;
1513
+ if (as < bs) return effectiveDirection === "asc" ? -1 : 1;
1514
+ if (as > bs) return effectiveDirection === "asc" ? 1 : -1;
784
1515
  return 0;
785
1516
  });
786
1517
  return copy;
787
- }, [data, columns, activeKey, activeDirection]);
1518
+ }, [data, columns, effectiveKey, effectiveDirection]);
1519
+ const visibleRows = (0, import_react4.useMemo)(() => {
1520
+ if (!pagination) return sorted;
1521
+ const pageSize = Math.max(1, pagination.pageSize);
1522
+ const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));
1523
+ const page = Math.min(Math.max(1, pagination.page), totalPages);
1524
+ const startIndex = (page - 1) * pageSize;
1525
+ return sorted.slice(startIndex, startIndex + pageSize);
1526
+ }, [pagination, sorted]);
1527
+ const selectedRows = selection ? sorted.filter(selection.isSelected) : [];
1528
+ const selectableRows = selection ? sorted.filter((row) => !isRowDisabled?.(row) && !isRowSelectionDisabled?.(row)) : [];
1529
+ const selectedRowCount = selection ? selectableRows.filter(selection.isSelected).length : 0;
1530
+ const allRowsSelected = selectableRows.length > 0 && selectedRowCount === selectableRows.length;
1531
+ const someRowsSelected = selectedRows.length > 0 && !allRowsSelected;
788
1532
  const handleSortClick = (key) => {
789
1533
  let nextDirection;
790
- if (activeKey !== key) {
1534
+ if (!activeKey || !activeDirection) {
1535
+ nextDirection = baselineKey === key && baselineDirection ? baselineDirection : "asc";
1536
+ } else if (activeKey !== key) {
791
1537
  nextDirection = "asc";
1538
+ } else if (baselineKey === key && baselineDirection) {
1539
+ nextDirection = activeDirection === baselineDirection ? baselineDirection === "asc" ? "desc" : "asc" : null;
792
1540
  } else if (activeDirection === "asc") {
793
1541
  nextDirection = "desc";
794
- } else if (activeDirection === "desc") {
795
- nextDirection = null;
796
1542
  } else {
797
- nextDirection = "asc";
1543
+ nextDirection = null;
798
1544
  }
799
1545
  const nextKey = nextDirection === null ? null : key;
800
1546
  if (isControlled) {
@@ -805,75 +1551,140 @@ function SortableTable({
805
1551
  onSortChange?.(nextKey, nextDirection);
806
1552
  }
807
1553
  };
808
- 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: [
809
- header && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
810
- 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: [
811
- /* @__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) => {
812
- const isActive = activeKey === col.key && activeDirection !== null;
813
- if (!col.sortable) {
814
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1554
+ 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: [
1555
+ header && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
1556
+ 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", { "aria-label": ariaLabel, className: "fractal-sortable-table-table", children: [
1557
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("tr", { className: "fractal-sortable-table-thead-row", children: [
1558
+ selection && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1559
+ "th",
1560
+ {
1561
+ className: "fractal-sortable-table-th fractal-sortable-table-selection-cell",
1562
+ scope: "col",
1563
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1564
+ Checkbox,
1565
+ {
1566
+ "aria-label": selection.selectAllLabel ?? "Select all rows",
1567
+ checked: allRowsSelected,
1568
+ disabled: selectableRows.length === 0 && selectedRows.length === 0,
1569
+ indeterminate: someRowsSelected,
1570
+ onCheckedChange: (checked) => {
1571
+ const rows = checked ? selectableRows : selectedRows;
1572
+ if (selection.onSelectAllChange) {
1573
+ selection.onSelectAllChange(rows, checked);
1574
+ return;
1575
+ }
1576
+ rows.forEach((row) => {
1577
+ if (selection.isSelected(row) !== checked) {
1578
+ selection.onSelectedChange(row, checked);
1579
+ }
1580
+ });
1581
+ }
1582
+ }
1583
+ )
1584
+ }
1585
+ ),
1586
+ columns.map((col) => {
1587
+ const isActive = activeKey === col.key && activeDirection !== null;
1588
+ if (!col.sortable) {
1589
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1590
+ "th",
1591
+ {
1592
+ className: "fractal-sortable-table-th",
1593
+ scope: "col",
1594
+ style: { width: col.width },
1595
+ children: col.header
1596
+ },
1597
+ col.key
1598
+ );
1599
+ }
1600
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
815
1601
  "th",
816
1602
  {
817
- className: "fractal-sortable-table-th",
1603
+ className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
1604
+ scope: "col",
818
1605
  style: { width: col.width },
819
- children: col.header
1606
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1607
+ "button",
1608
+ {
1609
+ type: "button",
1610
+ className: cn(
1611
+ "fractal-sortable-table-sort-button",
1612
+ isActive && "fractal-sortable-table-sort-button--active"
1613
+ ),
1614
+ onClick: () => handleSortClick(col.key),
1615
+ "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
1616
+ children: [
1617
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: col.header }),
1618
+ /* @__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 }) })
1619
+ ]
1620
+ }
1621
+ )
820
1622
  },
821
1623
  col.key
822
1624
  );
823
- }
824
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
825
- "th",
826
- {
827
- className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
828
- style: { width: col.width },
829
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
830
- "button",
831
- {
832
- type: "button",
833
- className: cn(
834
- "fractal-sortable-table-sort-button",
835
- isActive && "fractal-sortable-table-sort-button--active"
836
- ),
837
- onClick: () => handleSortClick(col.key),
838
- "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
839
- children: [
840
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: col.header }),
841
- /* @__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 }) })
842
- ]
843
- }
844
- )
845
- },
846
- col.key
847
- );
848
- }) }) }),
849
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
1625
+ })
1626
+ ] }) }),
1627
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { children: visibleRows.map((row, rowIndex) => {
850
1628
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
851
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1629
+ const disabled = isRowDisabled?.(row) ?? false;
1630
+ const selectionDisabled = disabled || (isRowSelectionDisabled?.(row) ?? false);
1631
+ const interactive = !disabled && Boolean(onRowClick || onRowDoubleClick);
1632
+ const action = !disabled && rowAction ? {
1633
+ label: rowAction.label(row, rowIndex),
1634
+ icon: rowAction.icon(row, rowIndex)
1635
+ } : null;
1636
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
852
1637
  "tr",
853
1638
  {
854
1639
  className: cn(
855
1640
  "fractal-sortable-table-row",
856
1641
  highlighted && "fractal-sortable-table-row--highlighted",
857
- onRowClick && "fractal-sortable-table-row--interactive"
1642
+ interactive && "fractal-sortable-table-row--interactive",
1643
+ disabled && "fractal-sortable-table-row--disabled"
858
1644
  ),
859
- onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
860
- onKeyDown: onRowClick ? (event) => {
1645
+ "data-disabled": disabled || void 0,
1646
+ onClick: !disabled && onRowClick ? () => onRowClick(row, rowIndex) : void 0,
1647
+ onDoubleClick: !disabled && onRowDoubleClick ? () => onRowDoubleClick(row, rowIndex) : void 0,
1648
+ onKeyDown: interactive ? (event) => {
861
1649
  if (event.key === "Enter" || event.key === " ") {
862
1650
  event.preventDefault();
863
- onRowClick(row, rowIndex);
1651
+ const activateRow = onRowClick ?? onRowDoubleClick;
1652
+ activateRow?.(row, rowIndex);
864
1653
  }
865
1654
  } : void 0,
866
- role: onRowClick ? "button" : void 0,
867
- tabIndex: onRowClick ? 0 : void 0,
868
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
869
- "td",
870
- {
871
- className: "fractal-sortable-table-td",
872
- style: { width: col.width, textAlign: col.align ?? "left" },
873
- children: col.render(row, rowIndex)
874
- },
875
- col.key
876
- ))
1655
+ "aria-label": action?.label,
1656
+ "aria-disabled": disabled || void 0,
1657
+ role: interactive ? "button" : void 0,
1658
+ tabIndex: interactive ? 0 : void 0,
1659
+ children: [
1660
+ selection && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { className: "fractal-sortable-table-td fractal-sortable-table-selection-cell", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1661
+ Checkbox,
1662
+ {
1663
+ "aria-label": selection.getRowLabel(row),
1664
+ checked: !selectionDisabled && selection.isSelected(row),
1665
+ disabled: selectionDisabled,
1666
+ onClick: (event) => event.stopPropagation(),
1667
+ onCheckedChange: (checked) => {
1668
+ if (!selectionDisabled) selection.onSelectedChange(row, checked);
1669
+ }
1670
+ }
1671
+ ) }),
1672
+ columns.map((col, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1673
+ "td",
1674
+ {
1675
+ className: cn(
1676
+ "fractal-sortable-table-td",
1677
+ action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1678
+ ),
1679
+ style: { width: col.width, textAlign: col.align ?? "left" },
1680
+ children: [
1681
+ col.render(row, rowIndex),
1682
+ 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 }) })
1683
+ ]
1684
+ },
1685
+ col.key
1686
+ ))
1687
+ ]
877
1688
  },
878
1689
  rowIndex
879
1690
  );
@@ -883,23 +1694,40 @@ function SortableTable({
883
1694
  }
884
1695
 
885
1696
  // src/components/Tabs/Tabs.tsx
886
- var import_react3 = require("react");
887
- var import_jsx_runtime14 = require("react/jsx-runtime");
1697
+ var import_react5 = require("react");
1698
+ var import_jsx_runtime21 = require("react/jsx-runtime");
888
1699
  function Tabs({
889
1700
  items,
890
1701
  defaultValue,
891
1702
  value: controlledValue,
892
1703
  onValueChange,
893
1704
  className,
894
- ariaLabel
1705
+ ariaLabel,
1706
+ divider = false,
1707
+ variant = "line"
895
1708
  }) {
896
- const reactId = (0, import_react3.useId)();
897
- const [internalValue, setInternalValue] = (0, import_react3.useState)(
1709
+ const reactId = (0, import_react5.useId)();
1710
+ const [internalValue, setInternalValue] = (0, import_react5.useState)(
898
1711
  defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
899
1712
  );
900
1713
  const isControlled = controlledValue !== void 0;
901
1714
  const activeId = isControlled ? controlledValue : internalValue;
902
- const tabRefs = (0, import_react3.useRef)({});
1715
+ const tabListRef = (0, import_react5.useRef)(null);
1716
+ const tabRefs = (0, import_react5.useRef)({});
1717
+ const [indicator, setIndicator] = (0, import_react5.useState)(null);
1718
+ (0, import_react5.useLayoutEffect)(() => {
1719
+ const updateIndicator = () => {
1720
+ const activeTab = tabRefs.current[activeId];
1721
+ if (!activeTab) return;
1722
+ setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
1723
+ };
1724
+ updateIndicator();
1725
+ const list = tabListRef.current;
1726
+ if (!list || typeof ResizeObserver === "undefined") return;
1727
+ const observer = new ResizeObserver(updateIndicator);
1728
+ observer.observe(list);
1729
+ return () => observer.disconnect();
1730
+ }, [activeId, items.length]);
903
1731
  const selectTab = (id) => {
904
1732
  if (isControlled) {
905
1733
  onValueChange?.(id);
@@ -909,6 +1737,10 @@ function Tabs({
909
1737
  }
910
1738
  };
911
1739
  const focusable = items.filter((i) => !i.disabled);
1740
+ const indicatorStyle = indicator ? {
1741
+ "--fractal-tabs-indicator-offset": `${indicator.offset}px`,
1742
+ "--fractal-tabs-indicator-width": `${indicator.width}px`
1743
+ } : void 0;
912
1744
  const onKeyDown = (event) => {
913
1745
  const currentIndex = focusable.findIndex((i) => i.id === activeId);
914
1746
  if (currentIndex === -1) return;
@@ -934,41 +1766,52 @@ function Tabs({
934
1766
  selectTab(nextId2);
935
1767
  requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
936
1768
  };
937
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cn("fractal-tabs", className), children: [
938
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "tablist", "aria-label": ariaLabel, className: "fractal-tabs-list", children: items.map((item) => {
939
- const isActive = item.id === activeId;
940
- const tabId = `${reactId}-tab-${item.id}`;
941
- const panelId = `${reactId}-panel-${item.id}`;
942
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
943
- "button",
944
- {
945
- ref: (el) => {
946
- tabRefs.current[item.id] = el;
947
- },
948
- id: tabId,
949
- role: "tab",
950
- type: "button",
951
- "aria-selected": isActive,
952
- "aria-controls": panelId,
953
- tabIndex: isActive ? 0 : -1,
954
- disabled: item.disabled,
955
- className: cn(
956
- "fractal-tabs-trigger",
957
- isActive && "fractal-tabs-trigger--active",
958
- item.disabled && "fractal-tabs-trigger--disabled"
959
- ),
960
- onClick: () => !item.disabled && selectTab(item.id),
961
- onKeyDown,
962
- children: item.label
963
- },
964
- item.id
965
- );
966
- }) }),
1769
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: cn("fractal-tabs", `fractal-tabs--${variant}`, divider && "fractal-tabs--divider", className), children: [
1770
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1771
+ "div",
1772
+ {
1773
+ ref: tabListRef,
1774
+ role: "tablist",
1775
+ "aria-label": ariaLabel,
1776
+ className: "fractal-tabs-list",
1777
+ "data-indicator-ready": indicator ? "true" : void 0,
1778
+ style: indicatorStyle,
1779
+ children: items.map((item) => {
1780
+ const isActive = item.id === activeId;
1781
+ const tabId = `${reactId}-tab-${item.id}`;
1782
+ const panelId = `${reactId}-panel-${item.id}`;
1783
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1784
+ "button",
1785
+ {
1786
+ ref: (el) => {
1787
+ tabRefs.current[item.id] = el;
1788
+ },
1789
+ id: tabId,
1790
+ role: "tab",
1791
+ type: "button",
1792
+ "aria-selected": isActive,
1793
+ "aria-controls": panelId,
1794
+ tabIndex: isActive ? 0 : -1,
1795
+ disabled: item.disabled,
1796
+ className: cn(
1797
+ "fractal-tabs-trigger",
1798
+ isActive && "fractal-tabs-trigger--active",
1799
+ item.disabled && "fractal-tabs-trigger--disabled"
1800
+ ),
1801
+ onClick: () => !item.disabled && selectTab(item.id),
1802
+ onKeyDown,
1803
+ children: item.label
1804
+ },
1805
+ item.id
1806
+ );
1807
+ })
1808
+ }
1809
+ ),
967
1810
  items.map((item) => {
968
1811
  const tabId = `${reactId}-tab-${item.id}`;
969
1812
  const panelId = `${reactId}-panel-${item.id}`;
970
1813
  const isActive = item.id === activeId;
971
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1814
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
972
1815
  "div",
973
1816
  {
974
1817
  id: panelId,
@@ -984,10 +1827,112 @@ function Tabs({
984
1827
  ] });
985
1828
  }
986
1829
 
1830
+ // src/components/ContentSwitcher/ContentSwitcher.tsx
1831
+ var React14 = __toESM(require("react"), 1);
1832
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1833
+ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1834
+ const switcherRef = React14.useRef(null);
1835
+ const buttonRefs = React14.useRef([]);
1836
+ const indicatorMotionReadyRef = React14.useRef(false);
1837
+ const activeIndex = items.findIndex((item) => item.value === value);
1838
+ React14.useLayoutEffect(() => {
1839
+ const switcher = switcherRef.current;
1840
+ const activeButton = buttonRefs.current[activeIndex];
1841
+ let motionFrame = 0;
1842
+ if (!switcher || !activeButton) {
1843
+ switcher?.removeAttribute("data-indicator-ready");
1844
+ switcher?.removeAttribute("data-indicator-animate");
1845
+ indicatorMotionReadyRef.current = false;
1846
+ return;
1847
+ }
1848
+ const updateIndicator = () => {
1849
+ const switcherRect = switcher.getBoundingClientRect();
1850
+ const activeButtonRect = activeButton.getBoundingClientRect();
1851
+ switcher.style.setProperty("--fractal-content-switcher-indicator-x", `${activeButtonRect.left - switcherRect.left - switcher.clientLeft}px`);
1852
+ switcher.style.setProperty("--fractal-content-switcher-indicator-y", `${activeButtonRect.top - switcherRect.top - switcher.clientTop}px`);
1853
+ switcher.style.setProperty("--fractal-content-switcher-indicator-width", `${activeButtonRect.width}px`);
1854
+ switcher.style.setProperty("--fractal-content-switcher-indicator-height", `${activeButtonRect.height}px`);
1855
+ switcher.setAttribute("data-indicator-ready", "true");
1856
+ if (!indicatorMotionReadyRef.current && motionFrame === 0) {
1857
+ motionFrame = window.requestAnimationFrame(() => {
1858
+ indicatorMotionReadyRef.current = true;
1859
+ switcher.setAttribute("data-indicator-animate", "true");
1860
+ motionFrame = 0;
1861
+ });
1862
+ }
1863
+ };
1864
+ updateIndicator();
1865
+ if (typeof ResizeObserver === "undefined") {
1866
+ return () => {
1867
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1868
+ };
1869
+ }
1870
+ const resizeObserver = new ResizeObserver(updateIndicator);
1871
+ resizeObserver.observe(switcher);
1872
+ buttonRefs.current.forEach((button) => {
1873
+ if (button) resizeObserver.observe(button);
1874
+ });
1875
+ return () => {
1876
+ resizeObserver.disconnect();
1877
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1878
+ };
1879
+ }, [activeIndex, items.length]);
1880
+ const moveFocus = (index, direction) => {
1881
+ let nextIndex = index;
1882
+ do {
1883
+ nextIndex = (nextIndex + direction + items.length) % items.length;
1884
+ } while (items[nextIndex]?.disabled && nextIndex !== index);
1885
+ if (!items[nextIndex]?.disabled) {
1886
+ buttonRefs.current[nextIndex]?.focus();
1887
+ onValueChange(items[nextIndex].value);
1888
+ }
1889
+ };
1890
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1891
+ "div",
1892
+ {
1893
+ className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className),
1894
+ role: "group",
1895
+ "aria-label": ariaLabel,
1896
+ ref: switcherRef,
1897
+ children: [
1898
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
1899
+ items.map((item, index) => {
1900
+ const active = item.value === value;
1901
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1902
+ "button",
1903
+ {
1904
+ className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
1905
+ type: "button",
1906
+ "aria-pressed": active,
1907
+ disabled: item.disabled,
1908
+ onClick: () => onValueChange(item.value),
1909
+ onKeyDown: (event) => {
1910
+ if (event.key === "ArrowRight") {
1911
+ event.preventDefault();
1912
+ moveFocus(index, 1);
1913
+ }
1914
+ if (event.key === "ArrowLeft") {
1915
+ event.preventDefault();
1916
+ moveFocus(index, -1);
1917
+ }
1918
+ },
1919
+ ref: (element) => {
1920
+ buttonRefs.current[index] = element;
1921
+ },
1922
+ children: item.label
1923
+ },
1924
+ item.value
1925
+ );
1926
+ })
1927
+ ]
1928
+ }
1929
+ );
1930
+ }
1931
+
987
1932
  // src/components/Disclosure/Disclosure.tsx
988
- var import_react4 = require("react");
989
- var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
990
- var import_jsx_runtime15 = require("react/jsx-runtime");
1933
+ var import_react6 = require("react");
1934
+ var import_fractal_icons11 = require("@mirror-physics/fractal-icons");
1935
+ var import_jsx_runtime23 = require("react/jsx-runtime");
991
1936
  function Disclosure({
992
1937
  title,
993
1938
  meta,
@@ -995,16 +1940,18 @@ function Disclosure({
995
1940
  defaultOpen = false,
996
1941
  open: controlledOpen,
997
1942
  onOpenChange,
1943
+ disabled = false,
998
1944
  className,
999
1945
  variant = "card"
1000
1946
  }) {
1001
- const reactId = (0, import_react4.useId)();
1947
+ const reactId = (0, import_react6.useId)();
1002
1948
  const headerId = `${reactId}-header`;
1003
1949
  const panelId = `${reactId}-panel`;
1004
- const [internalOpen, setInternalOpen] = (0, import_react4.useState)(defaultOpen);
1950
+ const [internalOpen, setInternalOpen] = (0, import_react6.useState)(defaultOpen);
1005
1951
  const isControlled = controlledOpen !== void 0;
1006
1952
  const isOpen = isControlled ? controlledOpen : internalOpen;
1007
1953
  const toggle = () => {
1954
+ if (disabled) return;
1008
1955
  const next = !isOpen;
1009
1956
  if (isControlled) {
1010
1957
  onOpenChange?.(next);
@@ -1013,17 +1960,18 @@ function Disclosure({
1013
1960
  onOpenChange?.(next);
1014
1961
  }
1015
1962
  };
1016
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1963
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1017
1964
  "div",
1018
1965
  {
1019
1966
  className: cn(
1020
1967
  "fractal-disclosure",
1021
1968
  variant === "card" && "fractal-disclosure--card",
1022
1969
  isOpen && "fractal-disclosure--open",
1970
+ disabled && "fractal-disclosure--disabled",
1023
1971
  className
1024
1972
  ),
1025
1973
  children: [
1026
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1974
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1027
1975
  "button",
1028
1976
  {
1029
1977
  type: "button",
@@ -1031,15 +1979,16 @@ function Disclosure({
1031
1979
  className: "fractal-disclosure-trigger",
1032
1980
  "aria-expanded": isOpen,
1033
1981
  "aria-controls": panelId,
1982
+ disabled,
1034
1983
  onClick: toggle,
1035
1984
  children: [
1036
- /* @__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 }) }),
1037
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1038
- meta && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1985
+ /* @__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 }) }),
1986
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1987
+ meta && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1039
1988
  ]
1040
1989
  }
1041
1990
  ),
1042
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1991
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1043
1992
  "div",
1044
1993
  {
1045
1994
  id: panelId,
@@ -1047,7 +1996,7 @@ function Disclosure({
1047
1996
  "aria-labelledby": headerId,
1048
1997
  className: "fractal-disclosure-panel",
1049
1998
  hidden: !isOpen,
1050
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1999
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1051
2000
  }
1052
2001
  )
1053
2002
  ]
@@ -1055,39 +2004,260 @@ function Disclosure({
1055
2004
  );
1056
2005
  }
1057
2006
 
2007
+ // src/components/LatticeLoader/LatticeLoader.tsx
2008
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2009
+ var LATTICE_COUNT = 160;
2010
+ var WAVE_PERIOD = 80;
2011
+ function LatticeLoader({ className, label = "Loading", ...props }) {
2012
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2013
+ "span",
2014
+ {
2015
+ "aria-label": label,
2016
+ className: cn("fractal-lattice-loader", className),
2017
+ role: "progressbar",
2018
+ ...props,
2019
+ children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2020
+ "span",
2021
+ {
2022
+ "aria-hidden": "true",
2023
+ className: "fractal-lattice-loader__cell",
2024
+ style: { "--fractal-lattice-index": index % WAVE_PERIOD }
2025
+ },
2026
+ index
2027
+ ))
2028
+ }
2029
+ );
2030
+ }
2031
+
2032
+ // src/components/Ghost/Ghost.tsx
2033
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2034
+ var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
2035
+ function Ghost({ className, width, height, radius, style, ...props }) {
2036
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2037
+ "div",
2038
+ {
2039
+ "aria-hidden": "true",
2040
+ className: cn("fractal-ghost", className),
2041
+ style: {
2042
+ width: toCssLength(width),
2043
+ height: toCssLength(height),
2044
+ borderRadius: toCssLength(radius),
2045
+ ...style
2046
+ },
2047
+ ...props
2048
+ }
2049
+ );
2050
+ }
2051
+ function GhostLine({ className, size = "md", width = "100%", ...props }) {
2052
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
2053
+ }
2054
+ function ButtonGhost({ className, size = "md", iconOnly = false, width, ...props }) {
2055
+ 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 });
2056
+ }
2057
+ function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
2058
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
2059
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "38%" }),
2060
+ /* @__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)) })
2061
+ ] });
2062
+ }
2063
+ function DataTableGhost({
2064
+ className,
2065
+ showHeader = true,
2066
+ headers,
2067
+ columns = 4,
2068
+ rows = 5,
2069
+ columnWidths,
2070
+ size = "md",
2071
+ ...props
2072
+ }) {
2073
+ const cells = Array.from({ length: columns }, (_, index) => index);
2074
+ 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: [
2075
+ (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)) }) }),
2076
+ /* @__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)) })
2077
+ ] }) });
2078
+ }
2079
+ function InputGhost({ className, labelWidth = "26%", ...props }) {
2080
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FormFieldGhost, { className, labelWidth, ...props });
2081
+ }
2082
+ function TextareaGhost({ className, labelWidth = "26%", ...props }) {
2083
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
2084
+ }
2085
+ function LabelGhost({ className, width = "26%", ...props }) {
2086
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
2087
+ }
2088
+ function FormFieldGhost({ className, labelWidth = "26%", multiline = false, ...props }) {
2089
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-field", className), ...props, children: [
2090
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LabelGhost, { width: labelWidth }),
2091
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
2092
+ ] });
2093
+ }
2094
+ function AlertGhost({ className, ...props }) {
2095
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
2096
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "30%" }),
2097
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { size: "sm", width: "78%" })
2098
+ ] });
2099
+ }
2100
+ function CheckboxGhost({ className, ...props }) {
2101
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
2102
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-choice__control" }),
2103
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" })
2104
+ ] });
2105
+ }
2106
+ var ToggleGhost = CheckboxGhost;
2107
+ function ChipGhost({ className, width = 74, ...props }) {
2108
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
2109
+ }
2110
+ function LinkGhost({ className, width = 96, ...props }) {
2111
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
2112
+ }
2113
+ var TextButtonGhost = LinkGhost;
2114
+ function DropdownGhost({ className, ...props }) {
2115
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropdown", className), ...props, children: [
2116
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "38%" }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-dropdown__chevron" })
2118
+ ] });
2119
+ }
2120
+ function ContentSwitcherGhost({ className, options = 3, ...props }) {
2121
+ 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)) });
2122
+ }
2123
+ var TabsGhost = ContentSwitcherGhost;
2124
+ function DisclosureGhost({ className, ...props }) {
2125
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
2126
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-disclosure__icon" }),
2127
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" })
2128
+ ] });
2129
+ }
2130
+ function PaginationGhost({ className, pages = 5, ...props }) {
2131
+ 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)) });
2132
+ }
2133
+ function FileDropzoneGhost({ className, ...props }) {
2134
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
2135
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-dropzone__icon" }),
2136
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "26%" }),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { size: "sm", width: "46%" })
2138
+ ] });
2139
+ }
2140
+ function PromptCardGhost({ className, ...props }) {
2141
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
2142
+ }
2143
+ function ConversationGhost({
2144
+ className,
2145
+ "aria-label": ariaLabel = "Loading conversation",
2146
+ ...props
2147
+ }) {
2148
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2149
+ "div",
2150
+ {
2151
+ "aria-busy": "true",
2152
+ "aria-label": ariaLabel,
2153
+ className: cn("fractal-ghost-conversation", className),
2154
+ role: "status",
2155
+ ...props,
2156
+ children: [
2157
+ /* @__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: [
2158
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "100%" }),
2159
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "86%" }),
2160
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "64%" })
2161
+ ] }) }),
2162
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--assistant", children: [
2163
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "92%" }),
2164
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "78%" }),
2165
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "58%" })
2166
+ ] })
2167
+ ]
2168
+ }
2169
+ );
2170
+ }
2171
+ function SortableTableGhost(props) {
2172
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DataTableGhost, { ...props });
2173
+ }
2174
+ function SidebarGhost({ className, items = 6, ...props }) {
2175
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
2176
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-sidebar__brand" }),
2177
+ /* @__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: [
2178
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, {}),
2179
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
2180
+ ] }, index)) })
2181
+ ] });
2182
+ }
2183
+ function ModalGhost({ className, title, lines = 3, ...props }) {
2184
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
2185
+ }
2186
+ function SidePanelGhost({ className, title, lines = 5, ...props }) {
2187
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
2188
+ }
2189
+ function SurfaceGhost({ className, title, lines = 3, ...props }) {
2190
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
2191
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fractal-ghost-surface__header", children: [
2192
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GhostLine, { width: "42%" }),
2193
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Ghost, { className: "fractal-ghost-surface__close" })
2194
+ ] }),
2195
+ title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "fractal-ghost-surface__title", children: title }),
2196
+ /* @__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)) })
2197
+ ] });
2198
+ }
2199
+
1058
2200
  // src/components/Sidebar/Sidebar.tsx
1059
- var React10 = __toESM(require("react"), 1);
1060
- var import_jsx_runtime16 = require("react/jsx-runtime");
1061
- var Sidebar = React10.forwardRef(
1062
- ({ className, width, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2201
+ var React15 = __toESM(require("react"), 1);
2202
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2203
+ var Sidebar = React15.forwardRef(
2204
+ ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1063
2205
  "aside",
1064
2206
  {
1065
2207
  ref,
1066
2208
  className: cn("fractal-sidebar", className),
2209
+ "data-compact": compact || void 0,
1067
2210
  style: { ...style, ...width ? { "--fractal-sidebar-width": width } : {} },
1068
2211
  ...props
1069
2212
  }
1070
2213
  )
1071
2214
  );
1072
2215
  Sidebar.displayName = "Sidebar";
1073
- var SidebarHeader = React10.forwardRef(
1074
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
2216
+ var SidebarHeader = React15.forwardRef(
2217
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1075
2218
  );
1076
2219
  SidebarHeader.displayName = "SidebarHeader";
1077
- var SidebarBrand = React10.forwardRef(
1078
- ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
2220
+ var SidebarBrand = React15.forwardRef(
2221
+ ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1079
2222
  );
1080
2223
  SidebarBrand.displayName = "SidebarBrand";
1081
- var SidebarNav = React10.forwardRef(
1082
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
2224
+ function SidebarAccountMenu({
2225
+ name,
2226
+ items,
2227
+ onSelect,
2228
+ triggerLabel = "Account menu",
2229
+ icon,
2230
+ className
2231
+ }) {
2232
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2233
+ Dropdown,
2234
+ {
2235
+ align: "left",
2236
+ className: cn("fractal-sidebar__account", className),
2237
+ items,
2238
+ onSelect,
2239
+ panelClassName: "fractal-sidebar__account-panel",
2240
+ selectedValue: "",
2241
+ triggerClassName: "fractal-sidebar__account-trigger",
2242
+ triggerContent: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
2243
+ icon && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
2244
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__account-name", children: name })
2245
+ ] }),
2246
+ triggerLabel,
2247
+ triggerVariant: "tertiary"
2248
+ }
2249
+ );
2250
+ }
2251
+ var SidebarNav = React15.forwardRef(
2252
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1083
2253
  );
1084
2254
  SidebarNav.displayName = "SidebarNav";
1085
- var SidebarSection = React10.forwardRef(
1086
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
2255
+ var SidebarSection = React15.forwardRef(
2256
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1087
2257
  );
1088
2258
  SidebarSection.displayName = "SidebarSection";
1089
- var SidebarNavItem = React10.forwardRef(
1090
- ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2259
+ var SidebarNavItem = React15.forwardRef(
2260
+ ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1091
2261
  "button",
1092
2262
  {
1093
2263
  ref,
@@ -1097,28 +2267,28 @@ var SidebarNavItem = React10.forwardRef(
1097
2267
  "aria-current": active ? "page" : void 0,
1098
2268
  ...props,
1099
2269
  children: [
1100
- icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1101
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1102
- endAdornment && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
2270
+ icon && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
2271
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
2272
+ endAdornment && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1103
2273
  ]
1104
2274
  }
1105
2275
  )
1106
2276
  );
1107
2277
  SidebarNavItem.displayName = "SidebarNavItem";
1108
- var SidebarFooter = React10.forwardRef(
1109
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
2278
+ var SidebarFooter = React15.forwardRef(
2279
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1110
2280
  );
1111
2281
  SidebarFooter.displayName = "SidebarFooter";
1112
2282
 
1113
2283
  // src/components/SidePanel/SidePanel.tsx
1114
2284
  var import_react_dom2 = require("react-dom");
1115
- var import_fractal_icons5 = require("@mirror-physics/fractal-icons");
1116
- var import_jsx_runtime17 = require("react/jsx-runtime");
1117
- function SidePanel({ open, onClose, title, description, children, footer, size = "md", className }) {
2285
+ var import_fractal_icons12 = require("@mirror-physics/fractal-icons");
2286
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2287
+ function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
1118
2288
  useEscapeDismiss(80, onClose, open);
1119
2289
  if (!open) return null;
1120
2290
  return (0, import_react_dom2.createPortal)(
1121
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2291
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1122
2292
  "aside",
1123
2293
  {
1124
2294
  className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
@@ -1127,15 +2297,15 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
1127
2297
  role: "dialog",
1128
2298
  onMouseDown: (event) => event.stopPropagation(),
1129
2299
  children: [
1130
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("header", { className: "fractal-side-panel__header", children: [
1131
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "fractal-side-panel__heading", children: [
1132
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { className: "fractal-side-panel__title", children: title }),
1133
- description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "fractal-side-panel__description", children: description })
2300
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("header", { className: "fractal-side-panel__header", children: [
2301
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "fractal-side-panel__heading", children: [
2302
+ 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 }),
2303
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "fractal-side-panel__description", children: description })
1134
2304
  ] }),
1135
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_fractal_icons5.Close, { size: 18 }) })
2305
+ /* @__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 }) })
1136
2306
  ] }),
1137
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-side-panel__body", children }),
1138
- footer && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
2307
+ /* @__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 }),
2308
+ footer && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
1139
2309
  ]
1140
2310
  }
1141
2311
  ) }),
@@ -1144,48 +2314,273 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
1144
2314
  }
1145
2315
 
1146
2316
  // src/components/Textarea/Textarea.tsx
1147
- var React11 = __toESM(require("react"), 1);
1148
- var import_jsx_runtime18 = require("react/jsx-runtime");
1149
- var Textarea = React11.forwardRef(
1150
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
2317
+ var React16 = __toESM(require("react"), 1);
2318
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2319
+ var Textarea = React16.forwardRef(
2320
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
1151
2321
  );
1152
2322
  Textarea.displayName = "Textarea";
2323
+
2324
+ // src/components/TextButton/TextButton.tsx
2325
+ var React17 = __toESM(require("react"), 1);
2326
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2327
+ var TextButton = React17.forwardRef(
2328
+ ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2329
+ "button",
2330
+ {
2331
+ ref,
2332
+ className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
2333
+ type: "button",
2334
+ ...props,
2335
+ children: [
2336
+ icon && iconPosition === "start" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
2337
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children }),
2338
+ icon && iconPosition === "end" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
2339
+ ]
2340
+ }
2341
+ )
2342
+ );
2343
+ TextButton.displayName = "TextButton";
2344
+
2345
+ // src/components/FileDropzone/FileDropzone.tsx
2346
+ var React18 = __toESM(require("react"), 1);
2347
+ var import_fractal_icons13 = require("@mirror-physics/fractal-icons");
2348
+ var import_jsx_runtime30 = require("react/jsx-runtime");
2349
+ function FileDropzone({
2350
+ files,
2351
+ onFilesChange,
2352
+ accept,
2353
+ multiple = true,
2354
+ disabled = false,
2355
+ title = "Drop files here or click to browse",
2356
+ description = "Files stay attached to this record.",
2357
+ className
2358
+ }) {
2359
+ const inputId = React18.useId();
2360
+ const inputRef = React18.useRef(null);
2361
+ const [isDragging, setIsDragging] = React18.useState(false);
2362
+ const addFiles = (nextFiles) => {
2363
+ if (disabled) return;
2364
+ const additions = Array.from(nextFiles);
2365
+ if (additions.length === 0) return;
2366
+ onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
2367
+ };
2368
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: cn("fractal-file-dropzone", className), children: [
2369
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2370
+ "input",
2371
+ {
2372
+ ref: inputRef,
2373
+ id: inputId,
2374
+ className: "fractal-file-dropzone__input",
2375
+ type: "file",
2376
+ accept,
2377
+ multiple,
2378
+ disabled,
2379
+ onChange: (event) => {
2380
+ if (event.target.files) addFiles(event.target.files);
2381
+ event.target.value = "";
2382
+ }
2383
+ }
2384
+ ),
2385
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
2386
+ "button",
2387
+ {
2388
+ className: "fractal-file-dropzone__target",
2389
+ "data-dragging": isDragging || void 0,
2390
+ type: "button",
2391
+ disabled,
2392
+ onClick: () => inputRef.current?.click(),
2393
+ onDragEnter: (event) => {
2394
+ event.preventDefault();
2395
+ if (!disabled) setIsDragging(true);
2396
+ },
2397
+ onDragOver: (event) => event.preventDefault(),
2398
+ onDragLeave: (event) => {
2399
+ event.preventDefault();
2400
+ setIsDragging(false);
2401
+ },
2402
+ onDrop: (event) => {
2403
+ event.preventDefault();
2404
+ setIsDragging(false);
2405
+ addFiles(event.dataTransfer.files);
2406
+ },
2407
+ children: [
2408
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_fractal_icons13.FileArrowUp, { "aria-hidden": "true", size: 20 }),
2409
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "fractal-file-dropzone__copy", children: [
2410
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__title", children: title }),
2411
+ description && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__description", children: description })
2412
+ ] })
2413
+ ]
2414
+ }
2415
+ ),
2416
+ 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: [
2417
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
2418
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
2419
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2420
+ "button",
2421
+ {
2422
+ className: "fractal-file-dropzone__remove",
2423
+ type: "button",
2424
+ "aria-label": `Remove ${file.name}`,
2425
+ disabled,
2426
+ onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
2427
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_fractal_icons13.Close, { "aria-hidden": "true", size: 14 })
2428
+ }
2429
+ )
2430
+ ] }, `${file.name}-${file.size}-${index}`)) })
2431
+ ] });
2432
+ }
2433
+ function formatFileSize(bytes) {
2434
+ if (bytes < 1024) return `${bytes} B`;
2435
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
2436
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2437
+ }
2438
+
2439
+ // src/components/Pagination/Pagination.tsx
2440
+ var import_fractal_icons14 = require("@mirror-physics/fractal-icons");
2441
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2442
+ function Pagination({
2443
+ page,
2444
+ pageSize,
2445
+ totalItems,
2446
+ onPageChange,
2447
+ pageSizeOptions,
2448
+ onPageSizeChange,
2449
+ ariaLabel = "Pagination",
2450
+ className
2451
+ }) {
2452
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
2453
+ const currentPage = Math.min(Math.max(page, 1), totalPages);
2454
+ const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
2455
+ const end = Math.min(currentPage * pageSize, totalItems);
2456
+ const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
2457
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
2458
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
2459
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "fractal-pagination__controls", children: [
2460
+ canChangePageSize && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2461
+ Dropdown,
2462
+ {
2463
+ align: "right",
2464
+ className: "fractal-pagination__page-size",
2465
+ direction: "up",
2466
+ items: pageSizeOptions.map((option) => ({
2467
+ value: String(option),
2468
+ description: `${option} per page`
2469
+ })),
2470
+ onSelect: (value) => onPageSizeChange(Number(value)),
2471
+ selectedValue: String(pageSize),
2472
+ size: "sm",
2473
+ triggerLabel: "Results per page",
2474
+ triggerVariant: "tertiary"
2475
+ }
2476
+ ),
2477
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2478
+ "button",
2479
+ {
2480
+ className: "fractal-pagination__button",
2481
+ type: "button",
2482
+ "aria-label": "Previous page",
2483
+ title: "Previous page",
2484
+ disabled: currentPage === 1 || totalItems === 0,
2485
+ onClick: () => onPageChange(currentPage - 1),
2486
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fractal_icons14.ArrowLeft, { "aria-hidden": "true", size: 16 })
2487
+ }
2488
+ ),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
2490
+ currentPage,
2491
+ " of ",
2492
+ totalPages
2493
+ ] }),
2494
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2495
+ "button",
2496
+ {
2497
+ className: "fractal-pagination__button",
2498
+ type: "button",
2499
+ "aria-label": "Next page",
2500
+ title: "Next page",
2501
+ disabled: currentPage === totalPages || totalItems === 0,
2502
+ onClick: () => onPageChange(currentPage + 1),
2503
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fractal_icons14.ArrowRight, { "aria-hidden": "true", size: 16 })
2504
+ }
2505
+ )
2506
+ ] })
2507
+ ] });
2508
+ }
1153
2509
  // Annotate the CommonJS export names for ESM import in node:
1154
2510
  0 && (module.exports = {
1155
2511
  Alert,
1156
2512
  AlertDescription,
2513
+ AlertGhost,
1157
2514
  AlertTitle,
2515
+ Breadcrumbs,
1158
2516
  Button,
2517
+ ButtonGhost,
1159
2518
  Card,
1160
2519
  CardContent,
1161
2520
  CardDescription,
1162
2521
  CardFooter,
2522
+ CardGhost,
1163
2523
  CardHeader,
1164
2524
  CardTitle,
2525
+ Checkbox,
2526
+ CheckboxGhost,
1165
2527
  Chip,
2528
+ ChipGhost,
2529
+ CodeBlock,
2530
+ ContentSwitcher,
2531
+ ContentSwitcherGhost,
2532
+ ConversationGhost,
1166
2533
  DataTable,
2534
+ DataTableGhost,
1167
2535
  Disclosure,
2536
+ DisclosureGhost,
1168
2537
  Dropdown,
2538
+ DropdownGhost,
1169
2539
  FeatureCard,
2540
+ FileDropzone,
2541
+ FileDropzoneGhost,
1170
2542
  FolderCard,
2543
+ Ghost,
2544
+ GhostLine,
1171
2545
  Input,
2546
+ InputGhost,
1172
2547
  Label,
2548
+ LabelGhost,
2549
+ LatticeLoader,
1173
2550
  Link,
2551
+ LinkGhost,
1174
2552
  Modal,
2553
+ ModalGhost,
2554
+ NumberInput,
2555
+ Pagination,
2556
+ PaginationGhost,
2557
+ PasswordInput,
1175
2558
  PromptCard,
2559
+ PromptCardGhost,
1176
2560
  PromptGrid,
1177
2561
  SidePanel,
2562
+ SidePanelGhost,
1178
2563
  Sidebar,
2564
+ SidebarAccountMenu,
1179
2565
  SidebarBrand,
1180
2566
  SidebarFooter,
2567
+ SidebarGhost,
1181
2568
  SidebarHeader,
1182
2569
  SidebarNav,
1183
2570
  SidebarNavItem,
1184
2571
  SidebarSection,
1185
2572
  SortableTable,
2573
+ SortableTableGhost,
2574
+ TableSearch,
1186
2575
  Tabs,
2576
+ TabsGhost,
2577
+ TextButton,
2578
+ TextButtonGhost,
1187
2579
  Textarea,
2580
+ TextareaGhost,
1188
2581
  Toggle,
2582
+ ToggleGhost,
2583
+ UILoader,
1189
2584
  cn,
1190
2585
  useEscapeDismiss
1191
2586
  });