@mirror-physics/fractal-ui 0.2.0-next.64 → 0.2.0-next.66

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.js CHANGED
@@ -927,6 +927,7 @@ function Toggle({ checked, onChange, label, className }) {
927
927
  }
928
928
 
929
929
  // src/components/Modal/Modal.tsx
930
+ import * as React10 from "react";
930
931
  import { createPortal } from "react-dom";
931
932
 
932
933
  // src/hooks/useEscapeDismiss.ts
@@ -1028,7 +1029,11 @@ function UILoader({ size = 48, tone = "neutral", className, style, label = "Load
1028
1029
  import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1029
1030
  var CloseIcon = () => /* @__PURE__ */ jsx13("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx13("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1030
1031
  function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
1032
+ const [bodyScrolled, setBodyScrolled] = React10.useState(false);
1031
1033
  useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
1034
+ React10.useEffect(() => {
1035
+ if (open) setBodyScrolled(false);
1036
+ }, [open]);
1032
1037
  if (!open) return null;
1033
1038
  const sizeClass = `fractal-modal-panel--${size}`;
1034
1039
  const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
@@ -1039,10 +1044,20 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
1039
1044
  className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
1040
1045
  onClick: (e) => e.stopPropagation(),
1041
1046
  children: [
1042
- /* @__PURE__ */ jsxs12("div", { className: "fractal-modal-title-row", children: [
1043
- /* @__PURE__ */ jsx13("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
1044
- !noClose && /* @__PURE__ */ jsx13("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ jsx13(CloseIcon, {}) })
1045
- ] }),
1047
+ /* @__PURE__ */ jsxs12(
1048
+ "div",
1049
+ {
1050
+ className: cn(
1051
+ "fractal-modal-title-row",
1052
+ scrollable && "fractal-modal-title-row--scrollable",
1053
+ scrollable && bodyScrolled && "fractal-modal-title-row--scrolled"
1054
+ ),
1055
+ children: [
1056
+ /* @__PURE__ */ jsx13("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
1057
+ !noClose && /* @__PURE__ */ jsx13("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ jsx13(CloseIcon, {}) })
1058
+ ]
1059
+ }
1060
+ ),
1046
1061
  /* @__PURE__ */ jsx13(
1047
1062
  "div",
1048
1063
  {
@@ -1053,6 +1068,7 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
1053
1068
  loading && "fractal-modal-body--loading",
1054
1069
  scrollable && "fractal-modal-body--scrollable"
1055
1070
  ),
1071
+ onScroll: scrollable ? (event) => setBodyScrolled(event.currentTarget.scrollTop > 0) : void 0,
1056
1072
  children: loading ? /* @__PURE__ */ jsx13(UILoader, { label: loadingLabel }) : children
1057
1073
  }
1058
1074
  ),
@@ -1084,7 +1100,7 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
1084
1100
  }
1085
1101
 
1086
1102
  // src/components/Dropdown/Dropdown.tsx
1087
- import * as React10 from "react";
1103
+ import * as React11 from "react";
1088
1104
  import { ChevronDown, ChevronLeft, ChevronRight as ChevronRight2, ChevronUp } from "@mirror-physics/fractal-icons";
1089
1105
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1090
1106
  var MARGIN = 4;
@@ -1108,10 +1124,10 @@ function Dropdown({
1108
1124
  closeOnSelect = true,
1109
1125
  disabled = false
1110
1126
  }) {
1111
- const [open, setOpen] = React10.useState(false);
1112
- const triggerRef = React10.useRef(null);
1113
- const panelRef = React10.useRef(null);
1114
- const [panelStyle, setPanelStyle] = React10.useState({});
1127
+ const [open, setOpen] = React11.useState(false);
1128
+ const triggerRef = React11.useRef(null);
1129
+ const panelRef = React11.useRef(null);
1130
+ const [panelStyle, setPanelStyle] = React11.useState({});
1115
1131
  const visibleItems = items.filter(
1116
1132
  (item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
1117
1133
  );
@@ -1121,7 +1137,7 @@ function Dropdown({
1121
1137
  const isUp = direction === "up";
1122
1138
  const isHorizontalDirection = direction === "left" || direction === "right";
1123
1139
  const ChevronIcon = direction === "up" ? ChevronUp : direction === "left" ? ChevronLeft : direction === "right" ? ChevronRight2 : ChevronDown;
1124
- React10.useLayoutEffect(() => {
1140
+ React11.useLayoutEffect(() => {
1125
1141
  if (!open || !triggerRef.current || !panelRef.current) return;
1126
1142
  const triggerRect = triggerRef.current.getBoundingClientRect();
1127
1143
  const panelRect = panelRef.current.getBoundingClientRect();
@@ -1172,7 +1188,7 @@ function Dropdown({
1172
1188
  }
1173
1189
  setPanelStyle({ top, left, right });
1174
1190
  }, [open, direction, isHorizontalDirection, isUp, align]);
1175
- React10.useEffect(() => {
1191
+ React11.useEffect(() => {
1176
1192
  if (!open) return;
1177
1193
  const handleClickOutside = (e) => {
1178
1194
  const target = e.target;
@@ -1224,14 +1240,14 @@ function Dropdown({
1224
1240
  const topDivider = item.border === "top" ? /* @__PURE__ */ jsx15("div", { className: "fractal-dropdown-separator" }) : null;
1225
1241
  const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ jsx15("div", { className: "fractal-dropdown-separator" }) : null;
1226
1242
  if (item.kind === "header") {
1227
- return /* @__PURE__ */ jsxs14(React10.Fragment, { children: [
1243
+ return /* @__PURE__ */ jsxs14(React11.Fragment, { children: [
1228
1244
  topDivider,
1229
1245
  /* @__PURE__ */ jsx15("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
1230
1246
  bottomDivider
1231
1247
  ] }, `header-${index}`);
1232
1248
  }
1233
1249
  const isSelected = item.value === selectedValue;
1234
- return /* @__PURE__ */ jsxs14(React10.Fragment, { children: [
1250
+ return /* @__PURE__ */ jsxs14(React11.Fragment, { children: [
1235
1251
  topDivider,
1236
1252
  /* @__PURE__ */ jsxs14(
1237
1253
  "button",
@@ -1261,9 +1277,9 @@ function Dropdown({
1261
1277
  }
1262
1278
 
1263
1279
  // src/components/Link/Link.tsx
1264
- import * as React11 from "react";
1280
+ import * as React12 from "react";
1265
1281
  import { jsx as jsx16 } from "react/jsx-runtime";
1266
- var Link = React11.forwardRef(
1282
+ var Link = React12.forwardRef(
1267
1283
  ({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ jsx16(
1268
1284
  "a",
1269
1285
  {
@@ -1276,9 +1292,9 @@ var Link = React11.forwardRef(
1276
1292
  Link.displayName = "Link";
1277
1293
 
1278
1294
  // src/components/Chip/Chip.tsx
1279
- import * as React12 from "react";
1295
+ import * as React13 from "react";
1280
1296
  import { jsx as jsx17 } from "react/jsx-runtime";
1281
- var Chip = React12.forwardRef(
1297
+ var Chip = React13.forwardRef(
1282
1298
  ({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ jsx17(
1283
1299
  "span",
1284
1300
  {
@@ -1334,12 +1350,13 @@ function Checkbox({
1334
1350
  }
1335
1351
 
1336
1352
  // src/components/SortableTable/SortableTable.tsx
1337
- import { useMemo as useMemo2, useState as useState5 } from "react";
1353
+ import { useMemo as useMemo2, useState as useState6 } from "react";
1338
1354
  import { ArrowUp, ArrowDown, ArrowsUpDown } from "@mirror-physics/fractal-icons";
1339
1355
  import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
1340
1356
  function SortableTable({
1341
1357
  columns,
1342
1358
  data,
1359
+ "aria-label": ariaLabel,
1343
1360
  emptyMessage,
1344
1361
  header,
1345
1362
  size = "md",
@@ -1359,8 +1376,8 @@ function SortableTable({
1359
1376
  onRowDoubleClick,
1360
1377
  rowAction
1361
1378
  }) {
1362
- const [internalKey, setInternalKey] = useState5(defaultSortKey ?? null);
1363
- const [internalDirection, setInternalDirection] = useState5(defaultSortDirection);
1379
+ const [internalKey, setInternalKey] = useState6(defaultSortKey ?? null);
1380
+ const [internalDirection, setInternalDirection] = useState6(defaultSortDirection);
1364
1381
  const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
1365
1382
  const activeKey = isControlled ? controlledKey : internalKey;
1366
1383
  const activeDirection = isControlled ? controlledDirection : internalDirection;
@@ -1430,7 +1447,7 @@ function SortableTable({
1430
1447
  };
1431
1448
  return /* @__PURE__ */ jsx19("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), children: /* @__PURE__ */ jsxs16("div", { className: "fractal-sortable-table-surface", children: [
1432
1449
  header && /* @__PURE__ */ jsx19("div", { className: "fractal-sortable-table-header", children: header }),
1433
- visibleRows.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsxs16("table", { className: "fractal-sortable-table-table", children: [
1450
+ visibleRows.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsxs16("table", { "aria-label": ariaLabel, className: "fractal-sortable-table-table", children: [
1434
1451
  /* @__PURE__ */ jsx19("thead", { children: /* @__PURE__ */ jsxs16("tr", { className: "fractal-sortable-table-thead-row", children: [
1435
1452
  selection && /* @__PURE__ */ jsx19(
1436
1453
  "th",
@@ -1462,6 +1479,7 @@ function SortableTable({
1462
1479
  "th",
1463
1480
  {
1464
1481
  className: "fractal-sortable-table-th",
1482
+ scope: "col",
1465
1483
  style: { width: col.width },
1466
1484
  children: col.header
1467
1485
  },
@@ -1472,6 +1490,7 @@ function SortableTable({
1472
1490
  "th",
1473
1491
  {
1474
1492
  className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
1493
+ scope: "col",
1475
1494
  style: { width: col.width },
1476
1495
  children: /* @__PURE__ */ jsxs16(
1477
1496
  "button",
@@ -1563,7 +1582,7 @@ function SortableTable({
1563
1582
  }
1564
1583
 
1565
1584
  // src/components/Tabs/Tabs.tsx
1566
- import { useId as useId2, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState6 } from "react";
1585
+ import { useId as useId2, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState7 } from "react";
1567
1586
  import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
1568
1587
  function Tabs({
1569
1588
  items,
@@ -1576,14 +1595,14 @@ function Tabs({
1576
1595
  variant = "line"
1577
1596
  }) {
1578
1597
  const reactId = useId2();
1579
- const [internalValue, setInternalValue] = useState6(
1598
+ const [internalValue, setInternalValue] = useState7(
1580
1599
  defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
1581
1600
  );
1582
1601
  const isControlled = controlledValue !== void 0;
1583
1602
  const activeId = isControlled ? controlledValue : internalValue;
1584
1603
  const tabListRef = useRef5(null);
1585
1604
  const tabRefs = useRef5({});
1586
- const [indicator, setIndicator] = useState6(null);
1605
+ const [indicator, setIndicator] = useState7(null);
1587
1606
  useLayoutEffect2(() => {
1588
1607
  const updateIndicator = () => {
1589
1608
  const activeTab = tabRefs.current[activeId];
@@ -1697,14 +1716,14 @@ function Tabs({
1697
1716
  }
1698
1717
 
1699
1718
  // src/components/ContentSwitcher/ContentSwitcher.tsx
1700
- import * as React13 from "react";
1719
+ import * as React14 from "react";
1701
1720
  import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
1702
1721
  function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
1703
- const switcherRef = React13.useRef(null);
1704
- const buttonRefs = React13.useRef([]);
1705
- const indicatorMotionReadyRef = React13.useRef(false);
1722
+ const switcherRef = React14.useRef(null);
1723
+ const buttonRefs = React14.useRef([]);
1724
+ const indicatorMotionReadyRef = React14.useRef(false);
1706
1725
  const activeIndex = items.findIndex((item) => item.value === value);
1707
- React13.useLayoutEffect(() => {
1726
+ React14.useLayoutEffect(() => {
1708
1727
  const switcher = switcherRef.current;
1709
1728
  const activeButton = buttonRefs.current[activeIndex];
1710
1729
  let motionFrame = 0;
@@ -1799,7 +1818,7 @@ function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = f
1799
1818
  }
1800
1819
 
1801
1820
  // src/components/Disclosure/Disclosure.tsx
1802
- import { useId as useId3, useState as useState7 } from "react";
1821
+ import { useId as useId3, useState as useState8 } from "react";
1803
1822
  import { ChevronRight as ChevronRight3, ChevronDown as ChevronDown2 } from "@mirror-physics/fractal-icons";
1804
1823
  import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
1805
1824
  function Disclosure({
@@ -1816,7 +1835,7 @@ function Disclosure({
1816
1835
  const reactId = useId3();
1817
1836
  const headerId = `${reactId}-header`;
1818
1837
  const panelId = `${reactId}-panel`;
1819
- const [internalOpen, setInternalOpen] = useState7(defaultOpen);
1838
+ const [internalOpen, setInternalOpen] = useState8(defaultOpen);
1820
1839
  const isControlled = controlledOpen !== void 0;
1821
1840
  const isOpen = isControlled ? controlledOpen : internalOpen;
1822
1841
  const toggle = () => {
@@ -2067,9 +2086,9 @@ function SurfaceGhost({ className, title, lines = 3, ...props }) {
2067
2086
  }
2068
2087
 
2069
2088
  // src/components/Sidebar/Sidebar.tsx
2070
- import * as React14 from "react";
2089
+ import * as React15 from "react";
2071
2090
  import { Fragment as Fragment3, jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
2072
- var Sidebar = React14.forwardRef(
2091
+ var Sidebar = React15.forwardRef(
2073
2092
  ({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ jsx25(
2074
2093
  "aside",
2075
2094
  {
@@ -2082,11 +2101,11 @@ var Sidebar = React14.forwardRef(
2082
2101
  )
2083
2102
  );
2084
2103
  Sidebar.displayName = "Sidebar";
2085
- var SidebarHeader = React14.forwardRef(
2104
+ var SidebarHeader = React15.forwardRef(
2086
2105
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx25("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
2087
2106
  );
2088
2107
  SidebarHeader.displayName = "SidebarHeader";
2089
- var SidebarBrand = React14.forwardRef(
2108
+ var SidebarBrand = React15.forwardRef(
2090
2109
  ({ className, type = "button", ...props }, ref) => /* @__PURE__ */ jsx25("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
2091
2110
  );
2092
2111
  SidebarBrand.displayName = "SidebarBrand";
@@ -2117,15 +2136,15 @@ function SidebarAccountMenu({
2117
2136
  }
2118
2137
  );
2119
2138
  }
2120
- var SidebarNav = React14.forwardRef(
2139
+ var SidebarNav = React15.forwardRef(
2121
2140
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx25("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
2122
2141
  );
2123
2142
  SidebarNav.displayName = "SidebarNav";
2124
- var SidebarSection = React14.forwardRef(
2143
+ var SidebarSection = React15.forwardRef(
2125
2144
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx25("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
2126
2145
  );
2127
2146
  SidebarSection.displayName = "SidebarSection";
2128
- var SidebarNavItem = React14.forwardRef(
2147
+ var SidebarNavItem = React15.forwardRef(
2129
2148
  ({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ jsxs21(
2130
2149
  "button",
2131
2150
  {
@@ -2144,7 +2163,7 @@ var SidebarNavItem = React14.forwardRef(
2144
2163
  )
2145
2164
  );
2146
2165
  SidebarNavItem.displayName = "SidebarNavItem";
2147
- var SidebarFooter = React14.forwardRef(
2166
+ var SidebarFooter = React15.forwardRef(
2148
2167
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx25("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
2149
2168
  );
2150
2169
  SidebarFooter.displayName = "SidebarFooter";
@@ -2183,17 +2202,17 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
2183
2202
  }
2184
2203
 
2185
2204
  // src/components/Textarea/Textarea.tsx
2186
- import * as React15 from "react";
2205
+ import * as React16 from "react";
2187
2206
  import { jsx as jsx27 } from "react/jsx-runtime";
2188
- var Textarea = React15.forwardRef(
2207
+ var Textarea = React16.forwardRef(
2189
2208
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx27("textarea", { ref, className: cn("fractal-textarea", className), ...props })
2190
2209
  );
2191
2210
  Textarea.displayName = "Textarea";
2192
2211
 
2193
2212
  // src/components/TextButton/TextButton.tsx
2194
- import * as React16 from "react";
2213
+ import * as React17 from "react";
2195
2214
  import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
2196
- var TextButton = React16.forwardRef(
2215
+ var TextButton = React17.forwardRef(
2197
2216
  ({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ jsxs23(
2198
2217
  "button",
2199
2218
  {
@@ -2212,7 +2231,7 @@ var TextButton = React16.forwardRef(
2212
2231
  TextButton.displayName = "TextButton";
2213
2232
 
2214
2233
  // src/components/FileDropzone/FileDropzone.tsx
2215
- import * as React17 from "react";
2234
+ import * as React18 from "react";
2216
2235
  import { Close as Close2, FileArrowUp } from "@mirror-physics/fractal-icons";
2217
2236
  import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
2218
2237
  function FileDropzone({
@@ -2225,9 +2244,9 @@ function FileDropzone({
2225
2244
  description = "Files stay attached to this record.",
2226
2245
  className
2227
2246
  }) {
2228
- const inputId = React17.useId();
2229
- const inputRef = React17.useRef(null);
2230
- const [isDragging, setIsDragging] = React17.useState(false);
2247
+ const inputId = React18.useId();
2248
+ const inputRef = React18.useRef(null);
2249
+ const [isDragging, setIsDragging] = React18.useState(false);
2231
2250
  const addFiles = (nextFiles) => {
2232
2251
  if (disabled) return;
2233
2252
  const additions = Array.from(nextFiles);