@tailor-platform/app-shell 1.14.0 → 1.16.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/LICENSE.md +21 -0
- package/dist/app-shell-core.css +1 -1
- package/dist/app-shell.d.ts +1203 -316
- package/dist/app-shell.js +4562 -3307
- package/dist/{appshell-CtS8Y3LW.js → appshell-B0wh5Lq0.js} +850 -549
- package/dist/style-entry.d.ts +118 -98
- package/dist/testing.d.ts +118 -98
- package/dist/testing.js +1 -1
- package/dist/themes/_template.css +1 -1
- package/dist/vite-plugin.d.ts +118 -98
- package/package.json +13 -13
- package/skills/app-shell-patterns/SKILL.md +108 -24
- package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
- package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
- package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
- package/skills/app-shell-patterns/references/api/define-module.md +247 -0
- package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
- package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
- package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
- package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
- package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
- package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
- package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
- package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
- package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
- package/skills/app-shell-patterns/references/api/use-app-shell-config.md +126 -0
- package/skills/app-shell-patterns/references/api/use-app-shell-data.md +146 -0
- package/skills/app-shell-patterns/references/api/use-app-shell.md +143 -0
- package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
- package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
- package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
- package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
- package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
- package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
- package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
- package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
- package/skills/app-shell-patterns/references/api/use-toast.md +107 -0
- package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
- package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
- package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
- package/skills/app-shell-patterns/references/components/alert.md +202 -0
- package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
- package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
- package/skills/app-shell-patterns/references/components/attachment.md +138 -0
- package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
- package/skills/app-shell-patterns/references/components/avatar.md +80 -0
- package/skills/app-shell-patterns/references/components/badge.md +309 -0
- package/skills/app-shell-patterns/references/components/button.md +164 -0
- package/skills/app-shell-patterns/references/components/card.md +109 -0
- package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
- package/skills/app-shell-patterns/references/components/combobox.md +318 -0
- package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
- package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
- package/skills/app-shell-patterns/references/components/data-table.md +953 -0
- package/skills/app-shell-patterns/references/components/date-picker.md +248 -0
- package/skills/app-shell-patterns/references/components/default-header.md +75 -0
- package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
- package/skills/app-shell-patterns/references/components/description-card.md +569 -0
- package/skills/app-shell-patterns/references/components/dialog.md +164 -0
- package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
- package/skills/app-shell-patterns/references/components/form.md +378 -0
- package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
- package/skills/app-shell-patterns/references/components/grid.md +184 -0
- package/skills/app-shell-patterns/references/components/input.md +83 -0
- package/skills/app-shell-patterns/references/components/layout.md +539 -0
- package/skills/app-shell-patterns/references/components/menu.md +218 -0
- package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
- package/skills/app-shell-patterns/references/components/select.md +283 -0
- package/skills/app-shell-patterns/references/components/sheet.md +237 -0
- package/skills/app-shell-patterns/references/components/sidebar-group.md +466 -0
- package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
- package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
- package/skills/app-shell-patterns/references/components/spinner.md +81 -0
- package/skills/app-shell-patterns/references/components/table.md +188 -0
- package/skills/app-shell-patterns/references/components/tabs.md +158 -0
- package/skills/app-shell-patterns/references/components/textarea.md +122 -0
- package/skills/app-shell-patterns/references/components/timeline.md +317 -0
- package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
- package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
- package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
- package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
- package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
- package/skills/app-shell-patterns/references/concepts/file-based-routing.md +350 -0
- package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +11 -4
- package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
- package/skills/app-shell-patterns/references/concepts/routing-navigation.md +387 -0
- package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +388 -0
- package/skills/app-shell-patterns/references/{fundamental/design-system.md → concepts/styling-theming.md} +260 -105
- package/skills/app-shell-patterns/references/migrations.md +34 -0
- package/skills/app-shell-patterns/references/pages/document-detail.md +1125 -0
- package/skills/app-shell-patterns/references/patterns/form-composer.md +44 -46
- package/skills/app-shell-patterns/references/patterns/form-modal.md +39 -100
- package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
- package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
- package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
- package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
- package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +14 -28
- package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
- package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +11 -86
- package/skills/app-shell-patterns/references/fundamental/components.md +0 -981
- package/skills/app-shell-patterns/references/patterns/detail-hero-with-actions.md +0 -201
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useRouteError
|
|
3
|
+
description: Hook to access error details in custom error boundaries
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/hooks/use-route-error.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# useRouteError
|
|
9
|
+
|
|
10
|
+
React Router hook to access error details within a custom error boundary component. Re-exported from `react-router` for convenience.
|
|
11
|
+
|
|
12
|
+
## Signature
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
const useRouteError: () => unknown;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Return Value
|
|
19
|
+
|
|
20
|
+
| Type | Description |
|
|
21
|
+
| --------- | ---------------------------------------------------------------------------- |
|
|
22
|
+
| `unknown` | The error that was thrown (typically `Error` object or route error response) |
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic Error Boundary
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { useRouteError } from "@tailor-platform/app-shell";
|
|
30
|
+
|
|
31
|
+
function ErrorBoundary() {
|
|
32
|
+
const error = useRouteError();
|
|
33
|
+
|
|
34
|
+
const message = error instanceof Error
|
|
35
|
+
? error.message
|
|
36
|
+
: "An unexpected error occurred";
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div>
|
|
40
|
+
<h1>Something went wrong</h1>
|
|
41
|
+
<p>{message}</p>
|
|
42
|
+
<button onClick={() => window.location.reload()}>
|
|
43
|
+
Try Again
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Use in Module Definition
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { defineModule } from "@tailor-platform/app-shell";
|
|
54
|
+
|
|
55
|
+
const myModule = defineModule({
|
|
56
|
+
path: "dashboard",
|
|
57
|
+
component: DashboardPage,
|
|
58
|
+
errorBoundary: <ErrorBoundary />,
|
|
59
|
+
resources: [...]
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Use in Resource Definition
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const productsModule = defineModule({
|
|
67
|
+
path: "products",
|
|
68
|
+
component: ProductsPage,
|
|
69
|
+
resources: [
|
|
70
|
+
defineResource({
|
|
71
|
+
path: ":id",
|
|
72
|
+
component: ProductDetail,
|
|
73
|
+
errorBoundary: <ErrorBoundary />,
|
|
74
|
+
}),
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Advanced Error Handling
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { isRouteErrorResponse, useRouteError } from "@tailor-platform/app-shell";
|
|
83
|
+
|
|
84
|
+
function ErrorBoundary() {
|
|
85
|
+
const error = useRouteError();
|
|
86
|
+
|
|
87
|
+
// Handle route error responses (404, 500, etc.)
|
|
88
|
+
if (isRouteErrorResponse(error)) {
|
|
89
|
+
return (
|
|
90
|
+
<div>
|
|
91
|
+
<h1>{error.status} {error.statusText}</h1>
|
|
92
|
+
<p>{error.data}</p>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Handle JavaScript errors
|
|
98
|
+
if (error instanceof Error) {
|
|
99
|
+
return (
|
|
100
|
+
<div>
|
|
101
|
+
<h1>Error</h1>
|
|
102
|
+
<p>{error.message}</p>
|
|
103
|
+
<pre>{error.stack}</pre>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Handle unknown errors
|
|
109
|
+
return (
|
|
110
|
+
<div>
|
|
111
|
+
<h1>Unknown Error</h1>
|
|
112
|
+
<p>Something went wrong</p>
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### With Error Logging
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
function ErrorBoundary() {
|
|
122
|
+
const error = useRouteError();
|
|
123
|
+
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
// Log to error tracking service
|
|
126
|
+
console.error("Route error:", error);
|
|
127
|
+
// analytics.trackError(error);
|
|
128
|
+
}, [error]);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div>
|
|
132
|
+
<h1>Error</h1>
|
|
133
|
+
<p>We've been notified and will fix this soon.</p>
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Custom Error Pages
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
function ErrorBoundary() {
|
|
143
|
+
const error = useRouteError();
|
|
144
|
+
|
|
145
|
+
if (isRouteErrorResponse(error)) {
|
|
146
|
+
if (error.status === 404) {
|
|
147
|
+
return <NotFoundPage />;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (error.status === 403) {
|
|
151
|
+
return <AccessDeniedPage />;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (error.status === 500) {
|
|
155
|
+
return <ServerErrorPage />;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return <GenericErrorPage error={error} />;
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Error Boundary Scope
|
|
164
|
+
|
|
165
|
+
Error boundaries can be defined at different levels:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// Module-level - catches errors in all resources
|
|
169
|
+
defineModule({
|
|
170
|
+
path: "products",
|
|
171
|
+
errorBoundary: <ModuleErrorBoundary />,
|
|
172
|
+
resources: [...]
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
// Resource-level - catches errors in specific resource
|
|
176
|
+
defineResource({
|
|
177
|
+
path: ":id",
|
|
178
|
+
errorBoundary: <ResourceErrorBoundary />,
|
|
179
|
+
component: ProductDetail
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
// Global - catches all unhandled errors
|
|
183
|
+
<AppShell
|
|
184
|
+
modules={modules}
|
|
185
|
+
errorBoundary={<GlobalErrorBoundary />}
|
|
186
|
+
/>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Important Notes
|
|
190
|
+
|
|
191
|
+
### Always Import from AppShell
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// ✅ Correct
|
|
195
|
+
import { useRouteError } from "@tailor-platform/app-shell";
|
|
196
|
+
|
|
197
|
+
// ❌ Wrong - won't work with AppShell's router
|
|
198
|
+
import { useRouteError } from "react-router";
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Error Boundaries Don't Catch
|
|
202
|
+
|
|
203
|
+
Error boundaries do **not** catch:
|
|
204
|
+
|
|
205
|
+
- Errors in event handlers (use try/catch)
|
|
206
|
+
- Async errors (use try/catch with async/await)
|
|
207
|
+
- Server-side rendering errors
|
|
208
|
+
- Errors thrown in the error boundary itself
|
|
209
|
+
|
|
210
|
+
## Related
|
|
211
|
+
|
|
212
|
+
- [defineModule](./define-module.md) - Module-level error boundaries
|
|
213
|
+
- [defineResource](./define-resource.md) - Resource-level error boundaries
|
|
214
|
+
- [AppShell Component](../components/app-shell.md) - Global error boundary
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useTheme
|
|
3
|
+
description: Hook for accessing and controlling theme (light/dark mode)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/hooks/use-theme.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# useTheme
|
|
9
|
+
|
|
10
|
+
React hook to access and control the current theme (light/dark mode).
|
|
11
|
+
|
|
12
|
+
## Signature
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { type ColorTheme, type ResolvedColorTheme } from "@tailor-platform/app-shell";
|
|
16
|
+
|
|
17
|
+
const useTheme: () => {
|
|
18
|
+
theme: ColorTheme;
|
|
19
|
+
resolvedTheme: ResolvedColorTheme;
|
|
20
|
+
setTheme: (theme: ColorTheme) => void;
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Return Value
|
|
25
|
+
|
|
26
|
+
### `theme`
|
|
27
|
+
|
|
28
|
+
- **Type:** `ColorTheme` (`"light" | "dark" | "system"`)
|
|
29
|
+
- **Description:** Current user preference. `"system"` means the OS setting is followed.
|
|
30
|
+
|
|
31
|
+
### `resolvedTheme`
|
|
32
|
+
|
|
33
|
+
- **Type:** `ResolvedColorTheme` (`"light" | "dark"`)
|
|
34
|
+
- **Description:** Concrete color mode after resolving `"system"`. Always `"light"` or `"dark"`.
|
|
35
|
+
|
|
36
|
+
### `setTheme()`
|
|
37
|
+
|
|
38
|
+
- **Type:** `(theme: ColorTheme) => void`
|
|
39
|
+
- **Description:** Set the color theme. Persisted to `localStorage` under the key `appshell-ui-theme`.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Display Current Theme
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { useTheme } from "@tailor-platform/app-shell";
|
|
47
|
+
|
|
48
|
+
function ThemeDisplay() {
|
|
49
|
+
const { theme } = useTheme();
|
|
50
|
+
|
|
51
|
+
return <div>Current theme: {theme}</div>;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Theme Toggle
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
function ThemeToggle() {
|
|
59
|
+
const { theme, setTheme } = useTheme();
|
|
60
|
+
|
|
61
|
+
const toggleTheme = () => {
|
|
62
|
+
setTheme(theme === "dark" ? "light" : "dark");
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return <button onClick={toggleTheme}>Toggle Theme</button>;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Theme Selector
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
function ThemeSelector() {
|
|
73
|
+
const { theme, setTheme } = useTheme();
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
|
|
77
|
+
<option value="light">Light</option>
|
|
78
|
+
<option value="dark">Dark</option>
|
|
79
|
+
<option value="system">System</option>
|
|
80
|
+
</select>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Conditional Rendering
|
|
86
|
+
|
|
87
|
+
Use `resolvedTheme` when you need a concrete `"light"` or `"dark"` value — it already accounts for `"system"`:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
function Logo() {
|
|
91
|
+
const { resolvedTheme } = useTheme();
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<img
|
|
95
|
+
src={resolvedTheme === "dark" ? "/logo-dark.png" : "/logo-light.png"}
|
|
96
|
+
alt="Logo"
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Theme Persistence
|
|
103
|
+
|
|
104
|
+
Theme preference is automatically saved to localStorage and restored on page load.
|
|
105
|
+
|
|
106
|
+
## Related
|
|
107
|
+
|
|
108
|
+
- [Styling & Theming](../concepts/styling-theming.md) - Theme customization
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useTimeZone
|
|
3
|
+
description: Hook to access the configured IANA timezone from AppShell context
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/hooks/use-time-zone.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# useTimeZone
|
|
9
|
+
|
|
10
|
+
React hook that returns a `TimeZone` object for the timezone configured on `AppShell`. Falls back to the user's local timezone when no timezone is configured.
|
|
11
|
+
|
|
12
|
+
Date/time components (`DateField`, `DatePicker`, `Calendar`) consume this hook automatically — use it when you need the same timezone in custom components.
|
|
13
|
+
|
|
14
|
+
## Signature
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
const useTimeZone: () => TimeZone;
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Return Value
|
|
21
|
+
|
|
22
|
+
A `TimeZone` object with the following properties:
|
|
23
|
+
|
|
24
|
+
### `value`
|
|
25
|
+
|
|
26
|
+
- **Type:** `string`
|
|
27
|
+
- **Description:** Raw IANA timezone identifier (e.g. `"America/Los_Angeles"`). Returns the value of AppShell's `timeZone` prop when configured, or the result of `getLocalTimeZone()` (the user's local timezone) when not.
|
|
28
|
+
|
|
29
|
+
### `today()`
|
|
30
|
+
|
|
31
|
+
- **Type:** `() => CalendarDate`
|
|
32
|
+
- **Description:** Returns today's date in this timezone.
|
|
33
|
+
|
|
34
|
+
### `now()`
|
|
35
|
+
|
|
36
|
+
- **Type:** `() => ZonedDateTime`
|
|
37
|
+
- **Description:** Returns the current instant in this timezone.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { useTimeZone } from "@tailor-platform/app-shell";
|
|
43
|
+
|
|
44
|
+
function TodayDisplay() {
|
|
45
|
+
const timeZone = useTimeZone();
|
|
46
|
+
const todayDate = timeZone.today();
|
|
47
|
+
|
|
48
|
+
return <span>Today: {todayDate.toString()}</span>;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Current timestamp
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { useTimeZone } from "@tailor-platform/app-shell";
|
|
56
|
+
|
|
57
|
+
function CurrentTimestamp() {
|
|
58
|
+
const timeZone = useTimeZone();
|
|
59
|
+
|
|
60
|
+
return <span>{timeZone.now().toString()}</span>;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Accessing the raw IANA string
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { useTimeZone } from "@tailor-platform/app-shell";
|
|
68
|
+
|
|
69
|
+
function TimeZoneLabel() {
|
|
70
|
+
const { value } = useTimeZone();
|
|
71
|
+
|
|
72
|
+
return <span>Timezone: {value}</span>;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Related
|
|
77
|
+
|
|
78
|
+
- [AppShell](../components/app-shell.md) — configure timezone via the `timeZone` prop
|
|
79
|
+
- [useResolvedLocale](./use-resolved-locale.md) — access the locale for formatting
|
|
80
|
+
- [DatePicker](../components/date-picker.md) — date input components that consume this timezone automatically
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useToast
|
|
3
|
+
description: Hook for displaying toast notifications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/hooks/use-toast.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# useToast
|
|
9
|
+
|
|
10
|
+
React hook to display toast notifications for user feedback.
|
|
11
|
+
|
|
12
|
+
## Signature
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
const useToast: () => {
|
|
16
|
+
toast: (props: ToastProps) => void;
|
|
17
|
+
};
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Parameters
|
|
21
|
+
|
|
22
|
+
### ToastProps
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
{
|
|
26
|
+
title?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
variant?: "default" | "success" | "error" | "warning";
|
|
29
|
+
duration?: number; // milliseconds
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Basic Toast
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { useToast } from "@tailor-platform/app-shell";
|
|
39
|
+
|
|
40
|
+
function SaveButton() {
|
|
41
|
+
const { toast } = useToast();
|
|
42
|
+
|
|
43
|
+
const handleSave = () => {
|
|
44
|
+
// Save logic...
|
|
45
|
+
toast({
|
|
46
|
+
title: "Saved!",
|
|
47
|
+
description: "Your changes have been saved.",
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return <button onClick={handleSave}>Save</button>;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Success Toast
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
function CreateButton() {
|
|
59
|
+
const { toast } = useToast();
|
|
60
|
+
|
|
61
|
+
const handleCreate = async () => {
|
|
62
|
+
await createItem();
|
|
63
|
+
toast({
|
|
64
|
+
title: "Created",
|
|
65
|
+
description: "Item created successfully.",
|
|
66
|
+
variant: "success",
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return <button onClick={handleCreate}>Create</button>;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Error Toast
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
function DeleteButton() {
|
|
78
|
+
const { toast } = useToast();
|
|
79
|
+
|
|
80
|
+
const handleDelete = async () => {
|
|
81
|
+
try {
|
|
82
|
+
await deleteItem();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
toast({
|
|
85
|
+
title: "Error",
|
|
86
|
+
description: error.message,
|
|
87
|
+
variant: "error",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return <button onClick={handleDelete}>Delete</button>;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Custom Duration
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
toast({
|
|
100
|
+
title: "Processing...",
|
|
101
|
+
duration: 5000, // 5 seconds
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Related
|
|
106
|
+
|
|
107
|
+
- [SidebarLayout](../components/sidebar-layout.md) - Toast provider included
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: ActionPanel
|
|
3
|
+
description: Display a title and a vertical list of actions with per-row loading and disabled states
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/components/action-panel.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# ActionPanel
|
|
9
|
+
|
|
10
|
+
`ActionPanel` is a presentational card component for rendering a vertical list of actions (icon + label). It is designed for ERP detail pages and side panels where available actions are often backend-driven.
|
|
11
|
+
|
|
12
|
+
## Import
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { ActionPanel } from "@tailor-platform/app-shell";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
<ActionPanel
|
|
22
|
+
title="Actions"
|
|
23
|
+
actions={[
|
|
24
|
+
{
|
|
25
|
+
key: "create-invoice",
|
|
26
|
+
label: "Create new sales invoice",
|
|
27
|
+
icon: <ReceiptIcon />,
|
|
28
|
+
onClick: () => openCreateInvoiceModal(),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
key: "view-docs",
|
|
32
|
+
label: "View documentation",
|
|
33
|
+
icon: <ExternalLinkIcon />,
|
|
34
|
+
onClick: () => window.open("/docs", "_blank", "noopener,noreferrer"),
|
|
35
|
+
},
|
|
36
|
+
]}
|
|
37
|
+
/>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Props
|
|
41
|
+
|
|
42
|
+
_Generated from the type surface — first-party props only._
|
|
43
|
+
|
|
44
|
+
### ActionPanelProps
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Default | Description |
|
|
47
|
+
| ------------ | -------------- | ------- | --------------------------------------------- |
|
|
48
|
+
| `actions` | `ActionItem[]` | - | List of actions to render |
|
|
49
|
+
| `className?` | `string` | - | Additional CSS classes for the card container |
|
|
50
|
+
| `title` | `string` | - | Card title |
|
|
51
|
+
|
|
52
|
+
## Exports
|
|
53
|
+
|
|
54
|
+
- `ActionPanel` — function
|
|
55
|
+
- `ActionPanelProps` — interface
|
|
56
|
+
|
|
57
|
+
### ActionItem
|
|
58
|
+
|
|
59
|
+
| Property | Type | Default | Description |
|
|
60
|
+
| ---------- | ----------------------------- | ------------ | --------------------------------------------------------------------- |
|
|
61
|
+
| `key` | `string` | **Required** | Unique key for stable rendering |
|
|
62
|
+
| `label` | `string` | **Required** | Action label shown to users |
|
|
63
|
+
| `icon` | `ReactNode` | **Required** | Icon rendered in a fixed 16px slot |
|
|
64
|
+
| `onClick` | `() => void \| Promise<void>` | - | Click handler for the action |
|
|
65
|
+
| `disabled` | `boolean` | `false` | Disables interaction and applies disabled styling |
|
|
66
|
+
| `loading` | `boolean` | `false` | Shows spinner, disables interaction, sets busy UI |
|
|
67
|
+
| `variant` | `"default" \| "destructive"` | `"default"` | Visual variant; use `"destructive"` for dangerous actions like delete |
|
|
68
|
+
|
|
69
|
+
## Behavior
|
|
70
|
+
|
|
71
|
+
- Rows are rendered as `<button type="button">` elements.
|
|
72
|
+
- `disabled` or `loading` makes the row non-interactive.
|
|
73
|
+
- When `loading` is `true`, the icon slot renders a spinner without shifting layout.
|
|
74
|
+
- Empty actions show a built-in fallback message: `No actions available`.
|
|
75
|
+
|
|
76
|
+
## With Loading State
|
|
77
|
+
|
|
78
|
+
Use parent state to control which row is loading:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
const [loadingKey, setLoadingKey] = useState<string | null>(null);
|
|
82
|
+
|
|
83
|
+
const handleConfirm = async () => {
|
|
84
|
+
setLoadingKey("confirm");
|
|
85
|
+
try {
|
|
86
|
+
await confirmOrder(orderId);
|
|
87
|
+
} finally {
|
|
88
|
+
setLoadingKey(null);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
<ActionPanel
|
|
93
|
+
title="Actions"
|
|
94
|
+
actions={[
|
|
95
|
+
{
|
|
96
|
+
key: "confirm",
|
|
97
|
+
label: "Confirm order",
|
|
98
|
+
icon: <CheckIcon />,
|
|
99
|
+
onClick: handleConfirm,
|
|
100
|
+
loading: loadingKey === "confirm",
|
|
101
|
+
},
|
|
102
|
+
]}
|
|
103
|
+
/>;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## CommandPalette Integration
|
|
107
|
+
|
|
108
|
+
`ActionPanel` automatically registers its enabled actions to the CommandPalette. Actions that are not `disabled`, not `loading`, and have an `onClick` handler are registered under the panel's `title` as the group name. Registration is cleaned up when the component unmounts.
|
|
109
|
+
|
|
110
|
+
This means users can discover and trigger any visible ActionPanel action via `Cmd+K` / `Ctrl+K` without any additional setup.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
// Actions in this panel will automatically appear in the CommandPalette
|
|
114
|
+
<ActionPanel
|
|
115
|
+
title="Order Actions"
|
|
116
|
+
actions={[
|
|
117
|
+
{ key: "confirm", label: "Confirm order", icon: <CheckIcon />, onClick: handleConfirm },
|
|
118
|
+
{ key: "cancel", label: "Cancel order", icon: <XIcon />, onClick: handleCancel },
|
|
119
|
+
]}
|
|
120
|
+
/>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> **Note:** `ActionPanel` must be rendered inside `AppShell` (which provides the required `CommandPaletteProvider`). Rendering it outside that tree will throw.
|
|
124
|
+
|
|
125
|
+
## Backend-Driven Pattern
|
|
126
|
+
|
|
127
|
+
In ERP apps, the backend often decides which actions are available for a document. A common setup:
|
|
128
|
+
|
|
129
|
+
1. Backend returns document data and available action keys.
|
|
130
|
+
2. Frontend maps each key to a registry entry (`label`, `icon`, `execute`).
|
|
131
|
+
3. Page builds `ActionItem[]` and wires `onClick`.
|
|
132
|
+
4. Page controls `loading` per key and passes it to `ActionPanel`.
|
|
133
|
+
|
|
134
|
+
This keeps `ActionPanel` simple and reusable across entity types.
|
|
135
|
+
|
|
136
|
+
## Accessibility
|
|
137
|
+
|
|
138
|
+
- Action list uses `role="list"` and each row wrapper uses `role="listitem"`.
|
|
139
|
+
- Buttons are keyboard accessible and include focus-visible states.
|
|
140
|
+
- Loading rows set `aria-busy="true"`.
|
|
141
|
+
- Disabled rows set `aria-disabled="true"` and native `disabled`.
|
|
142
|
+
|
|
143
|
+
## Styling
|
|
144
|
+
|
|
145
|
+
The component is styled with the library's internal `astw:`-prefixed utilities:
|
|
146
|
+
|
|
147
|
+
- Full width card
|
|
148
|
+
- Compact spacing for dense action lists
|
|
149
|
+
- Fixed icon slot for stable alignment
|
|
150
|
+
- Inline spinner for loading state
|
|
151
|
+
|
|
152
|
+
Use `className` on `ActionPanel` for card-level properties it does not set itself. Write **plain** utilities — see [Styling AppShell components](../concepts/styling-theming.md#styling-appshell-components).
|
|
153
|
+
|
|
154
|
+
## Examples in This Repo
|
|
155
|
+
|
|
156
|
+
- `examples/app-module` includes an **Action Panel Demo** resource.
|
|
157
|
+
- The **2 Columns** layout page also includes an ActionPanel with loading behavior.
|
|
158
|
+
|
|
159
|
+
## Related Components
|
|
160
|
+
|
|
161
|
+
- [Layout](./layout.md) - Compose page-level column layouts
|
|
162
|
+
- [DescriptionCard](./description-card.md) - Display structured record fields
|
|
163
|
+
- [Badge](./badge.md) - Show statuses and semantic labels
|
|
164
|
+
|
|
165
|
+
## Related Concepts
|
|
166
|
+
|
|
167
|
+
- [Modules and Resources](../concepts/modules-and-resources.md) - Organize pages and routes
|
|
168
|
+
- [Routing and Navigation](../concepts/routing-navigation.md) - Navigation patterns
|