@ai-matrx/design-system 0.11.2 → 0.11.4

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,135 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.4 — 2026-09-08
4
+
5
+ **0.11.3 SHIPPED THE FIX INTO A LAYER WHERE IT DID NOT APPLY — and the census
6
+ that forced found three older contracts in the same state.** Take this patch,
7
+ not 0.11.3.
8
+
9
+ 0.11.3 moved the sticky-footer geometry into a shipped `.matrx-dialog-footer`
10
+ rule inside `@layer matrx-design-system`. On the live matrx-frontend build that
11
+ rule was present in the CSSOM and its padding computed to **`0px`**:
12
+
13
+ ```
14
+ layer order → properties, [matrx-design-system-tokens, matrx-design-system],
15
+ theme, base, components, utilities
16
+ @layer base → *, ::after, ::before, ::backdrop { … margin: 0; padding: 0 }
17
+ ```
18
+
19
+ 🚨 **THE PREFLIGHT RULE.** Tailwind's preflight zeroes `margin`, `padding`,
20
+ `border` and `box-sizing` on every element from `@layer base` — and a host that
21
+ follows THIS PACKAGE'S OWN documented layer statement puts
22
+ `matrx-design-system` BELOW `base`. So a layered declaration of any of those
23
+ four is not lower-priority: it is **gone**, with no error and nothing on screen
24
+ to trace it by, in the consumer that followed the docs most carefully.
25
+
26
+ **The census that finding forced — three contracts that were already inert,
27
+ silently, in matrx-frontend:**
28
+
29
+ | Rule | Shipped | Property preflight ate |
30
+ |---|---|---|
31
+ | `.pb-safe` | 0.5.0 | `padding-bottom` — the safe-area floor under every BottomSheet body/footer and the CommandDialog mobile sheet |
32
+ | `.pt-safe` | 0.7.0 | `padding-top` — the notch clearance on a `direction="top"` Drawer |
33
+ | `.matrx-glass-thin-border` | 0.5.0 | `border` — the glass chrome's whole stroke |
34
+
35
+ All four now live **unlayered**, under a banner that says why, and the glass
36
+ rule is split so only its stroke leaves the layer (fill, blur and elevation
37
+ stay layered, so a host utility can still re-tint them).
38
+
39
+ **Guard:** `styles.test.ts` § THE PREFLIGHT RULE — no layered rule may declare
40
+ a preflight-reset property, and the four known contracts must be unlayered and
41
+ intact. Proven RED on the 0.11.3 sheet, where it named all three older
42
+ offenders as well as the new one.
43
+
44
+ ### Consumer action (C28)
45
+
46
+ **Take 0.11.4.** 0.11.3 has the correct structure and an inert footer rule: the
47
+ occlusion is gone but the footer renders with no padding and no bleed. Three
48
+ contracts get quietly *better* here — safe-area padding and the glass stroke
49
+ start working in every Tailwind host for the first time. One behaviour change
50
+ worth knowing: because `.matrx-dialog-footer`, `.pb-safe`, `.pt-safe` and the
51
+ glass stroke are now unlayered, a host utility on the same element no longer
52
+ overrides those specific properties. Pass geometry through the component's own
53
+ seams (`--dialog-pad`, `--dialog-pad-bottom`) rather than a padding utility.
54
+
55
+ ## 0.11.3 — 2026-09-07
56
+
57
+ **THE STICKY FOOTER STOPPED PAINTING OVER THE CONSEQUENCE.** `ConfirmDialog`'s
58
+ opaque footer covered the last ~8px of a multi-line consequence description —
59
+ the exact copy the platform's destructive-and-expensive-actions law requires
60
+ authors to write. Feedback `bf8fb00b`.
61
+
62
+ Measured in Chrome at 1280x800 on matrx-frontend, 0.11.2, with a real 3-line
63
+ folder-delete consequence:
64
+
65
+ ```
66
+ description.bottom = 429.3 footer.top = 421.7 overlap = 7.6px
67
+ scrollHeight === clientHeight === 228
68
+ ```
69
+
70
+ The second line is what made it a defect rather than a nuisance: **the card did
71
+ not scroll**, so the occluded pixels could never be revealed by any user
72
+ action. And the overlap was not a long-copy edge case — it was a constant 8px
73
+ at EVERY description length, in both themes, on `Dialog` as well as
74
+ `AlertDialog` and therefore on `ConfirmDialog`.
75
+
76
+ **Root cause.** Both footers bled over the card's bottom padding with
77
+ `mb-[calc(var(--dialog-pad,0px)*-1)]`. A negative bottom margin makes an
78
+ element's border box taller than the grid area (or flex line) its parent
79
+ allocated it, and `position: sticky` **clamps a box to its containing block** —
80
+ so the browser yanked the whole footer UP by `--dialog-pad` (24px) against a
81
+ `gap-4` (16px). 24 − 16 = the 8px of occlusion. Statically positioned, the same
82
+ negative margin renders exactly as intended; it is the interaction with
83
+ `sticky` that breaks it, which is why it survived review.
84
+
85
+ **The fix.** The bleed is bought without a negative block margin. The card hands
86
+ its bottom padding to the footer, and the footer reproduces it — so the footer's
87
+ box is exactly the space it was given, sticky has nothing to clamp, and the
88
+ opaque background still reaches the card's bottom edge with nothing scrolling
89
+ through beneath the actions. Two rules now ship in `styles.css`:
90
+
91
+ - `.matrx-dialog-footer` — the whole footer geometry (`position: sticky;
92
+ bottom: 0`, the top pad, the INLINE bleed, and
93
+ `padding-bottom: var(--dialog-pad-bottom, var(--dialog-pad, 0px))`). Sticky
94
+ clamps the block axis only, so the inline bleed stays a negative margin.
95
+ - `.matrx-dialog-card:has(> .matrx-dialog-footer) { padding-bottom: 0 }` — the
96
+ reservation, **unlayered on purpose** so it beats the card's own `p-6` /
97
+ `p-4 pb-safe` utilities. Layered, it would lose and the fix would be silently
98
+ absent in every consumer. It is conditional on `:has()`, so a `DialogContent`
99
+ with no footer keeps its full padding.
100
+
101
+ The mobile sheet's home-indicator clearance moved with the padding:
102
+ `.matrx-mobile-sheet` sets `--dialog-pad-bottom: max(0.75rem,
103
+ env(safe-area-inset-bottom, 0px))`, the same floor `pb-safe` had.
104
+
105
+ **Guards.** `src/sticky-footer-geometry.test.tsx` — proven failing on the
106
+ pre-fix sources (7 of its 8 assertions fail there) and passing here. It bans
107
+ the MECHANISM by census, not the two known sites: nothing `sticky` anywhere in
108
+ this package may carry a negative block margin. It also asserts the shipped
109
+ rules exist, that the reservation is unlayered, and that every card and footer
110
+ is wired to them. jsdom has no layout engine, so the paint itself is proven in
111
+ a real browser and that proof is permanent, not a one-off: matrx-frontend
112
+ `/demos/confirm-geometry` exposes `window.__confirmGeometry.runAll()`, which
113
+ opens the real package `ConfirmDialog` at 1-, 2-, 3- and 6-line consequences
114
+ and returns `descriptionBottom`, `footerTop`, `overlapPx` and whether the card
115
+ scrolls. Invariant: `overlapPx <= 0` at every length, light and dark.
116
+
117
+ **Why the existing tests all passed.** `confirm-dialog.test.tsx` asserts the
118
+ consequence's DOM text, its `aria-describedby` wiring, and the absence of
119
+ `line-clamp`/`truncate`. Every one of those was true the whole time. A guard
120
+ that cannot see geometry cannot catch a geometry defect — recorded here because
121
+ that is the class, not this instance.
122
+
123
+ ### Consumer action (C28)
124
+
125
+ **None** — no API change; the footer's rendered geometry is identical minus the
126
+ occlusion. Take the patch. Three assertions that spelled the footer contract as
127
+ the literal `sticky` utility now assert `matrx-dialog-footer`; no consumer
128
+ asserts on those class strings. Anything that overrode `DialogFooter`'s padding
129
+ through `className` still wins (the rule is layered); anything that set
130
+ `padding-bottom` on `DialogContent` itself while ALSO rendering a footer is now
131
+ overridden by the reservation, which is the point.
132
+
3
133
  ## 0.11.2
