@tailor-platform/app-shell 1.19.0 → 1.20.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.
Files changed (46) hide show
  1. package/dist/app-shell-core.css +2 -2
  2. package/dist/app-shell.d.ts +807 -130
  3. package/dist/app-shell.js +12419 -10930
  4. package/dist/{appshell-DQTz-QwK.js → appshell-B4QkQvXF.js} +377 -360
  5. package/dist/fonts/inter.css +7 -7
  6. package/dist/fonts/noto-sans-jp.css +116 -116
  7. package/dist/testing.d.ts +119 -89
  8. package/dist/testing.js +1 -1
  9. package/dist/vite-plugin.d.ts +119 -89
  10. package/package.json +10 -8
  11. package/skills/app-shell-patterns/SKILL.md +4 -3
  12. package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +32 -2
  13. package/skills/app-shell-patterns/references/api/define-module.md +5 -5
  14. package/skills/app-shell-patterns/references/api/router/use-params.md +2 -2
  15. package/skills/app-shell-patterns/references/api/use-ai-chat.md +46 -8
  16. package/skills/app-shell-patterns/references/api/use-app-shell-config.md +4 -4
  17. package/skills/app-shell-patterns/references/api/use-app-shell-data.md +5 -5
  18. package/skills/app-shell-patterns/references/api/use-app-shell.md +2 -2
  19. package/skills/app-shell-patterns/references/api/use-auth.md +3 -3
  20. package/skills/app-shell-patterns/references/api/use-route-error.md +12 -12
  21. package/skills/app-shell-patterns/references/components/action-panel.md +4 -2
  22. package/skills/app-shell-patterns/references/components/activity-card.md +3 -3
  23. package/skills/app-shell-patterns/references/components/ai-chat.md +37 -3
  24. package/skills/app-shell-patterns/references/components/app-shell.md +6 -5
  25. package/skills/app-shell-patterns/references/components/card.md +2 -2
  26. package/skills/app-shell-patterns/references/components/data-table.md +87 -31
  27. package/skills/app-shell-patterns/references/components/date-picker.md +2 -2
  28. package/skills/app-shell-patterns/references/components/default-sidebar.md +2 -2
  29. package/skills/app-shell-patterns/references/components/dialog.md +8 -0
  30. package/skills/app-shell-patterns/references/components/filter-rail.md +10 -3
  31. package/skills/app-shell-patterns/references/components/form.md +5 -5
  32. package/skills/app-shell-patterns/references/components/global-header-layout.md +31 -8
  33. package/skills/app-shell-patterns/references/components/layout.md +24 -17
  34. package/skills/app-shell-patterns/references/components/select.md +8 -0
  35. package/skills/app-shell-patterns/references/components/sidebar-group.md +9 -7
  36. package/skills/app-shell-patterns/references/components/sidebar-layout.md +74 -11
  37. package/skills/app-shell-patterns/references/components/sidebar-section.md +8 -8
  38. package/skills/app-shell-patterns/references/components/tabs.md +32 -2
  39. package/skills/app-shell-patterns/references/components/tree.md +342 -0
  40. package/skills/app-shell-patterns/references/components/with-guard.md +5 -5
  41. package/skills/app-shell-patterns/references/concepts/authentication.md +1 -1
  42. package/skills/app-shell-patterns/references/concepts/routing-navigation.md +3 -3
  43. package/skills/app-shell-patterns/references/concepts/styling-theming.md +13 -13
  44. package/skills/app-shell-patterns/references/migrations.md +20 -0
  45. package/skills/app-shell-patterns/references/pages/document-detail.md +8 -12
  46. package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +1 -1
