@ai-matrx/design-system 0.32.0 → 0.34.0

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,41 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.34.0 — 2026-09-21
4
+
5
+ **The release gate was red on main, and the red was a stale expectation.**
6
+
7
+ 0.33.0's tag could not publish: `default-copy-regressions.test.tsx` required a
8
+ JSON-`null` cell to copy as the literal word `null` in HTML and CSV, and
9
+ `@ai-matrx/kit` 0.16.1 had just stopped doing that on purpose — a host
10
+ normalises a missing cell to `null` so the row keeps its shape, and a row
11
+ copied out of this very table arrived in Sheets carrying `null` as TEXT in its
12
+ empty columns (observed live 2026-09-15). The same test's workbook leg had
13
+ always expected an empty cell, so it was asserting two answers for one value.
14
+ Both clauses now expect empty, with a clause that no copied cell may contain
15
+ the word again. No product code changed in this release beyond 0.33.0's
16
+ contents.
17
+
18
+ ## 0.33.0 — 2026-09-21
19
+
20
+ **The organization picker stops negating the matches one click below it, and a
21
+ frozen column stops showing the rows sliding under it.**
22
+
23
+ - `OrganizationPicker` — when every match for a search is a test organization,
24
+ the picker used to say *"Nothing matches “X” outside the test organizations
25
+ below."* `isTestFixture` rows are query-filtered, so those rows below **are**
26
+ matches for X: the sentence opened by denying the thing sitting one click
27
+ away, and a person who reads "nothing matches" retypes their search instead
28
+ of clicking. It now says what is true and carries the click that reveals
29
+ them — *"1 match for “vis” is in your test organizations — show them"* — and
30
+ reads "listed below" once open. Two clauses in
31
+ `src/organization-picker.test.tsx` hold the wording.
32
+ - `MatrxDataTable` frozen columns are painted **opaque**, with the paint taken
33
+ from the semantic surface tokens rather than a literal colour, so a frozen
34
+ column matches its theme instead of being a hardcoded swatch and the
35
+ scrolled rows no longer show through it.
36
+
37
+ Additive: no API changed.
38
+
3
39
  ## 0.32.0 — 2026-09-21
4
40
 
5
41
  **The organization picker stopped being a filing cabinet.**
@@ -10084,8 +10084,26 @@ function pixelWidth(width) {
10084
10084
  }
10085
10085
  return void 0;
10086
10086
  }
10087
- var FROZEN_CELL_CLASS = "sm:sticky sm:left-[var(--matrx-frozen-left)] sm:z-20 sm:bg-inherit";
10088
- var FROZEN_HEADER_CLASS = "sm:sticky sm:left-[var(--matrx-frozen-left)] sm:z-30";
10087
+ var FROZEN_CELL_CLASS = "sm:sticky sm:left-[var(--matrx-frozen-left)] sm:z-20 sm:bg-card";
10088
+ var FROZEN_HEADER_CLASS = "sm:sticky sm:left-[var(--matrx-frozen-left)] sm:z-30 sm:bg-muted";
10089
+ var FROZEN_ROW_TINT_CLASS = {
10090
+ slate: "sm:bg-[color-mix(in_oklab,var(--color-slate-100)_70%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-slate-800)_40%,var(--color-card))]",
10091
+ green: "sm:bg-[color-mix(in_oklab,var(--color-green-50)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-green-950)_40%,var(--color-card))]",
10092
+ amber: "sm:bg-[color-mix(in_oklab,var(--color-amber-50)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-amber-950)_40%,var(--color-card))]",
10093
+ red: "sm:bg-[color-mix(in_oklab,var(--color-red-50)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-red-950)_40%,var(--color-card))]",
10094
+ blue: "sm:bg-[color-mix(in_oklab,var(--color-blue-50)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-blue-950)_40%,var(--color-card))]",
10095
+ violet: "sm:bg-[color-mix(in_oklab,var(--color-violet-50)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-violet-950)_40%,var(--color-card))]",
10096
+ teal: "sm:bg-[color-mix(in_oklab,var(--color-teal-50)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-teal-950)_40%,var(--color-card))]"
10097
+ };
10098
+ var FROZEN_CELL_TINT_CLASS = {
10099
+ slate: "sm:bg-[color-mix(in_oklab,var(--color-slate-200)_70%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-slate-700)_50%,var(--color-card))]",
10100
+ green: "sm:bg-[color-mix(in_oklab,var(--color-green-100)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-green-900)_50%,var(--color-card))]",
10101
+ amber: "sm:bg-[color-mix(in_oklab,var(--color-amber-100)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-amber-900)_50%,var(--color-card))]",
10102
+ red: "sm:bg-[color-mix(in_oklab,var(--color-red-100)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-red-900)_50%,var(--color-card))]",
10103
+ blue: "sm:bg-[color-mix(in_oklab,var(--color-blue-100)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-blue-900)_50%,var(--color-card))]",
10104
+ violet: "sm:bg-[color-mix(in_oklab,var(--color-violet-100)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-violet-900)_50%,var(--color-card))]",
10105
+ teal: "sm:bg-[color-mix(in_oklab,var(--color-teal-100)_100%,var(--color-card))] dark:sm:bg-[color-mix(in_oklab,var(--color-teal-900)_50%,var(--color-card))]"
10106
+ };
10089
10107
  var FROZEN_EDGE_CLASS = "sm:shadow-[inset_-1px_0_0_var(--border)]";
