@ai-matrx/design-system 0.10.1 → 0.11.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,82 +1,72 @@
1
1
  # Changelog
2
2
 
3
- ## 0.10.1 — 2026-09-07
4
-
5
- **THE CENTRED DIALOG FLEW IN FROM OFF THE SCREEN.** 0.10.0 shipped a live
6
- regression: `Dialog`, `AlertDialog` and `CommandDialog` entered from beyond the
7
- top-left corner of the viewport and SNAPPED into place at the end of their
8
- 200ms animation. Independent review caught it on the live surface, measured it,
9
- and proved the cause rather than inferring it.
10
-
11
- **The cause is that one Tailwind class means two different things.**
12
-
13
- | | `translate-x-[-50%] translate-y-[-50%]` compiles to |
14
- |---|---|
15
- | Tailwind **v3** | `transform: translate(-50%, -50%)` REPLACED by an animation of `transform` |
16
- | Tailwind **v4** | `translate: -50% -50%` an independent property that **composes with** `transform` |
17
-
18
- 0.10.0's keyframes restated the centring inside `transform`
19
- (`translate(-50%,-48%)` -> `translate(-50%,-50%)`), which is correct under v3
20
- and doubles the centring under v4. Measured on the live element, viewport
21
- 2560x1289, `getComputedStyle(el).translate === "-50% -50%"` while
22
- `transform === "none"` at rest:
23
-
24
- | | x | y |
25
- |---|---|---|
26
- | resting (correct) | 128 | 32 |
27
- | `currentTime = 0` | **-966** | **-525** |
28
- | `currentTime = 100` | **-1015** | **-571** |
29
- | `currentTime = 199`, `el.style.translate = "none"` | 137 | 41 |
30
-
31
- That last row is the proof: removing the `translate` property mid-animation
32
- restores the resting position exactly, because the element was wearing the
33
- centring twice.
34
-
35
- **The fix is not a different spelling of the keyframes**there isn't one that
36
- works in both hosts. Restate the offset and v4 applies it twice; omit it and v3
37
- drops it for the animation's duration and snaps at the end. So the offset stops
38
- being a Tailwind utility at all. This package now owns it, in the `translate`
39
- property, in its own stylesheet:
40
-
41
- - `.matrx-dialog-centered` (`translate: -50% -50%`) carries the centring, and
42
- the keyframes carry ONLY the delta `opacity`, plus a 2% rise scaled up from
43
- 95% in `transform`, ending on `transform: none`. Resting geometry is
44
- byte-identical to 0.10.0's; `transform` and `translate` never restate each
45
- other again, in any host.
46
- - **Census the same hazard, one more surface.** `Select` in `popper` position
47
- held its 4px gap from the trigger with `data-[side=bottom]:translate-y-1` and
48
- three siblings, while `matrx-popper-*` keyframes animate `transform`. Same
49
- defect, 4px instead of half a viewport, failing the other way round (a v3
50
- host ate the gap for the animation and snapped it back). It is now
51
- `.matrx-popper-offset`, sized by the new `--matrx-popper-offset` token.
52
- - `Sheet`, the mobile bottom sheet and every other popper were **not** affected
53
- and are unchanged their translate utilities are zero-valued or absent.
54
-
55
- **The guard, proven failing-then-passing.** jsdom cannot measure a composite
56
- transform, so the hazard is asserted as a RULE over the sources in
57
- `motion.test.tsx`: *no component may pair a NON-ZERO Tailwind translate utility
58
- with a package motion class*, plus the centred keyframes may not mention `-50%`
59
- and must end on `transform: none`, plus each of the three surfaces must render
60
- the package's centring class. Restoring 0.10.0's exact shape (the utility in
61
- `DIALOG_DESKTOP_CLASSES` and the centring back in the keyframes) turns 4 of
62
- these red; the fix turns them green. `motion.test.tsx`'s old assertion that
63
- `translate-x-[-50%]` survives `animated={false}` PINNED the defect — it now
64
- asserts the centring class survives and the utility is gone. The C26 canaries
65
- grew too: both new rules are required in `styles.test.ts` and in the packed
66
- tarball.
3
+ ## 0.11.0 — 2026-09-07
4
+
5
+ **THE CONFIRM SURFACE MOVES IN.** `ConfirmDialog` and `ConfirmDialogHost` the
6
+ platform's `window.confirm` replacement now live here. They came from
7
+ `@ai-matrx/kit`, which is releasing 0.9.0 to delete its copy. Census row 19i,
8
+ decided on the row-20a Tooltip precedent: **one surface, one owner.**
9
+
10
+ **Why it had to move.** kit's confirm shipped a second, inlined AlertDialog with
11
+ its own hand-copied button class strings, a hardcoded `bg-black/80` scrim, and
12
+ the exact `data-[state=open]:animate-in … zoom-in-95 … slide-in-from-top-[48%]`
13
+ host-plugin utilities 0.10.0's motion sweep just finished removing from this
14
+ package. kit ships NO stylesheet, so that dialog was unanimated and off-theme in
15
+ three of the four consumers on the one surface in the product that stands
16
+ between a user and a destroyed thing. kit could not import 0.10.0's fix, because
17
+ **this package depends on kit**; importing back is a cycle. And giving kit its own
18
+ sheet would have invented a second required-CSS contract no consumer performs —
19
+ the C26 silent host contract, one layer down. The only correct move was this one.
20
+
21
+ **What it inherits by being here** — none of it hand-copied, all of it already
22
+ proven by this package's own guards:
23
+
24
+ - `matrx-motion-overlay` / `matrx-motion-dialog` / `matrx-spin`, whose rules ship
25
+ in `styles.css` and are asserted present in the packed tarball;
26
+ - `--matrx-overlay-scrim`, a token that answers to the host's theme, instead of
27
+ `bg-black/80`;
28
+ - `AlertDialog` ruling 3 clamped to `max-h-[85dvh]`, scrolling inside itself,
29
+ sticky footer. **This is what makes the platform's consequence-first copy law
30
+ survivable.** A confirmation that names everything it is about to destroy can be
31
+ long, and in kit's unclamped copy a long one pushed Cancel and Continue below
32
+ the fold of a short viewport. An AlertDialog does not dismiss on a backdrop
33
+ click, so that was a dead end on a destructive action. Fixed by the move, with
34
+ a guard;
35
+ - `buttonVariants` as the ONE source of button appearancethe destructive
36
+ confirm button is now literally the package's destructive button, including the
37
+ 44px coarse-pointer target, not a second hand-written copy of its classes;
38
+ - `PortalContainerProvider`, so a confirm opened inside a popped-out window panel
39
+ renders in THAT window's document without the host passing anything.
40
+
41
+ **Behavior is the kit port, verbatim.** Every prop, default and interaction is
42
+ unchanged; only the chrome underneath is the package's. The suite came across
43
+ whole and grew a third target: `src/confirm-dialog.test.tsx` proves the
44
+ imperative contract across the package boundary, proves the chrome is the
45
+ package's (a guard that fails the moment `bg-black` or `animate-in` comes back),
46
+ and proves the consequence-first copy contract the consequence renders in full,
47
+ is the dialog's `aria-describedby` description, is never clamped or truncated,
48
+ and never puts the actions out of reach however long it is.
49
+
50
+ ### Added
51
+
52
+ - `ConfirmDialog`, `ConfirmDialogProps` the declarative dialog (use it inline
53
+ when in-dialog `busy` state during async work is meaningful).
54
+ - `ConfirmDialogHost` — mount ONCE near the root of every provider tree.
55
+
56
+ ### Not added, on purpose
57
+
58
+ - `confirm()` is **not** re-exported from here. The imperative opener stays in
59
+ `@ai-matrx/kit/confirm-opener`, where it is pure TS with no React and no radix,
60
+ so hundreds of static call sites cost nothing. The host and the opener find each
61
+ other through the opener's `Symbol.for("ai-matrx.kit.confirm-opener-state")`
62
+ globalThis slot across packages and across module graphs.
67
63
 
