@ai-matrx/design-system 0.86.333 → 0.86.335

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 (69) hide show
  1. package/CHANGELOG.md +42 -62
  2. package/dist/carousel.cjs.map +1 -1
  3. package/dist/carousel.js +4 -4
  4. package/dist/{chunk-NNETFHGX.js → chunk-4CO5STZU.js} +18 -4
  5. package/dist/chunk-4CO5STZU.js.map +1 -0
  6. package/dist/{chunk-MFUNGDHO.js → chunk-B24DLFWR.js} +2 -2
  7. package/dist/{chunk-CSSD6NS4.js → chunk-DQUCOMAC.js} +2 -2
  8. package/dist/{chunk-6YZMGSQY.js → chunk-M34WPTPX.js} +2 -2
  9. package/dist/{chunk-VV6WZTH5.js → chunk-PBDQZPKV.js} +2 -2
  10. package/dist/{chunk-E4GS5QH7.js → chunk-Q2HWDJED.js} +2 -2
  11. package/dist/{chunk-ZOQ2XKXF.js → chunk-QOEKPR37.js} +5 -5
  12. package/dist/chunk-QOEKPR37.js.map +1 -0
  13. package/dist/{chunk-MEJVHDYJ.js → chunk-RGJPHRU3.js} +2 -2
  14. package/dist/{chunk-7NEVJKDZ.js → chunk-SUVIHUAD.js} +3 -3
  15. package/dist/{chunk-3MQMVPKO.js → chunk-VQ3G6AFN.js} +4 -4
  16. package/dist/clipboard-fallback-dialog.cjs.map +1 -1
  17. package/dist/clipboard-fallback-dialog.js +1 -1
  18. package/dist/controls.cjs +4 -4
  19. package/dist/controls.cjs.map +1 -1
  20. package/dist/controls.css +6 -0
  21. package/dist/controls.js +4 -4
  22. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  23. package/dist/data-table/data-row-inspector.js +4 -4
  24. package/dist/data-table/data-row-window.cjs.map +1 -1
  25. package/dist/data-table/data-row-window.js +5 -5
  26. package/dist/data-table/index.cjs +4 -4
  27. package/dist/data-table/index.cjs.map +1 -1
  28. package/dist/data-table/index.js +7 -7
  29. package/dist/data-table/pagination.cjs +4 -4
  30. package/dist/data-table/pagination.cjs.map +1 -1
  31. package/dist/data-table/pagination.js +2 -2
  32. package/dist/data-table/uuid-cell.cjs.map +1 -1
  33. package/dist/data-table/uuid-cell.js +2 -2
  34. package/dist/desktop.cjs.map +1 -1
  35. package/dist/desktop.js +3 -3
  36. package/dist/index.cjs +574 -385
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +115 -3
  39. package/dist/index.d.ts +115 -3
  40. package/dist/index.js +437 -268
  41. package/dist/index.js.map +1 -1
  42. package/dist/item.cjs +33 -17
  43. package/dist/item.cjs.map +1 -1
  44. package/dist/item.d.cts +7 -1
  45. package/dist/item.d.ts +7 -1
  46. package/dist/item.js +19 -17
  47. package/dist/item.js.map +1 -1
  48. package/dist/lite-table.cjs.map +1 -1
  49. package/dist/lite-table.js +1 -1
  50. package/dist/record-list.cjs +16 -2
  51. package/dist/record-list.cjs.map +1 -1
  52. package/dist/record-list.d.cts +7 -1
  53. package/dist/record-list.d.ts +7 -1
  54. package/dist/record-list.js +2 -2
  55. package/dist/settings.cjs.map +1 -1
  56. package/dist/settings.js +2 -2
  57. package/dist/writing-field.cjs.map +1 -1
  58. package/dist/writing-field.js +2 -2
  59. package/package.json +2 -2
  60. package/dist/chunk-NNETFHGX.js.map +0 -1
  61. package/dist/chunk-ZOQ2XKXF.js.map +0 -1
  62. /package/dist/{chunk-MFUNGDHO.js.map → chunk-B24DLFWR.js.map} +0 -0
  63. /package/dist/{chunk-CSSD6NS4.js.map → chunk-DQUCOMAC.js.map} +0 -0
  64. /package/dist/{chunk-6YZMGSQY.js.map → chunk-M34WPTPX.js.map} +0 -0
  65. /package/dist/{chunk-VV6WZTH5.js.map → chunk-PBDQZPKV.js.map} +0 -0
  66. /package/dist/{chunk-E4GS5QH7.js.map → chunk-Q2HWDJED.js.map} +0 -0
  67. /package/dist/{chunk-MEJVHDYJ.js.map → chunk-RGJPHRU3.js.map} +0 -0
  68. /package/dist/{chunk-7NEVJKDZ.js.map → chunk-SUVIHUAD.js.map} +0 -0
  69. /package/dist/{chunk-3MQMVPKO.js.map → chunk-VQ3G6AFN.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,25 +1,44 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.86.335
4
+
5
+ - **Select `hint` never truncates** (vault review, 2026-10-23): in the menu and on the trigger the label truncates and the option's `hint` (a short id) stays whole, so two long same-named options stay told apart (`data-select-hint`). Proof: `src/controls/select-search-hint.test.tsx`. Consumer action: none.
6
+
7
+ ## 0.86.334
8
+
9
+ No separate release note was written for this version; no consumer action known.
10
+
3
11
  ## 0.86.333
4
12
 
5
- UNVERIFIED: this release has no Unreleased entry and the source comparison could not be made (the caller supplied no source comparison). Whether source changed is unknown; consumer action is unknown.
6
- Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/design-system/src`.
13
+ SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
14
+ so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
15
+ Diff: `git diff 24afe9d748 91557e5a85 -- apps/shared/design-system/src`
16
+
17
+ Changed shipped source files (2):
18
+ - `apps/shared/design-system/src/tap-shortcut.ts`
19
+ - `apps/shared/design-system/src/tap-target/tap-features.tsx`
20
+
21
+ ## 0.86.332
22
+
23
+ Automatic changed-only republish (docs/metadata drift since the last published version; verified: `git diff 00cdf507e0 24afe9d748 -- apps/shared/design-system/src`
24
+ has no shipped-source changes outside tests, fixtures and docs). No consumer action required.
25
+
26
+ ## 0.86.331
27
+
28
+ - **Select `hint` and `searchAt`** (2026-10-23): an option's `hint` is muted text after its label in the menu and on the trigger (what tells two same-named options apart: a short id, an owner); `searchAt` puts a search row at the top of the menu once there are at least that many options (matches label, hint and group; "No match" when nothing does). Proof: `src/controls/select-search-hint.test.tsx`. Consumer action: none.
7
29
 
8
30
  ## 0.86.330
9
31
 
10
32
  - **menu-look: one left edge, no gutter** (Arman, 2026-10-23). `MenuLookRowBody` draws no icon column for a row without a glyph (it used to reserve an empty 16px slot). New `current` on `MenuLookItem` / `MenuLookRowBody`: `data-current`, medium-weight label and a check at the row's END (`cm-current`). New `MenuLookSearch`: the menu's own sticky header-row search, text on the rows' 12px edge. `MenuLookCheckboxItem` keeps its column on and off. Consumer action: drop any invisible check/placeholder glyph used to align rows, and mark the current row with `current`.
11
33
  - **item: `ProductSidebarTop` has one search door.** Removed `search.pool` (place search) and `matchSidebarPlaces`; `search` remains only for a list's own filter. Consumer action: a sidebar whose top row carries a search icon passes no `search`.
12
34
 
13
-
14
-
15
35
  ## 0.86.329
16
36
 
17
- - **Tile `dashed` and `hoverStyle="fill"`** (2026-10-23): the Tile migration had dropped AddTile's dashed border and the desktop `ListRow`'s pointer fill (`hover:bg-fill-secondary`). Both return as named Tile options: `dashed` (the "add another" tile) and `hoverStyle="fill"` (the desktop secondary fill, the accent outside the desktop look); `AddTile` and `ListRow` use them. Proof: `media-option.test.tsx`, `mac-table-parity.test.tsx`, `tile-named-options.test.tsx`. Consumer action: none.
37
+ - **New light entry `./tap-shortcut` (2026-10-23, FB5).** `formatTapShortcut`, `parseShortcut` and `TapShortcut` with no React, for plain helpers; `./tap-target` re-exports the same three. Consumer action: none.
18
38
 
19
39
  ## 0.86.328
20
40
 
21
41
  - **Tile `dashed` and `hoverStyle="fill"`** (2026-10-23): the Tile migration had dropped AddTile's dashed border and the desktop `ListRow`'s pointer fill (`hover:bg-fill-secondary`). Both return as named Tile options: `dashed` (the "add another" tile) and `hoverStyle="fill"` (the desktop secondary fill, the accent outside the desktop look); `AddTile` and `ListRow` use them. Proof: `media-option.test.tsx`, `mac-table-parity.test.tsx`, `tile-named-options.test.tsx`. Consumer action: none.
22
- - **Tile named options** (vault 0.1.33 review, 2026-10-23): `selectedStyle="primary"` (the open item of a master list: solid primary, every ink on it, hover too), `tooltip` (the native `title`; `title` stays the visible LABEL), `level` 1|2|3 (nesting: an icon-less child's title starts under its parent's), `fit` (sizes to its content, never shrinks or truncates the title: a code), `oneLine` (the secondary line is one line), `endInset="control"` (room for a control laid over the row's end). Proof: `src/controls/tile-named-options.test.tsx`. Consumer action: a Tile that passed a tooltip string as `title` moves it to `tooltip`; never put `data-surface="primary"` on a quiet Tile (use `selectedStyle="primary"`); replace `pl-*`/`pr-*` on a Tile (its padding is locked) with `level` / `endInset`.
23
42
 
24
43
  ## 0.86.327
25
44
 
@@ -27,7 +46,6 @@ Check the package's gitHead on npm against this version's gitHead: `git diff <pr
27
46
  - **menu-look: one left edge, no gutter** (Arman, 2026-10-23). `MenuLookRowBody` draws no icon column for a row without a glyph (it used to reserve an empty 16px slot). New `current` on `MenuLookItem` / `MenuLookRowBody`: `data-current`, medium-weight label and a check at the row's END (`cm-current`). New `MenuLookSearch`: the menu's own sticky header-row search, text on the rows' 12px edge. `MenuLookCheckboxItem` keeps its column on and off. Consumer action: drop any invisible check/placeholder glyph used to align rows, and mark the current row with `current`.
28
47
  - **item: `ProductSidebarTop` has one search door.** Removed `search.pool` (place search) and `matchSidebarPlaces`; `search` remains only for a list's own filter. Consumer action: a sidebar whose top row carries a search icon passes no `search`.
29
48
 
30
-
31
49
  ## 0.86.326
32
50
 
33
51
  SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
@@ -337,14 +355,12 @@ Changed shipped source files (3):
337
355
  - **Swipe deck: a finish and an empty screen worthy of the deck (Arman, 2026-10-22).** The end is the deck's own screen: a mark that draws itself (a ring filled by the score on a quiz), the headline (the group's pick, the score, or All done), "12 of 12 answered", a bar of how the answers split with chips that filter the list (Right / Wrong on a graded deck, else by answer), and every answer to look over — a row takes that answer back and returns to its card (undoable), a miss shows the right answer. `endActions` puts the host's way on (Back to brand) under it. No items is its own screen (fanned cards, `empty: {title, line, action}`), never a zero tally. `renderEnd` still replaces the end entirely; a host using it for an EmptyState should drop it for `endActions`. Guard: `src/swipe-deck/end-screens.test.tsx`. Consumer action: none (optional: drop `renderEnd`, pass `endActions` and `empty`).
