Skip to content

Commit 06ee7c2

Browse files
wemra3Hiroki UemuraclaudeIzumiSyCopilot
authored
feat(core): alias --destructive to the danger roles and move components off destructive utilities (#583)
* feat(core): alias --destructive to the danger solid role Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(core): Button destructive uses the danger roles Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(core): text-destructive utilities use text-danger-text Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(core): invalid borders and focus rings use the danger roles Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(core): destructive tints use bg-danger-surface Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(core): themes inherit --destructive from the danger roles Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(core): cover destructive aliases and Button danger utilities, update snapshots Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: document --destructive as the danger solid alias Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore: add changeset for the destructive danger alias Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(core): mark destructive tokens and utilities as deprecated --destructive, --destructive-foreground and their utilities will be removed in the next major (tailor-inc/platform-planning#2084), the same as --status-* and --alert-*. Button variant="destructive" stays undeprecated until a danger variant exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(core): list the destructive migration under 1.17.0 and fix the border replacement The destructive change ships in the same release as the colour roles, so the migration entry is 1.17.0. In the changeset, border-destructive maps to border-danger-solid for invalid states; border-danger-border is 1.67:1 on the card and is for decorative borders only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(core): move the destructive migration to 1.18.0 and use the danger role in the selection bar 1.17.0 shipped without this change, so the migration entry now lists it under 1.18.0. The DataTable selection bar (added in 1.17.0) used `text-destructive` for destructive overflow actions. It now uses `text-danger-text`, the same as ActionPanel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Hiroki Uemura <hiroki_uemurapartners.tailor.tech@Hirokis-MacBook-Pro.local> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Seiya IZUMI <IzumiSy@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com>
1 parent 406e5f6 commit 06ee7c2

41 files changed

Lines changed: 246 additions & 125 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"@tailor-platform/app-shell": minor
3+
---
4+
5+
`--destructive` and `--destructive-foreground` are now aliases of `--danger-solid` and `--danger-contrast`, and the shipped components read the danger roles instead of `destructive` utilities. The names, `Button variant="destructive"` and `text-destructive` keep working.
6+
7+
`--destructive`, `--destructive-foreground` and their utilities (`bg-destructive`, `text-destructive`, `border-destructive`, `text-destructive-foreground`) are deprecated and will be removed in the next major. They keep working in 1.x; new code uses the danger roles: `bg-danger-solid` for fills, `text-danger-text` for text, `text-danger-contrast` for text on the solid, and `border-danger-solid` for invalid-state borders (`border-danger-border` is for decorative borders only; it is 1.67:1 on the card). `Button variant="destructive"` has no replacement yet, so it is not deprecated in this release; the next major renames it to `danger`.
8+
9+
Visible changes in the default palette:
10+
11+
- Dark-mode `Button variant="destructive"` is a full `#dc2626` fill with white text. It was `#f87171` at 60% opacity. Hover uses `--danger-solid-hover`.
12+
- `text-destructive` now resolves to the solid colour: `#dc2626` in dark mode (was `#f87171`), which is below 4.5:1 as text on the dark card. Error text in components uses `text-danger-text` (light `#ce0c17`, dark `#ff9083`). Use `text-danger-text` for text in your own code.
13+
- Invalid borders and focus rings on `Input`, `Textarea`, `Checkbox`, `Field` and `DateField` read `--danger-solid`. The dark invalid border changes from `#f87171` to `#dc2626` (3.71:1 on the card).
14+
- `CsvImporter` error cells use `bg-danger-surface`, matching the warning cells.
15+
- A theme that overrides `--destructive` no longer changes the shipped components; override `--danger-solid` (and the other danger roles) instead. `cream`, `bloom` and the theme template no longer set `--destructive`; their values were the same as the default.

‎decisions/semantic-color-roles.md‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ This step is the status part of a two-axis palette. The rest is planned as follo
8383
| ------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ |
8484
| Status (this step) | `--primitive-{blue,green,amber,red}-*` | `--{info,success,warning,danger}-{role}` | done |
8585
| Ink and lines | `--primitive-gray-*` | base tokens read it (`--foreground`, `--muted-foreground`, `--border`, `--input`) | done for default; themes later |
86-
| Danger action | red | `--destructive` becomes an alias of `--danger-solid` once its text and border uses move to `--danger-text` / `--danger-border` | next |
86+
| Danger action | red | `--destructive` becomes an alias of `--danger-solid` once its text and border uses move to `--danger-text` / `--danger-border` | done (2026-10-06) |
8787
| Brand | an accent scale per theme (bloom and cream read blue, theme-tailor reads cyan) | `--primary`, `--ring` and brand tints read accent steps | with the Theme Generator |
8888

8989
`--status-*` and `--alert-*` stay as aliases for consumer code and are deprecated: the docs and changeset say so, and they are removed in the next major. Shipped components read the roles. An ESLint rule in `@tailor-platform/eslint-plugin-app-shell` that flags the old utilities and offers the role as a fix is a separate change.
@@ -108,3 +108,15 @@ The component variant names (`Badge` and `Alert` `error`, Badge `neutral`) are p
108108
- Alert description text is the same colour as the Alert title in the default palette.
109109
- Consumers who override `--status-*` or `--alert-*` keep working for their own `bg-status-*` and `bg-alert-*` utilities, which read those tokens. The shipped components (Badge, Alert, CsvImporter, MetricCard — its trend colours were literal `green-600` / `red-600` before) read the roles, not `--status-*` or `--alert-*`. To recolour them, override the roles (`--{intent}-*`); overriding `--status-*` or `--alert-*` no longer changes the components. `--status-*` and `--alert-*` remain for existing consumer code and are not used by components any more.
110110
- cream, bloom and `_template.css` values are not edited. The header comments now list `--{intent}-{role}` among the inherited tokens.
111+
112+
## Update 2026-10-06: danger action
113+
114+
The "Danger action" row of the target shape is done. `--destructive` and `--destructive-foreground` are aliases of `--danger-solid` and `--danger-contrast` in `default.css`, light and dark. This supersedes the first item under "Out of scope" and the Consequences bullet that says Button and `text-destructive` still follow `--destructive`.
115+
116+
- Names stay in 1.x but are deprecated. `--destructive`, `--destructive-foreground` and their utilities (`bg-destructive`, `text-destructive`, `border-destructive`, `text-destructive-foreground`) keep working and will be removed in the next major, the same as `--status-*` and `--alert-*` ([platform-planning#2084](https://github.com/tailor-inc/platform-planning/issues/2084)). Keeping a second name for one colour leaves two vocabularies, and `text-destructive` is below 4.5:1 as text on the dark card. `text-danger-text` is the role to prefer for text. `Button variant="destructive"` is not deprecated yet because there is no `danger` variant to move to; the next major renames it.
117+
- Shipped components read the danger roles directly: text uses `text-danger-text`; invalid borders use `border-danger-solid`; focus rings use `ring-danger-solid/20` (dark `/40`, toolbar `/30`); tints use `bg-danger-surface`; the static error box border uses `border-danger-border`. Nothing in `packages/core/src` uses a `destructive` utility.
118+
- Invalid inputs keep the solid. `border-danger-border` (step a6, 1.67:1 on the card) and step 8 (2.62:1 in light mode) are below the 3:1 non-text minimum. The solid is 4.83:1 in light mode and 3.71:1 in dark mode on the card. A unit test holds the solid at 3:1 or more over `--card` and `--background`.
119+
- Dark `Button variant="destructive"` is a full `#dc2626` fill (it was `#f87171` at 60% opacity). The white text on `#dc2626` is 4.83:1; hover is `--danger-solid-hover` (5.66:1). Radix and Primer use the mode's step 9 at full; shadcn uses `dark:bg-destructive/60`.
120+
- `cream`, `bloom` and `_template.css` no longer set `--destructive` (their values equalled the default). `_template.css` lists it under DO NOT SET. A theme that recolours destructive actions overrides `--danger-solid`.
121+
- Visible changes in the default palette: light `text-destructive` goes from `#dc2626` to `#ce0c17` through `text-danger-text`, and dark from `#f87171` to `#ff9083`; the dark invalid border goes from `#f87171` to `#dc2626`; CsvImporter error cells use `bg-danger-surface`, matching the warning cells (`bg-warning-surface`).
122+
- Outside this repository: `cp-apps/apps/couturier/src/theme-tailor.css` still overrides `--destructive`, and the Theme Generator still emits `destructive` as a constant. Both stop reaching the shipped components until they move to `--danger-*`.

‎docs-manifest.json‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"hashes": {
6666
"typeSurface": "7cb8a34c1c36eb02",
6767
"outline": "797e012e34847b80",
68-
"snapshot": "4f35ca1e1dbd4237",
68+
"snapshot": "e43bea5b03d30595",
6969
"outputMd": "824d1aa36bb7f194",
7070
"examples": null
7171
}
@@ -225,7 +225,7 @@
225225
"hashes": {
226226
"typeSurface": "16df9927f8394548",
227227
"outline": "200f12eb4bec959a",
228-
"snapshot": "d57452fa4b3c6640",
228+
"snapshot": "aa2095c057e2cbee",
229229
"outputMd": "bce0e2fada1d1638",
230230
"examples": "1ee01b1e27764cd2"
231231
}
@@ -259,7 +259,7 @@
259259
"hashes": {
260260
"typeSurface": "3886bf7012f24283",
261261
"outline": "916645fe8e5baf10",
262-
"snapshot": "5df639bf40a2bdd7",
262+
"snapshot": "2d057b30b9401e12",
263263
"outputMd": "14f7ba23f441df38",
264264
"examples": "e8f09fba5acb116f"
265265
}
@@ -677,7 +677,7 @@
677677
"hashes": {
678678
"typeSurface": "b795ce4e10be0653",
679679
"outline": "d9e8930edd2a191c",
680-
"snapshot": "403ee22f2996724f",
680+
"snapshot": "89321bc807b1eaa1",
681681
"outputMd": "c6a48c4d8e8b0078",
682682
"examples": null
683683
}
@@ -694,7 +694,7 @@
694694
"hashes": {
695695
"typeSurface": "7b374d45d53d4535",
696696
"outline": "79c9b0f08ca38027",
697-
"snapshot": "35421aa5421d2f9d",
697+
"snapshot": "88a0c82baaaa2a08",
698698
"outputMd": "91d901b17aed7781",
699699
"examples": null
700700
}
@@ -915,7 +915,7 @@
915915
"hashes": {
916916
"typeSurface": "7c5b64c579f508ee",
917917
"outline": "9b273bc9e509f1fe",
918-
"snapshot": "fda9439dc1f7124e",
918+
"snapshot": "e9b20c2459b52b79",
919919
"outputMd": "a3a6c9679af99d37",
920920
"examples": "fc036f7af21b9dd4"
921921
}
@@ -1067,9 +1067,9 @@
10671067
"symbols": [],
10681068
"hashes": {
10691069
"typeSurface": null,
1070-
"outline": "45dcfe4383a87ea9",
1070+
"outline": "16c1723900750d80",
10711071
"snapshot": null,
1072-
"outputMd": "2fa0b6a249d8bd4f",
1072+
"outputMd": "f095aa7055b83481",
10731073
"examples": null
10741074
}
10751075
},
@@ -1322,9 +1322,9 @@
13221322
"symbols": [],
13231323
"hashes": {
13241324
"typeSurface": null,
1325-
"outline": "e63d837190e71ff1",
1325+
"outline": "dcf033e2a63f0f03",
13261326
"snapshot": null,
1327-
"outputMd": "112b43c697d30369",
1327+
"outputMd": "3ebd9f5828c49ed7",
13281328
"examples": "4d19f4f688e0f0ac"
13291329
}
13301330
},
@@ -1374,7 +1374,7 @@
13741374
"hashes": {
13751375
"typeSurface": "3d9225f7356a29b2",
13761376
"outline": "40952524e46c333e",
1377-
"snapshot": "ec32c806ed617388",
1377+
"snapshot": "c8500808c03baa29",
13781378
"outputMd": "c940bc01cd573334",
13791379
"examples": "0712ee03ad6ce259"
13801380
}
@@ -1425,7 +1425,7 @@
14251425
"hashes": {
14261426
"typeSurface": "2d88f0306efcaa77",
14271427
"outline": "1257a84ccd91d5c3",
1428-
"snapshot": "3b402cab18147ef9",
1428+
"snapshot": "c85c431dcd58bc43",
14291429
"outputMd": "91d70b140c7bb747",
14301430
"examples": null
14311431
}
@@ -1694,7 +1694,7 @@
16941694
"packages/core/skills/app-shell-patterns/references/concepts/modules-and-resources.md": "bf15b5460f22d165",
16951695
"packages/core/skills/app-shell-patterns/references/concepts/routing-navigation.md": "8034c7f885994b29",
16961696
"packages/core/skills/app-shell-patterns/references/concepts/sidebar-navigation.md": "e342ef02dc2b9b86",
1697-
"packages/core/skills/app-shell-patterns/references/concepts/styling-theming.md": "112b43c697d30369",
1697+
"packages/core/skills/app-shell-patterns/references/concepts/styling-theming.md": "3ebd9f5828c49ed7",
16981698
"packages/core/skills/app-shell-patterns/references/components/action-panel.md": "71794d4b561e4d4b",
16991699
"packages/core/skills/app-shell-patterns/references/components/activity-card.md": "4f386e49380fb0b0",
17001700
"packages/core/skills/app-shell-patterns/references/components/ai-chat.md": "824d1aa36bb7f194",
@@ -1775,7 +1775,7 @@
17751775
"packages/core/skills/app-shell-patterns/references/patterns/interaction-toast.md": "f68bdab855730f48",
17761776
"packages/core/skills/app-shell-patterns/references/patterns/list-dense-scan.md": "d2c10cdbb00590a2",
17771777
"packages/core/skills/app-shell-patterns/references/pages/document-detail.md": "717ef4e7ae835aff",
1778-
"packages/core/skills/app-shell-patterns/references/migrations.md": "013c3fef2303b096",
1778+
"packages/core/skills/app-shell-patterns/references/migrations.md": "afad0935852bec9f",
17791779
"packages/core/skills/app-shell-patterns/SKILL.md": "4650734e91fbc858"
17801780
}
17811781
}

