@mirror-physics/fractal-ui 0.2.0-next.4 → 0.2.0-next.41

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,37 +32,73 @@ 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
+ ContentSwitcher: () => ContentSwitcher,
52
+ ContentSwitcherGhost: () => ContentSwitcherGhost,
44
53
  DataTable: () => DataTable,
54
+ DataTableGhost: () => DataTableGhost,
45
55
  Disclosure: () => Disclosure,
56
+ DisclosureGhost: () => DisclosureGhost,
46
57
  Dropdown: () => Dropdown,
58
+ DropdownGhost: () => DropdownGhost,
47
59
  FeatureCard: () => FeatureCard,
60
+ FileDropzone: () => FileDropzone,
61
+ FileDropzoneGhost: () => FileDropzoneGhost,
48
62
  FolderCard: () => FolderCard,
63
+ Ghost: () => Ghost,
64
+ GhostLine: () => GhostLine,
49
65
  Input: () => Input,
66
+ InputGhost: () => InputGhost,
50
67
  Label: () => Label,
68
+ LabelGhost: () => LabelGhost,
69
+ LatticeLoader: () => LatticeLoader,
51
70
  Link: () => Link,
71
+ LinkGhost: () => LinkGhost,
52
72
  Modal: () => Modal,
53
- PageHeader: () => PageHeader,
73
+ ModalGhost: () => ModalGhost,
74
+ NumberInput: () => NumberInput,
75
+ Pagination: () => Pagination,
76
+ PaginationGhost: () => PaginationGhost,
54
77
  PromptCard: () => PromptCard,
78
+ PromptCardGhost: () => PromptCardGhost,
55
79
  PromptGrid: () => PromptGrid,
80
+ SidePanel: () => SidePanel,
81
+ SidePanelGhost: () => SidePanelGhost,
56
82
  Sidebar: () => Sidebar,
83
+ SidebarAccountMenu: () => SidebarAccountMenu,
57
84
  SidebarBrand: () => SidebarBrand,
58
85
  SidebarFooter: () => SidebarFooter,
86
+ SidebarGhost: () => SidebarGhost,
59
87
  SidebarHeader: () => SidebarHeader,
60
88
  SidebarNav: () => SidebarNav,
61
89
  SidebarNavItem: () => SidebarNavItem,
62
90
  SidebarSection: () => SidebarSection,
63
91
  SortableTable: () => SortableTable,
92
+ SortableTableGhost: () => SortableTableGhost,
64
93
  Tabs: () => Tabs,
94
+ TabsGhost: () => TabsGhost,
95
+ TextButton: () => TextButton,
96
+ TextButtonGhost: () => TextButtonGhost,
97
+ Textarea: () => Textarea,
98
+ TextareaGhost: () => TextareaGhost,
65
99
  Toggle: () => Toggle,
100
+ ToggleGhost: () => ToggleGhost,
101
+ UILoader: () => UILoader,
66
102
  cn: () => cn,
67
103
  useEscapeDismiss: () => useEscapeDismiss
68
104
  });
@@ -120,7 +156,7 @@ var colorPalette = {
120
156
  var sizeConfig = {
121
157
  xs: { height: "28px", padding: "4px 8px", iconOnly: "28px", fontSize: "0.75rem" },
122
158
  sm: { height: "32px", padding: "6px 12px", iconOnly: "32px", fontSize: "0.75rem" },
123
- md: { height: "38px", padding: "8px 16px", iconOnly: "38px", fontSize: "0.875rem" },
159
+ md: { height: "40px", padding: "8px 16px", iconOnly: "40px", fontSize: "0.875rem" },
124
160
  lg: { height: "44px", padding: "10px 20px", iconOnly: "44px", fontSize: "1rem" },
125
161
  xl: { height: "56px", padding: "14px 28px", iconOnly: "56px", fontSize: "1rem" }
126
162
  };
@@ -235,44 +271,65 @@ var Button = React.forwardRef(
235
271
  );
236
272
  Button.displayName = "Button";
237
273
 
238
- // src/components/Card/Card.tsx
239
- var React2 = __toESM(require("react"), 1);
274
+ // src/components/Breadcrumbs/Breadcrumbs.tsx
240
275
  var import_fractal_icons = require("@mirror-physics/fractal-icons");
241
276
  var import_jsx_runtime2 = require("react/jsx-runtime");
277
+ function Breadcrumbs({
278
+ items,
279
+ ariaLabel = "Breadcrumbs",
280
+ separator = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fractal_icons.ChevronRight, { "aria-hidden": "true", size: 14 }),
281
+ className,
282
+ ...props
283
+ }) {
284
+ if (items.length === 0) return null;
285
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("nav", { "aria-label": ariaLabel, className: cn("fractal-breadcrumbs", className), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ol", { className: "fractal-breadcrumbs__list", children: items.map((item, index) => {
286
+ const isCurrent = index === items.length - 1;
287
+ const content = isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-current": "page", className: "fractal-breadcrumbs__current", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { className: "fractal-breadcrumbs__link", href: item.href ?? "#", onClick: item.onClick, children: item.label });
288
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "fractal-breadcrumbs__item", children: [
289
+ index > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", className: "fractal-breadcrumbs__separator", children: separator }),
290
+ content
291
+ ] }, index);
292
+ }) }) });
293
+ }
294
+
295
+ // src/components/Card/Card.tsx
296
+ var React2 = __toESM(require("react"), 1);
297
+ var import_fractal_icons2 = require("@mirror-physics/fractal-icons");
298
+ var import_jsx_runtime3 = require("react/jsx-runtime");
242
299
  var Card = React2.forwardRef(
243
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card", className), ...props })
300
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref, className: cn("fractal-card", className), ...props })
244
301
  );
245
302
  Card.displayName = "Card";
246
303
  var CardHeader = React2.forwardRef(
247
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card-header", className), ...props })
304
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref, className: cn("fractal-card-header", className), ...props })
248
305
  );
249
306
  CardHeader.displayName = "CardHeader";
250
307
  var CardTitle = React2.forwardRef(
251
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { ref, className: cn("fractal-card-title", className), ...props })
308
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { ref, className: cn("fractal-card-title", className), ...props })
252
309
  );
253
310
  CardTitle.displayName = "CardTitle";
254
311
  var CardDescription = React2.forwardRef(
255
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { ref, className: cn("fractal-card-description", className), ...props })
312
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { ref, className: cn("fractal-card-description", className), ...props })
256
313
  );
257
314
  CardDescription.displayName = "CardDescription";
258
315
  var CardContent = React2.forwardRef(
259
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card-content", className), ...props })
316
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref, className: cn("fractal-card-content", className), ...props })
260
317
  );
261
318
  CardContent.displayName = "CardContent";
262
319
  var CardFooter = React2.forwardRef(
263
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("fractal-card-footer", className), ...props })
320
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref, className: cn("fractal-card-footer", className), ...props })
264
321
  );
265
322
  CardFooter.displayName = "CardFooter";
266
323
  var FeatureCard = React2.forwardRef(
267
- ({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
268
- icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fractal-feature-card__icon", children: icon }),
269
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "fractal-feature-card__title", children: title }),
270
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "fractal-feature-card__description", children: description })
324
+ ({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
325
+ icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fractal-feature-card__icon", children: icon }),
326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "fractal-feature-card__title", children: title }),
327
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "fractal-feature-card__description", children: description })
271
328
  ] })
272
329
  );
273
330
  FeatureCard.displayName = "FeatureCard";
