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

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.d.ts CHANGED
@@ -255,6 +255,16 @@ interface SortableTableRowAction<T> {
255
255
  label: (row: T, index: number) => string;
256
256
  icon: (row: T, index: number) => ReactNode;
257
257
  }
258
+ interface SortableTableSelection<T> {
259
+ /** Returns whether a row is selected. Selection is controlled by the consumer. */
260
+ isSelected: (row: T) => boolean;
261
+ /** Called when an individual row or the select-all control changes selection. */
262
+ onSelectedChange: (row: T, selected: boolean) => void;
263
+ /** Accessible name for an individual row's checkbox. */
264
+ getRowLabel: (row: T) => string;
265
+ /** Accessible name for the header checkbox. */
266
+ selectAllLabel?: string;
267
+ }
258
268
  interface SortableTablePagination {
259
269
  page: number;
260
270
  pageSize: number;
@@ -262,6 +272,8 @@ interface SortableTablePagination {
262
272
  interface SortableTableProps<T> {
263
273
  columns: SortableTableColumn<T>[];
264
274
  data: T[];
275
+ /** Accessible name applied to the underlying table element. */
276
+ 'aria-label'?: string;
265
277
  emptyMessage?: string;
266
278
  header?: ReactNode;
267
279
  size?: 'sm' | 'md' | 'lg';
@@ -282,6 +294,10 @@ interface SortableTableProps<T> {
282
294
  */
283
295
  pagination?: SortableTablePagination;
284
296
  highlightRow?: (row: T, index: number) => boolean;
297
+ /** Adds a leading checkbox column with controlled row selection. */
298
+ selection?: SortableTableSelection<T>;
299
+ /** Disabled rows remain visible but cannot be selected or activated. */
300
+ isRowDisabled?: (row: T) => boolean;
285
301
  /** Invoked when a row is selected. Enables pointer and keyboard row activation. */
286
302
  onRowClick?: (row: T, index: number) => void;
287
303
  /** Invoked when a row is double-clicked. */
@@ -289,7 +305,7 @@ interface SortableTableProps<T> {
289
305
  /** Directional affordance displayed over the right edge of an interactive row. */
290
306
  rowAction?: SortableTableRowAction<T>;
291
307
  }
292
- declare function SortableTable<T>({ columns, data, emptyMessage, header, size, embedded, className, defaultSort, defaultSortKey, defaultSortDirection, sortKey: controlledKey, sortDirection: controlledDirection, onSortChange, pagination, highlightRow, onRowClick, onRowDoubleClick, rowAction, }: SortableTableProps<T>): React.JSX.Element;
308
+ declare function SortableTable<T>({ columns, data, 'aria-label': ariaLabel, emptyMessage, header, size, embedded, className, defaultSort, defaultSortKey, defaultSortDirection, sortKey: controlledKey, sortDirection: controlledDirection, onSortChange, pagination, highlightRow, selection, isRowDisabled, onRowClick, onRowDoubleClick, rowAction, }: SortableTableProps<T>): React.JSX.Element;
293
309
 
294
310
  interface TabItem {
295
311
  id: string;
@@ -545,4 +561,4 @@ declare function useEscapeDismiss(priority: number, handler: () => void, enabled
545
561
 
546
562
  declare function cn(...inputs: ClassValue[]): string;
547
563
 
548
- export { Alert, AlertDescription, AlertGhost, AlertTitle, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, Button, type ButtonColor, ButtonGhost, type ButtonGhostProps, type ButtonProps, type ButtonSize, type ButtonType, Card, CardContent, CardDescription, CardFooter, CardGhost, type CardGhostProps, CardHeader, CardTitle, Checkbox, CheckboxGhost, type CheckboxProps, Chip, ChipGhost, type ChipProps, type ChipTone, CodeBlock, type CodeBlockProps, ContentSwitcher, ContentSwitcherGhost, type ContentSwitcherItem, type ContentSwitcherProps, ConversationGhost, type ConversationGhostProps, DataTable, type DataTableColumn, DataTableGhost, type DataTableGhostProps, type DataTableProps, Disclosure, DisclosureGhost, type DisclosureProps, Dropdown, DropdownGhost, type DropdownItem, type DropdownProps, FeatureCard, type FeatureCardProps, FileDropzone, FileDropzoneGhost, type FileDropzoneProps, FolderCard, type FolderCardProps, type FormFieldGhostProps, Ghost, GhostLine, type GhostLineProps, type GhostProps, Input, InputGhost, type InputProps, Label, LabelGhost, type LabelProps, LatticeLoader, type LatticeLoaderProps, Link, LinkGhost, type LinkProps, type LinkSize, type LinkTheme, Modal, ModalGhost, type ModalProps, NumberInput, type NumberInputProps, Pagination, PaginationGhost, type PaginationProps, PasswordInput, type PasswordInputProps, PromptCard, PromptCardGhost, type PromptCardProps, type PromptCardTone, PromptGrid, type PromptGridProps, SidePanel, SidePanelGhost, type SidePanelProps, Sidebar, SidebarAccountMenu, type SidebarAccountMenuProps, SidebarBrand, SidebarFooter, SidebarGhost, type SidebarGhostProps, SidebarHeader, SidebarNav, SidebarNavItem, type SidebarNavItemProps, type SidebarProps, SidebarSection, type SortDirection, SortableTable, type SortableTableColumn, type SortableTableDefaultSort, SortableTableGhost, type SortableTablePagination, type SortableTableProps, type SortableTableRowAction, type SurfaceGhostProps, type TabItem, TableSearch, type TableSearchProps, type TableSearchType, Tabs, TabsGhost, type TabsProps, type TabsVariant, TextButton, TextButtonGhost, type TextButtonIconPosition, type TextButtonProps, type TextButtonSize, type TextButtonTone, Textarea, TextareaGhost, type TextareaProps, Toggle, ToggleGhost, type ToggleProps, UILoader, type UILoaderProps, type UILoaderTone, cn, useEscapeDismiss };
564
+ export { Alert, AlertDescription, AlertGhost, AlertTitle, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, Button, type ButtonColor, ButtonGhost, type ButtonGhostProps, type ButtonProps, type ButtonSize, type ButtonType, Card, CardContent, CardDescription, CardFooter, CardGhost, type CardGhostProps, CardHeader, CardTitle, Checkbox, CheckboxGhost, type CheckboxProps, Chip, ChipGhost, type ChipProps, type ChipTone, CodeBlock, type CodeBlockProps, ContentSwitcher, ContentSwitcherGhost, type ContentSwitcherItem, type ContentSwitcherProps, ConversationGhost, type ConversationGhostProps, DataTable, type DataTableColumn, DataTableGhost, type DataTableGhostProps, type DataTableProps, Disclosure, DisclosureGhost, type DisclosureProps, Dropdown, DropdownGhost, type DropdownItem, type DropdownProps, FeatureCard, type FeatureCardProps, FileDropzone, FileDropzoneGhost, type FileDropzoneProps, FolderCard, type FolderCardProps, type FormFieldGhostProps, Ghost, GhostLine, type GhostLineProps, type GhostProps, Input, InputGhost, type InputProps, Label, LabelGhost, type LabelProps, LatticeLoader, type LatticeLoaderProps, Link, LinkGhost, type LinkProps, type LinkSize, type LinkTheme, Modal, ModalGhost, type ModalProps, NumberInput, type NumberInputProps, Pagination, PaginationGhost, type PaginationProps, PasswordInput, type PasswordInputProps, PromptCard, PromptCardGhost, type PromptCardProps, type PromptCardTone, PromptGrid, type PromptGridProps, SidePanel, SidePanelGhost, type SidePanelProps, Sidebar, SidebarAccountMenu, type SidebarAccountMenuProps, SidebarBrand, SidebarFooter, SidebarGhost, type SidebarGhostProps, SidebarHeader, SidebarNav, SidebarNavItem, type SidebarNavItemProps, type SidebarProps, SidebarSection, type SortDirection, SortableTable, type SortableTableColumn, type SortableTableDefaultSort, SortableTableGhost, type SortableTablePagination, type SortableTableProps, type SortableTableRowAction, type SortableTableSelection, type SurfaceGhostProps, type TabItem, TableSearch, type TableSearchProps, type TableSearchType, Tabs, TabsGhost, type TabsProps, type TabsVariant, TextButton, TextButtonGhost, type TextButtonIconPosition, type TextButtonProps, type TextButtonSize, type TextButtonTone, Textarea, TextareaGhost, type TextareaProps, Toggle, ToggleGhost, type ToggleProps, UILoader, type UILoaderProps, type UILoaderTone, cn, useEscapeDismiss };
package/dist/index.js CHANGED
@@ -1340,6 +1340,7 @@ import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
1340
1340
  function SortableTable({
1341
1341
  columns,
1342
1342
  data,
1343
+ "aria-label": ariaLabel,
1343
1344
  emptyMessage,
1344
1345
  header,
1345
1346
  size = "md",
@@ -1353,6 +1354,8 @@ function SortableTable({
1353
1354
  onSortChange,
1354
1355
  pagination,
1355
1356
  highlightRow,
1357
+ selection,
1358
+ isRowDisabled,
1356
1359
  onRowClick,
1357
1360
  onRowDoubleClick,
1358
1361
  rowAction
@@ -1400,6 +1403,10 @@ function SortableTable({
1400
1403
  const startIndex = (page - 1) * pageSize;
1401
1404
  return sorted.slice(startIndex, startIndex + pageSize);
1402
1405
  }, [pagination, sorted]);
1406
+ const selectableRows = selection ? data.filter((row) => !isRowDisabled?.(row)) : [];
1407
+ const selectedRowCount = selection ? selectableRows.filter(selection.isSelected).length : 0;
1408
+ const allRowsSelected = selectableRows.length > 0 && selectedRowCount === selectableRows.length;
1409
+ const someRowsSelected = selectedRowCount > 0 && !allRowsSelected;
1403
1410
  const handleSortClick = (key) => {
1404
1411
  let nextDirection;
1405
1412
  if (!activeKey || !activeDirection) {
@@ -1424,62 +1431,92 @@ function SortableTable({
1424
1431
  };
1425
1432
  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: [
1426
1433
  header && /* @__PURE__ */ jsx19("div", { className: "fractal-sortable-table-header", children: header }),
1427
- visibleRows.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsxs16("table", { className: "fractal-sortable-table-table", children: [
1428
- /* @__PURE__ */ jsx19("thead", { children: /* @__PURE__ */ jsx19("tr", { className: "fractal-sortable-table-thead-row", children: columns.map((col) => {
1429
- const isActive = activeKey === col.key && activeDirection !== null;
1430
- if (!col.sortable) {
1434
+ 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: [
1435
+ /* @__PURE__ */ jsx19("thead", { children: /* @__PURE__ */ jsxs16("tr", { className: "fractal-sortable-table-thead-row", children: [
1436
+ selection && /* @__PURE__ */ jsx19(
1437
+ "th",
1438
+ {
1439
+ className: "fractal-sortable-table-th fractal-sortable-table-selection-cell",
1440
+ scope: "col",
1441
+ children: /* @__PURE__ */ jsx19(
1442
+ Checkbox,
1443
+ {
1444
+ "aria-label": selection.selectAllLabel ?? "Select all rows",
1445
+ checked: allRowsSelected,
1446
+ disabled: selectableRows.length === 0,
1447
+ indeterminate: someRowsSelected,
1448
+ onCheckedChange: (checked) => {
1449
+ selectableRows.forEach((row) => {
1450
+ if (selection.isSelected(row) !== checked) {
1451
+ selection.onSelectedChange(row, checked);
1452
+ }
1453
+ });
1454
+ }
1455
+ }
1456
+ )
1457
+ }
1458
+ ),
1459
+ columns.map((col) => {
1460
+ const isActive = activeKey === col.key && activeDirection !== null;
1461
+ if (!col.sortable) {
1462
+ return /* @__PURE__ */ jsx19(
1463
+ "th",
1464
+ {
1465
+ className: "fractal-sortable-table-th",
1466
+ scope: "col",
1467
+ style: { width: col.width },
1468
+ children: col.header
1469
+ },
1470
+ col.key
1471
+ );
1472
+ }
1431
1473
  return /* @__PURE__ */ jsx19(
1432
1474
  "th",
1433
1475
  {
1434
- className: "fractal-sortable-table-th",
1476
+ className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
1477
+ scope: "col",
1435
1478
  style: { width: col.width },
1436
- children: col.header
1479
+ children: /* @__PURE__ */ jsxs16(
1480
+ "button",
1481
+ {
1482
+ type: "button",
1483
+ className: cn(
1484
+ "fractal-sortable-table-sort-button",
1485
+ isActive && "fractal-sortable-table-sort-button--active"
1486
+ ),
1487
+ onClick: () => handleSortClick(col.key),
1488
+ "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
1489
+ children: [
1490
+ /* @__PURE__ */ jsx19("span", { children: col.header }),
1491
+ /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ jsx19(ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ jsx19(ArrowDown, { size: 14 }) : /* @__PURE__ */ jsx19(ArrowsUpDown, { size: 14 }) })
1492
+ ]
1493
+ }
1494
+ )
1437
1495
  },
1438
1496
  col.key
1439
1497
  );
1440
- }
1441
- return /* @__PURE__ */ jsx19(
1442
- "th",
1443
- {
1444
- className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
1445
- style: { width: col.width },
1446
- children: /* @__PURE__ */ jsxs16(
1447
- "button",
1448
- {
1449
- type: "button",
1450
- className: cn(
1451
- "fractal-sortable-table-sort-button",
1452
- isActive && "fractal-sortable-table-sort-button--active"
1453
- ),
1454
- onClick: () => handleSortClick(col.key),
1455
- "aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
1456
- children: [
1457
- /* @__PURE__ */ jsx19("span", { children: col.header }),
1458
- /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ jsx19(ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ jsx19(ArrowDown, { size: 14 }) : /* @__PURE__ */ jsx19(ArrowsUpDown, { size: 14 }) })
1459
- ]
1460
- }
1461
- )
1462
- },
1463
- col.key
1464
- );
1465
- }) }) }),
1498
+ })
1499
+ ] }) }),
1466
1500
  /* @__PURE__ */ jsx19("tbody", { children: visibleRows.map((row, rowIndex) => {
1467
1501
  const highlighted = highlightRow?.(row, rowIndex) ?? false;
1468
- const interactive = Boolean(onRowClick || onRowDoubleClick);
1469
- const action = rowAction ? {
1502
+ const disabled = isRowDisabled?.(row) ?? false;
1503
+ const interactive = !disabled && Boolean(onRowClick || onRowDoubleClick);
1504
+ const action = !disabled && rowAction ? {
1470
1505
  label: rowAction.label(row, rowIndex),
1471
1506
  icon: rowAction.icon(row, rowIndex)
1472
1507
  } : null;
1473
- return /* @__PURE__ */ jsx19(
1508
+ return /* @__PURE__ */ jsxs16(
1474
1509
  "tr",
1475
1510
  {
1476
1511
  className: cn(
1477
1512
  "fractal-sortable-table-row",
1478
1513
  highlighted && "fractal-sortable-table-row--highlighted",
1479
- interactive && "fractal-sortable-table-row--interactive"
1514
+ interactive && "fractal-sortable-table-row--interactive",
1515
+ disabled && "fractal-sortable-table-row--disabled"
1480
1516
  ),
1481
- onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
1482
- onDoubleClick: onRowDoubleClick ? () => onRowDoubleClick(row, rowIndex) : void 0,
1517
+ "data-disabled": disabled || void 0,
1518
+ onClick: !disabled && onRowClick ? () => onRowClick(row, rowIndex) : void 0,
1519
+ onDoubleClick: !disabled && onRowDoubleClick ? () => onRowDoubleClick(row, rowIndex) : void 0,
1483
1520
  onKeyDown: interactive ? (event) => {
1484
1521
  if (event.key === "Enter" || event.key === " ") {
1485
1522
  event.preventDefault();
@@ -1488,23 +1525,38 @@ function SortableTable({
1488
1525
  }
1489
1526
  } : void 0,
1490
1527
  "aria-label": action?.label,
1528
+ "aria-disabled": disabled || void 0,
1491
1529
  role: interactive ? "button" : void 0,
1492
1530
  tabIndex: interactive ? 0 : void 0,
1493
- children: columns.map((col, columnIndex) => /* @__PURE__ */ jsxs16(
1494
- "td",
1495
- {
1496
- className: cn(
1497
- "fractal-sortable-table-td",
1498
- action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1499
- ),
1500
- style: { width: col.width, textAlign: col.align ?? "left" },
1501
- children: [
1502
- col.render(row, rowIndex),
1503
- action && columnIndex === columns.length - 1 && /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
1504
- ]
1505
- },
1506
- col.key
1507
- ))
1531
+ children: [
1532
+ selection && /* @__PURE__ */ jsx19("td", { className: "fractal-sortable-table-td fractal-sortable-table-selection-cell", children: /* @__PURE__ */ jsx19(
1533
+ Checkbox,
1534
+ {
1535
+ "aria-label": selection.getRowLabel(row),
1536
+ checked: !disabled && selection.isSelected(row),
1537
+ disabled,
1538
+ onClick: (event) => event.stopPropagation(),
1539
+ onCheckedChange: (checked) => {
1540
+ if (!disabled) selection.onSelectedChange(row, checked);
1541
+ }
1542
+ }
1543
+ ) }),
1544
+ columns.map((col, columnIndex) => /* @__PURE__ */ jsxs16(
1545
+ "td",
1546
+ {
1547
+ className: cn(
1548
+ "fractal-sortable-table-td",
1549
+ action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
1550
+ ),
1551
+ style: { width: col.width, textAlign: col.align ?? "left" },
1552
+ children: [
1553
+ col.render(row, rowIndex),
1554
+ action && columnIndex === columns.length - 1 && /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
1555
+ ]
1556
+ },
1557
+ col.key
1558
+ ))
1559
+ ]
1508
1560
  },
1509
1561
  rowIndex
1510
1562
  );