10090
10108
 
10091
10109
  // src/field-formats/registry.ts
@@ -12749,23 +12767,29 @@ function MatrxDataTableCore({
12749
12767
  const styleFieldOf = tableStyle?.fieldOf ?? ((id) => id);
12750
12768
  const styleDocumentOf = tableStyle?.documentOf ?? ((row) => row);
12751
12769
  const noChoiceColor = () => void 0;
12752
- const rowTintClass = (row, id) => {
12753
- if (!tableStyle) return void 0;
12754
- const color = resolveRowColor(
12770
+ const rowTintColor = (row, id) => {
12771
+ if (!tableStyle) return null;
12772
+ return resolveRowColor(
12755
12773
  tableStyle.style,
12756
12774
  { id, data: styleDocumentOf(row) },
12757
12775
  tableStyle.choiceColorFor ?? noChoiceColor
12758
12776
  );
12777
+ };
12778
+ const rowTintClass = (row, id) => {
12779
+ const color = rowTintColor(row, id);
12759
12780
  return color ? ROW_TINT_CLASS[color] : void 0;
12760
12781
  };
12761
- const cellTintClass = (row, id, colId) => {
12762
- if (!tableStyle) return void 0;
12763
- const color = resolveCellColor(
12782
+ const cellTintColor = (row, id, colId) => {
12783
+ if (!tableStyle) return null;
12784
+ return resolveCellColor(
12764
12785
  tableStyle.style,
12765
12786
  { id, data: styleDocumentOf(row) },
12766
12787
  styleFieldOf(colId),
12767
12788
  tableStyle.choiceColorFor ?? noChoiceColor
12768
12789
  );
12790
+ };
12791
+ const cellTintClass = (row, id, colId) => {
12792
+ const color = cellTintColor(row, id, colId);
12769
12793
  return color ? CELL_TINT_CLASS[color] : void 0;
12770
12794
  };
12771
12795
  const declaredVisibleCopyColumns = (0, import_react21.useMemo)(
@@ -14611,7 +14635,10 @@ function MatrxDataTableCore({
14611
14635
  "th",
14612
14636
  {
14613
14637
  "data-matrx-table-selection-column": true,
14614
- className: "h-9 w-9 px-2 text-left align-middle",
14638
+ className: cn(
14639
+ "h-9 w-9 px-2 text-left align-middle",
14640
+ frozenColumns.selectionOffset !== null && "sm:sticky sm:left-0 sm:z-30 sm:bg-muted"
14641
+ ),
14615
14642
  style: fixedUtilityWidth(fixedTableGeometry?.selectionWidth),
14616
14643
  children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
14617
14644
  "div",
@@ -14873,6 +14900,9 @@ function MatrxDataTableCore({
14873
14900
  const displayRow = applyRowEdits(row, rowEdits);
14874
14901
  const controls = buildRecordControls(displayRow);
14875
14902
  const isChecked = selectedIdSet.has(id);
14903
+ const rowTint = rowTintColor(row, id);
14904
+ const canHoverFrozenCell = !rowTint && (detailEnabled || Boolean(onRowOpen) || canExpandRow(row));
14905
+ const frozenRowBackgroundClass = rowTint ? FROZEN_ROW_TINT_CLASS[rowTint] : highlightedIndex === index || isSelected ? "sm:bg-muted" : isChecked ? "sm:bg-[color-mix(in_oklab,var(--color-primary)_5%,var(--color-card))]" : zebra && index % 2 === 1 ? "sm:bg-[color-mix(in_oklab,var(--color-muted)_20%,var(--color-card))]" : "sm:bg-card";
14876
14906
  const rowNode = /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
14877
14907
  "tr",
14878
14908
  {
@@ -14900,7 +14930,7 @@ function MatrxDataTableCore({
14900
14930
  // Keep the mobile row opaque while the complete row scrolls
14901
14931
  // horizontally. The translucent zebra/hover tints remain
14902
14932
  // desktop-only so densely layered mobile content stays crisp.
14903
- "border-b border-border/60 bg-card transition-colors",
14933
+ "group/matrx-row border-b border-border/60 bg-card transition-colors",
14904
14934
  (detailEnabled || Boolean(onRowOpen) || canExpandRow(row)) && "cursor-pointer sm:hover:bg-muted/50",
14905
14935
  isSelected && "bg-muted",
14906
14936
  isChecked && "bg-primary/5",
@@ -14924,7 +14954,11 @@ function MatrxDataTableCore({
14924
14954
  // When a data column is frozen the checkbox
14925
14955
  // column has to freeze with it, or the first
14926
14956
  // frozen column slides over the checkboxes.
14927
- frozenColumns.selectionOffset !== null && "sm:sticky sm:left-0 sm:z-20 sm:bg-inherit"
14957
+ frozenColumns.selectionOffset !== null && cn(
14958
+ "sm:sticky sm:left-0 sm:z-20",
14959
+ frozenRowBackgroundClass,
14960
+ canHoverFrozenCell && "sm:group-hover/matrx-row:bg-[color-mix(in_oklab,var(--color-muted)_50%,var(--color-card))]"
14961
+ )
14928
14962
  ),
14929
14963
  style: fixedUtilityWidth(fixedTableGeometry?.selectionWidth),
14930
14964
  onClick: (e) => e.stopPropagation(),
@@ -14964,6 +14998,12 @@ function MatrxDataTableCore({
14964
14998
  const isColumnDragShadow = columnDragPreview?.draggedId === columnId(col) && columnDragPreview.targetId !== null;
14965
14999
  const sheetCell = spreadsheetEnabled ? sheet.cellProps(id, columnId(col)) : null;
14966
15000
  const carriesFillHandle = sheetCell !== null && sheet.isFillHandleCell(id, columnId(col));
15001
+ const frozen = frozenColumns.offsets[columnId(col)] !== void 0;
15002
+ const frozenCellTint = cellTintColor(
15003
+ row,
15004
+ id,
15005
+ columnId(col)
15006
+ );
14967
15007
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
14968
15008
  "td",
14969
15009
  {
@@ -14994,12 +15034,16 @@ function MatrxDataTableCore({
14994
15034
  isColumnDragShadow && "bg-primary/10 shadow-[inset_2px_0_0_var(--primary),inset_-2px_0_0_var(--primary)]",
14995
15035
  alignForFormat(col) === "center" && "text-center",
14996
15036
  alignForFormat(col) === "right" && "text-right",
14997
- frozenColumns.offsets[columnId(col)] !== void 0 && FROZEN_CELL_CLASS,
15037
+ frozen && FROZEN_CELL_CLASS,
15038
+ frozen && frozenRowBackgroundClass,
15039
+ frozen && sheetCell?.["data-matrx-cell-selected"] && "sm:bg-[color-mix(in_oklab,var(--color-primary)_10%,var(--color-card))]",
15040
+ frozen && canHoverFrozenCell && "sm:group-hover/matrx-row:bg-[color-mix(in_oklab,var(--color-muted)_50%,var(--color-card))]",
14998
15041
  frozenEdgeId === columnId(col) && FROZEN_EDGE_CLASS,
14999
15042
  // A cell tint paints OVER the row tint beneath
15000
15043
  // it, and the consumer's own hook comes last so
15001
15044
  // it can always win.
15002
15045
  cellTintClass(row, id, columnId(col)),
15046
+ frozen && frozenCellTint && FROZEN_CELL_TINT_CLASS[frozenCellTint],
15003
15047
  cellClassName?.(row, columnId(col), index)
15004
15048
  ),
15005
15049
  style: {