Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8028ed1
feat(core): alias --destructive to the danger solid role
Oct 6, 2026
1fab985
feat(core): Button destructive uses the danger roles
Oct 6, 2026
4d91438
refactor(core): text-destructive utilities use text-danger-text
Oct 6, 2026
46e4019
refactor(core): invalid borders and focus rings use the danger roles
Oct 6, 2026
2c8b84e
refactor(core): destructive tints use bg-danger-surface
Oct 6, 2026
0665ba7
refactor(core): themes inherit --destructive from the danger roles
Oct 6, 2026
44c6c9a
test(core): cover destructive aliases and Button danger utilities, up…
Oct 6, 2026
0eb7826
docs: document --destructive as the danger solid alias
Oct 6, 2026
39f68e2
chore: add changeset for the destructive danger alias
Oct 6, 2026
3b4ebe4
Merge branch 'main' into feat/destructive-danger-alias
Oct 7, 2026
0ffafab
Merge branch 'main' into feat/destructive-danger-alias
Oct 10, 2026
3fee8a9
refactor(core): default palette surfaces read the gray, white and alp…
Oct 12, 2026
668e1bc
feat(core): add a --backdrop role for modal backdrops
Oct 12, 2026
9eae3cc
docs: document --backdrop and the default palette reading the neutral…
Oct 12, 2026
3759991
test(core): pin the default neutral token values and the --backdrop b…
Oct 12, 2026
f599e2c
docs: correct the token step list and computed-value notes for the ne…
Oct 12, 2026
2b4765a
test(core): pin --foreground and --muted-foreground with the other ne…
Oct 12, 2026
60965fe
docs(decisions): keep the update to what this change does
Oct 12, 2026
c9c9249
Merge branch 'main' into feat/destructive-danger-alias
IzumiSy Oct 13, 2026
f88347a
Merge remote-tracking branch 'origin/main' into feat/destructive-dang…
Copilot Oct 13, 2026
0aa1390
docs(core): mark destructive tokens and utilities as deprecated
Oct 14, 2026
5da4615
refactor(core): rename --app-shell-type-* to --type-*
Oct 14, 2026
2bae1b0
Merge remote-tracking branch 'origin/main' into feat/destructive-dang…
Oct 14, 2026
6486082
Merge remote-tracking branch 'origin/main' into refactor/surface-gray…
Oct 14, 2026
1bc524a
docs(core): list the destructive migration under 1.17.0 and fix the b…
Oct 14, 2026
5e881de
Merge remote-tracking branch 'origin/main' into feat/destructive-dang…
Oct 18, 2026
342942a
fix(core): move the destructive migration to 1.18.0 and use the dange…
Oct 18, 2026
db32261
Merge remote-tracking branch 'origin/main' into refactor/type-token-p…
Oct 18, 2026
7c9817d
fix(core): keep the --app-shell-type-* names working after the rename
Oct 18, 2026
6138130
Merge remote-tracking branch 'origin/main' into refactor/surface-gray…
Oct 18, 2026
1808934
fix(core): read the deprecated type names in the bridge so scoped ove…
Oct 18, 2026
8ee7943
docs(core): list the tokens whose computed string changes, and name t…
Oct 18, 2026
174a541
chore: merge main into feat/destructive-danger-alias
Oct 19, 2026
deb88e0
chore: merge #583 (destructive danger alias) into refactor/surface-gr…
Oct 19, 2026
00bbbdf
chore: merge main into refactor/surface-gray-primitives
Oct 19, 2026
daf8fd8
chore: merge #593 (surface gray primitives) into refactor/type-token-…
Oct 19, 2026
1b7ce4e
chore: merge main into refactor/type-token-prefix
Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/type-token-prefix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@tailor-platform/app-shell": minor
---

Rename the typography role variables from `--app-shell-type-<role>-<size|line-height|weight|letter-spacing>` to `--type-<role>-<size|line-height|weight|letter-spacing>`, to match the colour roles (`--danger-*`, ...) and `--semantic-shadow-*`.

The old names still work: each `text-*` utility reads the matching `--app-shell-type-*` first and falls back to `--type-*`, so an override such as `--app-shell-type-heading-md-size` keeps its effect, on `:root` or on any other element. The old names are deprecated and will be removed in the next major. Rename them in your CSS:

```css
:root {
--type-heading-md-size: 1.25rem; /* was --app-shell-type-heading-md-size */
}
```

The `text-*` utilities (`text-heading-md`, ...) do not change.