274
331
  var FolderCard = React2.forwardRef(
275
- ({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
332
+ ({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
276
333
  "div",
277
334
  {
278
335
  ref,
@@ -288,11 +345,11 @@ var FolderCard = React2.forwardRef(
288
345
  className: cn("fractal-folder-card", selected && "fractal-folder-card--selected", className),
289
346
  ...props,
290
347
  children: [
291
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fractal-folder-card__header", children: [
292
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fractal_icons.Folder, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
293
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fractal-folder-card__name", children: name })
348
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "fractal-folder-card__header", children: [
349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_fractal_icons2.Folder, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
350
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fractal-folder-card__name", children: name })
294
351
  ] }),
295
- 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: [
352
+ sessionCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fractal-folder-card__footer", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "fractal-folder-card__sessions", children: [
296
353
  sessionCount,
297
354
  " ",
298
355
  sessionCount === 1 ? "session" : "sessions"
@@ -305,7 +362,7 @@ FolderCard.displayName = "FolderCard";
305
362
 
306
363
  // src/components/PromptCard/PromptCard.tsx
307
364
  var React3 = __toESM(require("react"), 1);
308
- var import_jsx_runtime3 = require("react/jsx-runtime");
365
+ var import_jsx_runtime4 = require("react/jsx-runtime");
309
366
  var titleToPrompt = (title) => typeof title === "string" || typeof title === "number" ? String(title) : "";
310
367
  var PromptCard = React3.forwardRef(
311
368
  ({
@@ -326,7 +383,7 @@ var PromptCard = React3.forwardRef(
326
383
  onPromptSelect?.(prompt ?? titleToPrompt(title));
327
384
  }
328
385
  };
329
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
386
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
330
387
  "button",
331
388
  {
332
389
  ref,
@@ -341,8 +398,8 @@ var PromptCard = React3.forwardRef(
341
398
  onClick: handleClick,
342
399
  ...props,
343
400
  children: [
344
- icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fractal-prompt-card__icon", "aria-hidden": "true", children: icon }),
345
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fractal-prompt-card__title", children: title })
401
+ icon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "fractal-prompt-card__icon", "aria-hidden": "true", children: icon }),
402
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "fractal-prompt-card__title", children: title })
346
403
  ]
347
404
  }
348
405
  );
@@ -350,7 +407,7 @@ var PromptCard = React3.forwardRef(
350
407
  );
351
408
  PromptCard.displayName = "PromptCard";
352
409
  var PromptGrid = React3.forwardRef(
353
- ({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
410
+ ({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
354
411
  "div",
355
412
  {
356
413
  ref,
@@ -368,9 +425,9 @@ PromptGrid.displayName = "PromptGrid";
368
425
 
369
426
  // src/components/Input/Input.tsx
370
427
  var React4 = __toESM(require("react"), 1);
371
- var import_jsx_runtime4 = require("react/jsx-runtime");
428
+ var import_jsx_runtime5 = require("react/jsx-runtime");
372
429
  var Input = React4.forwardRef(
373
- ({ className, type, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
430
+ ({ className, type, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
374
431
  "input",
375
432
  {
376
433
  type,
@@ -382,11 +439,91 @@ var Input = React4.forwardRef(
382
439
  );
383
440
  Input.displayName = "Input";
384
441
 
385
- // src/components/Label/Label.tsx
442
+ // src/components/NumberInput/NumberInput.tsx
386
443
  var React5 = __toESM(require("react"), 1);
387
- var import_jsx_runtime5 = require("react/jsx-runtime");
388
- var Label = React5.forwardRef(
389
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
444
+ var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
445
+ var import_jsx_runtime6 = require("react/jsx-runtime");
446
+ function NumberInput({
447
+ unit,
448
+ className,
449
+ value,
450
+ defaultValue,
451
+ disabled,
452
+ readOnly,
453
+ min,
454
+ max,
455
+ ...props
456
+ }) {
457
+ const inputRef = React5.useRef(null);
458
+ const numericValue = Number(value ?? defaultValue);
459
+ const characterCount = Math.max(String(value ?? defaultValue ?? "").length, 1);
460
+ const controlLabel = typeof props["aria-label"] === "string" ? props["aria-label"] : "value";
461
+ const decrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && min !== void 0 && numericValue <= Number(min);
462
+ const incrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && max !== void 0 && numericValue >= Number(max);
463
+ const changeByStep = (direction) => {
464
+ const input = inputRef.current;
465
+ if (!input) return;
466
+ if (direction === -1) input.stepDown();
467
+ else input.stepUp();
468
+ input.dispatchEvent(new Event("input", { bubbles: true }));
469
+ input.focus();
470
+ };
471
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
472
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
473
+ Input,
474
+ {
475
+ ref: inputRef,
476
+ type: "number",
477
+ value,
478
+ defaultValue,
479
+ disabled,
480
+ readOnly,
481
+ min,
482
+ max,
483
+ ...props
484
+ }
485
+ ),
486
+ unit && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
487
+ "span",
488
+ {
489
+ className: "fractal-number-input-unit",
490
+ style: { left: `calc(var(--space-3, 12px) + ${characterCount}ch)` },
491
+ "aria-hidden": "true",
492
+ children: unit
493
+ }
494
+ ),
495
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "fractal-number-input-controls", children: [
496
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
497
+ "button",
498
+ {
499
+ type: "button",
500
+ className: "fractal-number-input-step",
501
+ "aria-label": `Decrease ${controlLabel}`,
502
+ disabled: decrementDisabled,
503
+ onClick: () => changeByStep(-1),
504
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_fractal_icons3.Minus, { "aria-hidden": "true", size: 16 })
505
+ }
506
+ ),
507
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
508
+ "button",
509
+ {
510
+ type: "button",
511
+ className: "fractal-number-input-step",
512
+ "aria-label": `Increase ${controlLabel}`,
513
+ disabled: incrementDisabled,
514
+ onClick: () => changeByStep(1),
515
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_fractal_icons3.Plus, { "aria-hidden": "true", size: 16 })
516
+ }
517
+ )
518
+ ] })
519
+ ] });
520
+ }
521
+
522
+ // src/components/Label/Label.tsx
523
+ var React6 = __toESM(require("react"), 1);
524
+ var import_jsx_runtime7 = require("react/jsx-runtime");
525
+ var Label = React6.forwardRef(
526
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
390
527
  "label",
391
528
  {
392
529
  ref,
@@ -398,44 +535,48 @@ var Label = React5.forwardRef(
398
535
  Label.displayName = "Label";
399
536
 
400
537
  // src/components/Alert/Alert.tsx
401
- var React6 = __toESM(require("react"), 1);
402
- var import_jsx_runtime6 = require("react/jsx-runtime");
538
+ var React7 = __toESM(require("react"), 1);
539
+ var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
540
+ var import_jsx_runtime8 = require("react/jsx-runtime");
403
541
  var defaultIcons = {
404
- default: "\u2139",
405
- info: "\u2139",
406
- success: "\u2713",
407
- warning: "\u26A0",
408
- error: "\u2715"
542
+ default: import_fractal_icons4.CircleInfo,
543
+ info: import_fractal_icons4.CircleInfo,
544
+ success: import_fractal_icons4.CircleCheck,
545
+ warning: import_fractal_icons4.Warning,
546
+ error: import_fractal_icons4.CircleClose
409
547
  };
410
- var Alert = React6.forwardRef(
411
- ({ className, variant = "default", icon, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
412
- "div",
413
- {
414
- ref,
415
- role: "alert",
416
- className: cn("fractal-alert", `fractal-alert--${variant}`, className),
417
- ...props,
418
- children: [
419
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? defaultIcons[variant] }),
420
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fractal-alert-content", children })
421
- ]
422
- }
423
- )
548
+ var Alert = React7.forwardRef(
549
+ ({ className, variant = "default", icon, children, ...props }, ref) => {
550
+ const DefaultIcon = defaultIcons[variant];
551
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
552
+ "div",
553
+ {
554
+ ref,
555
+ role: "alert",
556
+ className: cn("fractal-alert", `fractal-alert--${variant}`, className),
557
+ ...props,
558
+ children: [
559
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DefaultIcon, { size: 18 }) }),
560
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-alert-content", children })
561
+ ]
562
+ }
563
+ );
564
+ }
424
565
  );
425
566
  Alert.displayName = "Alert";
426
- var AlertTitle = React6.forwardRef(
427
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h5", { ref, className: cn("fractal-alert-title", className), ...props })
567
+ var AlertTitle = React7.forwardRef(
568
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h5", { ref, className: cn("fractal-alert-title", className), ...props })
428
569
  );
429
570
  AlertTitle.displayName = "AlertTitle";
430
- var AlertDescription = React6.forwardRef(
431
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref, className: cn("fractal-alert-description", className), ...props })
571
+ var AlertDescription = React7.forwardRef(
572
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ref, className: cn("fractal-alert-description", className), ...props })
432
573
  );
433
574
  AlertDescription.displayName = "AlertDescription";
434
575
 
435
576
  // src/components/Toggle/Toggle.tsx
436
- var import_jsx_runtime7 = require("react/jsx-runtime");
577
+ var import_jsx_runtime9 = require("react/jsx-runtime");
437
578
  function Toggle({ checked, onChange, label, className }) {
438
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
579
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
439
580
  "button",
440
581
  {
441
582
  type: "button",
@@ -444,8 +585,8 @@ function Toggle({ checked, onChange, label, className }) {
444
585
  className: cn("fractal-toggle", className),
445
586
  onClick: () => onChange(!checked),
446
587
  children: [
447
- /* @__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") }) }),
448
- label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fractal-toggle-label", children: label })
588
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: cn("fractal-toggle-track", checked && "fractal-toggle-track--checked"), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: cn("fractal-toggle-thumb", checked && "fractal-toggle-thumb--checked") }) }),
589
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "fractal-toggle-label", children: label })
449
590
  ]
450
591
  }
451
592
  );
@@ -504,27 +645,84 @@ function useEscapeDismiss(priority, handler, enabled = true) {
504
645
  }, [priority, enabled]);
505
646
  }
506
647
 
648
+ // src/components/UILoader/UILoader.tsx
649
+ var import_react2 = require("react");
650
+ var import_jsx_runtime10 = require("react/jsx-runtime");
651
+ 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";
652
+ 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";
653
+ 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";
654
+ function UILoader({ size = 48, tone = "neutral", className, style, label = "Loading", ariaHidden = false }) {
655
+ const rawId = (0, import_react2.useId)().replace(/[^a-zA-Z0-9_-]/g, "");
656
+ const clipId = `fractal-ui-loader-clip-${rawId}`;
657
+ const gradientId = `fractal-ui-loader-gradient-${rawId}`;
658
+ const height = typeof size === "number" ? `${size}px` : size;
659
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
660
+ "span",
661
+ {
662
+ "aria-hidden": ariaHidden || void 0,
663
+ "aria-label": ariaHidden ? void 0 : label,
664
+ className: cn("fractal-ui-loader", `fractal-ui-loader--${tone}`, className),
665
+ role: ariaHidden ? void 0 : "status",
666
+ style,
667
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
668
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("defs", { children: [
669
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
670
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("stop", { className: "fractal-ui-loader__stop-start", offset: "0" }),
671
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("stop", { className: "fractal-ui-loader__stop-end", offset: "1" })
672
+ ] }),
673
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
674
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("stop", { offset: "0.4", stopColor: "white", stopOpacity: "0" }),
675
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("stop", { offset: "0.5", stopColor: "white", stopOpacity: "0.62" }),
676
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("stop", { offset: "0.6", stopColor: "white", stopOpacity: "0" })
677
+ ] }),
678
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("clipPath", { id: clipId, children: [
679
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: LEFT }),
680
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: CENTER }),
681
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: RIGHT })
682
+ ] })
683
+ ] }),
684
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: CENTER, fill: `url(#${gradientId})` }),
685
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: RIGHT, fill: `url(#${gradientId})` }),
686
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: LEFT, fill: `url(#${gradientId})` }),
687
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("g", { clipPath: `url(#${clipId})`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("g", { className: "fractal-ui-loader__shine-axis", transform: "translate(72 46) rotate(68.4)", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { className: "fractal-ui-loader__shine", x: "-160", y: "-100", width: "320", height: "200", fill: `url(#${gradientId}-shine)` }) }) })
688
+ ] })
689
+ }
690
+ );
691
+ }
692
+
507
693
  // src/components/Modal/Modal.tsx
508
- var import_jsx_runtime8 = require("react/jsx-runtime");
509
- 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" }) });
510
- function Modal({ open, onClose, title, children, danger, warn, footer, noClose, size = "sm", className }) {
511
- useEscapeDismiss(80, onClose, open && !noClose);
694
+ var import_jsx_runtime11 = require("react/jsx-runtime");
695
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime11.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_runtime11.jsx)("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
696
+ function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
697
+ useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
512
698
  if (!open) return null;
513
699
  const sizeClass = `fractal-modal-panel--${size}`;
514
700
  const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
515
701
  return (0, import_react_dom.createPortal)(
516
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
702
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
517
703
  "div",
518
704
  {
519
- className: cn("fractal-modal-panel", sizeClass, accentClass, className),
705
+ className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
520
706
  onClick: (e) => e.stopPropagation(),
521
707
  children: [
522
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "fractal-modal-title-row", children: [
523
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
524
- !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, {}) })
708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "fractal-modal-title-row", children: [
709
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
710
+ !noClose && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CloseIcon, {}) })
525
711
  ] }),
526
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("fractal-modal-body", size === "lg" && "fractal-modal-body--lg"), children }),
527
- footer && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fractal-modal-footer", children: footer })
712
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
713
+ "div",
714
+ {
715
+ "aria-busy": loading || void 0,
716
+ className: cn(
717
+ "fractal-modal-body",
718
+ size === "lg" && "fractal-modal-body--lg",
719
+ loading && "fractal-modal-body--loading",
720
+ scrollable && "fractal-modal-body--scrollable"
721
+ ),
722
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UILoader, { label: loadingLabel }) : children
723
+ }
724
+ ),
725
+ footer && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("fractal-modal-footer", scrollable && "fractal-modal-footer--divided"), children: footer })
528
726
  ]
529
727
  }
530
728
  ) }),
@@ -533,17 +731,17 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
533
731
  }
534
732
 
535
733
  // src/components/DataTable/DataTable.tsx
536
- var import_jsx_runtime9 = require("react/jsx-runtime");
734
+ var import_jsx_runtime12 = require("react/jsx-runtime");
537
735
  function DataTable({ columns, data, emptyMessage, header, size = "md", className }) {
538
- 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: [
539
- header && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fractal-datatable-header", children: header }),
540
- 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: [
541
- /* @__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)) }) }),
542
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
736
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn("fractal-datatable", `fractal-datatable--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fractal-datatable-surface", children: [
737
+ header && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fractal-datatable-header", children: header }),
738
+ data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { className: "fractal-datatable-table", children: [
739
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tr", { className: "fractal-datatable-thead-row", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "fractal-datatable-th", style: { width: col.width }, children: col.header }, col.key)) }) }),
740
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
543
741
  "tr",
544
742
  {
545
743
  className: "fractal-datatable-row",
546
- 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))
744
+ children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "fractal-datatable-td", style: { width: col.width }, children: col.render(row, rowIndex) }, col.key))
547
745
  },
548
746
  rowIndex
549
747
  )) })
@@ -552,9 +750,9 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
552
750
  }
553
751
 
554
752
  // src/components/Dropdown/Dropdown.tsx
555
- var React7 = __toESM(require("react"), 1);
556
- var import_fractal_icons2 = require("@mirror-physics/fractal-icons");
557
- var import_jsx_runtime10 = require("react/jsx-runtime");
753
+ var React8 = __toESM(require("react"), 1);
754
+ var import_fractal_icons5 = require("@mirror-physics/fractal-icons");
755
+ var import_jsx_runtime13 = require("react/jsx-runtime");
558
756
  var MARGIN = 4;
559
757
  function Dropdown({
560
758
  items,
@@ -565,18 +763,20 @@ function Dropdown({
565
763
  align = "left",
566
764
  triggerContent,
567
765
  label,
766
+ iconOnly = false,
568
767
  noChevron = false,
569
768
  size = "md",
570
769
  triggerVariant = "outline",
571
770
  className,
572
771
  triggerClassName,
573
772
  panelClassName,
574
- closeOnSelect = true
773
+ closeOnSelect = true,
774
+ disabled = false
575
775
  }) {
576
- const [open, setOpen] = React7.useState(false);
577
- const triggerRef = React7.useRef(null);
578
- const panelRef = React7.useRef(null);
579
- const [panelStyle, setPanelStyle] = React7.useState({});
776
+ const [open, setOpen] = React8.useState(false);
777
+ const triggerRef = React8.useRef(null);
778
+ const panelRef = React8.useRef(null);
779
+ const [panelStyle, setPanelStyle] = React8.useState({});
580
780
  const visibleItems = items.filter(
581
781
  (item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
582
782
  );
@@ -584,8 +784,8 @@ function Dropdown({
584
784
  const selectableItems = visibleItems.filter((i) => i.kind !== "header");
585
785
  const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
586
786
  const isUp = direction === "up";
587
- const ChevronIcon = isUp ? import_fractal_icons2.ChevronUp : import_fractal_icons2.ChevronDown;
588
- React7.useLayoutEffect(() => {
787
+ const ChevronIcon = isUp ? import_fractal_icons5.ChevronUp : import_fractal_icons5.ChevronDown;
788
+ React8.useLayoutEffect(() => {
589
789
  if (!open || !triggerRef.current || !panelRef.current) return;
590
790
  const triggerRect = triggerRef.current.getBoundingClientRect();
591
791
  const panelRect = panelRef.current.getBoundingClientRect();
@@ -619,7 +819,7 @@ function Dropdown({
619
819
  }
620
820
  setPanelStyle({ top, left, right });
621
821
  }, [open, isUp, align]);
622
- React7.useEffect(() => {
822
+ React8.useEffect(() => {
623
823
  if (!open) return;
624
824
  const handleClickOutside = (e) => {
625
825
  const target = e.target;
@@ -629,12 +829,13 @@ function Dropdown({
629
829
  document.addEventListener("mousedown", handleClickOutside);
630
830
  return () => document.removeEventListener("mousedown", handleClickOutside);
631
831
  }, [open]);
632
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
633
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
832
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
833
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
634
834
  "button",
635
835
  {
636
836
  ref: triggerRef,
637
837
  type: "button",
838
+ disabled,
638
839
  "aria-haspopup": "listbox",
639
840
  "aria-expanded": open,
640
841
  "aria-label": triggerLabel,
@@ -643,18 +844,19 @@ function Dropdown({
643
844
  "fractal-dropdown-trigger",
644
845
  `fractal-dropdown-trigger--${size}`,
645
846
  `fractal-dropdown-trigger--${triggerVariant}`,
847
+ iconOnly && "fractal-dropdown-trigger--icon-only",
646
848
  triggerClassName
647
849
  ),
648
850
  children: [
649
- triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
650
- selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
651
- selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
851
+ triggerContent != null ? triggerContent : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
852
+ selected.icon != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
853
+ selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-dropdown-selected-text", children: selected.description })
652
854
  ] }),
653
- !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 }) })
855
+ !noChevron && !iconOnly && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
654
856
  ]
655
857
  }
656
858
  ),
657
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
859
+ open && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
658
860
  "div",
659
861
  {
660
862
  ref: panelRef,
@@ -663,21 +865,21 @@ function Dropdown({
663
865
  className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
664
866
  style: panelStyle,
665
867
  children: [
666
- label != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-label", children: label }),
868
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-dropdown-label", children: label }),
667
869
  visibleItems.map((item, index) => {
668
- const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
669
- const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
870
+ const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
871
+ const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
670
872
  if (item.kind === "header") {
671
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
873
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(React8.Fragment, { children: [
672
874
  topDivider,
673
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
875
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
674
876
  bottomDivider
675
877
  ] }, `header-${index}`);
676
878
  }
677
879
  const isSelected = item.value === selectedValue;
678
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React7.Fragment, { children: [
880
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(React8.Fragment, { children: [
679
881
  topDivider,
680
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
882
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
681
883
  "button",
682
884
  {
683
885
  type: "button",
@@ -689,9 +891,9 @@ function Dropdown({
689
891
  },
690
892
  className: "fractal-dropdown-option",
691
893
  children: [
692
- item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
693
- item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
694
- item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
894
+ item.icon != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-dropdown-icon", children: item.icon }),
895
+ item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-dropdown-option-text", children: item.description }),
896
+ item.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fractal-dropdown-trailing", children: item.trailing })
695
897
  ]
696
898
  }
697
899
  ),
@@ -705,10 +907,10 @@ function Dropdown({
705
907
  }
706
908
 
707
909
  // src/components/Link/Link.tsx
708
- var React8 = __toESM(require("react"), 1);
709
- var import_jsx_runtime11 = require("react/jsx-runtime");
710
- var Link = React8.forwardRef(
711
- ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
910
+ var React9 = __toESM(require("react"), 1);
911
+ var import_jsx_runtime14 = require("react/jsx-runtime");
912
+ var Link = React9.forwardRef(
913
+ ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
712
914
  "a",
713
915
  {
714
916
  ref,
@@ -720,10 +922,10 @@ var Link = React8.forwardRef(
720
922
  Link.displayName = "Link";
721
923
 
722
924
  // src/components/Chip/Chip.tsx
723
- var React9 = __toESM(require("react"), 1);
724
- var import_jsx_runtime12 = require("react/jsx-runtime");
725
- var Chip = React9.forwardRef(
726
- ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
925
+ var React10 = __toESM(require("react"), 1);
926
+ var import_jsx_runtime15 = require("react/jsx-runtime");
927
+ var Chip = React10.forwardRef(
928
+ ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
727
929
  "span",
728
930
  {
729
931
  ref,
@@ -734,35 +936,69 @@ var Chip = React9.forwardRef(
734
936
  );
735
937
  Chip.displayName = "Chip";
736
938
 
939
+ // src/components/Checkbox/Checkbox.tsx
940
+ var import_fractal_icons6 = require("@mirror-physics/fractal-icons");
941
+ var import_jsx_runtime16 = require("react/jsx-runtime");
942
+ function Checkbox({ checked, onCheckedChange, className, disabled, onClick, onKeyDown, ...props }) {
943
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
944
+ "button",
945
+ {
946
+ ...props,
947
+ className: cn("fractal-checkbox", checked && "fractal-checkbox--checked", className),
948
+ type: "button",
949
+ role: "checkbox",
950
+ "aria-checked": checked,
951
+ disabled,
952
+ onClick: (event) => {
953
+ onClick?.(event);
954
+ if (!event.defaultPrevented) onCheckedChange(!checked);
955
+ },
956
+ onKeyDown: (event) => {
957
+ onKeyDown?.(event);
958
+ if (event.key === " " || event.key === "Enter") event.stopPropagation();
959
+ },
960
+ children: checked ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_fractal_icons6.CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_fractal_icons6.Checkbox, { "aria-hidden": "true", size: 18 })
961
+ }
962
+ );
963
+ }
964
+
737
965
  // src/components/SortableTable/SortableTable.tsx
738
- var import_react2 = require("react");
739
- var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
740
- var import_jsx_runtime13 = require("react/jsx-runtime");
966
+ var import_react3 = require("react");
967
+ var import_fractal_icons7 = require("@mirror-physics/fractal-icons");
968
+ var import_jsx_runtime17 = require("react/jsx-runtime");
741
969
  function SortableTable({
742
970
  columns,
743
971
  data,
744
972
  emptyMessage,
745
973
  header,
746
974
  size = "md",
975
+ embedded = false,
747
976
  className,
977
+ defaultSort,
748
978
  defaultSortKey = void 0,
749
979
  defaultSortDirection = null,
750
980
  sortKey: controlledKey,
751
981
  sortDirection: controlledDirection,
752
982
  onSortChange,
753
- highlightRow
983
+ highlightRow,
984
+ onRowClick,
985
+ rowAction
754
986
  }) {
755
- const [internalKey, setInternalKey] = (0, import_react2.useState)(defaultSortKey ?? null);
756
- const [internalDirection, setInternalDirection] = (0, import_react2.useState)(defaultSortDirection);
987
+ const [internalKey, setInternalKey] = (0, import_react3.useState)(defaultSortKey ?? null);
988
+ const [internalDirection, setInternalDirection] = (0, import_react3.useState)(defaultSortDirection);
757
989
  const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
758
990
  const activeKey = isControlled ? controlledKey : internalKey;
759
991
  const activeDirection = isControlled ? controlledDirection : internalDirection;
760
- const sorted = (0, import_react2.useMemo)(() => {
761
- if (!activeKey || !activeDirection) return data;
762
- const col = columns.find((c) => c.key === activeKey);
992
+ const baselineKey = defaultSort?.key ?? null;
993
+ const baselineDirection = defaultSort?.direction ?? null;
994
+ const effectiveKey = activeKey && activeDirection ? activeKey : baselineKey;
995
+ const effectiveDirection = activeKey && activeDirection ? activeDirection : baselineDirection;
996
+ const sorted = (0, import_react3.useMemo)(() => {
997
+ if (!effectiveKey || !effectiveDirection) return data;
998
+ const col = columns.find((c) => c.key === effectiveKey);
763
999
  if (!col) return data;
764
1000
  const accessor = col.sortAccessor ?? ((row) => {
765
- const value = row[activeKey];
1001
+ const value = row[effectiveKey];
766
1002
  return typeof value === "string" || typeof value === "number" ? value : null;
767
1003
  });
768
1004
  const copy = [...data];
@@ -773,26 +1009,28 @@ function SortableTable({
773
1009
  if (av == null) return 1;
774
1010
  if (bv == null) return -1;
775
1011
  if (typeof av === "number" && typeof bv === "number") {
776
- return activeDirection === "asc" ? av - bv : bv - av;
1012
+ return effectiveDirection === "asc" ? av - bv : bv - av;
777
1013
  }
778
1014
  const as = String(av).toLowerCase();
779
1015
  const bs = String(bv).toLowerCase();
780
- if (as < bs) return activeDirection === "asc" ? -1 : 1;
781
- if (as > bs) return activeDirection === "asc" ? 1 : -1;
1016
+ if (as < bs) return effectiveDirection === "asc" ? -1 : 1;
1017
+ if (as > bs) return effectiveDirection === "asc" ? 1 : -1;
782
1018
  return 0;
783
1019
  });
784
1020
  return copy;
785
- }, [data, columns, activeKey, activeDirection]);
1021
+ }, [data, columns, effectiveKey, effectiveDirection]);
786
1022
  const handleSortClick = (key) => {
787
1023
  let nextDirection;
788
- if (activeKey !== key) {
1024
+ if (!activeKey || !activeDirection) {
1025
+ nextDirection = baselineKey === key && baselineDirection ? baselineDirection : "asc";
1026
+ } else if (activeKey !== key) {
789
1027
  nextDirection = "asc";
1028
+ } else if (baselineKey === key && baselineDirection) {
1029
+ nextDirection = activeDirection === baselineDirection ? baselineDirection === "asc" ? "desc" : "asc" : null;
790
1030
  } else if (activeDirection === "asc") {
791
1031
  nextDirection = "desc";
792
- } else if (activeDirection === "desc") {
793
- nextDirection = null;
794
1032
  } else {
795
- nextDirection = "asc";
1033
+ nextDirection = null;
796
1034
  }
797
1035
  const nextKey = nextDirection === null ? null : key;
798
1036
  if (isControlled) {
@@ -803,13 +1041,13 @@ function SortableTable({
803
1041
  onSortChange?.(nextKey, nextDirection);
804
1042
  }
805
1043
  };
806
- 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: [
807
- header && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
808
- 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: [
809
- /* @__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) => {
1044
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "fractal-sortable-table-surface", children: [
1045
+ header && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
1046
+ sorted.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("table", { className: "fractal-sortable-table-table", children: [
1047
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tr", { className: "fractal-sortable-table-thead-row", children: columns.map((col) => {
810
1048
  const isActive = activeKey === col.key && activeDirection !== null;
811
1049
  if (!col.sortable) {
812
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1050
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
813
1051
  "th",
814
1052
  {
815
1053
  className: "fractal-sortable-table-th",
@@ -819,12 +1057,12 @@ function SortableTable({
819
1057
  col.key
820
1058
  );
821
1059
  }
822
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1060
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
823
1061
  "th",
824
1062
  {
825
1063
  className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
826
1064
  style: { width: col.width },
827
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1065
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
828
1066
  "button",
829
1067
  {
830
1068
  type: "button",
@@ -835,8 +1073,8 @@ function SortableTable({
835
1073
  onClick: () => handleSortClick(col.key),
836
1074
  "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
837
1075
  children: [
838
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: col.header }),
839
- /* @__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 }) })
1076
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: col.header }),
1077
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_fractal_icons7.ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_fractal_icons7.ArrowDown, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_fractal_icons7.ArrowsUpDown, { size: 14 }) })
840
1078
  ]
841
1079
  }
842
1080
  )
@@ -844,21 +1082,42 @@ function SortableTable({
844
1082
  col.key
845
1083
  );
846
1084
  }) }) }),
847
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
1085
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
848
1086
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
849
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1087
+ const action = rowAction ? {
1088
+ label: rowAction.label(row, rowIndex),
1089
+ icon: rowAction.icon(row, rowIndex)
1090
+ } : null;
1091
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
850
1092
  "tr",
851
1093
  {
852
1094
  className: cn(
853
1095
  "fractal-sortable-table-row",
854
- highlighted && "fractal-sortable-table-row--highlighted"
1096
+ highlighted && "fractal-sortable-table-row--highlighted",
1097
+ onRowClick && "fractal-sortable-table-row--interactive"
855
1098
  ),
856
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1099
+ onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
1100
+ onKeyDown: onRowClick ? (event) => {
1101
+ if (event.key === "Enter" || event.key === " ") {
1102
+ event.preventDefault();
1103
+ onRowClick(row, rowIndex);
1104
+ }
1105
+ } : void 0,
1106
+ "aria-label": action?.label,
1107
+ role: onRowClick ? "button" : void 0,
1108
+ tabIndex: onRowClick ? 0 : void 0,
1109
+ children: columns.map((col, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
857
1110
  "td",
858
1111
  {
859
- className: "fractal-sortable-table-td",
1112
+ className: cn(
1113
+ "fractal-sortable-table-td",
1114
+ action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1115
+ ),
860
1116
  style: { width: col.width, textAlign: col.align ?? "left" },
861
- children: col.render(row, rowIndex)
1117
+ children: [
1118
+ col.render(row, rowIndex),
1119
+ action && columnIndex === columns.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
1120
+ ]
862
1121
  },
863
1122
  col.key
864
1123
  ))
@@ -871,23 +1130,40 @@ function SortableTable({
871
1130
  }
872
1131
 
873
1132
  // src/components/Tabs/Tabs.tsx
874
- var import_react3 = require("react");
875
- var import_jsx_runtime14 = require("react/jsx-runtime");
1133
+ var import_react4 = require("react");
1134
+ var import_jsx_runtime18 = require("react/jsx-runtime");
876
1135
  function Tabs({
877
1136
  items,
878
1137
  defaultValue,
879
1138
  value: controlledValue,
880
1139
  onValueChange,
881
1140
  className,
882
- ariaLabel
1141
+ ariaLabel,
1142
+ divider = false,
1143
+ variant = "line"
883
1144
  }) {
884
- const reactId = (0, import_react3.useId)();
885
- const [internalValue, setInternalValue] = (0, import_react3.useState)(
1145
+ const reactId = (0, import_react4.useId)();
1146
+ const [internalValue, setInternalValue] = (0, import_react4.useState)(
886
1147
  defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
887
1148
  );
888
1149
  const isControlled = controlledValue !== void 0;
889
1150
  const activeId = isControlled ? controlledValue : internalValue;
890
- const tabRefs = (0, import_react3.useRef)({});
1151
+ const tabListRef = (0, import_react4.useRef)(null);
1152
+ const tabRefs = (0, import_react4.useRef)({});
1153
+ const [indicator, setIndicator] = (0, import_react4.useState)(null);
1154
+ (0, import_react4.useLayoutEffect)(() => {
1155
+ const updateIndicator = () => {
1156
+ const activeTab = tabRefs.current[activeId];
1157
+ if (!activeTab) return;
1158
+ setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
1159
+ };
1160
+ updateIndicator();
1161
+ const list = tabListRef.current;
1162
+ if (!list || typeof ResizeObserver === "undefined") return;
1163
+ const observer = new ResizeObserver(updateIndicator);
1164
+ observer.observe(list);
1165
+ return () => observer.disconnect();
1166
+ }, [activeId, items.length]);
891
1167
  const selectTab = (id) => {
892
1168
  if (isControlled) {
893
1169
  onValueChange?.(id);
@@ -897,6 +1173,10 @@ function Tabs({
897
1173
  }
898
1174
  };
899
1175
  const focusable = items.filter((i) => !i.disabled);
1176
+ const indicatorStyle = indicator ? {
1177
+ "--fractal-tabs-indicator-offset": `${indicator.offset}px`,
1178
+ "--fractal-tabs-indicator-width": `${indicator.width}px`
1179
+ } : void 0;
900
1180
  const onKeyDown = (event) => {
901
1181
  const currentIndex = focusable.findIndex((i) => i.id === activeId);
902
1182
  if (currentIndex === -1) return;
@@ -922,41 +1202,52 @@ function Tabs({
922
1202
  selectTab(nextId2);
923
1203
  requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
924
1204
  };
925
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cn("fractal-tabs", className), children: [
926
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "tablist", "aria-label": ariaLabel, className: "fractal-tabs-list", children: items.map((item) => {
927
- const isActive = item.id === activeId;
928
- const tabId = `${reactId}-tab-${item.id}`;
929
- const panelId = `${reactId}-panel-${item.id}`;
930
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
931
- "button",
932
- {
933
- ref: (el) => {
934
- tabRefs.current[item.id] = el;
935
- },
936
- id: tabId,
937
- role: "tab",
938
- type: "button",
939
- "aria-selected": isActive,
940
- "aria-controls": panelId,
941
- tabIndex: isActive ? 0 : -1,
942
- disabled: item.disabled,
943
- className: cn(
944
- "fractal-tabs-trigger",
945
- isActive && "fractal-tabs-trigger--active",
946
- item.disabled && "fractal-tabs-trigger--disabled"
947
- ),
948
- onClick: () => !item.disabled && selectTab(item.id),
949
- onKeyDown,
950
- children: item.label
951
- },
952
- item.id
953
- );
954
- }) }),
1205
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: cn("fractal-tabs", `fractal-tabs--${variant}`, divider && "fractal-tabs--divider", className), children: [
1206
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1207
+ "div",
1208
+ {
1209
+ ref: tabListRef,
1210
+ role: "tablist",
1211
+ "aria-label": ariaLabel,
1212
+ className: "fractal-tabs-list",
1213
+ "data-indicator-ready": indicator ? "true" : void 0,
1214
+ style: indicatorStyle,
1215
+ children: items.map((item) => {
1216
+ const isActive = item.id === activeId;
1217
+ const tabId = `${reactId}-tab-${item.id}`;
1218
+ const panelId = `${reactId}-panel-${item.id}`;
1219
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1220
+ "button",
1221
+ {
1222
+ ref: (el) => {
1223
+ tabRefs.current[item.id] = el;
1224
+ },
1225
+ id: tabId,
1226
+ role: "tab",
1227
+ type: "button",
1228
+ "aria-selected": isActive,
1229
+ "aria-controls": panelId,
1230
+ tabIndex: isActive ? 0 : -1,
1231
+ disabled: item.disabled,
1232
+ className: cn(
1233
+ "fractal-tabs-trigger",
1234
+ isActive && "fractal-tabs-trigger--active",
1235
+ item.disabled && "fractal-tabs-trigger--disabled"
1236
+ ),
1237
+ onClick: () => !item.disabled && selectTab(item.id),
1238
+ onKeyDown,
1239
+ children: item.label
1240
+ },
1241
+ item.id
1242
+ );
1243
+ })
1244
+ }
1245
+ ),
955
1246
  items.map((item) => {
956
1247
  const tabId = `${reactId}-tab-${item.id}`;
957
1248
  const panelId = `${reactId}-panel-${item.id}`;
958
1249
  const isActive = item.id === activeId;
959
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1250
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
960
1251
  "div",
961
1252
  {
962
1253
  id: panelId,
@@ -972,10 +1263,112 @@ function Tabs({
972
1263
  ] });
973
1264
  }
974
1265
 
1266
+ // src/components/ContentSwitcher/ContentSwitcher.tsx
1267
+ var React11 = __toESM(require("react"), 1);
1268
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1269
+ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1270
+ const switcherRef = React11.useRef(null);
1271
+ const buttonRefs = React11.useRef([]);
1272
+ const indicatorMotionReadyRef = React11.useRef(false);
1273
+ const activeIndex = items.findIndex((item) => item.value === value);
1274
+ React11.useLayoutEffect(() => {
1275
+ const switcher = switcherRef.current;
1276
+ const activeButton = buttonRefs.current[activeIndex];
1277
+ let motionFrame = 0;
1278
+ if (!switcher || !activeButton) {
1279
+ switcher?.removeAttribute("data-indicator-ready");
1280
+ switcher?.removeAttribute("data-indicator-animate");
1281
+ indicatorMotionReadyRef.current = false;
1282
+ return;
1283
+ }
1284
+ const updateIndicator = () => {
1285
+ const switcherRect = switcher.getBoundingClientRect();
1286
+ const activeButtonRect = activeButton.getBoundingClientRect();
1287
+ switcher.style.setProperty("--fractal-content-switcher-indicator-x", `${activeButtonRect.left - switcherRect.left - switcher.clientLeft}px`);
1288
+ switcher.style.setProperty("--fractal-content-switcher-indicator-y", `${activeButtonRect.top - switcherRect.top - switcher.clientTop}px`);
1289
+ switcher.style.setProperty("--fractal-content-switcher-indicator-width", `${activeButtonRect.width}px`);
1290
+ switcher.style.setProperty("--fractal-content-switcher-indicator-height", `${activeButtonRect.height}px`);
1291
+ switcher.setAttribute("data-indicator-ready", "true");
1292
+ if (!indicatorMotionReadyRef.current && motionFrame === 0) {
1293
+ motionFrame = window.requestAnimationFrame(() => {
1294
+ indicatorMotionReadyRef.current = true;
1295
+ switcher.setAttribute("data-indicator-animate", "true");
1296
+ motionFrame = 0;
1297
+ });
1298
+ }
1299
+ };
1300
+ updateIndicator();
1301
+ if (typeof ResizeObserver === "undefined") {
1302
+ return () => {
1303
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1304
+ };
1305
+ }
1306
+ const resizeObserver = new ResizeObserver(updateIndicator);
1307
+ resizeObserver.observe(switcher);
1308
+ buttonRefs.current.forEach((button) => {
1309
+ if (button) resizeObserver.observe(button);
1310
+ });
1311
+ return () => {
1312
+ resizeObserver.disconnect();
1313
+ if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
1314
+ };
1315
+ }, [activeIndex, items.length]);
1316
+ const moveFocus = (index, direction) => {
1317
+ let nextIndex = index;
1318
+ do {
1319
+ nextIndex = (nextIndex + direction + items.length) % items.length;
1320
+ } while (items[nextIndex]?.disabled && nextIndex !== index);
1321
+ if (!items[nextIndex]?.disabled) {
1322
+ buttonRefs.current[nextIndex]?.focus();
1323
+ onValueChange(items[nextIndex].value);
1324
+ }
1325
+ };
1326
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1327
+ "div",
1328
+ {
1329
+ className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className),
1330
+ role: "group",
1331
+ "aria-label": ariaLabel,
1332
+ ref: switcherRef,
1333
+ children: [
1334
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
1335
+ items.map((item, index) => {
1336
+ const active = item.value === value;
1337
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1338
+ "button",
1339
+ {
1340
+ className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
1341
+ type: "button",
1342
+ "aria-pressed": active,
1343
+ disabled: item.disabled,
1344
+ onClick: () => onValueChange(item.value),
1345
+ onKeyDown: (event) => {
1346
+ if (event.key === "ArrowRight") {
1347
+ event.preventDefault();
1348
+ moveFocus(index, 1);
1349
+ }
1350
+ if (event.key === "ArrowLeft") {
1351
+ event.preventDefault();
1352
+ moveFocus(index, -1);
1353
+ }
1354
+ },
1355
+ ref: (element) => {
1356
+ buttonRefs.current[index] = element;
1357
+ },
1358
+ children: item.label
1359
+ },
1360
+ item.value
1361
+ );
1362
+ })
1363
+ ]
1364
+ }
1365
+ );
1366
+ }
1367
+
975
1368
  // src/components/Disclosure/Disclosure.tsx
976
- var import_react4 = require("react");
977
- var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
978
- var import_jsx_runtime15 = require("react/jsx-runtime");
1369
+ var import_react5 = require("react");
1370
+ var import_fractal_icons8 = require("@mirror-physics/fractal-icons");
1371
+ var import_jsx_runtime20 = require("react/jsx-runtime");
979
1372
  function Disclosure({
980
1373
  title,
981
1374
  meta,
@@ -983,16 +1376,18 @@ function Disclosure({
983
1376
  defaultOpen = false,
984
1377
  open: controlledOpen,
985
1378
  onOpenChange,
1379
+ disabled = false,
986
1380
  className,
987
1381
  variant = "card"
988
1382
  }) {
989
- const reactId = (0, import_react4.useId)();
1383
+ const reactId = (0, import_react5.useId)();
990
1384
  const headerId = `${reactId}-header`;
991
1385
  const panelId = `${reactId}-panel`;
992
- const [internalOpen, setInternalOpen] = (0, import_react4.useState)(defaultOpen);
1386
+ const [internalOpen, setInternalOpen] = (0, import_react5.useState)(defaultOpen);
993
1387
  const isControlled = controlledOpen !== void 0;
994
1388
  const isOpen = isControlled ? controlledOpen : internalOpen;
995
1389
  const toggle = () => {
1390
+ if (disabled) return;
996
1391
  const next = !isOpen;
997
1392
  if (isControlled) {
998
1393
  onOpenChange?.(next);
@@ -1001,17 +1396,18 @@ function Disclosure({
1001
1396
  onOpenChange?.(next);
1002
1397
  }
1003
1398
  };
1004
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1399
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1005
1400
  "div",
1006
1401
  {
1007
1402
  className: cn(
1008
1403
  "fractal-disclosure",
1009
1404
  variant === "card" && "fractal-disclosure--card",
1010
1405
  isOpen && "fractal-disclosure--open",
1406
+ disabled && "fractal-disclosure--disabled",
1011
1407
  className
1012
1408
  ),
1013
1409
  children: [
1014
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1410
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1015
1411
  "button",
1016
1412
  {
1017
1413
  type: "button",
@@ -1019,15 +1415,16 @@ function Disclosure({
1019
1415
  className: "fractal-disclosure-trigger",
1020
1416
  "aria-expanded": isOpen,
1021
1417
  "aria-controls": panelId,
1418
+ disabled,
1022
1419
  onClick: toggle,
1023
1420
  children: [
1024
- /* @__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 }) }),
1025
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1026
- meta && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1421
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_fractal_icons8.ChevronDown, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_fractal_icons8.ChevronRight, { size: 16 }) }),
1422
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1423
+ meta && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1027
1424
  ]
1028
1425
  }
1029
1426
  ),
1030
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1427
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1031
1428
  "div",
1032
1429
  {
1033
1430
  id: panelId,
@@ -1035,7 +1432,7 @@ function Disclosure({
1035
1432
  "aria-labelledby": headerId,
1036
1433
  className: "fractal-disclosure-panel",
1037
1434
  hidden: !isOpen,
1038
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1435
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1039
1436
  }
1040
1437
  )
1041
1438
  ]
@@ -1043,39 +1440,232 @@ function Disclosure({
1043
1440
  );
1044
1441
  }
1045
1442
 
1443
+ // src/components/LatticeLoader/LatticeLoader.tsx
1444
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1445
+ var LATTICE_COUNT = 160;
1446
+ var WAVE_PERIOD = 80;
1447
+ function LatticeLoader({ className, label = "Loading", ...props }) {
1448
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1449
+ "span",
1450
+ {
1451
+ "aria-label": label,
1452
+ className: cn("fractal-lattice-loader", className),
1453
+ role: "progressbar",
1454
+ ...props,
1455
+ children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1456
+ "span",
1457
+ {
1458
+ "aria-hidden": "true",
1459
+ className: "fractal-lattice-loader__cell",
1460
+ style: { "--fractal-lattice-index": index % WAVE_PERIOD }
1461
+ },
1462
+ index
1463
+ ))
1464
+ }
1465
+ );
1466
+ }
1467
+
1468
+ // src/components/Ghost/Ghost.tsx
1469
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1470
+ var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
1471
+ function Ghost({ className, width, height, radius, style, ...props }) {
1472
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1473
+ "div",
1474
+ {
1475
+ "aria-hidden": "true",
1476
+ className: cn("fractal-ghost", className),
1477
+ style: {
1478
+ width: toCssLength(width),
1479
+ height: toCssLength(height),
1480
+ borderRadius: toCssLength(radius),
1481
+ ...style
1482
+ },
1483
+ ...props
1484
+ }
1485
+ );
1486
+ }
1487
+ function GhostLine({ className, size = "md", width = "100%", ...props }) {
1488
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
1489
+ }
1490
+ function ButtonGhost({ className, size = "md", iconOnly = false, width, ...props }) {
1491
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
1492
+ }
1493
+ function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
1494
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
1495
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: "38%" }),
1496
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: index === lines - 1 ? "62%" : "100%" }, index)) })
1497
+ ] });
1498
+ }
1499
+ function DataTableGhost({
1500
+ className,
1501
+ showHeader = true,
1502
+ headers,
1503
+ columns = 4,
1504
+ rows = 5,
1505
+ columnWidths,
1506
+ size = "md",
1507
+ ...props
1508
+ }) {
1509
+ const cells = Array.from({ length: columns }, (_, index) => index);
1510
+ return /* @__PURE__ */ (0, import_jsx_runtime22.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_runtime22.jsxs)("table", { className: "fractal-ghost-table__table", children: [
1511
+ (showHeader || headers) && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tr", { className: "fractal-ghost-table__head-row", children: cells.map((index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { style: { width: columnWidths?.[index] }, children: headers?.[index] ?? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { size: "sm", width: index === columns - 1 ? "62%" : "76%" }) }, index)) }) }),
1512
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tbody", { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tr", { className: "fractal-ghost-table__row", children: cells.map((columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { style: { width: columnWidths?.[columnIndex] }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: `${[72, 54, 82, 63, 46][(rowIndex + columnIndex) % 5]}%` }) }, columnIndex)) }, rowIndex)) })
1513
+ ] }) });
1514
+ }
1515
+ function InputGhost({ className, labelWidth = "26%", ...props }) {
1516
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FormFieldGhost, { className, labelWidth, ...props });
1517
+ }
1518
+ function TextareaGhost({ className, labelWidth = "26%", ...props }) {
1519
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
1520
+ }
1521
+ function LabelGhost({ className, width = "26%", ...props }) {
1522
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
1523
+ }
1524
+ function FormFieldGhost({ className, labelWidth = "26%", multiline = false, ...props }) {
1525
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-field", className), ...props, children: [
1526
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LabelGhost, { width: labelWidth }),
1527
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
1528
+ ] });
1529
+ }
1530
+ function AlertGhost({ className, ...props }) {
1531
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
1532
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: "30%" }),
1533
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { size: "sm", width: "78%" })
1534
+ ] });
1535
+ }
1536
+ function CheckboxGhost({ className, ...props }) {
1537
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
1538
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: "fractal-ghost-choice__control" }),
1539
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: "42%" })
1540
+ ] });
1541
+ }
1542
+ var ToggleGhost = CheckboxGhost;
1543
+ function ChipGhost({ className, width = 74, ...props }) {
1544
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
1545
+ }
1546
+ function LinkGhost({ className, width = 96, ...props }) {
1547
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
1548
+ }
1549
+ var TextButtonGhost = LinkGhost;
1550
+ function DropdownGhost({ className, ...props }) {
1551
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropdown", className), ...props, children: [
1552
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: "38%" }),
1553
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: "fractal-ghost-dropdown__chevron" })
1554
+ ] });
1555
+ }
1556
+ function ContentSwitcherGhost({ className, options = 3, ...props }) {
1557
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "aria-hidden": "true", className: cn("fractal-ghost-switcher", className), ...props, children: Array.from({ length: options }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, {}, index)) });
1558
+ }
1559
+ var TabsGhost = ContentSwitcherGhost;
1560
+ function DisclosureGhost({ className, ...props }) {
1561
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
1562
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: "fractal-ghost-disclosure__icon" }),
1563
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: "42%" })
1564
+ ] });
1565
+ }
1566
+ function PaginationGhost({ className, pages = 5, ...props }) {
1567
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "aria-hidden": "true", className: cn("fractal-ghost-pagination", className), ...props, children: Array.from({ length: pages }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, {}, index)) });
1568
+ }
1569
+ function FileDropzoneGhost({ className, ...props }) {
1570
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
1571
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: "fractal-ghost-dropzone__icon" }),
1572
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: "26%" }),
1573
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { size: "sm", width: "46%" })
1574
+ ] });
1575
+ }
1576
+ function PromptCardGhost({ className, ...props }) {
1577
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
1578
+ }
1579
+ function SortableTableGhost(props) {
1580
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DataTableGhost, { ...props });
1581
+ }
1582
+ function SidebarGhost({ className, items = 6, ...props }) {
1583
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
1584
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: "fractal-ghost-sidebar__brand" }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "fractal-ghost-sidebar__items", children: Array.from({ length: items }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "fractal-ghost-sidebar__item", children: [
1586
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, {}),
1587
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
1588
+ ] }, index)) })
1589
+ ] });
1590
+ }
1591
+ function ModalGhost({ className, title, lines = 3, ...props }) {
1592
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
1593
+ }
1594
+ function SidePanelGhost({ className, title, lines = 5, ...props }) {
1595
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
1596
+ }
1597
+ function SurfaceGhost({ className, title, lines = 3, ...props }) {
1598
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
1599
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "fractal-ghost-surface__header", children: [
1600
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: "42%" }),
1601
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Ghost, { className: "fractal-ghost-surface__close" })
1602
+ ] }),
1603
+ title && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "fractal-ghost-surface__title", children: title }),
1604
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GhostLine, { width: index === lines - 1 ? "64%" : "100%" }, index)) })
1605
+ ] });
1606
+ }
1607
+
1046
1608
  // src/components/Sidebar/Sidebar.tsx
