@ai-matrx/design-system 0.18.0 → 0.18.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.1 — 2026-09-12
4
+
5
+ Reorderable table columns now drag from the visible header label instead of a
6
+ separate grip. Ordinary click, Enter, and Space sorting remain intact, compact
7
+ headers remain accessible, and sticky headers continue to be the default.
8
+
9
+ ### Consumer action
10
+
11
+ Update to 0.18.1 to use direct header-label column dragging. No table
12
+ configuration changes are required.
13
+
3
14
  ## 0.18.0 — 2026-09-12
4
15
 
5
16
  Portable data-table copy controls now use the canonical Alchemy menu for rows,
@@ -460,7 +460,7 @@ module.exports = __toCommonJS(data_table_exports);
460
460
 
461
461
  // src/data-table/MatrxDataTable.tsx
462
462
  var import_react13 = require("react");
463
- var import_core2 = require("@dnd-kit/core");
463
+ var import_core3 = require("@dnd-kit/core");
464
464
 
465
465
  // src/data-table/icons.tsx
466
466
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -4019,6 +4019,7 @@ var import_url_state3 = require("@ai-matrx/kit/url-state");
4019
4019
 
4020
4020
  // src/data-table/ColumnHeaderCell.tsx
4021
4021
  var import_react7 = require("react");
4022
+ var import_core = require("@dnd-kit/core");
4022
4023
 
4023
4024
  // src/popover.tsx
4024
4025
  var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
@@ -4228,8 +4229,29 @@ function ColumnHeaderCell({
4228
4229
  filterShowCancel = false,
4229
4230
  filterFooterHint,
4230
4231
  allowNegation = false,
4231
- allowNullModes = false
4232
+ allowNullModes = false,
4233
+ reorderColumn
4232
4234
  }) {
4235
+ const reorderEnabled = reorderColumn !== void 0;
4236
+ const { attributes: reorderAttributes, listeners: reorderListeners, setNodeRef } = (0, import_core.useDraggable)(
4237
+ reorderColumn ? {
4238
+ id: `matrx-column-header:${reorderColumn.id}`,
4239
+ data: { matrxDragKind: "column-header", columnId: reorderColumn.id },
4240
+ disabled: false
4241
+ } : {
4242
+ id: `matrx-column-header:inactive:${labelText ?? "column"}`,
4243
+ disabled: true
4244
+ }
4245
+ );
4246
+ const reorderLabel = reorderColumn?.label ?? labelText ?? "column";
4247
+ const reorderActivator = reorderEnabled ? {
4248
+ ...reorderAttributes,
4249
+ ...reorderListeners,
4250
+ ref: setNodeRef,
4251
+ title: `Drag to reorder ${reorderLabel}.`,
4252
+ "aria-description": "Drag this column label to reorder it."
4253
+ } : void 0;
4254
+ const reorderClass = reorderEnabled ? "touch-none cursor-grab active:cursor-grabbing" : void 0;
4233
4255
  const filterActive = isColumnFilterActive(filterValue);
4234
4256
  const deferredFilter = filterApplyLabel !== void 0 || filterShowCancel || filterFooterHint !== void 0;
4235
4257
  const [filterOpen, setFilterOpen] = (0, import_react7.useState)(false);
@@ -4373,7 +4395,21 @@ function ColumnHeaderCell({
4373
4395
  );
4374
4396
  if (compact) {
4375
4397
  if (!sortable && !filterKind) {
4376
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn("flex items-center justify-center", className), children: label });
4398
+ if (!reorderEnabled) {
4399
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn("flex items-center justify-center", className), children: label });
4400
+ }
4401
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn("flex items-center justify-center", className), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4402
+ "button",
4403
+ {
4404
+ type: "button",
4405
+ ...reorderActivator,
4406
+ className: cn(
4407
+ "inline-flex items-center justify-center rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground",
4408
+ reorderClass
4409
+ ),
4410
+ children: label
4411
+ }
4412
+ ) });
4377
4413
  }
4378
4414
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4379
4415
  "div",
