@ai-matrx/design-system 0.21.8 → 0.21.10

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/data-table/copy-helpers.cjs.map +1 -1
  3. package/dist/data-table/copy-helpers.d.cts +1 -1
  4. package/dist/data-table/copy-helpers.d.ts +1 -1
  5. package/dist/data-table/copy-helpers.js.map +1 -1
  6. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  7. package/dist/data-table/data-row-inspector.js.map +1 -1
  8. package/dist/data-table/data-row-window.cjs.map +1 -1
  9. package/dist/data-table/data-row-window.js.map +1 -1
  10. package/dist/data-table/filter-engine.cjs +8 -3
  11. package/dist/data-table/filter-engine.cjs.map +1 -1
  12. package/dist/data-table/filter-engine.d.cts +4 -2
  13. package/dist/data-table/filter-engine.d.ts +4 -2
  14. package/dist/data-table/filter-engine.js +8 -3
  15. package/dist/data-table/filter-engine.js.map +1 -1
  16. package/dist/data-table/host.d.cts +1 -1
  17. package/dist/data-table/host.d.ts +1 -1
  18. package/dist/data-table/index.cjs +107 -32
  19. package/dist/data-table/index.cjs.map +1 -1
  20. package/dist/data-table/index.d.cts +2 -2
  21. package/dist/data-table/index.d.ts +2 -2
  22. package/dist/data-table/index.js +107 -32
  23. package/dist/data-table/index.js.map +1 -1
  24. package/dist/data-table/infer-filter.cjs +16 -6
  25. package/dist/data-table/infer-filter.cjs.map +1 -1
  26. package/dist/data-table/infer-filter.d.cts +1 -1
  27. package/dist/data-table/infer-filter.d.ts +1 -1
  28. package/dist/data-table/infer-filter.js +16 -6
  29. package/dist/data-table/infer-filter.js.map +1 -1
  30. package/dist/data-table/layered-filters.d.cts +1 -1
  31. package/dist/data-table/layered-filters.d.ts +1 -1
  32. package/dist/data-table/pagination.cjs +28 -14
  33. package/dist/data-table/pagination.cjs.map +1 -1
  34. package/dist/data-table/pagination.d.cts +7 -1
  35. package/dist/data-table/pagination.d.ts +7 -1
  36. package/dist/data-table/pagination.js +28 -14
  37. package/dist/data-table/pagination.js.map +1 -1
  38. package/dist/data-table/query-control.cjs +16 -6
  39. package/dist/data-table/query-control.cjs.map +1 -1
  40. package/dist/data-table/query-control.d.cts +1 -1
  41. package/dist/data-table/query-control.d.ts +1 -1
  42. package/dist/data-table/query-control.js +16 -6
  43. package/dist/data-table/query-control.js.map +1 -1
  44. package/dist/data-table/types.cjs.map +1 -1
  45. package/dist/data-table/types.d.cts +1 -1
  46. package/dist/data-table/types.d.ts +1 -1
  47. package/dist/data-table/url-state.d.cts +1 -1
  48. package/dist/data-table/url-state.d.ts +1 -1
  49. package/dist/data-table/xlsx.cjs.map +1 -1
  50. package/dist/data-table/xlsx.d.cts +1 -1
  51. package/dist/data-table/xlsx.d.ts +1 -1
  52. package/dist/data-table/xlsx.js.map +1 -1
  53. package/dist/{types-DsmrqJHN.d.cts → types-BAJiOaQL.d.cts} +8 -1
  54. package/dist/{types-Dpl8OW_m.d.ts → types-Da781-Wq.d.ts} +8 -1
  55. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { h as MatrxDataTableProps, i as TableViewSnapshot, c as MatrxDataTableRecordControls, j as ColumnMarker, M as MatrxColumnDef } from '../types-DsmrqJHN.cjs';
