@ai-matrx/design-system 0.3.1 → 0.4.1

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,91 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0 — 2026-08-30
4
+
5
+ **The package ships its CSS.** Closes the C26 clause of the all-inclusive
6
+ retrofit row: the package shipped ZERO stylesheets while three host-owned CSS
7
+ contracts were required for its components to render correctly. Any consumer
8
+ that was not matrx-frontend got a broken scroll cue, an unstyled glass control,
9
+ a flat input, and desktop-density text inside a phone sheet.
10
+
11
+ New exports:
12
+
13
+ - **`./styles.css` — REQUIRED structural CSS.** Extracted from matrx-frontend
14
+ `app/globals.css` (the tap-target precedent): the `.matrx-scroll-fade`
15
+ mask geometry (`useScrollFade`), the `.matrx-mobile-sheet` mobile density
16
+ restatement (`TabbedBottomSheet`), `.matrx-glass-thin-border` (BottomSheet
17
+ chrome), `.pb-safe`, `.shadow-input`. Zero hardcoded colour — every colour
18
+ resolves from a token, asserted by test and by the tarball canary.
19
+ - **`./tokens.css` — DEFAULT token values.** A neutral, sensible default for
20
+ every token the components and the structural CSS read, light and dark, so
21
+ the package renders correctly UNTHEMED in a fresh app. Not a brand: values
22
+ are host-owned and every default sits in the `matrx-design-system-tokens`
23
+ layer so any host declaration wins.
24
+ - **`./theme.css` — optional Tailwind v4 registration.** Maps the semantic
25
+ colour utilities onto the tokens and registers the package build as a
26
+ `@source`, so a fresh Tailwind app is one `@import` from drop-in.
27
+
28
+ Colour sweep (hardcoded colour in components is banned):
29
+
30
+ - `Input` — `text-black dark:text-white` → `text-foreground`;
31
+ `placeholder:text-neutral-400` → `placeholder:text-muted-foreground` (the
32
+ paired `dark:placeholder-text-neutral-600` was a typo'd class that never
33
+ existed and is gone); `focus-visible:ring-neutral-400/600` →
34
+ `focus-visible:ring-ring`; the dark autofill fill-colour now follows
35
+ `--foreground`. The dark elevation `shadow-[0px_0px_1px_1px_var(--neutral-700)]`
36
+ referenced a token defined nowhere, so it computed to no shadow — replaced by
37
+ an honest `dark:shadow-none`, which renders identically.
38
+ - `Badge` — `info` variant `border-blue-200 bg-blue-100 text-blue-800` →
39
+ `border-info/30 bg-info/15 text-info`; `error` variant → the same
40
+ `destructive` tokens its twin variant already used.
41
+ - `ScoreRing` — `scoreRingColorClasses` / `scoreAccentBgClasses` now return
42
+ `success` / `warning` / `destructive` token classes instead of
43
+ `green-500` / `orange-500` / `red-500`.
44
+ - Overlay scrims and the glass sheet divider are tokens
45
+ (`--matrx-overlay-scrim`, `--matrx-overlay-scrim-soft`,
46
+ `--matrx-overlay-scrim-drawer`, `--matrx-sheet-divider`) instead of
47
+ `bg-black/80`, `bg-black/20 dark:bg-black/30`, an inline `rgba(0,0,0,0.08)`,
48
+ and `border-white/[0.06]`.
49
+
50
+ Gate: the tarball canary now asserts all three sheets ship at the exact paths
51
+ their exports point to, that `styles.css` carries each contract rule and no
52
+ hardcoded colour, and that `tokens.css` defaults every token in both themes.
53
+ A new `styles.test.ts` fails the build if a component ever references a bare
54
+ class with no shipped rule, reads a token with no default, or reintroduces a
55
+ palette colour.
56
+
57
+ ### Consumer action
58
+
59
+ 1. **Import the two sheets at your app root** (`styles.css` is required —
60
+ without it the scroll fade, glass chrome, safe-area padding and input
61
+ elevation are missing):
62
+
63
+ ```tsx
64
+ import "@ai-matrx/design-system/tokens.css";
65
+ import "@ai-matrx/design-system/styles.css";
66
+ ```
67
+
68
+ 2. **Declare the layer order once**, as the first line of your Tailwind/CSS
69
+ entry, so the package's default token values stay below your own:
70
+
71
+ ```css
72
+ @layer matrx-design-system-tokens, matrx-design-system;
73
+ ```
74
+
75
+ 3. **Delete your host copies of the moved rules** — `.matrx-scroll-fade[…]`,
76
+ the `.matrx-mobile-sheet` block, `.matrx-glass-thin-border` (+ its
77
+ `:hover` / `:active` / `:has(> a:…)` states). They now ship in the package;
78
+ keeping both means two sources of truth. Rules that are members of a host
79
+ utility family (`.pb-safe` beside `pt-safe`/`mb-safe`/`mt-safe`) and
80
+ Tailwind-generated `.shadow-input` legitimately stay host-side — the
81
+ package versions sit in a lower layer and lose to them by design.
82
+ 4. **If you consumed the ScoreRing colour helpers' return strings**, they are
83
+ now `text-success` / `text-warning` / `text-destructive` (and the `bg-`
84
+ twins). Define those semantic colours in your theme, or map them.
85
+ 5. **A host that already maps the semantic colour vocabulary in its own
86
+ `@theme` does not need `theme.css`** — importing it would duplicate the
87
+ mapping.
88
+
3
89
  ## 0.3.1 — 2026-08-30