AppShell no longer defines the `--app-shell-type-*` variables. Code that reads them with `getComputedStyle(...).getPropertyValue()` gets an empty string; read `--type-*` instead.
2 changes: 1 addition & 1 deletion decisions/typography-roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Each role is a named set of four values: size, line height, weight, and letter s

### Two layers, as for colors

- `themes/default.css` holds the values as `--app-shell-type-<role>-<size|line-height|weight|letter-spacing>` on `:root`. A palette or an app can override them. The `--app-shell-` prefix follows the existing `--app-shell-font-sans` override variable and keeps these `:root` variables apart from variables defined by the app or other libraries.
- `themes/default.css` holds the values as `--type-<role>-<size|line-height|weight|letter-spacing>` on `:root`. A palette or an app can override them. They have no `--app-shell-` prefix, like the colour roles and `--semantic-shadow-*`. `--app-shell-font-sans` needs the prefix because `--font-*` is a Tailwind theme namespace; `--type-*` is not, and the bridge writes `--text-<role>`, so the names do not clash with the app's Tailwind. 1.17.0 shipped the variables as `--app-shell-type-*` before this rename, so each bridge entry reads the old name first (`var(--app-shell-type-<role>-<slot>, var(--type-<role>-<slot>))`). The fallback sits in the bridge, not in `default.css`, so it is resolved on the element that uses the utility: an app that overrides an old name keeps its value on `:root` and on any other element. The old names are deprecated and will be removed in the next major.
- `theme.bridge.css` maps them to Tailwind with `--text-<role>` and its `--line-height`, `--font-weight`, and `--letter-spacing` suffixes, inside the existing `@theme inline`.

`@theme inline` writes literal values into the utility. If the values sat in the bridge, they could not be overridden on `:root`. So the bridge holds only `var()` references.
Expand Down
6 changes: 3 additions & 3 deletions docs-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1322,9 +1322,9 @@
"symbols": [],
"hashes": {
"typeSurface": null,
"outline": "08ea14945176cd57",
"outline": "3d954fbe6c0db30e",
"snapshot": null,
"outputMd": "01cfefbafc469e58",
"outputMd": "eefb47e1f52f10e1",
"examples": "4d19f4f688e0f0ac"
}
},
Expand Down Expand Up @@ -1694,7 +1694,7 @@
"packages/core/skills/app-shell-patterns/references/concepts/modules-and-resources.md": "bf15b5460f22d165",
"packages/core/skills/app-shell-patterns/references/concepts/routing-navigation.md": "8034c7f885994b29",
"packages/core/skills/app-shell-patterns/references/concepts/sidebar-navigation.md": "e342ef02dc2b9b86",
"packages/core/skills/app-shell-patterns/references/concepts/styling-theming.md": "01cfefbafc469e58",
"packages/core/skills/app-shell-patterns/references/concepts/styling-theming.md": "eefb47e1f52f10e1",
"packages/core/skills/app-shell-patterns/references/components/action-panel.md": "71794d4b561e4d4b",
"packages/core/skills/app-shell-patterns/references/components/activity-card.md": "4f386e49380fb0b0",
"packages/core/skills/app-shell-patterns/references/components/ai-chat.md": "824d1aa36bb7f194",
Expand Down
6 changes: 3 additions & 3 deletions docs-src/concepts/styling-theming.docs.outline.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,12 @@ On an `h1` to `h6` element, the `cream` and `bloom` palettes replace the role's

Always use `tabular-nums` for numbers that stack in a column — without it, digits jitter between rows.

**Change a role.** Each role is four CSS variables named `--app-shell-type-<role>-<size|line-height|weight|letter-spacing>`. Override them on `:root` to change a role for the whole app. Typography has no dark variant, so one override applies to light and dark mode.
**Change a role.** Each role is four CSS variables named `--type-<role>-<size|line-height|weight|letter-spacing>`. Override them on `:root` to change a role for the whole app. Typography has no dark variant, so one override applies to light and dark mode. 1.17.0 named these variables `--app-shell-type-*`. The old names still work, but they are deprecated and will be removed in the next major; rename them to `--type-*`.

```css
:root {
--app-shell-type-heading-lg-size: 1.75rem;
--app-shell-type-heading-lg-line-height: calc(36 / 28);
--type-heading-lg-size: 1.75rem;
--type-heading-lg-line-height: calc(36 / 28);
}
```