@@ -219,12 +219,11 @@ Each intent has eight roles. The intents are `info`, `success`, `warning`, `dang
219
219
 
220
220
  The hue roles have the same values in every shipped palette. `cream` and `bloom` change brand and surface colors, not status colors. The `neutral` roles follow the palette, because they read the system tokens.
221
221
 
222
- **Contrast.** AppShell's thresholds are 4.5:1 for text (WCAG 1.4.3) and 3:1 for non-text (WCAG 1.4.11). In every shipped palette (`default`, `cream`, `bloom`), in light and dark mode, on `--card` and `--background`, `text` on `surface` and `contrast` on `solid` and `solid-hover` are at least 4.5:1 for the four hue intents, and `danger` `solid` (the invalid-input border) is at least 3:1. A browser test checks this in Chromium against the built stylesheet. Known exceptions:
222
+ **Contrast.** AppShell's thresholds are 4.5:1 for text (WCAG 1.4.3) and 3:1 for non-text (WCAG 1.4.11). In every shipped palette (`default`, `cream`, `bloom`), in light and dark mode, on `--card` and `--background`, `text` on `surface` and `contrast` on `solid` and `solid-hover` are at least 4.5:1 for all five intents, `text` on `surface-hover` is at least 4.5:1 for `neutral`, and `danger` `solid` (the invalid-input border) is at least 3:1. A browser test checks this in Chromium against the built stylesheet. Known exceptions:
223
223
 
224
- - `text` on `surface-hover` is below 4.5:1 for `danger` and `success` in light mode. The test holds it at 4.2:1 or more.
224
+ - `text` on `surface-hover` is below 4.5:1 for `danger` and `success` in light mode. This is on purpose: a lighter step would make the tinted background hard to tell apart from the page, and the hover harder to see. The test holds it at 4.2:1 or more.
225
225
  - In `cream` and `bloom`, the main content area is transparent over the shell gradient. At the top of the `bloom` light gradient, `text` on `surface` is 4.49:1 for `success` and 4.48:1 for `danger`. Put status content on a card when it needs to pass.
226
226
  - `warning` `solid` and `indicator` are 2.15:1 against a light card. Use them with a label, not as the only sign of a state.
227
- - The `neutral` intent reads the system tokens and is not checked.
228
227
 
229
228
  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.
230
229
 
@@ -411,7 +410,7 @@ function TypographyRoles() {
411
410
  }
412
411
  ```
413
412
 
414
- For headings, body copy, labels, and captions, use the [`Text`](../components/text.md) component. Do not style a bare `p`, `h1` to `h6`, or `span` with `text-sm`, `text-xs`, or `font-*`. A form field label is [`Field.Label`](../components/form.md), which already has the `label-md` role. `Text` applies the same roles with a `variant` prop. It renders a default element for each role (`h2` for headings, `p` for body text, `span` for the others). To set the element, such as the heading level, use an element component (`Text.h1` to `Text.h6`, `Text.p`, `Text.span`, `Text.div`):
413
+ For headings, body copy, labels, and captions, use the [`Text`](../components/text.md) component. Do not style a bare `p`, `h1` to `h6`, or `span` with `text-sm`, `text-xs`, or `font-*`. The `prefer-text-components` rule in `@tailor-platform/eslint-plugin-app-shell` reports a size on these elements, and a weight, line height, or letter spacing that is set without a role. It is not in `recommended`, so enable it in your `oxlint.config.ts`. A form field label is [`Field.Label`](../components/form.md), which already has the `label-md` role. `Text` applies the same roles with a `variant` prop. It renders a default element for each role (`h2` for headings, `p` for body text, `span` for the others). To set the element, such as the heading level, use an element component (`Text.h1` to `Text.h6`, `Text.p`, `Text.span`, `Text.div`):
415
414
 
416
415
  ```tsx
417
416
  <Text.h3 variant="heading-md">Line items</Text.h3>
@@ -530,21 +529,22 @@ Always give motion a reduced-motion escape (`motion-reduce:transition-none`, or
530
529
 
531
530
  ### Z-index
532
531
 
533
- These exist as raw `:root` variables in the shipped base layer, but are **not** bridged into Tailwind — `z-sidebar` is not a class. Use the stock numeric utility, or reference the variable when you need it to track AppShell's layering:
532
+ These exist as raw `:root` variables in the shipped base layer, but are **not** bridged into Tailwind — `z-nav` is not a class. Use the stock numeric utility, or reference the variable when you need it to track AppShell's layering:
534
533
 
535
- | Token | Value | Use |
536
- | ------------------ | ----- | ----------------------------- |
537
- | `--z-sidebar` | 10 | persistent sidebar |
538
- | `--z-sidebar-rail` | 20 | sidebar collapsed rail |
539
- | `--z-popup` | 50 | menu, tooltip, popover |
540
- | `--z-overlay` | 50 | modal, sheet, dialog backdrop |
534
+ | Token | Value | Use |
535
+ | ------------ | ----- | ----------------------------------------------------- |
536
+ | `--z-nav` | 10 | persistent sidebar |
537
+ | `--z-portal` | 50 | menu, tooltip, popover, modal, sheet, dialog backdrop |
538
+ | `--z-toast` | 100 | toast, always above overlays |
539
+
540
+ The old names still resolve: `--z-sidebar` is an alias of `--z-nav`, and `--z-popup` and `--z-overlay` are aliases of `--z-portal`. They are deprecated and will be removed in the next major. `--z-sidebar-rail` (20) is a value inside the sidebar, not a layer.
541
541
 
542
542
  ```tsx