1047
- var React10 = __toESM(require("react"), 1);
1048
- var import_jsx_runtime16 = require("react/jsx-runtime");
1049
- var Sidebar = React10.forwardRef(
1050
- ({ className, width, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1609
+ var React12 = __toESM(require("react"), 1);
1610
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1611
+ var Sidebar = React12.forwardRef(
1612
+ ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1051
1613
  "aside",
1052
1614
  {
1053
1615
  ref,
1054
1616
  className: cn("fractal-sidebar", className),
1617
+ "data-compact": compact || void 0,
1055
1618
  style: { ...style, ...width ? { "--fractal-sidebar-width": width } : {} },
1056
1619
  ...props
1057
1620
  }
1058
1621
  )
1059
1622
  );
1060
1623
  Sidebar.displayName = "Sidebar";
1061
- var SidebarHeader = React10.forwardRef(
1062
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1624
+ var SidebarHeader = React12.forwardRef(
1625
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1063
1626
  );
1064
1627
  SidebarHeader.displayName = "SidebarHeader";
1065
- var SidebarBrand = React10.forwardRef(
1066
- ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1628
+ var SidebarBrand = React12.forwardRef(
1629
+ ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1067
1630
  );
1068
1631
  SidebarBrand.displayName = "SidebarBrand";
1069
- var SidebarNav = React10.forwardRef(
1070
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1632
+ function SidebarAccountMenu({
1633
+ name,
1634
+ items,
1635
+ onSelect,
1636
+ triggerLabel = "Account menu",
1637
+ icon,
1638
+ className
1639
+ }) {
1640
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1641
+ Dropdown,
1642
+ {
1643
+ align: "left",
1644
+ className: cn("fractal-sidebar__account", className),
1645
+ items,
1646
+ onSelect,
1647
+ panelClassName: "fractal-sidebar__account-panel",
1648
+ selectedValue: "",
1649
+ triggerClassName: "fractal-sidebar__account-trigger",
1650
+ triggerContent: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
1651
+ icon && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
1652
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-sidebar__account-name", children: name })
1653
+ ] }),
1654
+ triggerLabel,
1655
+ triggerVariant: "tertiary"
1656
+ }
1657
+ );
1658
+ }
1659
+ var SidebarNav = React12.forwardRef(
1660
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1071
1661
  );
1072
1662
  SidebarNav.displayName = "SidebarNav";
1073
- var SidebarSection = React10.forwardRef(
1074
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1663
+ var SidebarSection = React12.forwardRef(
1664
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1075
1665
  );
1076
1666
  SidebarSection.displayName = "SidebarSection";
1077
- var SidebarNavItem = React10.forwardRef(
1078
- ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1667
+ var SidebarNavItem = React12.forwardRef(
1668
+ ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1079
1669
  "button",
1080
1670
  {
1081
1671
  ref,
@@ -1085,67 +1675,316 @@ var SidebarNavItem = React10.forwardRef(
1085
1675
  "aria-current": active ? "page" : void 0,
1086
1676
  ...props,
1087
1677
  children: [
1088
- icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1089
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1090
- endAdornment && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1678
+ icon && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1679
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1680
+ endAdornment && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1091
1681
  ]
1092
1682
  }
1093
1683
  )
1094
1684
  );
1095
1685
  SidebarNavItem.displayName = "SidebarNavItem";
1096
- var SidebarFooter = React10.forwardRef(
1097
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1686
+ var SidebarFooter = React12.forwardRef(
1687
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1098
1688
  );
1099
1689
  SidebarFooter.displayName = "SidebarFooter";
1100
1690
 
1101
- // src/components/PageHeader/PageHeader.tsx
1102
- var React11 = __toESM(require("react"), 1);
1103
- var import_jsx_runtime17 = require("react/jsx-runtime");
1104
- var PageHeader = React11.forwardRef(
1105
- ({ title, description, actions, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref, className: cn("fractal-page-header", className), ...props, children: [
1106
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "fractal-page-header__content", children: [
1107
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h1", { className: "fractal-page-header__title", children: title }),
1108
- description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "fractal-page-header__description", children: description })
1109
- ] }),
1110
- actions && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-page-header__actions", children: actions })
1111
- ] })
1691
+ // src/components/SidePanel/SidePanel.tsx
1692
+ var import_react_dom2 = require("react-dom");
1693
+ var import_fractal_icons9 = require("@mirror-physics/fractal-icons");
1694
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1695
+ function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
1696
+ useEscapeDismiss(80, onClose, open);
1697
+ if (!open) return null;
1698
+ return (0, import_react_dom2.createPortal)(
1699
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1700
+ "aside",
1701
+ {
1702
+ className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
1703
+ "aria-modal": "true",
1704
+ "aria-label": typeof title === "string" ? title : "Side panel",
1705
+ role: "dialog",
1706
+ onMouseDown: (event) => event.stopPropagation(),
1707
+ children: [
1708
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("header", { className: "fractal-side-panel__header", children: [
1709
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "fractal-side-panel__heading", children: [
1710
+ typeof title === "string" ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "fractal-side-panel__title", children: title }),
1711
+ description && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "fractal-side-panel__description", children: description })
1712
+ ] }),
1713
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_fractal_icons9.Close, { size: 18 }) })
1714
+ ] }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime24.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_runtime24.jsx)(UILoader, { label: loadingLabel }) : children }),
1716
+ footer && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
1717
+ ]
1718
+ }
1719
+ ) }),
1720
+ document.body
1721
+ );
1722
+ }
1723
+
1724
+ // src/components/Textarea/Textarea.tsx
1725
+ var React13 = __toESM(require("react"), 1);
1726
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1727
+ var Textarea = React13.forwardRef(
1728
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
1112
1729
  );
