@mirror-physics/fractal-ui 0.2.0-next.1 → 0.2.0-next.14

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