543
543
  <div className="z-50" />
544
- <div className="z-[var(--z-popup)]" />
544
+ <div className="z-[var(--z-portal)]" />
545
545
  ```
546
546
 
547
- Never invent a z value — `z-index: 9999` is always wrong. Popups and overlays share `50` intentionally: sequencing comes from DOM order, not z escalation.
547
+ Never invent a z value — `z-index: 9999` is always wrong. Popups and overlays share `50` intentionally: sequencing comes from DOM order, not z escalation. Every floating AppShell component (dialog, sheet, menu, select, combobox, tooltip, toast) renders through a portal to the end of `body`, and the layout root is `isolation: isolate`, so a z-index inside the page never reaches them. The toast is the one layer above the band: it is always visible over an open dialog or sheet.
548
548
 
549
549
  ### Icons
550
550
 
@@ -10,6 +10,7 @@ Each entry states which versions are affected, what breaks, how to detect it, an
10
10
 
11
11
  | Version | Change |
12
12
  | ------------- | ---------------------------------------------------------------------------------------------------------------------------- |
13
+ | 1.20.0 | [z-index tokens renamed; old names are aliases](#1200-z-index-tokens-renamed-old-names-are-aliases) |
13
14
  | 1.18.0 | [Destructive colours now resolve to the danger roles](#1180-destructive-colours-now-resolve-to-the-danger-roles) |
14
15
  | 1.17.0 | [Status and alert tokens now resolve to the colour roles](#1170-status-and-alert-tokens-now-resolve-to-the-colour-roles) |
15
16
  | 1.15.0 | [Base UI 1.8.0 breaks closed-`Select` and dialog-click tests](#1150-base-ui-180-breaks-closed-select-and-dialog-click-tests) |
@@ -23,6 +24,25 @@ Each entry states which versions are affected, what breaks, how to detect it, an
23
24
  | 1.0.2 | [`Toaster` no longer accepts `richColors`](#102-toaster-no-longer-accepts-richcolors) |
24
25
  | before 1.0 | [Pre-1.0 breaking changes](#before-10) |
25
26
 
27
+ ## 1.20.0: z-index tokens renamed; old names are aliases
28
+
29
+ **Applies to:** apps whose theme overrides `--z-sidebar`, `--z-sidebar-rail`, `--z-popup` or `--z-overlay`, and apps that reference those names on their own elements.
30
+
31
+ 1.20.0 names the z-index tokens by layer: `--z-nav` (10), `--z-portal` (50) and `--z-toast` (100). The old names keep working: `--z-sidebar` is now `var(--z-nav)`, and `--z-popup` and `--z-overlay` are both `var(--z-portal)`. They are deprecated and will be removed in the next major. Nothing errors, and nothing moves. Two things change silently:
32
+
33
+ - **Themes that override an old name no longer reach the components.** The sidebar reads `--z-nav`; dialogs, sheets, menus, selects, comboboxes and tooltips read `--z-portal`. An override of `--z-popup` or `--z-overlay` still changes `z-[var(--z-popup)]` on your own elements, but not AppShell's layers. There is one token for the whole portal band because popups and overlays share the value on purpose: the order inside the band is the order of opening, so a `Select` inside a `Dialog` is above it. Raising one above the other puts a `Select` or `Menu` opened inside a `Dialog` behind the dialog.
34
+ - **`--z-sidebar-rail` is no longer read by AppShell.** The sidebar rail orders itself inside the sidebar. The variable is still declared (20) for elements of your own that reference it, and it leaves the documented table.
35
+
36
+ How to detect it: search the app for `--z-sidebar`, `--z-popup` and `--z-overlay` in class names and in theme CSS. Open a `Dialog` with a `Select` inside it, a `Dialog` over a `Sheet`, and fire a toast over each after upgrading; the order should not change.
37
+
38
+ What to change:
39
+
40
+ - Replace `--z-sidebar` with `--z-nav`, and `--z-popup` and `--z-overlay` with `--z-portal`, in class names such as `z-[var(--z-portal)]` and in theme CSS.
41
+ - In a theme that moves AppShell's layers, set `--z-nav`, `--z-portal` or `--z-toast` instead of the old names. Remove the old names from the theme.
42
+ - Do not set `--z-sidebar-rail`; it no longer affects the rail.
43
+
44
+ The tokens are documented in [Styling & theming](https://github.com/tailor-platform/app-shell/blob/main/docs/concepts/styling-theming.md#z-index). The decision record is `decisions/floating-ui-stacking.md`.
45
+
26
46
  ## 1.18.0: destructive colours now resolve to the danger roles
27
47
 
28
48
  **Applies to:** apps that show `Button variant="destructive"` in dark mode, apps that use `text-destructive`, `border-destructive` or `bg-destructive` on their own elements, and apps whose theme overrides `--destructive` or `--destructive-foreground`.
@@ -619,9 +619,9 @@ const formatDay = (value: string) =>
619
619
  * or the two dates do not match every other value on the card.
620
620
  */
621
621
  const Value = ({ children }: { children: React.ReactNode }) => (
622
- <Text variant="body-md" className="text-foreground" render={<span />}>
622
+ <Text.span variant="body-md" className="text-foreground">
623
623
  {children}
624
- </Text>
624
+ </Text.span>
625
625
  );
626
626
 
627
627
  /** House link: primary colour at rest, underline only on hover. */
@@ -685,9 +685,9 @@ export default function PurchaseOrderDetailPage({
685
685
  {order.holds.map((hold) => (
686
686
  <div key={hold.id} className="flex items-start justify-between gap-4">
687
687
  <div>
688
- <Text variant="label-md" className="text-foreground" render={<p />}>
688
+ <Text.p variant="label-md" className="text-foreground">
689
689
  {hold.reason}
690
- </Text>
690
+ </Text.p>
691
691
  <Text variant="body-sm" className="text-muted-foreground">
692
692
  Placed by {hold.placedBy} on {formatDay(hold.placedAt)}
693
693
  </Text>
@@ -851,13 +851,9 @@ export default function PurchaseOrderDetailPage({
851
851
  <Table.Cell align="right" className="tabular-nums">
852
852
  {line.received}
853
853
  {line.received !== line.qty && (
854
- <Text
855
- variant="body-sm"
856
- className="ml-1 text-muted-foreground"
857
- render={<span />}
858
- >
854
+ <Text.span variant="body-sm" className="ml-1 text-muted-foreground">
859
855
  ({line.qty - line.received})
860
- </Text>
856
+ </Text.span>
861
857
  )}
862
858
  </Table.Cell>
863
859
  <Table.Cell align="right" className="tabular-nums">
@@ -939,9 +935,9 @@ export default function PurchaseOrderDetailPage({
939
935
  {file.name}
940
936
  <ExternalLink className="size-3 shrink-0" />
941
937
  </a>
942
- <Text variant="body-sm" className="shrink-0 text-muted-foreground" render={<span />}>
938
+ <Text.span variant="body-sm" className="shrink-0 text-muted-foreground">
943
939
  {file.sizeLabel} · {formatDay(file.uploadedAt)}
944
- </Text>
940
+ </Text.span>
945
941
  </div>
946
942
  ))}
947
943
  </Card.Content>
@@ -112,7 +112,7 @@ function InteractionMultiSelect() {
112
112
  cancelled; shipped orders are excluded. Cancelled orders can&apos;t be reopened.
113
113
  </Dialog.Description>
114
114
  </Dialog.Header>
115
- {cancelError && <p role="alert">{cancelError}</p>}
115
+ {cancelError && <Text.p role="alert">{cancelError}</Text.p>}
116
116
  <Dialog.Footer>
117
117
  <Dialog.Close render={<Button variant="outline" disabled={cancelling} />}>
118
118
  Keep orders