Expand Down
6 changes: 3 additions & 3 deletions docs/concepts/styling-theming.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 23 additions & 7 deletions packages/core/src/assets/theme-bridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,25 @@ describe("theme bridge", () => {

describe("typography roles", () => {
const slots = ["size", "line-height", "weight", "letter-spacing"] as const;
/** `--app-shell-type-<role>-<slot>` variables in the default palette, grouped by role. */
/** `--type-<role>-<slot>` variables in the default palette, grouped by role. */
const defined = new Map<string, Map<string, string>>();
for (const m of defaultTheme.matchAll(
/^\s*--app-shell-type-([a-z-]+)-(size|line-height|weight|letter-spacing):\s*([^;]+);/gm,
/^\s*--type-([a-z-]+)-(size|line-height|weight|letter-spacing):\s*([^;]+);/gm,
)) {
const role = m[1];
defined.set(role, (defined.get(role) ?? new Map()).set(m[2], m[3].trim()));
}
/** Bridge entries `--text-<role>[--<suffix>]: var(--app-shell-type-...)`, keyed by property name. */
/**
* Bridge entries `--text-<role>[--<suffix>]: var(--app-shell-type-X, var(--type-X))`,
* keyed by property name. The value is the `--type-*` name, or a marker when the
* entry does not read the same deprecated `--app-shell-type-*` name first.
*/
const bridgedText = new Map(
[...bridge.matchAll(/^\s*(--text-[a-z-]+):\s*var\((--app-shell-type-[a-z-]+)\);/gm)].map(
(m) => [m[1], m[2]],
),
[
...bridge.matchAll(
/^\s*(--text-[a-z-]+):\s*var\(\s*--app-shell-type-([a-z-]+),\s*var\(\s*--type-([a-z-]+)\s*\)\s*\);/gm,
),
].map((m) => [m[1], m[2] === m[3] ? `--type-${m[3]}` : `mismatched old name ${m[2]}`]),
);

it("pins the role count at 10", () => {
Expand All @@ -107,12 +113,22 @@ describe("theme bridge", () => {
const expected = new Map<string, string>();
for (const role of defined.keys()) {
for (const slot of slots) {
expected.set(`--text-${role}${suffix[slot]}`, `--app-shell-type-${role}-${slot}`);
expected.set(`--text-${role}${suffix[slot]}`, `--type-${role}-${slot}`);
}
}
expect(bridgedText).toEqual(expected);
});

it("reads the deprecated --app-shell-type-* name first in every bridge entry", () => {
// 1.17.0 shipped the roles under --app-shell-type-*. The bridge resolves the
// fallback on the element, so an old-name override keeps working at any scope.
const typeEntries = [...bridge.matchAll(/^\s*(--text-[a-z-]+):\s*([^;]+);/gm)].filter((m) =>
m[2].includes("--type-"),
);
expect(typeEntries.length).toBe(defined.size * slots.length);
expect(typeEntries.filter((m) => !bridgedText.has(m[1])).map((m) => m[1])).toEqual([]);
});

it("does not collide with a --color-* token that Tailwind resolves first", () => {
// `text-<name>` resolves against --color-<name> before --text-<name>.
const colors = [...bridge.matchAll(/^\s*--color-([a-z0-9-]+):/gm)].map((m) => m[1]);
Expand Down
166 changes: 126 additions & 40 deletions packages/core/src/assets/theme.bridge.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,47 +44,133 @@
*
* The `--text-*` namespace cannot set font-family. `text-code-sm` is used with
* `font-mono`.
*
* Each entry reads the deprecated `--app-shell-type-*` name first: 1.17.0
* shipped the roles under that name. The fallback is resolved on the element
* that uses the utility, so an old-name override keeps working at any scope,
* not only on `:root`. Remove the old names in the next major.
*/
--text-heading-lg: var(--app-shell-type-heading-lg-size);
--text-heading-lg--line-height: var(--app-shell-type-heading-lg-line-height);
--text-heading-lg--font-weight: var(--app-shell-type-heading-lg-weight);
--text-heading-lg--letter-spacing: var(--app-shell-type-heading-lg-letter-spacing);
--text-heading-md: var(--app-shell-type-heading-md-size);
--text-heading-md--line-height: var(--app-shell-type-heading-md-line-height);
--text-heading-md--font-weight: var(--app-shell-type-heading-md-weight);
--text-heading-md--letter-spacing: var(--app-shell-type-heading-md-letter-spacing);
--text-heading-sm: var(--app-shell-type-heading-sm-size);
--text-heading-sm--line-height: var(--app-shell-type-heading-sm-line-height);
--text-heading-sm--font-weight: var(--app-shell-type-heading-sm-weight);
--text-heading-sm--letter-spacing: var(--app-shell-type-heading-sm-letter-spacing);
--text-body-md: var(--app-shell-type-body-md-size);
--text-body-md--line-height: var(--app-shell-type-body-md-line-height);
--text-body-md--font-weight: var(--app-shell-type-body-md-weight);
--text-body-md--letter-spacing: var(--app-shell-type-body-md-letter-spacing);
--text-body-sm: var(--app-shell-type-body-sm-size);
--text-body-sm--line-height: var(--app-shell-type-body-sm-line-height);
--text-body-sm--font-weight: var(--app-shell-type-body-sm-weight);
--text-body-sm--letter-spacing: var(--app-shell-type-body-sm-letter-spacing);
--text-label-md: var(--app-shell-type-label-md-size);
--text-label-md--line-height: var(--app-shell-type-label-md-line-height);
--text-label-md--font-weight: var(--app-shell-type-label-md-weight);
--text-label-md--letter-spacing: var(--app-shell-type-label-md-letter-spacing);
--text-label-sm: var(--app-shell-type-label-sm-size);
--text-label-sm--line-height: var(--app-shell-type-label-sm-line-height);
--text-label-sm--font-weight: var(--app-shell-type-label-sm-weight);
--text-label-sm--letter-spacing: var(--app-shell-type-label-sm-letter-spacing);
--text-code-sm: var(--app-shell-type-code-sm-size);
--text-code-sm--line-height: var(--app-shell-type-code-sm-line-height);
--text-code-sm--font-weight: var(--app-shell-type-code-sm-weight);
--text-code-sm--letter-spacing: var(--app-shell-type-code-sm-letter-spacing);
--text-body-md-relaxed: var(--app-shell-type-body-md-relaxed-size);
--text-body-md-relaxed--line-height: var(--app-shell-type-body-md-relaxed-line-height);
--text-body-md-relaxed--font-weight: var(--app-shell-type-body-md-relaxed-weight);
--text-body-md-relaxed--letter-spacing: var(--app-shell-type-body-md-relaxed-letter-spacing);
--text-body-sm-relaxed: var(--app-shell-type-body-sm-relaxed-size);
--text-body-sm-relaxed--line-height: var(--app-shell-type-body-sm-relaxed-line-height);
--text-body-sm-relaxed--font-weight: var(--app-shell-type-body-sm-relaxed-weight);
--text-body-sm-relaxed--letter-spacing: var(--app-shell-type-body-sm-relaxed-letter-spacing);
--text-heading-lg: var(--app-shell-type-heading-lg-size, var(--type-heading-lg-size));
--text-heading-lg--line-height: var(
--app-shell-type-heading-lg-line-height,
var(--type-heading-lg-line-height)
);
--text-heading-lg--font-weight: var(
--app-shell-type-heading-lg-weight,
var(--type-heading-lg-weight)
);
--text-heading-lg--letter-spacing: var(
--app-shell-type-heading-lg-letter-spacing,
var(--type-heading-lg-letter-spacing)
);
--text-heading-md: var(--app-shell-type-heading-md-size, var(--type-heading-md-size));
--text-heading-md--line-height: var(
--app-shell-type-heading-md-line-height,
var(--type-heading-md-line-height)
);
--text-heading-md--font-weight: var(
--app-shell-type-heading-md-weight,
var(--type-heading-md-weight)
);
--text-heading-md--letter-spacing: var(
--app-shell-type-heading-md-letter-spacing,
var(--type-heading-md-letter-spacing)
);
--text-heading-sm: var(--app-shell-type-heading-sm-size, var(--type-heading-sm-size));
--text-heading-sm--line-height: var(
--app-shell-type-heading-sm-line-height,
var(--type-heading-sm-line-height)
);
--text-heading-sm--font-weight: var(
--app-shell-type-heading-sm-weight,
var(--type-heading-sm-weight)
);
--text-heading-sm--letter-spacing: var(
--app-shell-type-heading-sm-letter-spacing,
var(--type-heading-sm-letter-spacing)
);
--text-body-md: var(--app-shell-type-body-md-size, var(--type-body-md-size));
--text-body-md--line-height: var(
--app-shell-type-body-md-line-height,
var(--type-body-md-line-height)
);
--text-body-md--font-weight: var(--app-shell-type-body-md-weight, var(--type-body-md-weight));
--text-body-md--letter-spacing: var(
--app-shell-type-body-md-letter-spacing,
var(--type-body-md-letter-spacing)
);
--text-body-sm: var(--app-shell-type-body-sm-size, var(--type-body-sm-size));
--text-body-sm--line-height: var(
--app-shell-type-body-sm-line-height,
var(--type-body-sm-line-height)
);
--text-body-sm--font-weight: var(--app-shell-type-body-sm-weight, var(--type-body-sm-weight));
--text-body-sm--letter-spacing: var(
--app-shell-type-body-sm-letter-spacing,
var(--type-body-sm-letter-spacing)
);
--text-label-md: var(--app-shell-type-label-md-size, var(--type-label-md-size));
--text-label-md--line-height: var(
--app-shell-type-label-md-line-height,
var(--type-label-md-line-height)
);
--text-label-md--font-weight: var(--app-shell-type-label-md-weight, var(--type-label-md-weight));
--text-label-md--letter-spacing: var(
--app-shell-type-label-md-letter-spacing,
var(--type-label-md-letter-spacing)
);
--text-label-sm: var(--app-shell-type-label-sm-size, var(--type-label-sm-size));
--text-label-sm--line-height: var(
--app-shell-type-label-sm-line-height,
var(--type-label-sm-line-height)
);
--text-label-sm--font-weight: var(--app-shell-type-label-sm-weight, var(--type-label-sm-weight));
--text-label-sm--letter-spacing: var(
--app-shell-type-label-sm-letter-spacing,
var(--type-label-sm-letter-spacing)
);
--text-code-sm: var(--app-shell-type-code-sm-size, var(--type-code-sm-size));
--text-code-sm--line-height: var(
--app-shell-type-code-sm-line-height,
var(--type-code-sm-line-height)
);
--text-code-sm--font-weight: var(--app-shell-type-code-sm-weight, var(--type-code-sm-weight));
--text-code-sm--letter-spacing: var(
--app-shell-type-code-sm-letter-spacing,
var(--type-code-sm-letter-spacing)
);
--text-body-md-relaxed: var(
--app-shell-type-body-md-relaxed-size,
var(--type-body-md-relaxed-size)
);
--text-body-md-relaxed--line-height: var(
--app-shell-type-body-md-relaxed-line-height,
var(--type-body-md-relaxed-line-height)
);
--text-body-md-relaxed--font-weight: var(
--app-shell-type-body-md-relaxed-weight,
var(--type-body-md-relaxed-weight)
);
--text-body-md-relaxed--letter-spacing: var(
--app-shell-type-body-md-relaxed-letter-spacing,
var(--type-body-md-relaxed-letter-spacing)
);
--text-body-sm-relaxed: var(
--app-shell-type-body-sm-relaxed-size,
var(--type-body-sm-relaxed-size)
);
--text-body-sm-relaxed--line-height: var(
--app-shell-type-body-sm-relaxed-line-height,
var(--type-body-sm-relaxed-line-height)
);
--text-body-sm-relaxed--font-weight: var(
--app-shell-type-body-sm-relaxed-weight,
var(--type-body-sm-relaxed-weight)
);
--text-body-sm-relaxed--letter-spacing: var(
--app-shell-type-body-sm-relaxed-letter-spacing,
var(--type-body-sm-relaxed-letter-spacing)
);

--color-background: var(--background);
--color-foreground: var(--foreground);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/assets/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* Inherited from default.css — do not duplicate in new palettes:
* --ring, --sidebar-*, --backdrop, --primitive-* (colour scales), --status-*, --alert-*,
* --destructive, --destructive-foreground (aliases of the danger roles),
* --app-shell-type-* (typography roles).
* --type-* (typography roles).
* The colour roles --{intent}-{role} inherit too; a palette overrides them
* only to recolour the status components. Typography roles are inherited
* the same way: do not copy the defaults, override only the variables
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/assets/themes/_template.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
*
* DO NOT SET (inherited from `:root` in default.css):
* --ring, --sidebar-*, --backdrop, --primitive-* (colour scales), --status-*, --alert-*,
* --destructive, --destructive-foreground, --app-shell-type-*
* --destructive, --destructive-foreground, --type-*
* The colour roles --{info|success|warning|danger|neutral}-{role} also inherit.
* Override a role only to recolour the status components (Badge, Alert, ...)
* for this palette; never set --status-*, --alert-* or --destructive*, they alias the roles
* (--destructive is the danger solid; recolour it with --danger-solid).
* Typography roles (--app-shell-type-*) inherit too: do not copy the defaults,
* Typography roles (--type-*) inherit too: do not copy the defaults,
* override only the variables whose values differ.
*
* PREVIEW: `/showcase/colors` in the Vite example app.
Expand Down
Loading
Loading