4
90
 
5
91
  - `@ai-matrx/kit` is now a REAL dependency (`^0.7.3`) instead of a peer
package/README.md CHANGED
@@ -13,18 +13,57 @@ import { Badge, Button } from "@ai-matrx/design-system";
13
13
  <Badge variant="success">Ready</Badge>
14
14
  ```
15
15
 
16
- The package intentionally does not ship product colors. Hosts define the normal Tailwind semantic tokens (`primary`, `background`, `border`, `muted`, `success`, and `warning`), so one component follows each product's theme without forking behavior. A few ported components additionally reference host-owned CSS contracts and degrade gracefully without them: the glass tokens/utilities used by the BottomSheet family, the `.matrx-scroll-fade` styling for `useScrollFade`, and the `shadow-input` utility.
17
-
18
16
  Host-shaped systems are injected, never imported: wrap subtrees in `PortalContainerProvider` to point nested Popover portals at a dialog or popout body, and hand `OverflowToolbar` your menu and tooltip systems through its `renderOverflowMenu` / `renderTooltip` props. `@ai-matrx/kit` is a real dependency (installed automatically).
19
17
 
20
- Tailwind CSS v4 ignores `node_modules` by default. Registry consumers must register the package build beside their Tailwind import:
18
+ ## Styling the package ships its CSS, the host owns the values
19
+
20
+ The package is **opinionated about the token contract and ships every rule its
21
+ components need to work**; it is **not** opinionated about your colours.
22
+
23
+ ```tsx
24
+ // app root, once
25
+ import "@ai-matrx/design-system/tokens.css"; // default token VALUES — override these
26
+ import "@ai-matrx/design-system/styles.css"; // structural CSS — required
27
+ ```
28
+
29
+ ```css
30
+ /* your Tailwind/CSS entry — FIRST line, before @import "tailwindcss" */
31
+ @layer matrx-design-system-tokens, matrx-design-system;
32
+ ```
33
+
34
+ - **`styles.css` (required)** — every rule the components need to render right:
35
+ the `.matrx-scroll-fade` mask geometry behind `useScrollFade`, the
36
+ `.matrx-mobile-sheet` density restatement `TabbedBottomSheet` sets, the
37
+ `.matrx-glass-thin-border` chrome, `.pb-safe`, `.shadow-input`. It hardcodes
38
+ no colour: every colour resolves from a token.
39
+ - **`tokens.css` (default values)** — a neutral, sensible default for every
40
+ token the package reads, in both themes, so a fresh app renders correctly
41
+ **unthemed**. This is not a brand.
42
+ - **`theme.css` (Tailwind v4 hosts, optional)** —
43
+ `@import "@ai-matrx/design-system/theme.css";` from your Tailwind entry maps
44
+ the semantic colour utilities (`bg-background`, `text-muted-foreground`, …)
45
+ onto those tokens and registers the package build as a scan source. A host
46
+ that already maps this vocabulary (matrx-frontend does, as a branded
47
+ superset) skips this file and keeps its own.
48
+
49
+ **Overriding with your brand.** Redeclare any token — `--primary`,
50
+ `--background`, the `--matrx-glass-*` material, the overlay scrims — anywhere
51
+ in your own CSS. The package defaults live in the
52
+ `matrx-design-system-tokens` layer, and the one-line `@layer` declaration
53
+ above puts that layer at the bottom of the cascade, so **any** host
54
+ declaration wins: layered or unlayered, before or after, whatever the
55
+ specificity. Declare the layer order once and the question never arises.
56
+
57
+ Tailwind CSS v4 ignores `node_modules` by default, so a host that does not
58
+ import `theme.css` still registers the package build beside its Tailwind
59
+ import:
21
60
 
22
61
  ```css