4
134
 
5
135
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/dist/index.cjs CHANGED
@@ -1060,9 +1060,13 @@ var AlertDialogContent = React7.forwardRef(({ className, children, container, an
1060
1060
  ref,
1061
1061
  "data-slot": "alert-dialog-content",
1062
1062
  className: cn(
1063
- `fixed left-[50%] top-[50%] z-[10000] grid min-w-0 w-full max-w-lg ${CENTERED_DIALOG} gap-4 border bg-background p-6 shadow-lg`,
1063
+ `matrx-dialog-card fixed left-[50%] top-[50%] z-[10000] grid min-w-0 w-full max-w-lg ${CENTERED_DIALOG} gap-4 border bg-background p-6 shadow-lg`,
1064
1064
  // Ruling 3 — never taller than the viewport, always scrollable, and
1065
1065
  // the footer stays reachable via --dialog-pad like Dialog's.
1066
+ // Ruling 5 (0.11.3) — `matrx-dialog-card` hands the bottom padding to
1067
+ // a sticky footer when there is one, so the footer's box matches the
1068
+ // space the grid gave it and sticky never clamps it up over the
1069
+ // consequence copy.
1066
1070
  "max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full",
1067
1071
  "sm:rounded-lg",
1068
1072
  animated && MOTION_DIALOG,
@@ -1100,9 +1104,12 @@ var AlertDialogFooter = ({
1100
1104
  className: cn(
1101
1105
  "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
1102
1106
  // Ruling 3/4 — sticky to the card edges so a scrolled body never shows
1103
- // through under the actions, and safe-area padded on a phone.
1104
- "sticky bottom-0 z-10 bg-background pt-3",
1105
- "mx-[calc(var(--dialog-pad,0px)*-1)] mb-[calc(var(--dialog-pad,0px)*-1)] px-[var(--dialog-pad,0px)] pb-[var(--dialog-pad,0px)]",
1107
+ // through under the actions, and safe-area padded on a phone. ALL of
1108
+ // that geometry is `matrx-dialog-footer`, a rule this package SHIPS
1109
+ // (styles.css), because the utility spelling of it carried a negative
1110
+ // block margin that sticky clamped — painting the footer over the last
1111
+ // 8px of the consequence at every description length (0.11.3).
1112
+ "matrx-dialog-footer bg-background",
1106
1113
  className
1107
1114
  ),
1108
1115
  ...props
@@ -2123,8 +2130,8 @@ var DialogContentPrimitive = React17.forwardRef((props, ref) => {
2123
2130
  );
2124
2131
  });
2125
2132
  DialogContentPrimitive.displayName = "DialogContentPrimitive";
2126
- var DIALOG_DESKTOP_CLASSES2 = `fixed left-[50%] top-[50%] z-[10000] grid min-w-0 w-full max-w-lg ${CENTERED_DIALOG} gap-4 max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip border bg-background p-6 shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full sm:rounded-lg`;
2127
- var DIALOG_MOBILE_SHEET_CLASSES2 = "matrx-mobile-sheet fixed inset-x-0 bottom-0 left-0 right-0 top-auto z-[10000] flex min-w-0 flex-col w-full max-w-full max-h-[90dvh] translate-x-0 translate-y-0 gap-4 [--dialog-pad:1rem] overflow-x-clip border-t bg-background p-4 pb-safe shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full rounded-t-2xl rounded-b-none overflow-y-auto overscroll-contain";
2133
+ var DIALOG_DESKTOP_CLASSES2 = `matrx-dialog-card fixed left-[50%] top-[50%] z-[10000] grid min-w-0 w-full max-w-lg ${CENTERED_DIALOG} gap-4 max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip border bg-background p-6 shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full sm:rounded-lg`;
2134
+ var DIALOG_MOBILE_SHEET_CLASSES2 = "matrx-mobile-sheet matrx-dialog-card fixed inset-x-0 bottom-0 left-0 right-0 top-auto z-[10000] flex min-w-0 flex-col w-full max-w-full max-h-[90dvh] translate-x-0 translate-y-0 gap-4 [--dialog-pad:1rem] overflow-x-clip border-t bg-background p-4 pb-safe shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full rounded-t-2xl rounded-b-none overflow-y-auto overscroll-contain";
2128
2135
  var DIALOG_MOBILE_SHEET_OVERRIDE2 = "inset-x-0 bottom-0 left-0 right-0 top-auto translate-x-0 translate-y-0 w-full max-w-full max-h-[90dvh] rounded-b-none rounded-t-2xl overflow-y-auto";
2129
2136
  var DialogContent = React17.forwardRef(
2130
2137
  ({
@@ -2228,8 +2235,12 @@ var DialogFooter = ({
2228
2235
  "data-slot": "dialog-footer",
2229
2236
  className: cn(
2230
2237
  "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
2231
- "sticky bottom-0 z-10 bg-background pt-3",
2232
- "mx-[calc(var(--dialog-pad,0px)*-1)] mb-[calc(var(--dialog-pad,0px)*-1)] px-[var(--dialog-pad,0px)] pb-[var(--dialog-pad,0px)]",
2238
+ // Ruling 3 — the geometry is `matrx-dialog-footer`, a rule this package
2239
+ // SHIPS (styles.css). It used to be utilities, one of which was a
2240
+ // negative block margin that `position: sticky` clamps — the footer was
2241
+ // yanked up over the row above it by `--dialog-pad` minus the card gap
2242
+ // (0.11.3). The card gives the footer its bottom padding instead.
2243
+ "matrx-dialog-footer bg-background",
2233
2244
  className
2234
2245
  ),
2235
2246
  ...props