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

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