4
- export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, d as MatrxDataTableDensity, n as MatrxDataTableDetailConfig, o as MatrxDataTableEditConfig, p as MatrxDataTableEmptyState, q as MatrxDataTableFilterUi, r as MatrxDataTableHierarchyConfig, s as MatrxDataTableHierarchyMove, t as MatrxDataTableMobileCardControls, u as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, v as MatrxDataTableSelectionConfig, w as MatrxDataTableSourceProcessing, x as MatrxDataTableToolbar, y as MatrxDataTableUrlStateConfig, z as MatrxDataTableWindowConfig, B as MatrxTablePagination, D as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, E as TableViewQuery, F as TextFilterMode, G as ToolbarFacet } from '../types-DsmrqJHN.cjs';
3
+ import { h as MatrxDataTableProps, i as TableViewSnapshot, c as MatrxDataTableRecordControls, j as ColumnMarker, M as MatrxColumnDef } from '../types-BAJiOaQL.cjs';
4
+ export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, d as MatrxDataTableDensity, n as MatrxDataTableDetailConfig, o as MatrxDataTableEditConfig, p as MatrxDataTableEmptyState, q as MatrxDataTableFilterUi, r as MatrxDataTableHierarchyConfig, s as MatrxDataTableHierarchyMove, t as MatrxDataTableMobileCardControls, u as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, v as MatrxDataTableSelectionConfig, w as MatrxDataTableSourceProcessing, x as MatrxDataTableToolbar, y as MatrxDataTableUrlStateConfig, z as MatrxDataTableWindowConfig, B as MatrxTablePagination, D as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, E as TableViewQuery, F as TextFilterMode, G as ToolbarFacet } from '../types-BAJiOaQL.cjs';
5
5
  export { MatrxDataTableHost, MatrxDataTableProvider, MatrxTableRowAlchemy, TableDoors, TableEntityRefProps, TableLinkProps, TablePeekProps, TableSidePanelProps, TableToolbarActionProps, TableWindowPanelProps, useMatrxDataTableHost, useMatrxTableRowAlchemy } from './host.cjs';
6
6
  import { CopyControlProps } from './copy-types.cjs';
7
7
  export { AgentPayloadInput } from './copy-types.cjs';
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { h as MatrxDataTableProps, i as TableViewSnapshot, c as MatrxDataTableRecordControls, j as ColumnMarker, M as MatrxColumnDef } from '../types-Dpl8OW_m.js';
4
- export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, d as MatrxDataTableDensity, n as MatrxDataTableDetailConfig, o as MatrxDataTableEditConfig, p as MatrxDataTableEmptyState, q as MatrxDataTableFilterUi, r as MatrxDataTableHierarchyConfig, s as MatrxDataTableHierarchyMove, t as MatrxDataTableMobileCardControls, u as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, v as MatrxDataTableSelectionConfig, w as MatrxDataTableSourceProcessing, x as MatrxDataTableToolbar, y as MatrxDataTableUrlStateConfig, z as MatrxDataTableWindowConfig, B as MatrxTablePagination, D as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, E as TableViewQuery, F as TextFilterMode, G as ToolbarFacet } from '../types-Dpl8OW_m.js';
3
+ import { h as MatrxDataTableProps, i as TableViewSnapshot, c as MatrxDataTableRecordControls, j as ColumnMarker, M as MatrxColumnDef } from '../types-Da781-Wq.js';
4
+ export { A as AnyOfColumnSearch, k as CellEditType, l as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, m as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, d as MatrxDataTableDensity, n as MatrxDataTableDetailConfig, o as MatrxDataTableEditConfig, p as MatrxDataTableEmptyState, q as MatrxDataTableFilterUi, r as MatrxDataTableHierarchyConfig, s as MatrxDataTableHierarchyMove, t as MatrxDataTableMobileCardControls, u as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, v as MatrxDataTableSelectionConfig, w as MatrxDataTableSourceProcessing, x as MatrxDataTableToolbar, y as MatrxDataTableUrlStateConfig, z as MatrxDataTableWindowConfig, B as MatrxTablePagination, D as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, E as TableViewQuery, F as TextFilterMode, G as ToolbarFacet } from '../types-Da781-Wq.js';
5
5
  export { MatrxDataTableHost, MatrxDataTableProvider, MatrxTableRowAlchemy, TableDoors, TableEntityRefProps, TableLinkProps, TablePeekProps, TableSidePanelProps, TableToolbarActionProps, TableWindowPanelProps, useMatrxDataTableHost, useMatrxTableRowAlchemy } from './host.js';