338
356
  - **A peek never leaves the screen vertically.** `PeekCard`'s height (fit, fixed and loading) is capped by `--matrx-peek-room`, which `PeekHoverCard` and `PeekPopover` set from the popper's available height; a card with no room above or below its trigger shrinks and scrolls inside instead of losing its title off the top. Consumer action: none.
339
357
 
340
-
341
358
  - **`ProductSidebarTop` (`./item`) — the top of every product sidebar** (Arman 2026-10-22): optional modes slot, Search, New, the chosen related places (`›`, a place with `children` opens a flyout), "More" (every other place, extra `moreGroups`, "Edit sidebar…"). Extracted from the conversation sidebar's top; `SidebarPlacesChooser` is the dialog's "Above More" section, `SidebarEditDialog` the dialog's chrome; `splitSidebarPlaces` / `matchSidebarPlaces` the pure halves. Which places sit above More is the host's layered knob. Consumer action: none (additive).
342
359
 
343
360
  ## 0.86.294
344
361
 
345
362
  - **A peek never leaves the screen vertically.** `PeekCard`'s height (fit, fixed and loading) is capped by `--matrx-peek-room`, which `PeekHoverCard` and `PeekPopover` set from the popper's available height; a card with no room above or below its trigger shrinks and scrolls inside instead of losing its title off the top. Consumer action: none.
