@mirror-physics/fractal-ui 0.2.0-next.5 → 0.2.0-next.51

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