6
6
  import { CopyControlProps } from './copy-types.js';
7
7
  export { AgentPayloadInput } from './copy-types.js';
@@ -1951,6 +1951,7 @@ function PageNavigationControl({
1951
1951
  }
1952
1952
  function PaginationAction({
1953
1953
  HostAction,
1954
+ compact = false,
1954
1955
  active = false,
1955
1956
  disabledHint,
1956
1957
  visibilityClassName = "inline-flex",
@@ -1979,6 +1980,7 @@ function PaginationAction({
1979
1980
  onClick: props.onClick,
1980
1981
  className: cn(
1981
1982
  PAGINATION_ACTION_CLASS,
1983
+ compact && "h-8 w-8 min-h-8 min-w-8",
1982
1984
  active && PAGINATION_ACTIVE_CLASS,
1983
1985
  fallbackClassName
1984
1986
  ),
@@ -1992,6 +1994,8 @@ var PAGINATION_ACTION_CLASS = "h-11 w-11 min-h-11 min-w-11 rounded-md border bor
1992
1994
  var PAGINATION_ACTIVE_CLASS = "border-primary bg-primary text-primary-foreground hover:bg-primary/90";
1993
1995
  function GenericTablePagination({
1994
1996
  totalItems,
1997
+ unknownTotal,
1998
+ isFetching = false,
1995
1999
  itemsPerPage,
1996
2000
  currentPage,
1997
2001
  onPageChange,
@@ -2032,11 +2036,12 @@ function GenericTablePagination({
2032
2036
  (_, i) => startPage + i
2033
2037
  );
2034
2038
  };
2035
- const isFirstPageDisabled = currentPage <= 1;
2036
- const isLastPageDisabled = currentPage >= totalPages;
2039
+ const isFirstPageDisabled = isFetching || currentPage <= 1;
2040
+ const isLastPageDisabled = isFetching || (unknownTotal ? !unknownTotal.hasNextPage : currentPage >= totalPages);
2037
2041
  const startItem = totalItems === 0 ? 0 : progressive ? 1 : (currentPage - 1) * effectiveItemsPerPage + 1;
2038
2042
  const endItem = Math.min(progressive?.shownCount ?? currentPage * effectiveItemsPerPage, totalItems);
2039
2043
  const defaultLabelFormat = (start, end, total) => {
2044
+ if (unknownTotal) return `${unknownTotal.pageRowCount.toLocaleString()} on page ${currentPage.toLocaleString()}`;
2040
2045
  if (progressive) return progressive.loadedCount !== void 0 && progressive.loadedCount !== total ? `${end} shown / ${total} matching \xB7 ${progressive.loadedCount} loaded` : `${end} shown / ${total} loaded`;
2041
2046
  return compact ? `${start}-${end} of ${total}` : `Showing ${start} to ${end} of ${total} entries`;
2042
2047
  };
@@ -2061,6 +2066,7 @@ function GenericTablePagination({
2061
2066
  children: /* @__PURE__ */ jsxs13(
2062
2067
  Select,
2063
2068
  {
2069
+ disabled: isFetching,
2064
2070
  value: itemsPerPage.toString(),
2065
2071
  onValueChange: (value) => onItemsPerPageChange(parseInt(value)),
2066
2072
  children: [
@@ -2077,7 +2083,7 @@ function GenericTablePagination({
2077
2083
  ),
2078
2084
  /* @__PURE__ */ jsxs13(SelectContent, { children: [
2079
2085
  availablePageSizes.map((size) => /* @__PURE__ */ jsx20(SelectItem, { value: size.toString(), children: size }, size)),
2080
- showAllOption ? /* @__PURE__ */ jsx20(SelectItem, { value: allValue.toString(), children: allOptionLabel }) : null
2086
+ showAllOption && !unknownTotal ? /* @__PURE__ */ jsx20(SelectItem, { value: allValue.toString(), children: allOptionLabel }) : null
2081
2087
  ] })
2082
2088
  ]
2083
2089
  }
@@ -2089,7 +2095,7 @@ function GenericTablePagination({
2089
2095
  {
2090
2096
  className: cn("flex min-w-0 justify-center", infoContainerClassName),
2091
2097
  children: showPageInfo && !hideEntriesInfo && /* @__PURE__ */ jsxs13(Fragment, { children: [
2092
- /* @__PURE__ */ jsx20("span", { className: "truncate text-xs tabular-nums text-muted-foreground sm:hidden", children: progressive ? `${endItem}/${totalItems} ${progressive.loadedCount !== void 0 && progressive.loadedCount !== totalItems ? "matching" : "loaded"}` : `${startItem}-${endItem} / ${totalItems}` }),
2098
+ /* @__PURE__ */ jsx20("span", { className: "truncate text-xs tabular-nums text-muted-foreground sm:hidden", children: labelFormat ? formatLabel(startItem, endItem, totalItems) : unknownTotal ? defaultLabelFormat(startItem, endItem, totalItems) : progressive ? `${endItem}/${totalItems} ${progressive.loadedCount !== void 0 && progressive.loadedCount !== totalItems ? "matching" : "loaded"}` : `${startItem}-${endItem} / ${totalItems}` }),
2093
2099
  /* @__PURE__ */ jsx20(
2094
2100
  "span",
2095
2101
  {
@@ -2114,7 +2120,7 @@ function GenericTablePagination({
2114
2120
  }
2115
2121
  ) }),
2116
2122
  /* @__PURE__ */ jsx20(TooltipContent, { children: "Show more already-loaded rows" })
2117
- ] }) : null : showPageControls && /* @__PURE__ */ jsxs13(
2123
+ ] }) : null : showPageControls && (unknownTotal ? currentPage > 1 || unknownTotal.hasNextPage : totalPages > 1) && /* @__PURE__ */ jsxs13(
2118
2124
  "div",
2119
2125
  {
2120
2126
  className: cn(
@@ -2127,8 +2133,9 @@ function GenericTablePagination({
2127
2133
  PaginationAction,
2128
2134
  {
2129
2135
  HostAction: host.ToolbarAction,
2136
+ compact,
2130
2137
  ariaLabel: "First page",
2131
- disabledHint: "Already on the first page",
2138
+ disabledHint: isFetching ? "Loading source page" : "Already on the first page",
2132
2139
  visibilityClassName: "hidden sm:inline-flex",
2133
2140
  fallbackClassName: navButtonClassName,
2134
2141
  onClick: () => onPageChange(1),
@@ -2140,41 +2147,46 @@ function GenericTablePagination({
2140
2147
  PaginationAction,
2141
2148
  {
2142
2149
  HostAction: host.ToolbarAction,
2150
+ compact,
2143
2151
  ariaLabel: "Previous page",
2144
- disabledHint: "Already on the first page",
2152
+ disabledHint: isFetching ? "Loading source page" : "Already on the first page",
2145
2153
  fallbackClassName: navButtonClassName,
2146
2154
  onClick: () => onPageChange(currentPage - 1),
2147
2155
  disabled: isFirstPageDisabled,
2148
2156
  children: /* @__PURE__ */ jsx20(ChevronLeft, { className: "h-5 w-5" })
2149
2157
  }
2150
2158
  ),
2151
- getPageNumbers(3).map((page) => /* @__PURE__ */ jsx20(
2159
+ !unknownTotal && getPageNumbers(3).map((page) => /* @__PURE__ */ jsx20(
2152
2160
  PaginationAction,
2153
2161
  {
2154
2162
  HostAction: host.ToolbarAction,
2163
+ compact,
2155
2164
  ariaLabel: `Page ${page}`,
2156
2165
  active: currentPage === page,
2157
- disabledHint: `Already on page ${page}`,
2166
+ disabledHint: isFetching ? "Loading source page" : `Already on page ${page}`,
2158
2167
  visibilityClassName: cn(
2159
2168
  "sm:hidden",
2160
2169
  page === currentPage ? "inline-flex" : "hidden min-[360px]:inline-flex"
2161
2170
  ),
2162
2171
  fallbackClassName: page === currentPage ? pageActiveButtonClassName : pageButtonClassName,
2163
2172
  onClick: () => onPageChange(page),
2173
+ disabled: isFetching,
2164
2174
  children: /* @__PURE__ */ jsx20("span", { children: page })
2165
2175
  },
2166
2176
  `mobile-${page}`
2167
2177
  )),
2168
- getPageNumbers().map((page) => /* @__PURE__ */ jsx20(
2178
+ !unknownTotal && getPageNumbers().map((page) => /* @__PURE__ */ jsx20(
2169
2179
  PaginationAction,
2170
2180
  {
2171
2181
  HostAction: host.ToolbarAction,
2182
+ compact,
2172
2183
  ariaLabel: `Page ${page}`,
2173
2184
  active: currentPage === page,
2174
- disabledHint: `Already on page ${page}`,
2185
+ disabledHint: isFetching ? "Loading source page" : `Already on page ${page}`,
2175
2186
  visibilityClassName: "hidden sm:inline-flex",
2176
2187
  fallbackClassName: currentPage === page ? pageActiveButtonClassName : pageButtonClassName,
2177
2188
  onClick: () => onPageChange(page),
2189
+ disabled: isFetching,
2178
2190
  children: /* @__PURE__ */ jsx20("span", { children: page })
2179
2191
  },
2180
2192
  `desktop-${page}`
@@ -2183,20 +2195,22 @@ function GenericTablePagination({
2183
2195
  PaginationAction,
2184
2196
  {
2185
2197
  HostAction: host.ToolbarAction,
2198
+ compact,
2186
2199
  ariaLabel: "Next page",
2187
- disabledHint: "Already on the last page",
2200
+ disabledHint: isFetching ? "Loading source page" : "Already on the last page",
2188
2201
  fallbackClassName: navButtonClassName,
2189
2202
  onClick: () => onPageChange(currentPage + 1),
2190
2203
  disabled: isLastPageDisabled,
2191
2204
  children: /* @__PURE__ */ jsx20(ChevronRight, { className: "h-5 w-5" })
2192
2205
  }
2193
2206
  ),
2194
- /* @__PURE__ */ jsx20(
2207
+ !unknownTotal && /* @__PURE__ */ jsx20(
2195
2208
  PaginationAction,
2196
2209
  {
2197
2210
  HostAction: host.ToolbarAction,
2211
+ compact,
2198
2212
  ariaLabel: "Last page",
2199
- disabledHint: "Already on the last page",
2213
+ disabledHint: isFetching ? "Loading source page" : "Already on the last page",
2200
2214
  visibilityClassName: "hidden sm:inline-flex",
2201
2215
  fallbackClassName: navButtonClassName,
2202
2216
  onClick: () => onPageChange(totalPages),
@@ -5031,6 +5045,7 @@ function layeredFilterRuleSummary(rule, fields) {
5031
5045
  // src/data-table/filter-engine.ts
5032
5046
  var SELECT_EMPTY_VALUE = "__empty__";
5033
5047
  var SELECT_NOT_EMPTY_VALUE = "__not_empty__";
5048
+ var SELECT_NULL_VALUE = "__null__";
5034
5049
  function columnId(col) {
5035
5050
  if (col.id) return col.id;
5036
5051
  if (col.accessorKey) return String(col.accessorKey);
@@ -5105,11 +5120,14 @@ function passesColumnFilter(value, filter) {
5105
5120
  return s.toLowerCase().includes(q);
5106
5121
  }
5107
5122
  case "select": {
5123
+ if (filter.values !== void 0 && filter.values.length === 0) {
5124
+ return false;
5125
+ }
5108
5126
  const selected = filter.values ?? (filter.value && filter.value !== "__all__" ? [filter.value] : []);
5109
5127
  if (selected.length === 0) return true;
5110
5128
  const values = selectCellValues(value);
5111
5129
  return selected.some(
5112
- (v) => v === SELECT_EMPTY_VALUE ? values.length === 0 : v === SELECT_NOT_EMPTY_VALUE ? values.length > 0 : values.includes(v)
5130
+ (v) => v === SELECT_NULL_VALUE ? value == null : v === SELECT_EMPTY_VALUE ? values.length === 0 : v === SELECT_NOT_EMPTY_VALUE ? values.length > 0 : v === "" ? value === "" || Array.isArray(value) && value.includes("") : values.includes(v)
5113
5131
  );
5114
5132
  }
5115
5133
  case "boolean": {
@@ -5190,7 +5208,7 @@ function countActiveColumnFilters(filters) {
5190
5208
  if (f.value.trim() || f.mode && f.mode !== "contains") n += 1;
5191
5209
  break;
5192
5210
  case "select":
5193
- if (f.values ? f.values.length > 0 : f.value && f.value !== "__all__")
5211
+ if (f.values !== void 0 || f.value && f.value !== "__all__")
5194
5212
  n += 1;
5195
5213
  break;
5196
5214
  case "boolean":
@@ -5209,7 +5227,7 @@ function isColumnFilterActive(filter) {
5209
5227
  case "text":
5210
5228
  return filter.value.trim().length > 0 || filter.mode !== void 0 && filter.mode !== "contains";
5211
5229
  case "select":
5212
- return filter.values ? filter.values.length > 0 : Boolean(filter.value) && filter.value !== "__all__";
5230
+ return filter.values !== void 0 ? true : Boolean(filter.value) && filter.value !== "__all__";
5213
5231
  case "boolean":
5214
5232
  return true;
5215
5233
  case "number":
@@ -6358,14 +6376,12 @@ function SearchableSelectFilter({
6358
6376
  const toggle = (v) => {
6359
6377
  if (single) {
6360
6378
  onChange(
6361
- selected.length === 1 && selected[0] === v ? void 0 : { kind: "select", value: v }
6379
+ selected.length === 1 && selected[0] === v ? void 0 : { kind: "select", value: v, ...v === "" ? { values: [v] } : {} }
6362
6380
  );
6363
6381
  return;
6364
6382
  }
6365
6383
  const next = selected.includes(v) ? selected.filter((x) => x !== v) : [...selected, v];
6366
- onChange(
6367
- next.length === 0 ? void 0 : { kind: "select", value: next[0] ?? "", values: next }
6368
- );
6384
+ onChange({ kind: "select", value: next[0] ?? "", values: next });
6369
6385
  };
6370
6386
  return /* @__PURE__ */ jsxs22("div", { className: "space-y-1 px-0", children: [
6371
6387
  /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between px-1 pb-1", children: [
@@ -6401,7 +6417,17 @@ function SearchableSelectFilter({
6401
6417
  CommandItem,
6402
6418
  {
6403
6419
  value: "__all__",
6404
- onSelect: () => onChange(void 0),
6420
+ onSelect: () => single ? onChange(void 0) : onChange({
6421
+ kind: "select",
6422
+ value: options.find(
6423
+ (option) => option.value !== SELECT_NOT_EMPTY_VALUE
6424
+ )?.value ?? "",
6425
+ // `(not empty)` matches every populated value. Including
6426
+ // it would make unchecking a concrete value ineffective.
6427
+ values: options.filter(
6428
+ (option) => option.value !== SELECT_NOT_EMPTY_VALUE
6429
+ ).map((option) => option.value)
6430
+ }),
6405
6431
  className: "text-xs",
6406
6432
  children: "All"
6407
6433
  }
@@ -6421,6 +6447,9 @@ function SearchableSelectFilter({
6421
6447
  /* @__PURE__ */ jsx31(
6422
6448
  "span",
6423
6449
  {
6450
+ role: single ? "radio" : "checkbox",
6451
+ "aria-label": o.label,
6452
+ "aria-checked": active,
6424
6453
  className: cn(
6425
6454
  "flex h-3.5 w-3.5 shrink-0 items-center justify-center border",
6426
6455
  single ? "rounded-full" : "rounded-sm",
@@ -8459,10 +8488,13 @@ function collectSelectOptions(col, rows) {
8459
8488
  const seen = /* @__PURE__ */ new Set();
8460
8489
  const options = [];
8461
8490
  let hasEmpty = false;
8491
+ let hasEmptyCollection = false;
8462
8492
  for (const row of rows) {
8463
- const values = selectCellValues(getCellValue(row, col));
8493
+ const cell = getCellValue(row, col);
8494
+ const values = selectCellValues(cell);
8464
8495
  if (values.length === 0) {
8465
8496
  hasEmpty = true;
8497
+ if (Array.isArray(cell)) hasEmptyCollection = true;
8466
8498
  continue;
8467
8499
  }
8468
8500
  for (const value of values) {
@@ -8471,12 +8503,18 @@ function collectSelectOptions(col, rows) {
8471
8503
  options.push({ value, label: value });
8472
8504
  }
8473
8505
  }
8474
- const base = col.filterOptions?.length ? [...col.filterOptions] : options.sort((a, b) => a.label.localeCompare(b.label));
8506
+ const base = col.filterOptions?.length ? col.filterOptions.map((option) => ({
8507
+ ...option,
8508
+ label: option.label.trim() ? option.label : option.value === "" ? "(empty string)" : option.value.trim() ? option.value : "(whitespace)"
8509
+ })) : options.sort((a, b) => a.label.localeCompare(b.label));
8475
8510
  if (hasEmpty) {
8476
- base.unshift(
8477
- { value: SELECT_EMPTY_VALUE, label: "(empty)" },
8478
- { value: SELECT_NOT_EMPTY_VALUE, label: "(not empty)" }
8479
- );
8511
+ const emptyOption = !hasEmptyCollection && base.some((option) => option.value === "") ? { value: SELECT_NULL_VALUE, label: "(null)" } : { value: SELECT_EMPTY_VALUE, label: "(empty)" };
8512
+ const additions = [];
8513
+ if (!base.some((option) => option.value === emptyOption.value)) additions.push(emptyOption);
8514
+ if (!base.some((option) => option.value === SELECT_NOT_EMPTY_VALUE)) {
8515
+ additions.push({ value: SELECT_NOT_EMPTY_VALUE, label: "(not empty)" });
8516
+ }
8517
+ base.unshift(...additions);
8480
8518
  }
8481
8519
  return base;
8482
8520
  }
@@ -8687,6 +8725,24 @@ function MatrxDataTableWithUrlState({
8687
8725
  );
8688
8726
  }
8689
8727
  var COLUMN_REORDER_ACTIVATION_DISTANCE = 6;
8728
+ var ROW_INTERACTIVE_DESCENDANT_SELECTOR = [
8729
+ "a",
8730
+ "button",
8731
+ "input",
8732
+ "select",
8733
+ "textarea",
8734
+ '[role="button"]',
8735
+ '[role="combobox"]',
8736
+ '[contenteditable="true"]',
8737
+ "[data-matrx-cell-control]"
8738
+ ].join(", ");
8739
+ function rowEventTargetsInteractiveDescendant(target) {
8740
+ const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
8741
+ return element?.closest(ROW_INTERACTIVE_DESCENDANT_SELECTOR) !== null;
8742
+ }
8743
+ function opensRowHref(event) {
8744
+ return event.metaKey || event.ctrlKey || event.shiftKey || event.button === 1;
8745
+ }
8690
8746
  function TableContextPassthrough({ children }) {
8691
8747
  return /* @__PURE__ */ jsx41(Fragment7, { children });
8692
8748
  }
@@ -8741,6 +8797,7 @@ function MatrxDataTableCore({
8741
8797
  tableClassName,
8742
8798
  mobileCards,
8743
8799
  mobileCardsBreakpoint = "sm",
8800
+ getRowHref,
8744
8801
  onRowOpen,
8745
8802
  density
8746
8803
  }) {
@@ -9219,7 +9276,12 @@ function MatrxDataTableCore({
9219
9276
  0,
9220
9277
  ...visibleActionStrips.map((element) => Math.ceil(element.scrollWidth))
9221
9278
  );
9222
- const actionsWidth = actionContentWidth || headerActionsWidth;
9279
+ const actionsHeader = table?.querySelector("th[data-matrx-table-actions-column]");
9280
+ const actionsLabel = actionsHeader?.querySelector("[data-matrx-table-actions-label]");
9281
+ const headerPadding = actionsHeader ? getComputedStyle(actionsHeader) : void 0;
9282
+ const measuredLabelWidth = actionsLabel?.getBoundingClientRect().width ?? 0;
9283
+ const labelWidth = measuredLabelWidth > 0 ? Math.ceil(measuredLabelWidth + (Number.parseFloat(headerPadding?.paddingLeft ?? "0") || 0) + (Number.parseFloat(headerPadding?.paddingRight ?? "0") || 0)) : 0;
9284
+ const actionsWidth = Math.max(actionContentWidth, labelWidth) || headerActionsWidth;
9223
9285
  return {
9224
9286
  ...headerTotal > 0 ? { tableWidth: Math.ceil(headerTotal) } : {},
9225
9287
  ...selectionWidth === void 0 ? {} : { selectionWidth },
@@ -10848,9 +10910,9 @@ function MatrxDataTableCore({
10848
10910
  "th",
10849
10911
  {
10850
10912
  "data-matrx-table-actions-column": true,
10851
- className: "h-9 w-px px-2 text-right align-middle text-xs font-semibold uppercase tracking-wide text-muted-foreground",
10913
+ className: "h-9 w-px whitespace-nowrap px-2 text-right align-middle text-xs font-semibold uppercase tracking-wide text-muted-foreground",
10852
10914
  style: fixedUtilityWidth(fixedTableGeometry?.actionsWidth),
10853
- children: "Actions"
10915
+ children: /* @__PURE__ */ jsx41("span", { "data-matrx-table-actions-label": true, className: "inline-block whitespace-nowrap", children: "Actions" })
10854
10916
  }
10855
10917
  )
10856
10918
  ] })
@@ -10896,9 +10958,22 @@ function MatrxDataTableCore({
10896
10958
  "data-row-id": id,
10897
10959
  "data-state": isSelected ? "selected" : void 0,
10898
10960
  onClick: (e) => {
10899
- if (e.target.closest('a, button, input, select, textarea, [role="button"], [role="combobox"], [contenteditable="true"]')) return;
10961
+ if (rowEventTargetsInteractiveDescendant(e.target)) return;
10962
+ if (opensRowHref(e)) {
10963
+ const href = getRowHref?.(row);
10964
+ if (href) window.open(href, "_blank", "noopener");
10965
+ return;
10966
+ }
10900
10967
  openRow(row);
10901
10968
  },
10969
+ onAuxClick: (e) => {
10970
+ if (e.button !== 1 || rowEventTargetsInteractiveDescendant(e.target)) return;
10971
+ const href = getRowHref?.(row);
10972
+ if (href) {
10973
+ e.preventDefault();
10974
+ window.open(href, "_blank", "noopener");
10975
+ }
10976
+ },
10902
10977
  className: cn(
10903
10978
  // Keep the mobile row opaque while the complete row scrolls
10904
10979
  // horizontally. The translucent zebra/hover tints remain