23
62
  @import "tailwindcss";
24
63
  @source "../node_modules/@ai-matrx/design-system/dist";
25
64
  ```
26
65
 
27
- Workspace consumers point `@source` at `apps/shared/design-system/src`. This is required package setup, not an optional styling enhancement.
66
+ Workspace consumers point `@source` at `apps/shared/design-system/src`.
28
67
 
29
68
  ## Release gate
30
69
 
package/dist/index.cjs CHANGED
@@ -122,8 +122,8 @@ var badgeVariants = (0, import_class_variance_authority.cva)(
122
122
  outline: "border-border text-foreground",
123
123
  success: "border-transparent bg-success/15 text-success",
124
124
  warning: "border-transparent bg-warning/15 text-warning",
125
- info: "border-blue-200 bg-blue-100 text-blue-800",
126
- error: "border-transparent bg-red-500/15 text-red-700 dark:text-red-400",
125
+ info: "border-info/30 bg-info/15 text-info",
126
+ error: "border-transparent bg-destructive/15 text-destructive",
127
127
  neutral: "border-border bg-muted text-muted-foreground"
128
128
  }
129
129
  },
@@ -328,8 +328,8 @@ function BottomSheet({
328
328
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
329
329
  import_vaul.Drawer.Overlay,
330
330
  {
331
- className: cn("fixed inset-0 z-50 bg-black/80", "fixed inset-0 z-50"),
332
- style: { background: "rgba(0, 0, 0, 0.08)" }
331
+ className: cn("fixed inset-0 z-50 bg-[var(--matrx-overlay-scrim)]", "fixed inset-0 z-50"),
332
+ style: { background: "var(--matrx-overlay-scrim-drawer)" }
333
333
  }
334
334
  ),
335
335
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -406,7 +406,7 @@ function BottomSheetFooter({
406
406
  "div",
407
407
  {
408
408
  className: cn(
409
- "flex-shrink-0 px-4 py-3 pb-safe border-t border-white/[0.06]",
409
+ "flex-shrink-0 px-4 py-3 pb-safe border-t border-[var(--matrx-sheet-divider)]",
410
410
  className
411
411
  ),
412
412
  children
@@ -530,7 +530,7 @@ var CommandDialogContent = React5.forwardRef(({ className, children, container,
530
530
  isModal ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
531
531
  DialogPrimitive.Overlay,
532
532
  {
533
- className: "fixed inset-0 z-[10000] bg-black/20 dark:bg-black/30 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
533
+ className: "fixed inset-0 z-[10000] bg-[var(--matrx-overlay-scrim-soft)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
534
534
  }
535
535
  ) : null,
536
536
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
@@ -1124,14 +1124,14 @@ function EditableLabel({
1124
1124
  var React7 = __toESM(require("react"), 1);
1125
1125
  var import_jsx_runtime11 = require("react/jsx-runtime");
1126
1126
  var getVariantStyles = (variant = "default") => {
1127
- const baseStyles = `flex h-10 w-full border border-border bg-background text-black dark:text-white shadow-input rounded-md px-3 py-2 text-sm file:border-0 file:bg-transparent
1128
- file:text-sm file:font-medium placeholder:text-neutral-400 dark:placeholder-text-neutral-600
1129
- focus-visible:outline-none focus-visible:ring-[2px] focus-visible:ring-neutral-400 dark:focus-visible:ring-neutral-600
1127
+ const baseStyles = `flex h-10 w-full border border-border bg-background text-foreground shadow-input rounded-md px-3 py-2 text-sm file:border-0 file:bg-transparent
1128
+ file:text-sm file:font-medium placeholder:text-muted-foreground
1129
+ focus-visible:outline-none focus-visible:ring-[2px] focus-visible:ring-ring
1130
1130
  disabled:cursor-not-allowed disabled:opacity-50
1131
- dark:shadow-[0px_0px_1px_1px_var(--neutral-700)]
1131
+ dark:shadow-none
1132
1132
  transition duration-400
1133
1133
  [&:-webkit-autofill]:bg-background [&:-webkit-autofill]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] [&:-webkit-autofill]:[caret-color:currentColor]
1134
- dark:[&:-webkit-autofill]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] dark:[&:-webkit-autofill]:[-webkit-text-fill-color:white]
1134
+ dark:[&:-webkit-autofill]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] dark:[&:-webkit-autofill]:[-webkit-text-fill-color:hsl(var(--foreground))]
1135
1135
  [&:-webkit-autofill:hover]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:focus]:shadow-[0_0_0_1000px_hsl(var(--background))_inset]`;