@@ -4390,9 +4426,13 @@ function ColumnHeaderCell({
4390
4426
  type: "button",
4391
4427
  "aria-label": menuLabel,
4392
4428
  title: menuLabel,
4393
- onClick: (e) => e.stopPropagation(),
4429
+ onClick: (event) => {
4430
+ event.stopPropagation();
4431
+ },
4432
+ ...reorderActivator,
4394
4433
  className: cn(
4395
4434
  "relative inline-flex items-center justify-center rounded p-0.5 transition-colors",
4435
+ reorderClass,
4396
4436
  isSorted || filterActive ? "text-foreground" : "text-muted-foreground hover:text-foreground"
4397
4437
  ),
4398
4438
  children: [
@@ -4428,8 +4468,10 @@ function ColumnHeaderCell({
4428
4468
  {
4429
4469
  type: "button",
4430
4470
  onClick: onHeaderSortClick,
4471
+ ...reorderActivator,
4431
4472
  className: cn(
4432
4473
  "inline-flex min-w-0 items-center gap-1 rounded px-0.5 py-0.5 text-left text-xs font-semibold uppercase tracking-wide transition-colors",
4474
+ reorderClass,
4433
4475
  isSorted ? "text-foreground" : "text-muted-foreground hover:text-foreground"
4434
4476
  ),
4435
4477
  children: [
@@ -4437,6 +4479,17 @@ function ColumnHeaderCell({
4437
4479
  isSorted ? sortDirection === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArrowUp, { className: "h-3 w-3 shrink-0 text-primary" }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArrowDown, { className: "h-3 w-3 shrink-0 text-primary" }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArrowUpDown, { className: "h-3 w-3 shrink-0 opacity-40" })
4438
4480
  ]
4439
4481
  }
4482
+ ) : reorderEnabled ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4483
+ "button",
4484
+ {
4485
+ type: "button",
4486
+ ...reorderActivator,
4487
+ className: cn(
4488
+ "min-w-0 truncate rounded px-0.5 py-0.5 text-left text-xs font-semibold uppercase tracking-wide text-muted-foreground hover:text-foreground",
4489
+ reorderClass
4490
+ ),
4491
+ children: label
4492
+ }
4440
4493
  ) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: label }),
4441
4494
  filterKind ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "inline-flex items-center", children: [
4442
4495
  /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Popover, { open: filterOpen, onOpenChange: setFilterOpen, children: [
@@ -4759,7 +4812,7 @@ function parseOptionalNumber(raw) {
4759
4812
 
4760
4813
  // src/data-table/ColumnManager.tsx
4761
4814
  var import_react8 = require("react");
4762
- var import_core = require("@dnd-kit/core");
4815
+ var import_core2 = require("@dnd-kit/core");
4763
4816
  init_filter_engine();
4764
4817
  var import_jsx_runtime26 = require("react/jsx-runtime");
4765
4818
  function ColumnManager({
@@ -4809,7 +4862,7 @@ function ColumnManager({
4809
4862
  return next;
4810
4863
  });
4811
4864
  };
4812
- (0, import_core.useDndMonitor)({
4865
+ (0, import_core2.useDndMonitor)({
4813
4866
  onDragStart(event) {
4814
4867
  if (event.active.data.current?.matrxDragKind !== "column-manager") return;
4815
4868
  setDraggedColumnId(String(event.active.data.current.columnId));
@@ -4927,14 +4980,14 @@ function ColumnManagerDropTarget({
4927
4980
  className,
4928
4981
  children
4929
4982
  }) {
4930
- const { setNodeRef } = (0, import_core.useDroppable)({
4983
+ const { setNodeRef } = (0, import_core2.useDroppable)({
4931
4984
  id: `matrx-column-manager:${id}`,
4932
4985
  data: { matrxDragKind: "column-manager", columnId: id }
4933
4986
  });
4934
4987
  return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: setNodeRef, "data-matrx-column-manager-drop-target": id, className, children });
4935
4988
  }
4936
4989
  function ColumnManagerDragHandle({ id, label }) {
4937
- const { attributes, listeners, setNodeRef } = (0, import_core.useDraggable)({
4990
+ const { attributes, listeners, setNodeRef } = (0, import_core2.useDraggable)({
4938
4991
  id: `matrx-column-manager:${id}`,
4939
4992
  data: { matrxDragKind: "column-manager", columnId: id }
4940
4993
  });
@@ -6558,6 +6611,7 @@ function MatrxDataTableWithUrlState({
6558
6611
  }
6559
6612
  );
6560
6613
  }
6614
+ var COLUMN_REORDER_ACTIVATION_DISTANCE = 6;
6561
6615
  function MatrxDataTableCore({
6562
6616
  data: suppliedData,
6563
6617
  columns,
@@ -6629,8 +6683,10 @@ function MatrxDataTableCore({
6629
6683
  );
6630
6684
  const [internalSearch, setInternalSearch] = (0, import_react13.useState)("");
6631
6685
  const [draggedRowId, setDraggedRowId] = (0, import_react13.useState)(null);
6632
- const hierarchySensors = (0, import_core2.useSensors)(
6633
- (0, import_core2.useSensor)(import_core2.PointerSensor, { activationConstraint: { distance: 6 } })
6686
+ const hierarchySensors = (0, import_core3.useSensors)(
6687
+ (0, import_core3.useSensor)(import_core3.PointerSensor, {
6688
+ activationConstraint: { distance: COLUMN_REORDER_ACTIVATION_DISTANCE }
6689
+ })
6634
6690
  );
6635
6691
  const toolbarSearchControlled = toolbar?.searchValue !== void 0;
6636
6692
  const searchValue = controlledQuery ? controlledQuery.state.search : toolbarSearchControlled ? toolbar?.searchValue ?? "" : internalSearch;
@@ -7471,11 +7527,11 @@ function MatrxDataTableCore({
7471
7527
  } : facet
7472
7528
  ) : toolbar?.facets;
7473
7529
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
7474
- import_core2.DndContext,
7530
+ import_core3.DndContext,
7475
7531
  {
7476
7532
  sensors: hierarchySensors,
7477
- collisionDetection: import_core2.pointerWithin,
7478
- measuring: { droppable: { strategy: import_core2.MeasuringStrategy.Always } },
7533
+ collisionDetection: import_core3.pointerWithin,
7534
+ measuring: { droppable: { strategy: import_core3.MeasuringStrategy.Always } },
7479
7535
  onDragStart: (event) => {
7480
7536
  const kind = event.active.data.current?.matrxDragKind;
7481
7537
  if (kind === "column-header") {
@@ -7688,6 +7744,7 @@ function MatrxDataTableCore({
7688
7744
  size: "sm",
7689
7745
  className: "h-7 gap-1 px-2 text-xs text-muted-foreground",
7690
7746
  onClick: clearAllFilters,
7747
+ "aria-label": "Clear all filters",
7691
7748
  title: "Clear all filters",
7692
7749
  children: [
7693
7750
  /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Eraser, { className: "h-3.5 w-3.5" }),
@@ -8046,45 +8103,43 @@ function MatrxDataTableCore({
8046
8103
  col.align === "right" && "text-right"
8047
8104
  ),
8048
8105
  style: columnWidthVar(col.width),
8049
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(ColumnHeaderDropZone, { id, enabled: reorderableColumns, children: [
8050
- reorderableColumns ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ColumnReorderHandle, { id, label: headerLabel }) : null,
8051
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8052
- ColumnHeaderCell,
8053
- {
8054
- label: col.header,
8055
- labelText: headerLabel,
8056
- sortable: col.sortable !== false,
8057
- isSorted: Boolean(isSorted),
8058
- sortDirection: sort?.direction ?? defaultSortDirection,
8059
- onSortAsc: () => setSort({ id, direction: "asc" }),
8060
- onSortDesc: () => setSort({ id, direction: "desc" }),
8061
- onClearSort: () => setSort(null),
8062
- onHeaderSortClick: () => {
8063
- if (!isSorted) {
8064
- setSort({ id, direction: defaultSortDirection });
8065
- return;
8066
- }
8067
- if (sort?.direction === "asc") {
8068
- setSort({ id, direction: "desc" });
8069
- return;
8070
- }
8071
- setSort(null);
8072
- },
8073
- filterKind: meta?.kind ?? null,
8074
- filterValue: columnFilters[id],
8075
- onFilterChange: (next) => setColumnFilter(id, next),
8076
- selectOptions: meta?.options,
8077
- selectSingle: col.filterSingle,
8078
- filterApplyLabel: filterUi?.applyLabel,
8079
- filterShowCancel: filterUi?.showCancel,
8080
- filterFooterHint: filterUi?.footerHint,
8081
- allowNegation: filterUi?.allowNegation,
8082
- allowNullModes: filterUi?.allowNullModes,
8083
- align: col.align,
8084
- compact: col.compact
8085
- }
8086
- )
8087
- ] })
8106
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ColumnHeaderDropZone, { id, enabled: reorderableColumns, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8107
+ ColumnHeaderCell,
8108
+ {
8109
+ label: col.header,
8110
+ labelText: headerLabel,
8111
+ sortable: col.sortable !== false,
8112
+ isSorted: Boolean(isSorted),
8113
+ sortDirection: sort?.direction ?? defaultSortDirection,
8114
+ onSortAsc: () => setSort({ id, direction: "asc" }),
8115
+ onSortDesc: () => setSort({ id, direction: "desc" }),
8116
+ onClearSort: () => setSort(null),
8117
+ onHeaderSortClick: () => {
8118
+ if (!isSorted) {
8119
+ setSort({ id, direction: defaultSortDirection });
8120
+ return;
8121
+ }
8122
+ if (sort?.direction === "asc") {
8123
+ setSort({ id, direction: "desc" });
8124
+ return;
8125
+ }
8126
+ setSort(null);
8127
+ },
8128
+ filterKind: meta?.kind ?? null,
8129
+ filterValue: columnFilters[id],
8130
+ onFilterChange: (next) => setColumnFilter(id, next),
8131
+ selectOptions: meta?.options,
8132
+ selectSingle: col.filterSingle,
8133
+ filterApplyLabel: filterUi?.applyLabel,
8134
+ filterShowCancel: filterUi?.showCancel,
8135
+ filterFooterHint: filterUi?.footerHint,
8136
+ allowNegation: filterUi?.allowNegation,
8137
+ allowNullModes: filterUi?.allowNullModes,
8138
+ align: col.align,
8139
+ compact: col.compact,
8140
+ reorderColumn: reorderableColumns ? { id, label: headerLabel } : void 0
8141
+ }
8142
+ ) })
8088
8143
  },
8089
8144
  id
8090
8145
  );
@@ -8660,7 +8715,7 @@ function MatrxDataTableCore({
8660
8715
  ]
8661
8716
  }
8662
8717
  ),
8663
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_core2.DragOverlay, { children: draggedRow ? (
8718
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_core3.DragOverlay, { children: draggedRow ? (
8664
8719
  // w-max: the overlay inherits the ACTIVE node's size, and the active
8665
8720
  // node is the 16px grip handle — without it the label wraps to one
8666
8721
  // character per line.
@@ -8675,7 +8730,7 @@ function HierarchyDragHandle({
8675
8730
  label,
8676
8731
  disabled
8677
8732
  }) {
8678
- const { attributes, listeners, setNodeRef } = (0, import_core2.useDraggable)({
8733
+ const { attributes, listeners, setNodeRef } = (0, import_core3.useDraggable)({
8679
8734
  id,
8680
8735
  disabled
8681
8736
  });
@@ -8699,7 +8754,7 @@ function HierarchyRootDropTarget({
8699
8754
  label,
8700
8755
  draggedLabel
8701
8756
  }) {
8702
- const { isOver, setNodeRef } = (0, import_core2.useDroppable)({ id: "__root__" });
8757
+ const { isOver, setNodeRef } = (0, import_core3.useDroppable)({ id: "__root__" });
8703
8758
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
8704
8759
  "div",
8705
8760
  {
@@ -8723,7 +8778,7 @@ function HierarchyDragIndicatorLayer({
8723
8778
  const [indicator, setIndicator] = (0, import_react13.useState)(
8724
8779
  null
8725
8780
  );
8726
- (0, import_core2.useDndMonitor)({
8781
+ (0, import_core3.useDndMonitor)({
8727
8782
  onDragMove(event) {
8728
8783
  const container = scrollRef.current;
8729
8784
  const overId = event.over ? String(event.over.id) : null;
@@ -8823,7 +8878,7 @@ function HierarchyDroppableRow({
8823
8878
  disabled,
8824
8879
  children
8825
8880
  }) {
8826
- const { setNodeRef } = (0, import_core2.useDroppable)({ id, disabled });
8881
+ const { setNodeRef } = (0, import_core3.useDroppable)({ id, disabled });
8827
8882
  if (!(0, import_react13.isValidElement)(children) || children.type !== "tr") return children;
8828
8883
  const row = children;
8829
8884
  return (0, import_react13.cloneElement)(row, {
@@ -8836,33 +8891,13 @@ function ColumnHeaderDropZone({
8836
8891
  enabled,
8837
8892
  children
8838
8893
  }) {
8839
- const { setNodeRef } = (0, import_core2.useDroppable)({
8894
+ const { setNodeRef } = (0, import_core3.useDroppable)({
8840
8895
  id: `matrx-column-header:${id}`,
8841
8896
  disabled: !enabled,
8842
8897
  data: { matrxDragKind: "column-header", columnId: id }
8843
8898
  });
8844
8899
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { ref: setNodeRef, className: "flex min-w-0 items-center", children });
8845
8900
  }
8846
- function ColumnReorderHandle({ id, label }) {
8847
- const { attributes, listeners, setNodeRef } = (0, import_core2.useDraggable)({
8848
- id: `matrx-column-header:${id}`,
8849
- data: { matrxDragKind: "column-header", columnId: id }
8850
- });
8851
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8852
- "button",
8853
- {
8854
- ref: setNodeRef,
8855
- type: "button",
8856
- className: "mr-1 flex h-7 w-5 shrink-0 touch-none cursor-grab items-center justify-center text-muted-foreground hover:text-foreground active:cursor-grabbing",
8857
- "aria-label": `Reorder ${label}`,
8858
- title: `Drag to reorder ${label}`,
8859
- onClick: (event) => event.stopPropagation(),
8860
- ...attributes,
8861
- ...listeners,
8862
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(GripVertical, { className: "h-3.5 w-3.5" })
8863
- }
8864
- );
8865
- }
8866
8901
  function columnWidthVar(width) {
8867
8902
  if (width === void 0) return void 0;
8868
8903
  return {