68
64
  ### Consumer action (C28)
69
65
 
70
- **None.** No API changed, no class a consumer writes changed, and resting
71
- geometry is identical. Take the patch.
72
-
73
- Named, because they are the ones that regressed: **aidream/dashboard**,
74
- **aidream/workflow-studio** and **matrx-extend** loaded no animation rules at
75
- all before 0.10.0, so their dialogs had always appeared instantly and correctly
76
- centred — 0.10.0 is what gave them a dialog that flies in from off-screen.
77
- matrx-frontend was NOT visibly changed by either release: its pre-0.10.0
78
- `tw-animate-css` spelling had the identical stacking flaw. All four are correct
79
- on 0.10.1.
66
+ Mount `<ConfirmDialogHost />` from **here** and keep calling `confirm()` from
67
+ `@ai-matrx/kit/confirm-opener`. The full repointing diff — host, dialog, and the
68
+ imperative import — is in `@ai-matrx/kit` CHANGELOG § 0.9.0 § Consumer action.
69
+ Take both releases together: design-system >= 0.11.0 with kit >= 0.9.0.
80
70
 
81
71
  ## 0.10.0 — 2026-09-07
82
72
 
package/README.md CHANGED
@@ -5,9 +5,28 @@ The small, semantic UI foundation shared by AI Matrx React applications — prim
5
5
  **Controls:** Button, Badge, Label, Separator, the Input family, the Textarea family, Checkbox, Switch, RadioGroup, Slider, Toggle + ToggleGroup, Avatar, Progress.