‎docs-src/concepts/styling-theming.docs.outline.md‎

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,16 @@ Surfaces are named by **role**, not by depth — there is no numbered `surface-1
147147

148148
#### Brand & action
149149

150-
| Token | Use | Tailwind |
151-
| -------------------------------------------- | -------------------------------- | -------------------------------------------- |
152-
| `--primary` / `--primary-foreground` | primary buttons, emphasis | `bg-primary` / `text-primary-foreground` |
153-
| `--secondary` / `--secondary-foreground` | secondary buttons, neutral chips | `bg-secondary` / `text-secondary-foreground` |
154-
| `--accent` / `--accent-foreground` | hover and selected nav states | `bg-accent` / `text-accent-foreground` |
155-
| `--destructive` / `--destructive-foreground` | destructive actions, errors | `bg-destructive` / `text-destructive` |
150+
| Token | Use | Tailwind |
151+
| -------------------------------------------- | ------------------------------------------- | -------------------------------------------- |
152+
| `--primary` / `--primary-foreground` | primary buttons, emphasis | `bg-primary` / `text-primary-foreground` |
153+
| `--secondary` / `--secondary-foreground` | secondary buttons, neutral chips | `bg-secondary` / `text-secondary-foreground` |
154+
| `--accent` / `--accent-foreground` | hover and selected nav states | `bg-accent` / `text-accent-foreground` |
155+
| `--destructive` / `--destructive-foreground` | deprecated alias of danger solid / contrast | `bg-destructive` / `text-destructive` |
156+
157+
**Deprecated.** `--destructive`, `--destructive-foreground` and their utilities remain for existing code and will be removed in the next major. New code uses the danger roles: `bg-danger-solid`, `text-danger-contrast`, and `text-danger-text` for text. `Button variant="destructive"` is not deprecated yet; the next major renames it to `danger`.
158+
159+
`--destructive` and `--destructive-foreground` are aliases of the danger `solid` and `contrast` roles ([semantic color roles](#semantic-color-roles)), so `bg-destructive` is the danger solid fill in both modes and `Button variant="destructive"` reads the danger roles directly. `text-destructive` still works and resolves to the solid. For text, use `text-danger-text`, which meets 4.5:1 on `--card` and `--background`; the solid is `#dc2626` in dark mode, 3.71:1 on the dark card. To recolour destructive actions, override `--danger-solid` (and the other danger roles), not `--destructive`.
156160