346
363
 
347
-
348
364
  - **`ProductSidebarTop` (`./item`) — the top of every product sidebar** (Arman 2026-10-22): optional modes slot, Search, New, the chosen related places (`›`, a place with `children` opens a flyout), "More" (every other place, extra `moreGroups`, "Edit sidebar…"). Extracted from the conversation sidebar's top; `SidebarPlacesChooser` is the dialog's "Above More" section, `SidebarEditDialog` the dialog's chrome; `splitSidebarPlaces` / `matchSidebarPlaces` the pure halves. Which places sit above More is the host's layered knob. Consumer action: none (additive).
349
365
 
350
366
  ## 0.86.293
@@ -808,7 +824,6 @@ Changed shipped source files (1):
808
824
 
809
825
  - `SiteIcon` uses the package's pulse motion while loading, so a host without Tailwind animation utilities gets the same loading feedback. Formula consumer guards follow kit/Airtable's blank `YEAR` / `MONTH` / `DAY` result (`null`); nonempty invalid dates still refuse. Consumer action: none.
810
826
 
811
-
812
827
  - **`SiteIcon` — a website's own icon.** `<SiteIcon site={urlOrHost} iconUrl? fallback? size? className? />` (root export and `@ai-matrx/design-system/site-icon`) reserves its box, shimmers while loading, and tries the caller's icon URL, then Google's favicon service (a 16px answer is Google's default globe and falls through), then DuckDuckGo's (a 48px answer is its default). The generic glyph (a globe by default) shows only when no real icon exists. Also exports `siteHostname`. Use it for every site / URL / domain / source avatar instead of a hand-placed Globe or Link. Consumer action: none.