6
6
  **Surfaces:** Card, Table, Tabs, Accordion, Collapsible, ScrollArea, Popover, Tooltip, HoverCard, Sheet, Dialog, AlertDialog, Drawer, BottomSheet + TabbedBottomSheet, Alert, Resizable, Skeleton.
7
7
  **Menus:** DropdownMenu, ContextMenu, Command / CommandDialog, Select, CreatablePicker.
8
- **Composed:** EditableLabel, SegmentedControl, ScoreRing, OverflowToolbar.
8
+ **Composed:** EditableLabel, SegmentedControl, ScoreRing, OverflowToolbar, ConfirmDialog + ConfirmDialogHost.
9
9
  **Hooks + utilities:** `useScrollFade`, `useIsMobile`, `usePortalContainer`, `useDialogContainer`, `useDrawerDirection`, `cn`.
10
10
 
11
+ **The confirm dialog lives here; the imperative `confirm()` lives in `@ai-matrx/kit`.** Since 0.11.0 / kit 0.9.0 the surface is one implementation, in the package that owns AlertDialog, the motion layer and the overlay scrim token. Mount the host once near your provider root and call `confirm()` from anywhere — they share one registry through a `globalThis` slot:
12
+
13
+ ```tsx
14
+ // app root, once
15
+ import { ConfirmDialogHost } from "@ai-matrx/design-system";
16
+ <ConfirmDialogHost />
17
+
18
+ // anywhere — a thunk, a util, a click handler
19
+ import { confirm } from "@ai-matrx/kit/confirm-opener";
20
+ if (!(await confirm({
21
+ title: "Re-run research",
22
+ description: "This discards the 14 pages you already have (~$50 and 10 minutes) and starts over.",
23
+ variant: "destructive",
24
+ confirmLabel: "Discard and re-run",
25
+ }))) return;
26
+ ```
27
+
28
+ Use the declarative `<ConfirmDialog open … busy />` inline instead when the dialog must stay open with a spinner while async work finishes. Name the consequence: a confirmation that says only "Are you sure?" does not satisfy the platform's destructive-and-expensive-actions law.
29
+
11
30
  **The Tooltip lives here, and only here.** `@ai-matrx/tap-target` used to ship its own copy; since design-system 0.7.0 / tap-target 0.2.0 it consumes this one and re-exports nothing.
12
31
 
13
32
  Where hosts had forked a primitive over DENSITY, density is a prop, not a fork: `Card size="sm|md|lg"`, `Table size="sm|md"`, `Accordion size="sm|md"`, `Switch`/`Avatar`/`Checkbox`/`Slider`/`RadioGroup`/`Toggle` `size`, `ResizableHandle size="xs".."4xl"`. It is declared once on the root and every item reads it from context, so a card cannot mix paddings and a radio group cannot mix control sizes.