157161
There are no `-hover` or `-active` brand tokens. Express interaction states with Tailwind variants and opacity — `hover:bg-primary/90`, `active:bg-primary/80` — which is what AppShell's own components do.
158162

@@ -195,7 +199,7 @@ In the default palette, `text` on `surface` and `contrast` on `solid` and `solid
195199

196200
Most `surface` and `border` values are translucent tints, so an opacity modifier compounds rather than replaces — `bg-info-surface/50` halves the tint's alpha instead of setting it to 50%. Some light-mode values are opaque instead of translucent: the `warning` surface, surface-hover and border, the `info` border and the `danger` surface-hover. They do not blend with a tinted parent. All dark-mode values are translucent.
197201

198-
`Badge`, `Alert`, `CsvImporter` and `MetricCard` read these roles directly, not `--status-*` or `--alert-*`. To recolour them, override the roles. `Badge` `error` and `subtle-error`, and `Alert` `error`, follow `--danger-*`. They no longer follow `--destructive`, which still drives `Button` and `text-destructive`.
202+
`Badge`, `Alert`, `CsvImporter` and `MetricCard` read these roles directly, not `--status-*` or `--alert-*`. To recolour them, override the roles. `Badge` `error` and `subtle-error`, and `Alert` `error`, follow `--danger-*`. `Button variant="destructive"`, invalid input borders and error text follow `--danger-*` too, and `--destructive` is an alias of `--danger-solid`.
199203

200204
#### Sidebar & charts
201205

@@ -654,7 +658,7 @@ These are visual-composition rules every screen must follow, regardless of patte
654658

655659
| Intent | Pick |
656660
| ---------------------------------- | ------------------------------------------------------------------------------------------------------- |
657-
| Destructive action (delete, void) | `Button variant="destructive"`; `bg-destructive` on custom surfaces; confirm in a dialog at `shadow-lg` |
661+
| Destructive action (delete, void) | `Button variant="destructive"`; `bg-danger-solid` on custom surface; confirm in a dialog at `shadow-lg` |
658662
| Non-blocking caution | `Badge variant="warning"`, or `bg-warning-surface text-warning-text` |
659663
| Confirmation / completed state | `Badge variant="success"`, or `bg-success-surface text-success-text` |
660664
| Informational callout | `Badge variant="info"`, or `Alert variant="info"` |

0 commit comments

Comments
 (0)