1136
1136
  switch (variant) {
1137
1137
  case "destructive":
@@ -1410,15 +1410,15 @@ var DEFAULT_SCORE_THRESHOLDS = {
1410
1410
  };
1411
1411
  function scoreRingColorClasses(pct, thresholds = DEFAULT_SCORE_THRESHOLDS) {
1412
1412
  if (pct === null) return "text-muted-foreground";
1413
- if (pct >= thresholds.good) return "text-green-500";
1414
- if (pct >= thresholds.warning) return "text-orange-500";
1415
- return "text-red-500";
1413
+ if (pct >= thresholds.good) return "text-success";
1414
+ if (pct >= thresholds.warning) return "text-warning";
1415
+ return "text-destructive";
1416
1416
  }
1417
1417
  function scoreAccentBgClasses(pct, thresholds = DEFAULT_SCORE_THRESHOLDS) {
1418
1418
  if (pct === null) return "bg-muted-foreground/30";
1419
- if (pct >= thresholds.good) return "bg-green-500";
1420
- if (pct >= thresholds.warning) return "bg-orange-500";
1421
- return "bg-red-500";
1419
+ if (pct >= thresholds.good) return "bg-success";
1420
+ if (pct >= thresholds.warning) return "bg-warning";
1421
+ return "bg-destructive";
1422
1422
  }
1423
1423
  function ScoreRing({
1424
1424
  pct,
@@ -1725,7 +1725,7 @@ var SheetOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PU
1725
1725
  SheetPrimitive.Overlay,
1726
1726
  {
1727
1727
  className: cn(
1728
- "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1728
+ "fixed inset-0 z-50 bg-[var(--matrx-overlay-scrim)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1729
1729
  className
1730
1730
  ),
1731
1731
  ...props,