@mirror-physics/fractal-ui 0.2.0-next.65 → 0.2.0-next.67

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
@@ -1031,6 +1031,7 @@ function Toggle({ checked, onChange, label, className }) {
1031
1031
  }
1032
1032
 
1033
1033
  // src/components/Modal/Modal.tsx
1034
+ var React10 = __toESM(require("react"), 1);
1034
1035
  var import_react_dom = require("react-dom");
1035
1036
 
1036
1037
  // src/hooks/useEscapeDismiss.ts
@@ -1132,7 +1133,11 @@ function UILoader({ size = 48, tone = "neutral", className, style, label = "Load
1132
1133
  var import_jsx_runtime14 = require("react/jsx-runtime");
1133
1134
  var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime14.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_runtime14.jsx)("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1134
1135
  function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
1136
+ const [bodyScrolled, setBodyScrolled] = React10.useState(false);
1135
1137
  useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
1138
+ React10.useEffect(() => {
1139
+ if (open) setBodyScrolled(false);
1140
+ }, [open]);
1136
1141
  if (!open) return null;
1137
1142
  const sizeClass = `fractal-modal-panel--${size}`;
1138
1143
  const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
@@ -1143,10 +1148,20 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
1143
1148
  className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
1144
1149
  onClick: (e) => e.stopPropagation(),
1145
1150
  children: [
1146
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "fractal-modal-title-row", children: [
1147
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
1148
- !noClose && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CloseIcon, {}) })
1149
- ] }),
1151
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1152
+ "div",
1153
+ {
1154
+ className: cn(
1155
+ "fractal-modal-title-row",
1156
+ scrollable && "fractal-modal-title-row--scrollable",
1157
+ scrollable && bodyScrolled && "fractal-modal-title-row--scrolled"
1158
+ ),
1159
+ children: [
1160
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
1161
+ !noClose && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CloseIcon, {}) })
1162
+ ]
1163
+ }
1164
+ ),
1150
1165
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1151
1166
  "div",
1152
1167
  {
@@ -1157,6 +1172,7 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
1157
1172
  loading && "fractal-modal-body--loading",
1158
1173
  scrollable && "fractal-modal-body--scrollable"
1159
1174
  ),
1175
+ onScroll: scrollable ? (event) => setBodyScrolled(event.currentTarget.scrollTop > 0) : void 0,
1160
1176
  children: loading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UILoader, { label: loadingLabel }) : children
1161
1177
  }
1162
1178
  ),
@@ -1188,7 +1204,7 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
1188
1204
  }
1189
1205
 
1190
1206
  // src/components/Dropdown/Dropdown.tsx
1191
- var React10 = __toESM(require("react"), 1);
1207
+ var React11 = __toESM(require("react"), 1);
1192
1208
  var import_fractal_icons8 = require("@mirror-physics/fractal-icons");
1193
1209
  var import_jsx_runtime16 = require("react/jsx-runtime");
1194
1210
  var MARGIN = 4;
