@mirror-physics/fractal-ui 0.2.0-next.2 → 0.2.0-next.21

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
@@ -40,18 +40,24 @@ __export(index_exports, {
40
40
  CardFooter: () => CardFooter,
41
41
  CardHeader: () => CardHeader,
42
42
  CardTitle: () => CardTitle,
43
+ Checkbox: () => Checkbox,
43
44
  Chip: () => Chip,
45
+ ContentSwitcher: () => ContentSwitcher,
44
46
  DataTable: () => DataTable,
45
47
  Disclosure: () => Disclosure,
46
48
  Dropdown: () => Dropdown,
47
49
  FeatureCard: () => FeatureCard,
50
+ FileDropzone: () => FileDropzone,
48
51
  FolderCard: () => FolderCard,
49
52
  Input: () => Input,
50
53
  Label: () => Label,
54
+ LatticeLoader: () => LatticeLoader,
51
55
  Link: () => Link,
52
56
  Modal: () => Modal,
57
+ Pagination: () => Pagination,
53
58
  PromptCard: () => PromptCard,
54
59
  PromptGrid: () => PromptGrid,
60
+ SidePanel: () => SidePanel,
55
61
  Sidebar: () => Sidebar,
56
62
  SidebarBrand: () => SidebarBrand,
57
63
  SidebarFooter: () => SidebarFooter,
@@ -61,6 +67,8 @@ __export(index_exports, {
61
67
  SidebarSection: () => SidebarSection,
62
68
  SortableTable: () => SortableTable,
63
69
  Tabs: () => Tabs,
70
+ TextButton: () => TextButton,
71
+ Textarea: () => Textarea,
64
72
  Toggle: () => Toggle,
65
73
  cn: () => cn,
66
74
  useEscapeDismiss: () => useEscapeDismiss
@@ -119,7 +127,7 @@ var colorPalette = {
119
127
  var sizeConfig = {
120
128
  xs: { height: "28px", padding: "4px 8px", iconOnly: "28px", fontSize: "0.75rem" },
121
129
  sm: { height: "32px", padding: "6px 12px", iconOnly: "32px", fontSize: "0.75rem" },
122
- md: { height: "38px", padding: "8px 16px", iconOnly: "38px", fontSize: "0.875rem" },
130
+ md: { height: "40px", padding: "8px 16px", iconOnly: "40px", fontSize: "0.875rem" },
123
131
  lg: { height: "44px", padding: "10px 20px", iconOnly: "44px", fontSize: "1rem" },
124
132
  xl: { height: "56px", padding: "14px 28px", iconOnly: "56px", fontSize: "1rem" }
125
133
  };
@@ -733,23 +741,52 @@ var Chip = React9.forwardRef(
733
741
  );
734
742
  Chip.displayName = "Chip";
735
743
 
736
- // src/components/SortableTable/SortableTable.tsx
737
- var import_react2 = require("react");
744
+ // src/components/Checkbox/Checkbox.tsx
738
745
  var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
739
746
  var import_jsx_runtime13 = require("react/jsx-runtime");
747
+ function Checkbox({ checked, onCheckedChange, className, disabled, onClick, onKeyDown, ...props }) {
748
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
749
+ "button",
750
+ {
751
+ ...props,
752
+ className: cn("fractal-checkbox", checked && "fractal-checkbox--checked", className),
753
+ type: "button",
754
+ role: "checkbox",
755
+ "aria-checked": checked,
756
+ disabled,
757
+ onClick: (event) => {
758
+ onClick?.(event);
759
+ if (!event.defaultPrevented) onCheckedChange(!checked);
760
+ },
761
+ onKeyDown: (event) => {
762
+ onKeyDown?.(event);
763
+ if (event.key === " " || event.key === "Enter") event.stopPropagation();
764
+ },
765
+ children: checked ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_fractal_icons3.Checkbox, { "aria-hidden": "true", size: 18 })
766
+ }
767
+ );
768
+ }
769
+
770
+ // src/components/SortableTable/SortableTable.tsx
771
+ var import_react2 = require("react");
772
+ var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
773
+ var import_jsx_runtime14 = require("react/jsx-runtime");
740
774
  function SortableTable({
741
775
  columns,
742
776
  data,
743
777
  emptyMessage,
744
778
  header,
745
779
  size = "md",
780
+ embedded = false,
746
781
  className,
747
782
  defaultSortKey = void 0,
748
783
  defaultSortDirection = null,
749
784
  sortKey: controlledKey,
750
785
  sortDirection: controlledDirection,
751
786
  onSortChange,
752
- highlightRow
787
+ highlightRow,
788
+ onRowClick,
789
+ rowAction
753
790
  }) {
754
791
  const [internalKey, setInternalKey] = (0, import_react2.useState)(defaultSortKey ?? null);
755
792
  const [internalDirection, setInternalDirection] = (0, import_react2.useState)(defaultSortDirection);
@@ -802,13 +839,13 @@ function SortableTable({
802
839
  onSortChange?.(nextKey, nextDirection);
803
840
  }
804
841
  };
805
- 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: [
806
- header && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
807
- 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: [
808
- /* @__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) => {
842
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "fractal-sortable-table-surface", children: [
843
+ header && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "fractal-sortable-table-header", children: header }),
844
+ sorted.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("table", { className: "fractal-sortable-table-table", children: [
845
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tr", { className: "fractal-sortable-table-thead-row", children: columns.map((col) => {
809
846
  const isActive = activeKey === col.key && activeDirection !== null;
810
847
  if (!col.sortable) {
811
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
848
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
812
849
  "th",
813
850
  {
814
851
  className: "fractal-sortable-table-th",
@@ -818,12 +855,12 @@ function SortableTable({
818
855
  col.key
819
856
  );
820
857
  }
821
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
858
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
822
859
  "th",
823
860
  {
824
861
  className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
825
862
  style: { width: col.width },
826
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
863
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
827
864
  "button",
828
865
  {
829
866
  type: "button",
@@ -834,8 +871,8 @@ function SortableTable({
834
871
  onClick: () => handleSortClick(col.key),
835
872
  "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
836
873
  children: [
837
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: col.header }),
838
- /* @__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 }) })
874
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: col.header }),
875
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_fractal_icons4.ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_fractal_icons4.ArrowDown, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_fractal_icons4.ArrowsUpDown, { size: 14 }) })
839
876
  ]
840
877
  }
841
878
  )
@@ -843,21 +880,42 @@ function SortableTable({
843
880
  col.key
844
881
  );
845
882
  }) }) }),
846
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
883
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tbody", { children: sorted.map((row, rowIndex) => {
847
884
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
848
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
885
+ const action = rowAction ? {
886
+ label: rowAction.label(row, rowIndex),
887
+ icon: rowAction.icon(row, rowIndex)
888
+ } : null;
889
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
849
890
  "tr",
850
891
  {
851
892
  className: cn(
852
893
  "fractal-sortable-table-row",
853
- highlighted && "fractal-sortable-table-row--highlighted"
894
+ highlighted && "fractal-sortable-table-row--highlighted",
895
+ onRowClick && "fractal-sortable-table-row--interactive"
854
896
  ),
855
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
897
+ onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
898
+ onKeyDown: onRowClick ? (event) => {
899
+ if (event.key === "Enter" || event.key === " ") {
900
+ event.preventDefault();
901
+ onRowClick(row, rowIndex);
902
+ }
903
+ } : void 0,
904
+ "aria-label": action?.label,
905
+ role: onRowClick ? "button" : void 0,
906
+ tabIndex: onRowClick ? 0 : void 0,
907
+ children: columns.map((col, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
856
908
  "td",
857
909
  {
858
- className: "fractal-sortable-table-td",
910
+ className: cn(
911
+ "fractal-sortable-table-td",
912
+ action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
913
+ ),
859
914
  style: { width: col.width, textAlign: col.align ?? "left" },
860
- children: col.render(row, rowIndex)
915
+ children: [
916
+ col.render(row, rowIndex),
917
+ action && columnIndex === columns.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
918
+ ]
861
919
  },
862
920
  col.key
863
921
  ))
@@ -871,14 +929,15 @@ function SortableTable({
871
929
 
872
930
  // src/components/Tabs/Tabs.tsx
873
931
  var import_react3 = require("react");
874
- var import_jsx_runtime14 = require("react/jsx-runtime");
932
+ var import_jsx_runtime15 = require("react/jsx-runtime");
875
933
  function Tabs({
876
934
  items,
877
935
  defaultValue,
878
936
  value: controlledValue,
879
937
  onValueChange,
880
938
  className,
881
- ariaLabel
939
+ ariaLabel,
940
+ divider = false
882
941
  }) {
883
942
  const reactId = (0, import_react3.useId)();
884
943
  const [internalValue, setInternalValue] = (0, import_react3.useState)(
@@ -886,7 +945,22 @@ function Tabs({
886
945
  );
887
946
  const isControlled = controlledValue !== void 0;
888
947
  const activeId = isControlled ? controlledValue : internalValue;
948
+ const tabListRef = (0, import_react3.useRef)(null);
889
949
  const tabRefs = (0, import_react3.useRef)({});
950
+ const [indicator, setIndicator] = (0, import_react3.useState)(null);
951
+ (0, import_react3.useLayoutEffect)(() => {
952
+ const updateIndicator = () => {
953
+ const activeTab = tabRefs.current[activeId];
954
+ if (!activeTab) return;
955
+ setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
956
+ };
957
+ updateIndicator();
958
+ const list = tabListRef.current;
959
+ if (!list || typeof ResizeObserver === "undefined") return;
960
+ const observer = new ResizeObserver(updateIndicator);
961
+ observer.observe(list);
962
+ return () => observer.disconnect();
963
+ }, [activeId, items.length]);
890
964
  const selectTab = (id) => {
891
965
  if (isControlled) {
892
966
  onValueChange?.(id);
@@ -896,6 +970,10 @@ function Tabs({
896
970
  }
897
971
  };
898
972
  const focusable = items.filter((i) => !i.disabled);
973
+ const indicatorStyle = indicator ? {
974
+ "--fractal-tabs-indicator-offset": `${indicator.offset}px`,
975
+ "--fractal-tabs-indicator-width": `${indicator.width}px`
976
+ } : void 0;
899
977
  const onKeyDown = (event) => {
900
978
  const currentIndex = focusable.findIndex((i) => i.id === activeId);
901
979
  if (currentIndex === -1) return;
@@ -921,41 +999,52 @@ function Tabs({
921
999
  selectTab(nextId2);
922
1000
  requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
923
1001
  };
924
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cn("fractal-tabs", className), children: [
925
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "tablist", "aria-label": ariaLabel, className: "fractal-tabs-list", children: items.map((item) => {
926
- const isActive = item.id === activeId;
927
- const tabId = `${reactId}-tab-${item.id}`;
928
- const panelId = `${reactId}-panel-${item.id}`;
929
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
930
- "button",
931
- {
932
- ref: (el) => {
933
- tabRefs.current[item.id] = el;
934
- },
935
- id: tabId,
936
- role: "tab",
937
- type: "button",
938
- "aria-selected": isActive,
939
- "aria-controls": panelId,
940
- tabIndex: isActive ? 0 : -1,
941
- disabled: item.disabled,
942
- className: cn(
943
- "fractal-tabs-trigger",
944
- isActive && "fractal-tabs-trigger--active",
945
- item.disabled && "fractal-tabs-trigger--disabled"
946
- ),
947
- onClick: () => !item.disabled && selectTab(item.id),
948
- onKeyDown,
949
- children: item.label
950
- },
951
- item.id
952
- );
953
- }) }),
1002
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("fractal-tabs", divider && "fractal-tabs--divider", className), children: [
1003
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1004
+ "div",
1005
+ {
1006
+ ref: tabListRef,
1007
+ role: "tablist",
1008
+ "aria-label": ariaLabel,
1009
+ className: "fractal-tabs-list",
1010
+ "data-indicator-ready": indicator ? "true" : void 0,
1011
+ style: indicatorStyle,
1012
+ children: items.map((item) => {
1013
+ const isActive = item.id === activeId;
1014
+ const tabId = `${reactId}-tab-${item.id}`;
1015
+ const panelId = `${reactId}-panel-${item.id}`;
1016
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1017
+ "button",
1018
+ {
1019
+ ref: (el) => {
1020
+ tabRefs.current[item.id] = el;
1021
+ },
1022
+ id: tabId,
1023
+ role: "tab",
1024
+ type: "button",
1025
+ "aria-selected": isActive,
1026
+ "aria-controls": panelId,
1027
+ tabIndex: isActive ? 0 : -1,
1028
+ disabled: item.disabled,
1029
+ className: cn(
1030
+ "fractal-tabs-trigger",
1031
+ isActive && "fractal-tabs-trigger--active",
1032
+ item.disabled && "fractal-tabs-trigger--disabled"
1033
+ ),
1034
+ onClick: () => !item.disabled && selectTab(item.id),
1035
+ onKeyDown,
1036
+ children: item.label
1037
+ },
1038
+ item.id
1039
+ );
1040
+ })
1041
+ }
1042
+ ),
954
1043
  items.map((item) => {
955
1044
  const tabId = `${reactId}-tab-${item.id}`;
956
1045
  const panelId = `${reactId}-panel-${item.id}`;
957
1046
  const isActive = item.id === activeId;
958
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1047
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
959
1048
  "div",
960
1049
  {
961
1050
  id: panelId,
@@ -971,10 +1060,55 @@ function Tabs({
971
1060
  ] });
972
1061
  }
973
1062
 
1063
+ // src/components/ContentSwitcher/ContentSwitcher.tsx
1064
+ var React10 = __toESM(require("react"), 1);
1065
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1066
+ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1067
+ const buttonRefs = React10.useRef([]);
1068
+ const moveFocus = (index, direction) => {
1069
+ let nextIndex = index;
1070
+ do {
1071
+ nextIndex = (nextIndex + direction + items.length) % items.length;
1072
+ } while (items[nextIndex]?.disabled && nextIndex !== index);
1073
+ if (!items[nextIndex]?.disabled) {
1074
+ buttonRefs.current[nextIndex]?.focus();
1075
+ onValueChange(items[nextIndex].value);
1076
+ }
1077
+ };
1078
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className), role: "group", "aria-label": ariaLabel, children: items.map((item, index) => {
1079
+ const active = item.value === value;
1080
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1081
+ "button",
1082
+ {
1083
+ className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
1084
+ type: "button",
1085
+ "aria-pressed": active,
1086
+ disabled: item.disabled,
1087
+ onClick: () => onValueChange(item.value),
1088
+ onKeyDown: (event) => {
1089
+ if (event.key === "ArrowRight") {
1090
+ event.preventDefault();
1091
+ moveFocus(index, 1);
1092
+ }
1093
+ if (event.key === "ArrowLeft") {
1094
+ event.preventDefault();
1095
+ moveFocus(index, -1);
1096
+ }
1097
+ },
1098
+ ref: (element) => {
1099
+ buttonRefs.current[index] = element;
1100
+ },
1101
+ children: item.label
1102
+ },
1103
+ item.value
1104
+ );
1105
+ }) });
1106
+ }
1107
+
974
1108
  // src/components/Disclosure/Disclosure.tsx
975
1109
  var import_react4 = require("react");
976
- var import_fractal_icons4 = require("@mirror-physics/fractal-icons");
977
- var import_jsx_runtime15 = require("react/jsx-runtime");
1110
+ var import_fractal_icons5 = require("@mirror-physics/fractal-icons");
1111
+ var import_jsx_runtime17 = require("react/jsx-runtime");
978
1112
  function Disclosure({
979
1113
  title,
980
1114
  meta,
@@ -982,6 +1116,7 @@ function Disclosure({
982
1116
  defaultOpen = false,
983
1117
  open: controlledOpen,
984
1118
  onOpenChange,
1119
+ disabled = false,
985
1120
  className,
986
1121
  variant = "card"
987
1122
  }) {
@@ -992,6 +1127,7 @@ function Disclosure({
992
1127
  const isControlled = controlledOpen !== void 0;
993
1128
  const isOpen = isControlled ? controlledOpen : internalOpen;
994
1129
  const toggle = () => {
1130
+ if (disabled) return;
995
1131
  const next = !isOpen;
996
1132
  if (isControlled) {
997
1133
  onOpenChange?.(next);
@@ -1000,17 +1136,18 @@ function Disclosure({
1000
1136
  onOpenChange?.(next);
1001
1137
  }
1002
1138
  };
1003
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1139
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1004
1140
  "div",
1005
1141
  {
1006
1142
  className: cn(
1007
1143
  "fractal-disclosure",
1008
1144
  variant === "card" && "fractal-disclosure--card",
1009
1145
  isOpen && "fractal-disclosure--open",
1146
+ disabled && "fractal-disclosure--disabled",
1010
1147
  className
1011
1148
  ),
1012
1149
  children: [
1013
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1150
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1014
1151
  "button",
1015
1152
  {
1016
1153
  type: "button",
@@ -1018,15 +1155,16 @@ function Disclosure({
1018
1155
  className: "fractal-disclosure-trigger",
1019
1156
  "aria-expanded": isOpen,
1020
1157
  "aria-controls": panelId,
1158
+ disabled,
1021
1159
  onClick: toggle,
1022
1160
  children: [
1023
- /* @__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 }) }),
1024
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1025
- meta && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1161
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_fractal_icons5.ChevronDown, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_fractal_icons5.ChevronRight, { size: 16 }) }),
1162
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "fractal-disclosure-title", children: title }),
1163
+ meta && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "fractal-disclosure-meta", children: meta })
1026
1164
  ]
1027
1165
  }
1028
1166
  ),
1029
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1167
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1030
1168
  "div",
1031
1169
  {
1032
1170
  id: panelId,
@@ -1034,7 +1172,7 @@ function Disclosure({
1034
1172
  "aria-labelledby": headerId,
1035
1173
  className: "fractal-disclosure-panel",
1036
1174
  hidden: !isOpen,
1037
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1175
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fractal-disclosure-panel-inner", children })
1038
1176
  }
1039
1177
  )
1040
1178
  ]
@@ -1042,11 +1180,36 @@ function Disclosure({
1042
1180
  );
1043
1181
  }
1044
1182
 
1183
+ // src/components/LatticeLoader/LatticeLoader.tsx
1184
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1185
+ var LATTICE_COUNT = 160;
1186
+ var WAVE_PERIOD = 80;
1187
+ function LatticeLoader({ className, label = "Loading", ...props }) {
1188
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1189
+ "span",
1190
+ {
1191
+ "aria-label": label,
1192
+ className: cn("fractal-lattice-loader", className),
1193
+ role: "progressbar",
1194
+ ...props,
1195
+ children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1196
+ "span",
1197
+ {
1198
+ "aria-hidden": "true",
1199
+ className: "fractal-lattice-loader__cell",
1200
+ style: { "--fractal-lattice-index": index % WAVE_PERIOD }
1201
+ },
1202
+ index
1203
+ ))
1204
+ }
1205
+ );
1206
+ }
1207
+
1045
1208
  // src/components/Sidebar/Sidebar.tsx
1046
- var React10 = __toESM(require("react"), 1);
1047
- var import_jsx_runtime16 = require("react/jsx-runtime");
1048
- var Sidebar = React10.forwardRef(
1049
- ({ className, width, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1209
+ var React11 = __toESM(require("react"), 1);
1210
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1211
+ var Sidebar = React11.forwardRef(
1212
+ ({ className, width, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1050
1213
  "aside",
1051
1214
  {
1052
1215
  ref,
@@ -1057,24 +1220,24 @@ var Sidebar = React10.forwardRef(
1057
1220
  )
1058
1221
  );
1059
1222
  Sidebar.displayName = "Sidebar";
1060
- var SidebarHeader = React10.forwardRef(
1061
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1223
+ var SidebarHeader = React11.forwardRef(
1224
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
1062
1225
  );
1063
1226
  SidebarHeader.displayName = "SidebarHeader";
1064
- var SidebarBrand = React10.forwardRef(
1065
- ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1227
+ var SidebarBrand = React11.forwardRef(
1228
+ ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
1066
1229
  );
1067
1230
  SidebarBrand.displayName = "SidebarBrand";
1068
- var SidebarNav = React10.forwardRef(
1069
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1231
+ var SidebarNav = React11.forwardRef(
1232
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
1070
1233
  );
1071
1234
  SidebarNav.displayName = "SidebarNav";
1072
- var SidebarSection = React10.forwardRef(
1073
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1235
+ var SidebarSection = React11.forwardRef(
1236
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
1074
1237
  );
1075
1238
  SidebarSection.displayName = "SidebarSection";
1076
- var SidebarNavItem = React10.forwardRef(
1077
- ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1239
+ var SidebarNavItem = React11.forwardRef(
1240
+ ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1078
1241
  "button",
1079
1242
  {
1080
1243
  ref,
@@ -1084,18 +1247,245 @@ var SidebarNavItem = React10.forwardRef(
1084
1247
  "aria-current": active ? "page" : void 0,
1085
1248
  ...props,
1086
1249
  children: [
1087
- icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1088
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1089
- endAdornment && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1250
+ icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
1251
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fractal-sidebar__nav-item-label", children }),
1252
+ endAdornment && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
1090
1253
  ]
1091
1254
  }
1092
1255
  )
1093
1256
  );
1094
1257
  SidebarNavItem.displayName = "SidebarNavItem";
1095
- var SidebarFooter = React10.forwardRef(
1096
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1258
+ var SidebarFooter = React11.forwardRef(
1259
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
1097
1260
  );
1098
1261
  SidebarFooter.displayName = "SidebarFooter";
1262
+
1263
+ // src/components/SidePanel/SidePanel.tsx
1264
+ var import_react_dom2 = require("react-dom");
1265
+ var import_fractal_icons6 = require("@mirror-physics/fractal-icons");
1266
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1267
+ function SidePanel({ open, onClose, title, description, children, footer, size = "md", className }) {
1268
+ useEscapeDismiss(80, onClose, open);
1269
+ if (!open) return null;
1270
+ return (0, import_react_dom2.createPortal)(
1271
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1272
+ "aside",
1273
+ {
1274
+ className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
1275
+ "aria-modal": "true",
1276
+ "aria-label": typeof title === "string" ? title : "Side panel",
1277
+ role: "dialog",
1278
+ onMouseDown: (event) => event.stopPropagation(),
1279
+ children: [
1280
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("header", { className: "fractal-side-panel__header", children: [
1281
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "fractal-side-panel__heading", children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h2", { className: "fractal-side-panel__title", children: title }),
1283
+ description && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "fractal-side-panel__description", children: description })
1284
+ ] }),
1285
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_fractal_icons6.Close, { size: 18 }) })
1286
+ ] }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "fractal-side-panel__body", children }),
1288
+ footer && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("footer", { className: "fractal-side-panel__footer", children: footer })
1289
+ ]
1290
+ }
1291
+ ) }),
1292
+ document.body
1293
+ );
1294
+ }
1295
+
1296
+ // src/components/Textarea/Textarea.tsx
1297
+ var React12 = __toESM(require("react"), 1);
1298
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1299
+ var Textarea = React12.forwardRef(
1300
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
1301
+ );
1302
+ Textarea.displayName = "Textarea";
1303
+
1304
+ // src/components/TextButton/TextButton.tsx
1305
+ var React13 = __toESM(require("react"), 1);
1306
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1307
+ var TextButton = React13.forwardRef(
1308
+ ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1309
+ "button",
1310
+ {
1311
+ ref,
1312
+ className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
1313
+ type: "button",
1314
+ ...props,
1315
+ children: [
1316
+ icon && iconPosition === "start" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
1317
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children }),
1318
+ icon && iconPosition === "end" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
1319
+ ]
1320
+ }
1321
+ )
1322
+ );
1323
+ TextButton.displayName = "TextButton";
1324
+
1325
+ // src/components/FileDropzone/FileDropzone.tsx
1326
+ var React14 = __toESM(require("react"), 1);
1327
+ var import_fractal_icons7 = require("@mirror-physics/fractal-icons");
1328
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1329
+ function FileDropzone({
1330
+ files,
1331
+ onFilesChange,
1332
+ accept,
1333
+ multiple = true,
1334
+ disabled = false,
1335
+ title = "Drop files here or click to browse",
1336
+ description = "Files stay attached to this record.",
1337
+ className
1338
+ }) {
1339
+ const inputId = React14.useId();
1340
+ const inputRef = React14.useRef(null);
1341
+ const [isDragging, setIsDragging] = React14.useState(false);
1342
+ const addFiles = (nextFiles) => {
1343
+ if (disabled) return;
1344
+ const additions = Array.from(nextFiles);
1345
+ if (additions.length === 0) return;
1346
+ onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
1347
+ };
1348
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("fractal-file-dropzone", className), children: [
1349
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1350
+ "input",
1351
+ {
1352
+ ref: inputRef,
1353
+ id: inputId,
1354
+ className: "fractal-file-dropzone__input",
1355
+ type: "file",
1356
+ accept,
1357
+ multiple,
1358
+ disabled,
1359
+ onChange: (event) => {
1360
+ if (event.target.files) addFiles(event.target.files);
1361
+ event.target.value = "";
1362
+ }
1363
+ }
1364
+ ),
1365
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1366
+ "button",
1367
+ {
1368
+ className: "fractal-file-dropzone__target",
1369
+ "data-dragging": isDragging || void 0,
1370
+ type: "button",
1371
+ disabled,
1372
+ onClick: () => inputRef.current?.click(),
1373
+ onDragEnter: (event) => {
1374
+ event.preventDefault();
1375
+ if (!disabled) setIsDragging(true);
1376
+ },
1377
+ onDragOver: (event) => event.preventDefault(),
1378
+ onDragLeave: (event) => {
1379
+ event.preventDefault();
1380
+ setIsDragging(false);
1381
+ },
1382
+ onDrop: (event) => {
1383
+ event.preventDefault();
1384
+ setIsDragging(false);
1385
+ addFiles(event.dataTransfer.files);
1386
+ },
1387
+ children: [
1388
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fractal_icons7.FileArrowUp, { "aria-hidden": "true", size: 20 }),
1389
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "fractal-file-dropzone__copy", children: [
1390
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-file-dropzone__title", children: title }),
1391
+ description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-file-dropzone__description", children: description })
1392
+ ] })
1393
+ ]
1394
+ }
1395
+ ),
1396
+ files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("li", { className: "fractal-file-dropzone__file", children: [
1397
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
1398
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
1399
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1400
+ "button",
1401
+ {
1402
+ className: "fractal-file-dropzone__remove",
1403
+ type: "button",
1404
+ "aria-label": `Remove ${file.name}`,
1405
+ disabled,
1406
+ onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
1407
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fractal_icons7.Close, { "aria-hidden": "true", size: 14 })
1408
+ }
1409
+ )
1410
+ ] }, `${file.name}-${file.size}-${index}`)) })
1411
+ ] });
1412
+ }
1413
+ function formatFileSize(bytes) {
1414
+ if (bytes < 1024) return `${bytes} B`;
1415
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
1416
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1417
+ }
1418
+
1419
+ // src/components/Pagination/Pagination.tsx
1420
+ var import_fractal_icons8 = require("@mirror-physics/fractal-icons");
1421
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1422
+ function Pagination({
1423
+ page,
1424
+ pageSize,
1425
+ totalItems,
1426
+ onPageChange,
1427
+ pageSizeOptions,
1428
+ onPageSizeChange,
1429
+ ariaLabel = "Pagination",
1430
+ className
1431
+ }) {
1432
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
1433
+ const currentPage = Math.min(Math.max(page, 1), totalPages);
1434
+ const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
1435
+ const end = Math.min(currentPage * pageSize, totalItems);
1436
+ const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
1437
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
1438
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "fractal-pagination__controls", children: [
1440
+ canChangePageSize && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1441
+ Dropdown,
1442
+ {
1443
+ align: "right",
1444
+ className: "fractal-pagination__page-size",
1445
+ direction: "up",
1446
+ items: pageSizeOptions.map((option) => ({
1447
+ value: String(option),
1448
+ description: `${option} per page`
1449
+ })),
1450
+ onSelect: (value) => onPageSizeChange(Number(value)),
1451
+ selectedValue: String(pageSize),
1452
+ size: "sm",
1453
+ triggerLabel: "Results per page",
1454
+ triggerVariant: "tertiary"
1455
+ }
1456
+ ),
1457
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1458
+ "button",
1459
+ {
1460
+ className: "fractal-pagination__button",
1461
+ type: "button",
1462
+ "aria-label": "Previous page",
1463
+ title: "Previous page",
1464
+ disabled: currentPage === 1 || totalItems === 0,
1465
+ onClick: () => onPageChange(currentPage - 1),
1466
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_fractal_icons8.ArrowLeft, { "aria-hidden": "true", size: 16 })
1467
+ }
1468
+ ),
1469
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
1470
+ currentPage,
1471
+ " of ",
1472
+ totalPages
1473
+ ] }),
1474
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1475
+ "button",
1476
+ {
1477
+ className: "fractal-pagination__button",
1478
+ type: "button",
1479
+ "aria-label": "Next page",
1480
+ title: "Next page",
1481
+ disabled: currentPage === totalPages || totalItems === 0,
1482
+ onClick: () => onPageChange(currentPage + 1),
1483
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_fractal_icons8.ArrowRight, { "aria-hidden": "true", size: 16 })
1484
+ }
1485
+ )
1486
+ ] })
1487
+ ] });
1488
+ }
1099
1489
  // Annotate the CommonJS export names for ESM import in node:
1100
1490
  0 && (module.exports = {
1101
1491
  Alert,
@@ -1108,18 +1498,24 @@ SidebarFooter.displayName = "SidebarFooter";
1108
1498
  CardFooter,
1109
1499
  CardHeader,
1110
1500
  CardTitle,
1501
+ Checkbox,
1111
1502
  Chip,
1503
+ ContentSwitcher,
1112
1504
  DataTable,
1113
1505
  Disclosure,
1114
1506
  Dropdown,
1115
1507
  FeatureCard,
1508
+ FileDropzone,
1116
1509
  FolderCard,
1117
1510
  Input,
1118
1511
  Label,
1512
+ LatticeLoader,
1119
1513
  Link,
1120
1514
  Modal,
1515
+ Pagination,
1121
1516
  PromptCard,
1122
1517
  PromptGrid,
1518
+ SidePanel,
1123
1519
  Sidebar,
1124
1520
  SidebarBrand,
1125
1521
  SidebarFooter,
@@ -1129,6 +1525,8 @@ SidebarFooter.displayName = "SidebarFooter";
1129
1525
  SidebarSection,
1130
1526
  SortableTable,
1131
1527
  Tabs,
1528
+ TextButton,
1529
+ Textarea,
1132
1530
  Toggle,
1133
1531
  cn,
1134
1532
  useEscapeDismiss