813
828
 
814
829
  - **`TextInputDialog` takes `allowEmpty`.** An "(optional)" note no longer leaves Confirm disabled until something is typed: with `allowEmpty` the button is enabled on an empty value and submits `""`. Default false, so every existing caller is unchanged.
@@ -1771,7 +1786,6 @@ Changed shipped source files (2):
1771
1786
 
1772
1787
  - `MatrxDataTable` (spreadsheet mode): a double-click edits the cell when it has an editor, and opens the row (`onRowOpen`) from a cell that cannot be edited or from the row's margin; a double-click inside an editor or control stays theirs. A single click still only selects.
1773
1788
 
1774
-
1775
1789
  ## 0.86.158
1776
1790
 
1777
1791
  SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
@@ -1845,7 +1859,6 @@ Changed shipped source files (4):
1845
1859
  - **`Field` / `SearchField` `filled`: the leading search of a home page** — a 48px capsule with no frame, the `--muted` fill, a 16px value and a 20px glyph; on focus it turns `--card` with a soft lift (Google Docs / Drive home search). One per page. Consumer action: none; opt in with `<SearchField filled />`.
1846
1860
  - **The pill-inset guard sees a border-drawn busy spinner.** An element with `role="status"` / `"progressbar"` inside a pill is ink by its box (its rings are absolute, so the walker skipped them and every pill whose icon became a spinner read "44px left vs 20px right"). Proof: `pill-inset-guard.test.tsx` (red before).
