@ai-matrx/design-system 0.11.1 → 0.11.3

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,89 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.3 — 2026-09-07
4
+
5
+ **THE STICKY FOOTER STOPPED PAINTING OVER THE CONSEQUENCE.** `ConfirmDialog`'s
6
+ opaque footer covered the last ~8px of a multi-line consequence description —
7
+ the exact copy the platform's destructive-and-expensive-actions law requires
8
+ authors to write. Feedback `bf8fb00b`.
9
+
10
+ Measured in Chrome at 1280x800 on matrx-frontend, 0.11.2, with a real 3-line
11
+ folder-delete consequence:
12
+
13
+ ```
14
+ description.bottom = 429.3 footer.top = 421.7 overlap = 7.6px
15
+ scrollHeight === clientHeight === 228
16
+ ```
17
+
18
+ The second line is what made it a defect rather than a nuisance: **the card did
19
+ not scroll**, so the occluded pixels could never be revealed by any user
20
+ action. And the overlap was not a long-copy edge case — it was a constant 8px
21
+ at EVERY description length, in both themes, on `Dialog` as well as
22
+ `AlertDialog` and therefore on `ConfirmDialog`.
23
+
24
+ **Root cause.** Both footers bled over the card's bottom padding with
25
+ `mb-[calc(var(--dialog-pad,0px)*-1)]`. A negative bottom margin makes an
26
+ element's border box taller than the grid area (or flex line) its parent
27
+ allocated it, and `position: sticky` **clamps a box to its containing block** —
28
+ so the browser yanked the whole footer UP by `--dialog-pad` (24px) against a
29
+ `gap-4` (16px). 24 − 16 = the 8px of occlusion. Statically positioned, the same
30
+ negative margin renders exactly as intended; it is the interaction with
31
+ `sticky` that breaks it, which is why it survived review.
32
+
33
+ **The fix.** The bleed is bought without a negative block margin. The card hands
34
+ its bottom padding to the footer, and the footer reproduces it — so the footer's
35
+ box is exactly the space it was given, sticky has nothing to clamp, and the
36
+ opaque background still reaches the card's bottom edge with nothing scrolling
37
+ through beneath the actions. Two rules now ship in `styles.css`:
38
+
39
+ - `.matrx-dialog-footer` — the whole footer geometry (`position: sticky;
40
+ bottom: 0`, the top pad, the INLINE bleed, and
41
+ `padding-bottom: var(--dialog-pad-bottom, var(--dialog-pad, 0px))`). Sticky
42
+ clamps the block axis only, so the inline bleed stays a negative margin.
43
+ - `.matrx-dialog-card:has(> .matrx-dialog-footer) { padding-bottom: 0 }` — the
44
+ reservation, **unlayered on purpose** so it beats the card's own `p-6` /
45
+ `p-4 pb-safe` utilities. Layered, it would lose and the fix would be silently
46
+ absent in every consumer. It is conditional on `:has()`, so a `DialogContent`
47
+ with no footer keeps its full padding.
48
+
49
+ The mobile sheet's home-indicator clearance moved with the padding:
50
+ `.matrx-mobile-sheet` sets `--dialog-pad-bottom: max(0.75rem,
51
+ env(safe-area-inset-bottom, 0px))`, the same floor `pb-safe` had.
52
+
53
+ **Guards.** `src/sticky-footer-geometry.test.tsx` — proven failing on the
54
+ pre-fix sources (7 of its 8 assertions fail there) and passing here. It bans
55
+ the MECHANISM by census, not the two known sites: nothing `sticky` anywhere in
56
+ this package may carry a negative block margin. It also asserts the shipped
57
+ rules exist, that the reservation is unlayered, and that every card and footer
58
+ is wired to them. jsdom has no layout engine, so the paint itself is proven in
59
+ a real browser and that proof is permanent, not a one-off: matrx-frontend
60
+ `/demos/confirm-geometry` exposes `window.__confirmGeometry.runAll()`, which
61
+ opens the real package `ConfirmDialog` at 1-, 2-, 3- and 6-line consequences
62
+ and returns `descriptionBottom`, `footerTop`, `overlapPx` and whether the card
63
+ scrolls. Invariant: `overlapPx <= 0` at every length, light and dark.
64
+
65
+ **Why the existing tests all passed.** `confirm-dialog.test.tsx` asserts the
66
+ consequence's DOM text, its `aria-describedby` wiring, and the absence of
67
+ `line-clamp`/`truncate`. Every one of those was true the whole time. A guard
68
+ that cannot see geometry cannot catch a geometry defect — recorded here because
69
+ that is the class, not this instance.
70
+
71
+ ### Consumer action (C28)
72
+
73
+ **None** — no API change; the footer's rendered geometry is identical minus the
74
+ occlusion. Take the patch. Three assertions that spelled the footer contract as
75
+ the literal `sticky` utility now assert `matrx-dialog-footer`; no consumer
76
+ asserts on those class strings. Anything that overrode `DialogFooter`'s padding
77
+ through `className` still wins (the rule is layered); anything that set
78
+ `padding-bottom` on `DialogContent` itself while ALSO rendering a footer is now
79
+ overridden by the reservation, which is the point.
80
+
81
+ ## 0.11.2
82
+
83
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
84
+ `git diff npm/design-system/v0.11.1..npm/design-system/v0.11.2 -- apps/shared/design-system`).
85
+ No source changes intended and no consumer action required.
86
+
3
87
  ## 0.11.1 — 2026-09-07
4
88
 
5
89
  **The 0.10.1 dialog-centring fix, on the current line.** 0.11.0 was cut and
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