@tailor-platform/app-shell 1.18.0 → 1.19.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/dist/app-shell-core.css +1 -1
- package/dist/app-shell.d.ts +330 -89
- package/dist/app-shell.js +8451 -7633
- package/dist/{appshell-Y1AYCuVJ.js → appshell-DQTz-QwK.js} +484 -374
- package/dist/style-entry.d.ts +1 -656
- package/dist/testing.d.ts +61 -56
- package/dist/testing.js +1 -1
- package/dist/vite-plugin.d.ts +61 -56
- package/package.json +8 -5
- package/skills/app-shell-patterns/SKILL.md +37 -27
- package/skills/app-shell-patterns/references/api/aggregations.md +131 -0
- package/skills/app-shell-patterns/references/components/action-panel.md +55 -23
- package/skills/app-shell-patterns/references/components/badge.md +7 -3
- package/skills/app-shell-patterns/references/components/data-table.md +430 -49
- package/skills/app-shell-patterns/references/components/form.md +19 -9
- package/skills/app-shell-patterns/references/components/item-list.md +191 -0
- package/skills/app-shell-patterns/references/components/select.md +10 -0
- package/skills/app-shell-patterns/references/components/text.md +75 -38
- package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +16 -14
- package/skills/app-shell-patterns/references/concepts/styling-theming.md +19 -11
- package/skills/app-shell-patterns/references/migrations.md +2 -2
- package/skills/app-shell-patterns/references/pages/document-detail.md +36 -25
- package/skills/app-shell-patterns/references/patterns/form-modal.md +4 -1
- package/dist/semantic-contrast.test.ts +0 -227
- package/dist/theme-bridge.test.ts +0 -182
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: app-shell-patterns
|
|
3
3
|
description: "Best-practice UI patterns and correct component usage for building pages in apps that use @tailor-platform/app-shell. Use when: building or editing any screen, page, list, table, detail view, form, modal, dialog, wizard, or bulk/confirm/toast interaction in an app with @tailor-platform/app-shell installed — when choosing the right AppShell component, layout, or design token for a UI — or when upgrading @tailor-platform/app-shell, or diagnosing styling, theming, or dark-mode breakage that appeared after a version bump."
|
|
4
|
+
metadata:
|
|
5
|
+
app-shell-version: "1.19.0"
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# App-Shell Patterns
|
|
@@ -9,6 +11,10 @@ description: "Best-practice UI patterns and correct component usage for building
|
|
|
9
11
|
|
|
10
12
|
Select and implement the correct UI pattern using @tailor-platform/app-shell components.
|
|
11
13
|
|
|
14
|
+
## Version
|
|
15
|
+
|
|
16
|
+
This skill was generated from `@tailor-platform/app-shell` **1.19.0**. Before relying on it, compare that with the version installed in the app you're working on (resolve `@tailor-platform/app-shell/package.json` from that app, not the monorepo root). If they differ, this copy is stale: tell the user and suggest re-syncing it from the installed package's `skills/app-shell-patterns/` directory.
|
|
17
|
+
|
|
12
18
|
## Concepts
|
|
13
19
|
|
|
14
20
|
Cross-cutting guides that underpin every screen — styling & theming and the token system, GraphQL data access, building custom components, plus auth and routing. Patterns and components build on these.
|
|
@@ -64,6 +70,7 @@ Every AppShell component, its API surface, and usage guidance. Read the entry fo
|
|
|
64
70
|
| [GlobalHeaderLayout](references/components/global-header-layout.md) | Opinionated layout with an app-wide header above the whole shell and a sidebar that collapses to a persistent icon rail |
|
|
65
71
|
| [Grid](references/components/grid.md) | Generic CSS-Grid layout primitive for equal or custom-width columns with responsive reflow, auto-fit, and spanning |
|
|
66
72
|
| [Input](references/components/input.md) | Styled text input with consistent theming |
|
|
73
|
+
| [ItemList](references/components/item-list.md) | Compact icon-and-label lists for consistent navigation inside and outside the Sidebar |
|
|
67
74
|
| [Layout](references/components/layout.md) | Responsive column layout component for organizing page content in 1, 2, or 3 columns |
|
|
68
75
|
| [Menu](references/components/menu.md) | Dropdown menu with a compound component API, supporting checkbox/radio items, groups, separators, and nested sub-menus |
|
|
69
76
|
| [MetricCard](references/components/metric-card.md) | Compact card for dashboard KPI summaries with title, value, optional trend and description |
|
|
@@ -87,33 +94,34 @@ Every AppShell component, its API surface, and usage guidance. Read the entry fo
|
|
|
87
94
|
|
|
88
95
|
Hooks, factory functions, guards, and router utilities exported by AppShell.
|
|
89
96
|
|
|
90
|
-
| Name | Description
|
|
91
|
-
| ------------------------------------------------------------------------------------------ |
|
|
92
|
-
| [
|
|
93
|
-
| [
|
|
94
|
-
| [
|
|
95
|
-
| [
|
|
96
|
-
| [
|
|
97
|
-
| [
|
|
98
|
-
| [
|
|
99
|
-
| [
|
|
100
|
-
| [
|
|
101
|
-
| [
|
|
102
|
-
| [
|
|
103
|
-
| [
|
|
104
|
-
| [
|
|
105
|
-
| [
|
|
106
|
-
| [
|
|
107
|
-
| [
|
|
108
|
-
| [
|
|
109
|
-
| [
|
|
110
|
-
| [
|
|
111
|
-
| [
|
|
112
|
-
| [
|
|
113
|
-
| [
|
|
114
|
-
| [
|
|
115
|
-
| [
|
|
116
|
-
| [
|
|
97
|
+
| Name | Description |
|
|
98
|
+
| ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
99
|
+
| [Value aggregations](references/api/aggregations.md) | Reusable selector-based sum, average, minimum, maximum, and non-null count over row collections, with optional result-only transformation |
|
|
100
|
+
| [createAIGatewayClient](references/api/create-ai-gateway-client.md) | Create a low-level AI Gateway client that reuses AppShell authentication |
|
|
101
|
+
| [createTypedPaths](references/api/create-typed-paths.md) | Generate type-safe route paths from file-based routing |
|
|
102
|
+
| [defineI18nLabels](references/api/define-i18n-labels.md) | Type-safe locale-first labels for component text and localized navigation metadata |
|
|
103
|
+
| [defineModule](references/api/define-module.md) | Define a top-level module that appears in the main navigation |
|
|
104
|
+
| [defineResource](references/api/define-resource.md) | Define a nested resource (page) within a module |
|
|
105
|
+
| [hidden](references/api/guards/hidden.md) | Guard function that denies access and returns 404 Not Found |
|
|
106
|
+
| [Guards Overview](references/api/guards/overview.md) | Access control system for routes and components using guard functions |
|
|
107
|
+
| [pass](references/api/guards/pass.md) | Guard function that allows access and continues to the next guard |
|
|
108
|
+
| [redirectTo](references/api/guards/redirect-to.md) | Guard function that redirects to another page |
|
|
109
|
+
| [useLocation](references/api/router/use-location.md) | Hook to access current location object with pathname, search, and state |
|
|
110
|
+
| [useNavigate](references/api/router/use-navigate.md) | Hook for programmatic navigation between routes |
|
|
111
|
+
| [useParams](references/api/router/use-params.md) | Hook to access dynamic route parameters |
|
|
112
|
+
| [useAIChat](references/api/use-ai-chat.md) | Simple text-only chat hook for AI Gateway |
|
|
113
|
+
| [useAppShell](references/api/use-app-shell.md) | Hook to access AppShell context data and configuration |
|
|
114
|
+
| [useAppShellConfig](references/api/use-app-shell-config.md) | Hook to access AppShell configuration data |
|
|
115
|
+
| [useAppShellData](references/api/use-app-shell-data.md) | Hook to access custom context data passed to AppShell |
|
|
116
|
+
| [useAuth](references/api/use-auth.md) | Hook for accessing authentication state and methods |
|
|
117
|
+
| [useOverrideBreadcrumb](references/api/use-override-breadcrumb.md) | Hook for dynamically overriding breadcrumb titles from within page components |
|
|
118
|
+
| [usePageMeta](references/api/use-page-meta.md) | Hook to resolve page metadata from route path |
|
|
119
|
+
| [useRegisterCommandPaletteActions](references/api/use-register-command-palette-actions.md) | Hook for registering contextual page actions into the CommandPalette |
|
|
120
|
+
| [useResolvedLocale](references/api/use-resolved-locale.md) | Hook to access the full BCP-47 locale and language code from AppShell context |
|
|
121
|
+
| [useRouteError](references/api/use-route-error.md) | Hook to access error details in custom error boundaries |
|
|
122
|
+
| [useTheme](references/api/use-theme.md) | Hook for accessing and controlling theme (light/dark mode) |
|
|
123
|
+
| [useTimeZone](references/api/use-time-zone.md) | Hook to access the configured IANA timezone from AppShell context |
|
|
124
|
+
| [useToast](references/api/use-toast.md) | Hook for displaying toast notifications |
|
|
117
125
|
|
|
118
126
|
## Available Pages
|
|
119
127
|
|
|
@@ -179,6 +187,8 @@ Full rationale in [`styling-theming`](references/concepts/styling-theming.md)
|
|
|
179
187
|
|
|
180
188
|
- **One primary action per view:** at most one primary/filled `Button`; everything else is `outline`/`secondary`/`ghost`.
|
|
181
189
|
- **Status badges by semantic color:** a **filled** semantic variant for the record's primary/lifecycle status, **`outline-*`** for secondary statuses, **`subtle-*`** for tags; reserve brand `default` for non-status emphasis.
|
|
190
|
+
- **Text uses `Text` and typography roles:** render headings, body copy, labels, and captions with [`Text`](references/components/text.md) and a `variant` (`heading-md`, `body-md`, `body-sm`, `label-md`, …) — never a bare `<p>`, `<h*>`, or `<span>` styled with size and weight utilities such as `text-lg font-semibold` or `text-sm`. Set the heading level with `Text.h1` to `Text.h6` (`<Text.h3 variant="heading-md">`), not by its size, and the color with a token in `className`. For other plain elements use `Text.p`, `Text.span` or `Text.div`; use `render` only to compose with another component. On an element you style yourself, such as a `th`, use the role utility (`text-label-md`). Pick the size with `variant`: a size class such as `text-sm` on `Text` has no effect. `Layout.Header` already renders the page title, and a form field label is [`Field.Label`](references/components/form.md), which already has the label role. Role table and color pairings: [`styling-theming`](references/concepts/styling-theming.md) → Typography.
|
|
191
|
+
- **Status and feedback color by semantic role:** use a component variant first (`Badge`, `Alert`, `Button variant="destructive"`). On your own element, use the roles `{info|success|warning|danger|neutral}-{surface|border|solid|text|contrast|indicator}`, for example `bg-warning-surface text-warning-text border-warning-border`. Error text is `text-danger-text`. Never write the deprecated `--status-*`, `--alert-*` or `--destructive` tokens or their utilities (`bg-status-*`, `text-alert-*`, `bg-destructive`, `text-destructive`) in new code; the next major removes them. When you edit a screen that still uses them, replace them: `text-destructive` → `text-danger-text`, `bg-status-completed` → `bg-success-solid`, `bg-alert-warning-background` → `bg-warning-surface`. Full mapping: [`styling-theming`](references/concepts/styling-theming.md) → Semantic color roles.
|
|
182
192
|
- **No duplicate actions:** an action lives in exactly one place — never repeat the same action in both `Layout.Header` and `ActionPanel`.
|
|
183
193
|
- **Action placement:** primary CTA + status in `Layout.Header`; workflow actions in `ActionPanel`; back/navigation in the breadcrumb — never in `ActionPanel`.
|
|
184
194
|
- **Metric tiles always go in a `Grid`** (`columns={{ initial: 1, md: 2, xl: 4 }}`) — never one-per-row.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Value aggregations
|
|
3
|
+
description: Reusable selector-based sum, average, minimum, maximum, and non-null count over row collections, with optional result-only transformation
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/hooks/aggregations.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# Value aggregations
|
|
9
|
+
|
|
10
|
+
`aggregations` creates reusable callbacks that select values from a row collection and aggregate them. Each callback accepts `{ rows: readonly TRow[] }`; the module has no dependency on React, DataTable, or column definitions.
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import { aggregations, type Aggregation } from "@tailor-platform/app-shell";
|
|
14
|
+
|
|
15
|
+
type Line = { quantity: number | null };
|
|
16
|
+
|
|
17
|
+
const sum = aggregations.sum((row: Line) => row.quantity);
|
|
18
|
+
sum({ rows: [{ quantity: 1 }, { quantity: 2 }, { quantity: null }] }); // 3
|
|
19
|
+
sum({ rows: [{ quantity: 4 }, { quantity: 5 }] }); // 9: no previous aggregate state
|
|
20
|
+
|
|
21
|
+
const summary: Aggregation<Line, string> = aggregations.sum(
|
|
22
|
+
(row: Line) => row.quantity,
|
|
23
|
+
(value) => (value === null ? "Unavailable" : `${value} units`),
|
|
24
|
+
);
|
|
25
|
+
summary({ rows: [{ quantity: 1 }, { quantity: 2 }] }); // "3 units"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Operations
|
|
29
|
+
|
|
30
|
+
| Factory | Result | Empty or all-nullish selected values |
|
|
31
|
+
| ------------------------------ | --------------------------------------- | ------------------------------------ |
|
|
32
|
+
| `aggregations.sum(selector)` | Sum of finite numbers | `0` |
|
|
33
|
+
| `aggregations.avg(selector)` | Average of finite numbers | `null` |
|
|
34
|
+
| `aggregations.min(selector)` | Minimum finite number | `null` |
|
|
35
|
+
| `aggregations.max(selector)` | Maximum finite number | `null` |
|
|
36
|
+
| `aggregations.count(selector)` | Count of non-nullish values of any type | `0` |
|
|
37
|
+
|
|
38
|
+
A selector is required. It receives one row at a time and determines the values to aggregate. Numeric selectors must return `number | null | undefined`; count selectors may return any type. There is no automatic field lookup or connection to a column's `id`, `accessor`, or rendered content.
|
|
39
|
+
|
|
40
|
+
Each factory returns an `Aggregation<TRow, TResult>` callback. Pass a read-only or mutable row array through `{ rows }`; aggregation does not mutate it or retain state between invocations. Selectors and transformers must be pure and must not mutate rows. Exceptions from either callback propagate to the caller.
|
|
41
|
+
|
|
42
|
+
All operations skip selected `null` and `undefined` values. Numeric operations also validate selected values at runtime and return `null` for the entire result if any other value is not a finite JavaScript number, including numeric strings, booleans, dates, `NaN`, and infinities. They do not coerce values, compare dates or strings, or return a partial result. Average divides by the number of non-nullish numeric values, not the row count.
|
|
43
|
+
|
|
44
|
+
Calculations use ordinary JavaScript numbers. A non-finite calculated result returns `null`; for average, this includes an intermediate sum overflow even when the mathematical average could be finite. These functions do not provide arbitrary-precision arithmetic.
|
|
45
|
+
|
|
46
|
+
`count(selector)` counts selected `0`, `false`, and `""` as present values. It counts non-nullish values, not truthy values; use `rows.length` when every row should count.
|
|
47
|
+
|
|
48
|
+
## Optional transformer
|
|
49
|
+
|
|
50
|
+
Pass a second function to transform the final result:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
const averageText = aggregations.avg(
|
|
54
|
+
(row: Line) => row.quantity,
|
|
55
|
+
(value) => value?.toFixed(2) ?? "–",
|
|
56
|
+
);
|
|
57
|
+
averageText({ rows: [{ quantity: 1 }, { quantity: null }, { quantity: 2 }] }); // "1.50"
|
|
58
|
+
|
|
59
|
+
const detailed = aggregations.sum(
|
|
60
|
+
(row: Line) => row.quantity,
|
|
61
|
+
(total) => ({ total, valid: total !== null }),
|
|
62
|
+
);
|
|
63
|
+
detailed({ rows: [{ quantity: 1 }, { quantity: 2 }] }); // { total: 3, valid: true }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The transformer is called exactly once per aggregation invocation, including for empty or invalid input. Numeric transformers receive `number | null`; count transformers receive `number`. Its return type becomes the callback's result type, and may be text, JSX, an object, or another value. The aggregation library does not interpret the transformed result.
|
|
67
|
+
|
|
68
|
+
A transformer receives only the result, not rows, selected values, columns, or UI context. Filter `rows` before invoking the callback when the calculation needs a different input set.
|
|
69
|
+
|
|
70
|
+
For detached callbacks, annotate the selector's row parameter as above so the row and transformed result types can both be inferred. Row types are not restricted to objects; for example, `aggregations.sum<number>((value) => value)({ rows: [1, 2] })` returns `3`.
|
|
71
|
+
|
|
72
|
+
## Composing with business validation
|
|
73
|
+
|
|
74
|
+
An aggregation is an ordinary callback, so a wrapper can validate the supplied rows before calling it. Keep business rules in the wrapper, numeric calculation in the aggregation, and result formatting in the transformer. The transformer is not an error handler: it receives `null` for invalid numeric results but has no row context or business-error details; selector exceptions still propagate.
|
|
75
|
+
|
|
76
|
+
For example, reject mixed currencies before adding monetary amounts:
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
type MoneyLine = { amount: number | null; currency: string };
|
|
80
|
+
|
|
81
|
+
const sumAmount = aggregations.sum(
|
|
82
|
+
(row: MoneyLine) => row.amount,
|
|
83
|
+
(total) => (total === null ? "Invalid amount" : total.toLocaleString("en-US")),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const moneyFooter = (ctx: { rows: readonly MoneyLine[] }) => {
|
|
87
|
+
const currencies = new Set(
|
|
88
|
+
ctx.rows.filter((row) => row.amount != null).map((row) => row.currency),
|
|
89
|
+
);
|
|
90
|
+
if (currencies.size > 1) {
|
|
91
|
+
return `Mixed currencies: ${[...currencies].join(", ")}`;
|
|
92
|
+
}
|
|
93
|
+
return sumAmount(ctx);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
moneyFooter({
|
|
97
|
+
rows: [
|
|
98
|
+
{ amount: 1000, currency: "JPY" },
|
|
99
|
+
{ amount: 500, currency: "JPY" },
|
|
100
|
+
],
|
|
101
|
+
}); // "1,500"
|
|
102
|
+
moneyFooter({
|
|
103
|
+
rows: [
|
|
104
|
+
{ amount: 1000, currency: "JPY" },
|
|
105
|
+
{ amount: 500, currency: "USD" },
|
|
106
|
+
],
|
|
107
|
+
}); // "Mixed currencies: JPY, USD"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The guard ignores nullish amounts because they do not contribute to the sum. A rejected currency combination returns directly without evaluating the selector or transformer. Neither the wrapper nor the helper converts currencies or provides arbitrary-precision arithmetic.
|
|
111
|
+
|
|
112
|
+
Pass `moneyFooter` directly as a column's `footer`. See the [runnable DataTable example](../components/data-table.md#composing-with-business-validation) to toggle mixed currencies and observe the composed behavior.
|
|
113
|
+
|
|
114
|
+
## DataTable integration
|
|
115
|
+
|
|
116
|
+
Pass an aggregation callback directly to a column footer. It is an ordinary footer renderer that reads the current `ctx.rows`; DataTable needs no aggregation-specific handling:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { aggregations, createColumnHelper } from "@tailor-platform/app-shell";
|
|
120
|
+
|
|
121
|
+
const { column } = createColumnHelper<{ quantity: number | null }>();
|
|
122
|
+
column({
|
|
123
|
+
id: "quantity",
|
|
124
|
+
type: "number",
|
|
125
|
+
footer: aggregations.sum((row) => row.quantity),
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Inline selectors infer the row type from the surrounding footer definition. The selector is the source of truth even when the column has an `accessor`; write the same calculation in the selector if the footer should aggregate a computed cell value.
|
|
130
|
+
|
|
131
|
+
Use a transformer for simple footer text or JSX. DataTable only accepts callback results it can render; object-producing aggregations remain available for non-UI use. For the current-page scope, loading behavior, and custom renderers, see [DataTable column footers](../components/data-table.md#column-footers).
|
|
@@ -17,24 +17,30 @@ import { ActionPanel } from "@tailor-platform/app-shell";
|
|
|
17
17
|
|
|
18
18
|
## Basic Usage
|
|
19
19
|
|
|
20
|
+
<example-preview name="basic-usage"></example-preview>
|
|
21
|
+
|
|
20
22
|
```tsx
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
function BasicUsage() {
|
|
24
|
+
return (
|
|
25
|
+
<ActionPanel
|
|
26
|
+
title="Actions"
|
|
27
|
+
actions={[
|
|
28
|
+
{
|
|
29
|
+
key: "create-invoice",
|
|
30
|
+
label: "Create new sales invoice",
|
|
31
|
+
icon: <Receipt />,
|
|
32
|
+
onClick: () => {},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "view-docs",
|
|
36
|
+
label: "View documentation",
|
|
37
|
+
icon: <ExternalLink />,
|
|
38
|
+
onClick: () => {},
|
|
39
|
+
},
|
|
40
|
+
]}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
38
44
|
```
|
|
39
45
|
|
|
40
46
|
## Props
|
|
@@ -43,11 +49,12 @@ _Generated from the type surface — first-party props only._
|
|
|
43
49
|
|
|
44
50
|
### ActionPanelProps
|
|
45
51
|
|
|
46
|
-
| Prop
|
|
47
|
-
|
|
|
48
|
-
| `actions`
|
|
49
|
-
| `className?`
|
|
50
|
-
| `
|
|
52
|
+
| Prop | Type | Default | Description |
|
|
53
|
+
| --------------- | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
54
|
+
| `actions` | `ActionItem[]` | - | List of actions to render |
|
|
55
|
+
| `className?` | `string` | - | Additional CSS classes for the card container |
|
|
56
|
+
| `emptyContent?` | `ReactNode` | - | Content shown with consistent padding when actions is empty. Defaults to a localized "No actions available" message. Strings use the default body text styling; other React nodes render unchanged. Pass null to hide the empty content and its additional vertical spacing while keeping the card and title. |
|
|
57
|
+
| `title` | `string` | - | Card title |
|
|
51
58
|
|
|
52
59
|
## Exports
|
|
53
60
|
|
|
@@ -71,7 +78,32 @@ _Generated from the type surface — first-party props only._
|
|
|
71
78
|
- Rows are rendered as `<button type="button">` elements.
|
|
72
79
|
- `disabled` or `loading` makes the row non-interactive.
|
|
73
80
|
- When `loading` is `true`, the icon slot renders a spinner without shifting layout.
|
|
74
|
-
- Empty actions show a
|
|
81
|
+
- Empty actions show `emptyContent`, which defaults to a styled message localized using the AppShell locale: `No actions available` in English or `利用可能なアクションはありません` in Japanese.
|
|
82
|
+
|
|
83
|
+
## Custom Empty Content
|
|
84
|
+
|
|
85
|
+
Pass a string or any `ReactNode` to `emptyContent` to replace the default content when `actions` is empty. Strings use the same muted `Text` body styling as the default message. Other React nodes render directly inside `Card.Content` without a paragraph wrapper and control their own typography. `Card.Content` owns the spacing, and the title, empty content, and action icons share the same 32px horizontal inset. Action rows retain horizontal padding around their hover backgrounds and focus rings. Custom empty content is ignored when actions are present.
|
|
86
|
+
|
|
87
|
+
<example-preview name="custom-empty-content"></example-preview>
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
function CustomEmptyContent() {
|
|
91
|
+
return (
|
|
92
|
+
<ActionPanel
|
|
93
|
+
title="操作"
|
|
94
|
+
actions={[]}
|
|
95
|
+
emptyContent={
|
|
96
|
+
<div>
|
|
97
|
+
<p>利用可能な操作はありません</p>
|
|
98
|
+
<p>ステータスが変わると、操作が表示されます。</p>
|
|
99
|
+
</div>
|
|
100
|
+
}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Pass `null` to hide the empty content and its additional vertical spacing while keeping the card and its title. To hide the entire panel when no actions are available, render it conditionally with `actions.length > 0`.
|
|
75
107
|
|
|
76
108
|
## With Loading State
|
|
77
109
|
|
|
@@ -32,6 +32,7 @@ function BasicUsage() {
|
|
|
32
32
|
<Badge variant="subtle-warning">Subtle Warning</Badge>
|
|
33
33
|
<Badge variant="subtle-error">Subtle Error</Badge>
|
|
34
34
|
<Badge variant="subtle-info">Subtle Info</Badge>
|
|
35
|
+
<Badge variant="subtle-neutral">Subtle Neutral</Badge>
|
|
35
36
|
</div>
|
|
36
37
|
);
|
|
37
38
|
}
|
|
@@ -54,6 +55,7 @@ Filled variants for high emphasis, plus subtle variants for lower-emphasis statu
|
|
|
54
55
|
<Badge variant="subtle-warning">Needs Attention</Badge>
|
|
55
56
|
<Badge variant="subtle-error">Needs Review</Badge>
|
|
56
57
|
<Badge variant="subtle-info">In Progress</Badge>
|
|
58
|
+
<Badge variant="subtle-neutral">Archived</Badge>
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
### Outline Variants with Status Dots
|
|
@@ -74,9 +76,9 @@ _Generated from the type surface — first-party props only._
|
|
|
74
76
|
|
|
75
77
|
### BadgeProps
|
|
76
78
|
|
|
77
|
-
| Prop | Type
|
|
78
|
-
| ---------- |
|
|
79
|
-
| `variant?` | `"error" \| "neutral" \| "success" \| "warning" \| "info" \| "default" \| "subtle-success" \| "subtle-warning" \| "subtle-error" \| "subtle-info" \| "outline-success" \| "outline-warning" \| "outline-error" \| "outline-info" \| "outline-neutral" \| null` | `"default"` | Visual style variant |
|
|
79
|
+
| Prop | Type | Default | Description |
|
|
80
|
+
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------------------- |
|
|
81
|
+
| `variant?` | `"error" \| "neutral" \| "success" \| "warning" \| "info" \| "default" \| "subtle-success" \| "subtle-warning" \| "subtle-error" \| "subtle-info" \| "subtle-neutral" \| "outline-success" \| "outline-warning" \| "outline-error" \| "outline-info" \| "outline-neutral" \| null` | `"default"` | Visual style variant |
|
|
80
82
|
|
|
81
83
|
## Exports
|
|
82
84
|
|
|
@@ -99,6 +101,7 @@ type BadgeVariant =
|
|
|
99
101
|
| "subtle-warning" // Low-emphasis yellow
|
|
100
102
|
| "subtle-error" // Low-emphasis red/destructive
|
|
101
103
|
| "subtle-info" // Low-emphasis blue
|
|
104
|
+
| "subtle-neutral" // Low-emphasis gray
|
|
102
105
|
// Outline variants with status dots
|
|
103
106
|
| "outline-success"
|
|
104
107
|
| "outline-warning"
|
|
@@ -225,6 +228,7 @@ function ProductBadge({ product }: { product: Product }) {
|
|
|
225
228
|
| `subtle-warning` | ![Subtle yellow badge] | Low-emphasis pending or attention states |
|
|
226
229
|
| `subtle-error` | ![Subtle red badge] | Low-emphasis failures or exceptions |
|
|
227
230
|
| `subtle-info` | ![Subtle blue badge] | Low-emphasis informational or in-progress |
|
|
231
|
+
| `subtle-neutral` | ![Subtle gray badge] | Low-emphasis tags with no status |
|
|
228
232
|
|
|
229
233
|
### Outline Variants
|
|
230
234
|
|