1113
- PageHeader.displayName = "PageHeader";
1730
+ Textarea.displayName = "Textarea";
1731
+
1732
+ // src/components/TextButton/TextButton.tsx
1733
+ var React14 = __toESM(require("react"), 1);
1734
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1735
+ var TextButton = React14.forwardRef(
1736
+ ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1737
+ "button",
1738
+ {
1739
+ ref,
1740
+ className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
1741
+ type: "button",
1742
+ ...props,
1743
+ children: [
1744
+ icon && iconPosition === "start" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
1745
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children }),
1746
+ icon && iconPosition === "end" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
1747
+ ]
1748
+ }
1749
+ )
1750
+ );
1751
+ TextButton.displayName = "TextButton";
1752
+
1753
+ // src/components/FileDropzone/FileDropzone.tsx
1754
+ var React15 = __toESM(require("react"), 1);
1755
+ var import_fractal_icons10 = require("@mirror-physics/fractal-icons");
1756
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1757
+ function FileDropzone({
1758
+ files,
1759
+ onFilesChange,
1760
+ accept,
1761
+ multiple = true,
1762
+ disabled = false,
1763
+ title = "Drop files here or click to browse",
1764
+ description = "Files stay attached to this record.",
1765
+ className
1766
+ }) {
1767
+ const inputId = React15.useId();
1768
+ const inputRef = React15.useRef(null);
1769
+ const [isDragging, setIsDragging] = React15.useState(false);
1770
+ const addFiles = (nextFiles) => {
1771
+ if (disabled) return;
1772
+ const additions = Array.from(nextFiles);
1773
+ if (additions.length === 0) return;
1774
+ onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
1775
+ };
1776
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("fractal-file-dropzone", className), children: [
1777
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1778
+ "input",
1779
+ {
1780
+ ref: inputRef,
1781
+ id: inputId,
1782
+ className: "fractal-file-dropzone__input",
1783
+ type: "file",
1784
+ accept,
1785
+ multiple,
1786
+ disabled,
1787
+ onChange: (event) => {
1788
+ if (event.target.files) addFiles(event.target.files);
1789
+ event.target.value = "";
1790
+ }
1791
+ }
1792
+ ),
1793
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1794
+ "button",
1795
+ {
1796
+ className: "fractal-file-dropzone__target",
1797
+ "data-dragging": isDragging || void 0,
1798
+ type: "button",
1799
+ disabled,
1800
+ onClick: () => inputRef.current?.click(),
1801
+ onDragEnter: (event) => {
1802
+ event.preventDefault();
1803
+ if (!disabled) setIsDragging(true);
1804
+ },
1805
+ onDragOver: (event) => event.preventDefault(),
1806
+ onDragLeave: (event) => {
1807
+ event.preventDefault();
1808
+ setIsDragging(false);
1809
+ },
1810
+ onDrop: (event) => {
1811
+ event.preventDefault();
1812
+ setIsDragging(false);
1813
+ addFiles(event.dataTransfer.files);
1814
+ },
1815
+ children: [
1816
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fractal_icons10.FileArrowUp, { "aria-hidden": "true", size: 20 }),
1817
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "fractal-file-dropzone__copy", children: [
1818
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "fractal-file-dropzone__title", children: title }),
1819
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "fractal-file-dropzone__description", children: description })
1820
+ ] })
1821
+ ]
1822
+ }
1823
+ ),
1824
+ files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("li", { className: "fractal-file-dropzone__file", children: [
1825
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
1826
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
1827
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1828
+ "button",
1829
+ {
1830
+ className: "fractal-file-dropzone__remove",
1831
+ type: "button",
1832
+ "aria-label": `Remove ${file.name}`,
1833
+ disabled,
1834
+ onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
1835
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fractal_icons10.Close, { "aria-hidden": "true", size: 14 })
1836
+ }
1837
+ )
1838
+ ] }, `${file.name}-${file.size}-${index}`)) })
1839
+ ] });
1840
+ }
1841
+ function formatFileSize(bytes) {
1842
+ if (bytes < 1024) return `${bytes} B`;
1843
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
1844
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1845
+ }
1846
+
1847
+ // src/components/Pagination/Pagination.tsx
1848
+ var import_fractal_icons11 = require("@mirror-physics/fractal-icons");
1849
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1850
+ function Pagination({
1851
+ page,
1852
+ pageSize,
1853
+ totalItems,
1854
+ onPageChange,
1855
+ pageSizeOptions,
1856
+ onPageSizeChange,
1857
+ ariaLabel = "Pagination",
1858
+ className
1859
+ }) {
1860
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
1861
+ const currentPage = Math.min(Math.max(page, 1), totalPages);
1862
+ const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
1863
+ const end = Math.min(currentPage * pageSize, totalItems);
1864
+ const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
1865
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
1866
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
1867
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "fractal-pagination__controls", children: [
1868
+ canChangePageSize && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1869
+ Dropdown,
1870
+ {
1871
+ align: "right",
1872
+ className: "fractal-pagination__page-size",
1873
+ direction: "up",
1874
+ items: pageSizeOptions.map((option) => ({
1875
+ value: String(option),
1876
+ description: `${option} per page`
1877
+ })),
1878
+ onSelect: (value) => onPageSizeChange(Number(value)),
1879
+ selectedValue: String(pageSize),
1880
+ size: "sm",
1881
+ triggerLabel: "Results per page",
1882
+ triggerVariant: "tertiary"
1883
+ }
1884
+ ),
1885
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1886
+ "button",
1887
+ {
1888
+ className: "fractal-pagination__button",
1889
+ type: "button",
1890
+ "aria-label": "Previous page",
1891
+ title: "Previous page",
1892
+ disabled: currentPage === 1 || totalItems === 0,
1893
+ onClick: () => onPageChange(currentPage - 1),
1894
+ children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fractal_icons11.ArrowLeft, { "aria-hidden": "true", size: 16 })
1895
+ }
1896
+ ),
1897
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
1898
+ currentPage,
1899
+ " of ",
1900
+ totalPages
1901
+ ] }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1903
+ "button",
1904
+ {
1905
+ className: "fractal-pagination__button",
1906
+ type: "button",
1907
+ "aria-label": "Next page",
1908
+ title: "Next page",
1909
+ disabled: currentPage === totalPages || totalItems === 0,
1910
+ onClick: () => onPageChange(currentPage + 1),
1911
+ children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fractal_icons11.ArrowRight, { "aria-hidden": "true", size: 16 })
1912
+ }
1913
+ )
1914
+ ] })
1915
+ ] });
1916
+ }
1114
1917
  // Annotate the CommonJS export names for ESM import in node:
1115
1918
  0 && (module.exports = {
1116
1919
  Alert,
1117
1920
  AlertDescription,
1921
+ AlertGhost,
1118
1922
  AlertTitle,
1923
+ Breadcrumbs,
1119
1924
  Button,
1925
+ ButtonGhost,
1120
1926
  Card,
1121
1927
  CardContent,
1122
1928
  CardDescription,
1123
1929
  CardFooter,
1930
+ CardGhost,
1124
1931
  CardHeader,
1125
1932
  CardTitle,
1933
+ Checkbox,
1934
+ CheckboxGhost,
1126
1935
  Chip,
1936
+ ChipGhost,
1937
+ ContentSwitcher,
1938
+ ContentSwitcherGhost,
1127
1939
  DataTable,
1940
+ DataTableGhost,
1128
1941
  Disclosure,
1942
+ DisclosureGhost,
1129
1943
  Dropdown,
1944
+ DropdownGhost,
1130
1945
  FeatureCard,
1946
+ FileDropzone,
1947
+ FileDropzoneGhost,
1131
1948
  FolderCard,
1949
+ Ghost,
1950
+ GhostLine,
1132
1951
  Input,
1952
+ InputGhost,
1133
1953
  Label,
1954
+ LabelGhost,
1955
+ LatticeLoader,
1134
1956
  Link,
1957
+ LinkGhost,
1135
1958
  Modal,
1136
- PageHeader,
1959
+ ModalGhost,
1960
+ NumberInput,
1961
+ Pagination,
1962
+ PaginationGhost,
1137
1963
  PromptCard,
1964
+ PromptCardGhost,
1138
1965
  PromptGrid,
1966
+ SidePanel,
1967
+ SidePanelGhost,
1139
1968
  Sidebar,
1969
+ SidebarAccountMenu,
1140
1970
  SidebarBrand,
1141
1971
  SidebarFooter,
1972
+ SidebarGhost,
1142
1973
  SidebarHeader,
1143
1974
  SidebarNav,
1144
1975
  SidebarNavItem,
1145
1976
  SidebarSection,
1146
1977
  SortableTable,
1978
+ SortableTableGhost,
1147
1979
  Tabs,
1980
+ TabsGhost,
1981
+ TextButton,
1982
+ TextButtonGhost,
1983
+ Textarea,
1984
+ TextareaGhost,
1148
1985
  Toggle,
1986
+ ToggleGhost,
1987
+ UILoader,
1149
1988
  cn,
1150
1989
  useEscapeDismiss
1151
1990
  });