@@ -1212,10 +1228,10 @@ function Dropdown({
1212
1228
  closeOnSelect = true,
1213
1229
  disabled = false
1214
1230
  }) {
1215
- const [open, setOpen] = React10.useState(false);
1216
- const triggerRef = React10.useRef(null);
1217
- const panelRef = React10.useRef(null);
1218
- const [panelStyle, setPanelStyle] = React10.useState({});
1231
+ const [open, setOpen] = React11.useState(false);
1232
+ const triggerRef = React11.useRef(null);
1233
+ const panelRef = React11.useRef(null);
1234
+ const [panelStyle, setPanelStyle] = React11.useState({});
1219
1235
  const visibleItems = items.filter(
1220
1236
  (item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
1221
1237
  );
@@ -1225,7 +1241,7 @@ function Dropdown({
1225
1241
  const isUp = direction === "up";
1226
1242
  const isHorizontalDirection = direction === "left" || direction === "right";
1227
1243
  const ChevronIcon = direction === "up" ? import_fractal_icons8.ChevronUp : direction === "left" ? import_fractal_icons8.ChevronLeft : direction === "right" ? import_fractal_icons8.ChevronRight : import_fractal_icons8.ChevronDown;
1228
- React10.useLayoutEffect(() => {
1244
+ React11.useLayoutEffect(() => {
1229
1245
  if (!open || !triggerRef.current || !panelRef.current) return;
1230
1246
  const triggerRect = triggerRef.current.getBoundingClientRect();
1231
1247
  const panelRect = panelRef.current.getBoundingClientRect();
@@ -1276,7 +1292,7 @@ function Dropdown({
1276
1292
  }
1277
1293
  setPanelStyle({ top, left, right });
1278
1294
  }, [open, direction, isHorizontalDirection, isUp, align]);
1279
- React10.useEffect(() => {
1295
+ React11.useEffect(() => {
1280
1296
  if (!open) return;
1281
1297
  const handleClickOutside = (e) => {
1282
1298
  const target = e.target;
@@ -1328,14 +1344,14 @@ function Dropdown({
1328
1344
  const topDivider = item.border === "top" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
1329
1345
  const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fractal-dropdown-separator" }) : null;
1330
1346
  if (item.kind === "header") {
1331
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React10.Fragment, { children: [
1347
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React11.Fragment, { children: [
1332
1348
  topDivider,
1333
1349
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
1334
1350
  bottomDivider
1335
1351
  ] }, `header-${index}`);
1336
1352
  }
1337
1353
  const isSelected = item.value === selectedValue;
1338
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React10.Fragment, { children: [
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React11.Fragment, { children: [
1339
1355
  topDivider,
1340
1356
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1341
1357
  "button",
@@ -1365,9 +1381,9 @@ function Dropdown({
1365
1381
  }
1366
1382
 
1367
1383
  // src/components/Link/Link.tsx
1368
- var React11 = __toESM(require("react"), 1);
1384
+ var React12 = __toESM(require("react"), 1);
1369
1385
  var import_jsx_runtime17 = require("react/jsx-runtime");
1370
- var Link = React11.forwardRef(
1386
+ var Link = React12.forwardRef(
1371
1387
  ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1372
1388
  "a",
1373
1389
  {
@@ -1380,9 +1396,9 @@ var Link = React11.forwardRef(
1380
1396
  Link.displayName = "Link";
1381
1397
 
1382
1398
  // src/components/Chip/Chip.tsx
1383
- var React12 = __toESM(require("react"), 1);
1399
+ var React13 = __toESM(require("react"), 1);
1384
1400
  var import_jsx_runtime18 = require("react/jsx-runtime");
1385
- var Chip = React12.forwardRef(
1401
+ var Chip = React13.forwardRef(
1386
1402
  ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1387
1403
  "span",
1388
1404
  {
@@ -1460,6 +1476,7 @@ function SortableTable({
1460
1476
  highlightRow,
1461
1477
  selection,
1462
1478
  isRowDisabled,
1479
+ isRowSelectionDisabled,
1463
1480
  onRowClick,
1464
1481
  onRowDoubleClick,
1465
1482
  rowAction
@@ -1507,7 +1524,7 @@ function SortableTable({
1507
1524
  const startIndex = (page - 1) * pageSize;
1508
1525
  return sorted.slice(startIndex, startIndex + pageSize);
1509
1526
  }, [pagination, sorted]);
1510
- const selectableRows = selection ? data.filter((row) => !isRowDisabled?.(row)) : [];
1527
+ const selectableRows = selection ? data.filter((row) => !isRowDisabled?.(row) && !isRowSelectionDisabled?.(row)) : [];
1511
1528
  const selectedRowCount = selection ? selectableRows.filter(selection.isSelected).length : 0;
1512
1529
  const allRowsSelected = selectableRows.length > 0 && selectedRowCount === selectableRows.length;
1513
1530
  const someRowsSelected = selectedRowCount > 0 && !allRowsSelected;
@@ -1604,6 +1621,7 @@ function SortableTable({
1604
1621
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { children: visibleRows.map((row, rowIndex) => {
1605
1622
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
1606
1623
  const disabled = isRowDisabled?.(row) ?? false;
1624
+ const selectionDisabled = disabled || (isRowSelectionDisabled?.(row) ?? false);
1607
1625
  const interactive = !disabled && Boolean(onRowClick || onRowDoubleClick);
1608
1626
  const action = !disabled && rowAction ? {
1609
1627
  label: rowAction.label(row, rowIndex),
@@ -1637,11 +1655,11 @@ function SortableTable({
1637
1655
  Checkbox,
1638
1656
  {
1639
1657
  "aria-label": selection.getRowLabel(row),
1640
- checked: !disabled && selection.isSelected(row),
1641
- disabled,
1658
+ checked: !selectionDisabled && selection.isSelected(row),
1659
+ disabled: selectionDisabled,
1642
1660
  onClick: (event) => event.stopPropagation(),
1643
1661
  onCheckedChange: (checked) => {
1644
- if (!disabled) selection.onSelectedChange(row, checked);
1662
+ if (!selectionDisabled) selection.onSelectedChange(row, checked);
1645
1663
  }
1646
1664
  }
1647
1665
  ) }),
@@ -1804,14 +1822,14 @@ function Tabs({
1804
1822
  }
1805
1823
 
1806
1824
  // src/components/ContentSwitcher/ContentSwitcher.tsx
1807
- var React13 = __toESM(require("react"), 1);
1825
+ var React14 = __toESM(require("react"), 1);
1808
1826
  var import_jsx_runtime22 = require("react/jsx-runtime");
1809
1827
  function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1810
- const switcherRef = React13.useRef(null);
1811
- const buttonRefs = React13.useRef([]);
1812
- const indicatorMotionReadyRef = React13.useRef(false);
1828
+ const switcherRef = React14.useRef(null);
1829
+ const buttonRefs = React14.useRef([]);
1830
+ const indicatorMotionReadyRef = React14.useRef(false);
1813
1831
  const activeIndex = items.findIndex((item) => item.value === value);
1814
- React13.useLayoutEffect(() => {
1832
+ React14.useLayoutEffect(() => {
1815
1833
  const switcher = switcherRef.current;
1816
1834
  const activeButton = buttonRefs.current[activeIndex];
1817
1835
  let motionFrame = 0;
@@ -2174,9 +2192,9 @@ function SurfaceGhost({ className, title, lines = 3, ...props }) {
2174
2192
  }
2175
2193
 
2176
2194
  // src/components/Sidebar/Sidebar.tsx
2177
- var React14 = __toESM(require("react"), 1);
2195
+ var React15 = __toESM(require("react"), 1);
2178
2196
  var import_jsx_runtime26 = require("react/jsx-runtime");
2179
- var Sidebar = React14.forwardRef(
2197
+ var Sidebar = React15.forwardRef(
2180
2198
  ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2181
2199
  "aside",
2182
2200
  {
@@ -2189,11 +2207,11 @@ var Sidebar = React14.forwardRef(
2189
2207
  )
2190
2208
  );
2191
2209
  Sidebar.displayName = "Sidebar";
2192
- var SidebarHeader = React14.forwardRef(
2210
+ var SidebarHeader = React15.forwardRef(
2193
2211
  ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
2194
2212
  );
2195
2213
  SidebarHeader.displayName = "SidebarHeader";
2196
- var SidebarBrand = React14.forwardRef(
2214
+ var SidebarBrand = React15.forwardRef(
2197
2215
  ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
2198
2216
  );
2199
2217
  SidebarBrand.displayName = "SidebarBrand";
@@ -2224,15 +2242,15 @@ function SidebarAccountMenu({
2224
2242
  }
2225
2243
  );
2226
2244
  }
2227
- var SidebarNav = React14.forwardRef(
2245
+ var SidebarNav = React15.forwardRef(
2228
2246
  ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
2229
2247
  );
2230
2248
  SidebarNav.displayName = "SidebarNav";
2231
- var SidebarSection = React14.forwardRef(
2249
+ var SidebarSection = React15.forwardRef(
2232
2250
  ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
2233
2251
  );
2234
2252
  SidebarSection.displayName = "SidebarSection";
2235
- var SidebarNavItem = React14.forwardRef(
2253
+ var SidebarNavItem = React15.forwardRef(
2236
2254
  ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
2237
2255
  "button",
2238
2256
  {
@@ -2251,7 +2269,7 @@ var SidebarNavItem = React14.forwardRef(
2251
2269
  )
2252
2270
  );
2253
2271
  SidebarNavItem.displayName = "SidebarNavItem";
2254
- var SidebarFooter = React14.forwardRef(
2272
+ var SidebarFooter = React15.forwardRef(
2255
2273
  ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
2256
2274
  );
2257
2275
  SidebarFooter.displayName = "SidebarFooter";
@@ -2290,17 +2308,17 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
2290
2308
  }
2291
2309
 
2292
2310
  // src/components/Textarea/Textarea.tsx
2293
- var React15 = __toESM(require("react"), 1);
2311
+ var React16 = __toESM(require("react"), 1);
2294
2312
  var import_jsx_runtime28 = require("react/jsx-runtime");
2295
- var Textarea = React15.forwardRef(
2313
+ var Textarea = React16.forwardRef(
2296
2314
  ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("textarea", { ref, className: cn("fractal-textarea", className), ...props })
2297
2315
  );
2298
2316
  Textarea.displayName = "Textarea";
2299
2317
 
2300
2318
  // src/components/TextButton/TextButton.tsx
2301
- var React16 = __toESM(require("react"), 1);
2319
+ var React17 = __toESM(require("react"), 1);
2302
2320
  var import_jsx_runtime29 = require("react/jsx-runtime");
2303
- var TextButton = React16.forwardRef(
2321
+ var TextButton = React17.forwardRef(
2304
2322
  ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2305
2323
  "button",
2306
2324
  {
@@ -2319,7 +2337,7 @@ var TextButton = React16.forwardRef(
2319
2337
  TextButton.displayName = "TextButton";
2320
2338
 
2321
2339
  // src/components/FileDropzone/FileDropzone.tsx
2322
- var React17 = __toESM(require("react"), 1);
2340
+ var React18 = __toESM(require("react"), 1);
2323
2341
  var import_fractal_icons13 = require("@mirror-physics/fractal-icons");
2324
2342
  var import_jsx_runtime30 = require("react/jsx-runtime");
2325
2343
  function FileDropzone({
@@ -2332,9 +2350,9 @@ function FileDropzone({
2332
2350
  description = "Files stay attached to this record.",
2333
2351
  className
2334
2352
  }) {
2335
- const inputId = React17.useId();
2336
- const inputRef = React17.useRef(null);
2337
- const [isDragging, setIsDragging] = React17.useState(false);
2353
+ const inputId = React18.useId();
2354
+ const inputRef = React18.useRef(null);
2355
+ const [isDragging, setIsDragging] = React18.useState(false);
2338
2356
  const addFiles = (nextFiles) => {
2339
2357
  if (disabled) return;
2340
2358
  const additions = Array.from(nextFiles);