1847
1861
 
1848
-
1849
1862
  ## 0.86.149
1850
1863
 
1851
1864
  SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
@@ -2680,20 +2693,10 @@ Automatic changed-only republish (docs/metadata drift since the last tag — see
2680
2693
  No source changes intended and no consumer action required.
2681
2694
 
2682
2695
  ## 0.86.27
2683
- ### Unreleased
2684
-
2685
- - New entry `@ai-matrx/design-system/carousel`: `Carousel`, THE slide strip. `mode="viewer"` swipes (scroll-snap),
2686
- steps with arrows and Left/Right/Home/End, shows dots, a counter and a thumbnail strip, in 1:1, 4:5, 9:16 or
2687
- 16:9 with no layout shift. `mode="editor"` adds add / duplicate / delete / reorder (drag a thumbnail or
2688
- move earlier/later) / edit / version history / export. The host draws every slide through `renderSlide`
2689
- (images, text-on-image social slides, presentation slides) and owns storage: edits leave through
2690
- `onSlidesChange`, a slide update also leaves through `onSlideChange` with the previous version
2691
- (`pushVersion` keeps a bounded newest-first list), export is a callback. Pure slide logic is exported
2692
- (`moveSlide`, `insertSlide`, `duplicateSlide`, `removeSlide`, `replaceSlide`, `pushVersion`).
2693
-
2694
- `Carousel` wraps itself in its own `TooltipProvider`, so its controls render in any host root.
2695
2696
 
2696
- **Consumer action:** none; replace any hand-built multi-image grid or unused Embla wrapper with `<Carousel>`.
2697
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
2698
+ `git diff npm/design-system/v0.86.26..npm/design-system/v0.86.27 -- apps/shared/design-system`).
2699
+ No source changes intended and no consumer action required.
2697
2700
 
2698
2701
  ## 0.86.27
2699
2702
 
@@ -3063,27 +3066,13 @@ No source changes intended and no consumer action required.
3063
3066
 
3064
3067
  ## 0.80.0
3065
3068
 
3066
- Desktop standard, HIG review fixes, at the design-system level so every screen inherits them:
3067
-
3068
- - `DataTable` is a CSS grid with column kinds (`Column.kind`: flex, text, numeric, status, date,
3069
- action; inferred from `numeric`/`width` when absent). Only the flex column truncates; numbers,
3070
- ids, statuses, dates and actions fit their content and are never cut ("PID 1…" is gone); spare
3071
- width goes to the flex column up to its content, then is shared by every column; sideways scroll
3072
- only when the fitted columns exceed the width. One row density (`h-row-table`, 28 px) for every
3073
- row and header; headers never wrap. New exports `columnKind`, `ColumnKind`.
3074
- - `Page` notices sit in a foot bar in the layout flow (never floating over content); `Notices` is an
3075
- in-flow stack. Page rhythm on the HIG scale (20 px margins and section gaps; no reserved header or
3076
- section-title bands).
3077
- - Dialogs from the desktop entry are macOS sheets (`DialogContent`, `DialogHeader`, `DialogTitle`,
3078
- `DialogDescription`, `DialogFooter` from `./sheet`).
3079
- - Dark mode: green is the dark systemGreen (never amber/lime); a selected row uses the accent at
3080
- selected-row strength; status dots are desaturated. Light selection is one step deeper than the
3081
- tint.
3082
- - `StateView kind="empty"` draws a standard empty glyph and a quiet title; `Sparkline` axis labels
3083
- sit outside the plot (never over the line); field placeholders are always the system font.
3084
-
3085
- **Consumer action:** remove any `className` that positioned a `Notices` stack absolutely
3086
- (`top-*`, `bottom-*`); place it in its container's flow instead.
3069
+ No layout shift, dialogs included (Arman, 2026-10-07).
3070
+
3071
+ - **`NoticeSlot`** (new): the message slot of a dialog or sheet, a fixed-height box that is always there, so an error appearing in it or leaving moves nothing around it. A longer banner is clipped to the slot, never grown.
3072
+ - **Lint `desktop/no-shifting-notice`**: a `Dialog` / `DialogContent` / `AlertDialogContent` is no longer a home for a Banner (it grew the dialog); `NoticeSlot` is.
3073
+ - **`Page` / `Notices`**: notices that render nothing leave no box and no scroll room (the stack is hidden while empty); the scroll room at the page's foot is exactly the stack's measured height (less the foot padding the page already has), so a tall stack never covers the last rows. `Notices` takes `onHeight`.
3074
+
3075
+ **Consumer action:** a Banner / ErrorBanner directly inside a dialog now fails the lint; put it in `<NoticeSlot>`.
3087
3076
 
3088
3077
  ## 0.79.5
3089
3078
 
@@ -3249,7 +3238,6 @@ No source changes intended and no consumer action required.
3249
3238
 
3250
3239
  - `DataRowInspector` (the detail panel and row window's View tab) labels each field by its column's own name when the table has one, else through kit's `displayLabel` (`spineStatus` -> `Spine Status`, `createdAt` -> `Created At`), never the raw key. New optional `labelForField(key)`; `MatrxDataTable` passes its column headers.
3251
3240
 
3252
-
3253
3241
  ## 0.72.3
3254
3242
 
3255
3243
  Automatic changed-only republish (docs/metadata drift since the last tag — see
@@ -4448,7 +4436,6 @@ No source changes intended and no consumer action required.
4448
4436
  Frontend, Dashboard, Records Grid and desktop callers are migrated without changing writes.
4449
4437
  Guards: `TableIconActions.test.tsx`, edit-actions, layout-look, density and row-cost tests.
4450
4438
 
4451
-
4452
4439
  - **Custom fields on every list (lane 7 STANDARD-TABLES W5).** `MatrxDataTable` takes `rowToken`
4453
4440
  (the registry token of its rows); the host port `useCustomFieldColumns(token, organizationIds)` —
4454
4441
  a hook bound once — answers that token's custom-field columns for the rows' own organizations
@@ -5010,16 +4997,14 @@ Automatic changed-only republish (docs/metadata drift since the last tag — see
5010
4997
  No source changes intended and no consumer action required.
5011
4998
 
5012
4999
  ## Unreleased
5000
+ ### lane RENDER-3 (2026-09-27): the table's toolbar, column headers, footer and pager draw only when what they show changed
5013
5001
 
5014
- - **New light entry `./tap-shortcut` (2026-10-23, FB5).** `formatTapShortcut`, `parseShortcut` and `TapShortcut` with no React, for plain helpers; `./tap-target` re-exports the same three. Consumer action: none.
5015
- - **Loaders and SimpleTooltip are owned here (one-canonical, packages-copies lane, 2026-10-21).** New root exports `LoadingSpinner`, `MatrxMiniLoader`, `SuspenseLoader`, `ShimmerText` (+ `useShimmerSweep`, `SHIMMER_STYLE`), `SimpleTooltip`, `AdvancedTooltip`; internal `WorkflowIcon` glyph (no icon-library dependency, C19). Each was a copy in `@ai-matrx/rich-content` (`utils/lifted/`) and matrx-frontend. Consumer action: import the named exports from `@ai-matrx/design-system` and delete the host copy (`SuspenseLoader`, `MatrxMiniLoader`, `LoadingSpinner` were default exports in the host).
5016
-
5017
- - **No page-wide `:has()` (review 6b, 2026-10-21).** `SidebarMenuItem` pads its button through a child-only `:has()` (was `group-has-*`, a universal subject); the key-window highlight in `desktop.css` and `MessageList` reads `:not([data-window-active] *)` instead of `:root:not(:has([data-window-active]))`. Each made one DOM insertion restyle the whole phone notes page (114 ms against 8 ms). A list outside every window now highlights on focus even while a floating window exists elsewhere.
5018
- - **Every tooltip is a tooltip again — and every native `title` is one too** (Arman, 2026-09-28: "we've lost all of our tooltips… all we have are these shitty browser ones"). Three defects, one surface:
5019
- 1. *No tooltip animated since 0.10.0.* `.matrx-motion-popper`'s open rules keyed on `data-state="open"`, which Radix Tooltip never emits (`delayed-open` / `instant-open`), so every tooltip popped in still. The open rules now match all three.
5020
- 2. *The surface was the browser's.* White, thin grey border, 12px dark text — indistinguishable from macOS's own `title` box. `TooltipContent` now wears `.matrx-tooltip`: a dark, high-contrast chip in both themes (Linear / GitHub / Vercel), re-scoping `--popover`, `--foreground`, `--muted-foreground` and `--border` inside it so rich content stays legible. New tokens `--matrx-tooltip`, `--matrx-tooltip-foreground`, `--matrx-tooltip-muted-foreground`, `--matrx-tooltip-border`, `--matrx-tooltip-shadow` re-brand every tooltip at once.
5021
- 3. *Half the controls on a page used `title=`.* `TooltipProvider` now installs THE TITLE TAKEOVER (`title-tooltips.ts`, exported as `acquireTitleTooltips`): while any provider is mounted, hovering (mouse/pen) or keyboard-focusing an element with a `title` lifts the attribute for as long as it is held and shows the same chip instead; the `title` is restored on leave. A `TooltipTrigger` (now stamped `data-matrx-tooltip-trigger`) keeps its own tooltip and never gets a second. `data-title-side` on an element or ancestor picks the side; `data-native-title` opts a subtree out; `<TooltipProvider titleTooltips={false}>` opts a provider out. It never draws a tooltip that only repeats text already readable in full inside the element (an expanded sidebar row), and still draws it when that text is hidden or truncated.
5022
- Proof: `title-tooltips.test.tsx` (every case red on 0.49.19). Consumer action: none required — a host that already mounts `TooltipProvider` gets all three. A host test asserting `bg-popover`'s computed color on a tooltip reads the chip's token now.
5002
+ - **`MatrxDataTable` memoises its own chrome** (`MatrxTableChrome`): the toolbar row, the `<thead>`, the `<tfoot>` and the pager are each drawn again only when a value they read changed — every prop and table value each part reads, directly and through the handlers it hands out, compared by value where the table re-derives them (columns key by key, widths, the frozen band, the column window, the header filters' options). Measured before on /data-v2 (native grid, published 0.47.2): one cell edit rendered 7,815 components, ~7.5k of them this chrome, on each of the table's ~10 renders per edit. jsdom guard (records-ui `one-cell-edit-redraws-one-row.test.tsx`, merged grid): toolbar 2,012 → 0, header 3,080 → 0, footer + pager 1,180 → 0.
5003
+ - **Handlers the kept chrome hands out act on the table as it is now** (`chromeLatest`): the toolbar's copy of "the view" (human, JSON, agent text, sheet rows, "Filter & sort before copying") copies the rows after the last edit; select-all, "Show more" and applying a saved view read the latest rows.
5004
+ - **dnd-kit's options are module values** (pointer sensor, accessibility, measuring). Written inline they were new objects on every render, so the drag context moved every render and redrew every column header (each is a draggable and a drop zone).
5005
+ - **Stable identities for what the chrome holds:** a controlled query with no layered filters reads one empty list; `useTableNotice().notify` is one object per host; `useCopySubsetVariant()` returns one function.
5006
+ - **A toolbar copy config that BUILDS its menu from the rows while drawing** (`references`, `aiVariants`, `aiCustom` or `export` declared with parameters) still redraws the toolbar with the rows; one declared with no parameter cannot read them and never does.
5007
+ - **Consumer action:** a host that hands `toolbar`, `columns`, `query`, `footerRows`, `columnState`, `grouping` or `copy` must pass a NEW object when what it shows changes (inline objects already are — the chrome then redraws on every render, as before). A host that wants the saving holds them still; `footerRows` is the footer's signal — a host whose footer cells read state from elsewhere passes a new `footerRows` array when that state changes.
5023
5008
 
5024
5009
  ## 0.49.19
5025
5010
  ### Unreleased
@@ -5177,7 +5162,6 @@ No source changes intended and no consumer action required.
5177
5162
 
5178
5163
  - The adaptive `BottomSheet` has no 60dvh minimum (it keeps the 90dvh maximum): a two-action sheet was mostly empty and hosts overrode it with `min-h-0`. Proof: `bottom-sheet.test.tsx`, red on the old class.
5179
5164
 
5180
-
5181
5165
  ### (2026-09-27 — an empty table)
5182
5166
 
5183
5167
  - **An empty table (nothing searched or filtered) draws no pager** — "0-0 of 0" and a disabled pager said nothing the empty state did not. A search or filter that matched nothing keeps its footer (it still says what was searched).
@@ -5328,7 +5312,6 @@ No source changes intended and no consumer action required.
5328
5312
  - Checkbox rows (sections, columns, "Only selected rows") sit beside their labels at checkbox size (`.matrx-alchemy-check`); the text-input rule no longer styles checkboxes into 36px boxes stacked above their labels.
5329
5313
  - Proof: `src/content-transfer/sections-workspace.test.tsx` (red before, green after). Needs `@ai-matrx/kit` with the rebundled core.
5330
5314
 
5331
-
5332
5315
  ## 0.46.4
5333
5316
 
5334
5317
  Automatic changed-only republish (docs/metadata drift since the last tag — see
@@ -6158,7 +6141,6 @@ None. Every new prop is optional and every default is today's behavior. `MatrxCo
6158
6141
  ignored when the column already supplies `cell`; a consumer's own renderer can ask for the same
6159
6142
  text with the exported `formatColumnValue(col, value)` instead of writing a second money formatter.
6160
6143
 
6161
-
6162
6144
  ## 0.21.14 — 2026-09-19
6163
6145
 
6164
6146
  Alchemy renders the kit's new `queued` transfer outcome (`@ai-matrx/kit` 0.16.0): a write that was
@@ -6479,7 +6461,6 @@ Alchemy adopts approved Portal sample B: 22px artwork with a tighter optical cro
6479
6461
 
6480
6462
  Update `@ai-matrx/design-system`; no host styling or prop changes.
6481
6463
 
6482
-
6483
6464
  ## 0.19.5 — 2026-09-13
6484
6465
 
6485
6466
  Data-table append receipts remain visible after terminal loads and across remote response or error states. Footer containment now keeps the 44px action controls and 20px action glyphs visible without mobile clipping.
@@ -6900,7 +6881,6 @@ sources into `controlled-append`; the table cannot infer an endpoint or cursor.
6900
6881
  Use `@ai-matrx/data/react` `usePaginatedData` or an equivalent receipt, key every
6901
6882
  source-affecting input, and pass the application-resolved scrolling preference.
6902
6883
 
6903
-
6904
6884
  ## 0.14.3 — 2026-09-11
6905
6885
 
6906
6886
  `ConfirmDialog` now renders its accessible description through Radix's