@tailor-platform/app-shell 1.15.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.
Files changed (98) hide show
  1. package/dist/app-shell-core.css +1 -1
  2. package/dist/app-shell.d.ts +208 -114
  3. package/dist/app-shell.js +3449 -3446
  4. package/dist/{appshell-DLVBFo5J.js → appshell-B0wh5Lq0.js} +625 -512
  5. package/dist/style-entry.d.ts +116 -96
  6. package/dist/testing.d.ts +116 -96
  7. package/dist/testing.js +1 -1
  8. package/dist/vite-plugin.d.ts +116 -96
  9. package/package.json +8 -8
  10. package/skills/app-shell-patterns/SKILL.md +101 -14
  11. package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
  12. package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
  13. package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
  14. package/skills/app-shell-patterns/references/api/define-module.md +247 -0
  15. package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
  16. package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
  17. package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
  18. package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
  19. package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
  20. package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
  21. package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
  22. package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
  23. package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
  24. package/skills/app-shell-patterns/references/api/use-app-shell-config.md +126 -0
  25. package/skills/app-shell-patterns/references/api/use-app-shell-data.md +146 -0
  26. package/skills/app-shell-patterns/references/api/use-app-shell.md +143 -0
  27. package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
  28. package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
  29. package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
  30. package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
  31. package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
  32. package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
  33. package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
  34. package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
  35. package/skills/app-shell-patterns/references/api/use-toast.md +107 -0
  36. package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
  37. package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
  38. package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
  39. package/skills/app-shell-patterns/references/components/alert.md +202 -0
  40. package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
  41. package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
  42. package/skills/app-shell-patterns/references/components/attachment.md +138 -0
  43. package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
  44. package/skills/app-shell-patterns/references/components/avatar.md +80 -0
  45. package/skills/app-shell-patterns/references/components/badge.md +309 -0
  46. package/skills/app-shell-patterns/references/components/button.md +164 -0
  47. package/skills/app-shell-patterns/references/components/card.md +109 -0
  48. package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
  49. package/skills/app-shell-patterns/references/components/combobox.md +318 -0
  50. package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
  51. package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
  52. package/skills/app-shell-patterns/references/components/data-table.md +953 -0
  53. package/skills/app-shell-patterns/references/components/date-picker.md +248 -0
  54. package/skills/app-shell-patterns/references/components/default-header.md +75 -0
  55. package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
  56. package/skills/app-shell-patterns/references/components/description-card.md +569 -0
  57. package/skills/app-shell-patterns/references/components/dialog.md +164 -0
  58. package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
  59. package/skills/app-shell-patterns/references/components/form.md +378 -0
  60. package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
  61. package/skills/app-shell-patterns/references/components/grid.md +184 -0
  62. package/skills/app-shell-patterns/references/components/input.md +83 -0
  63. package/skills/app-shell-patterns/references/components/layout.md +539 -0
  64. package/skills/app-shell-patterns/references/components/menu.md +218 -0
  65. package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
  66. package/skills/app-shell-patterns/references/components/select.md +283 -0
  67. package/skills/app-shell-patterns/references/components/sheet.md +237 -0
  68. package/skills/app-shell-patterns/references/components/sidebar-group.md +466 -0
  69. package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
  70. package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
  71. package/skills/app-shell-patterns/references/components/spinner.md +81 -0
  72. package/skills/app-shell-patterns/references/components/table.md +188 -0
  73. package/skills/app-shell-patterns/references/components/tabs.md +158 -0
  74. package/skills/app-shell-patterns/references/components/textarea.md +122 -0
  75. package/skills/app-shell-patterns/references/components/timeline.md +317 -0
  76. package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
  77. package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
  78. package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
  79. package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
  80. package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
  81. package/skills/app-shell-patterns/references/concepts/file-based-routing.md +350 -0
  82. package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +11 -4
  83. package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
  84. package/skills/app-shell-patterns/references/concepts/routing-navigation.md +387 -0
  85. package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +388 -0
  86. package/skills/app-shell-patterns/references/{fundamental/design-system.md → concepts/styling-theming.md} +258 -110
  87. package/skills/app-shell-patterns/references/migrations.md +34 -0
  88. package/skills/app-shell-patterns/references/pages/{detail.md → document-detail.md} +4 -27
  89. package/skills/app-shell-patterns/references/patterns/form-composer.md +43 -45
  90. package/skills/app-shell-patterns/references/patterns/form-modal.md +39 -100
  91. package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
  92. package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
  93. package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
  94. package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
  95. package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +13 -27
  96. package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
  97. package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +11 -86
  98. package/skills/app-shell-patterns/references/fundamental/components.md +0 -1009
@@ -0,0 +1,458 @@
1
+ ---
2
+ title: SidebarItem
3
+ description: Individual navigation item for customizing sidebar with icons, active states, and external links
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/sidebar-item.docs.outline.md — do not edit by hand. -->
7
+
8
+ # SidebarItem
9
+
10
+ `SidebarItem` represents an individual navigation link in the sidebar. It automatically resolves titles and icons from resource definitions, supports localized title overrides, and provides active state highlighting.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { SidebarItem } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ ```tsx
21
+ import { DefaultSidebar, SidebarItem } from "@tailor-platform/app-shell";
22
+
23
+ <DefaultSidebar>
24
+ <SidebarItem to="/dashboard" />
25
+ <SidebarItem to="/products" />
26
+ <SidebarItem to="/orders" />
27
+ </DefaultSidebar>;
28
+ ```
29
+
30
+ When you only provide `to`, the title and icon are automatically resolved from the matching resource's `meta` property.
31
+
32
+ ## Props
33
+
34
+ | Prop | Type | Default | Description |
35
+ | ------------- | ---------------------- | ------------- | ---------------------------------------------- |
36
+ | `to` | `string` | **Required** | Target URL (internal or external) |
37
+ | `title` | `LocalizedString` | Auto-resolved | Override the display title (i18n supported) |
38
+ | `icon` | `React.ReactNode` | Auto-resolved | Override the icon |
39
+ | `external` | `boolean` | `false` | Opens link in new tab with external icon |
40
+ | `activeMatch` | `"exact" \| "prefix"` | `"prefix"` | How to match the current path for active state |
41
+ | `render` | `(props) => ReactNode` | - | Custom render function for full control |
42
+
43
+ ## Auto-Resolution
44
+
45
+ ### Title Resolution
46
+
47
+ The title is automatically resolved from the resource's `meta.title`:
48
+
49
+ ```tsx
50
+ // In your module definition
51
+ const dashboardModule = defineModule({
52
+ path: "dashboard",
53
+ component: DashboardPage,
54
+ meta: {
55
+ title: "Dashboard", // ← Automatically used
56
+ },
57
+ });
58
+
59
+ // In sidebar - no title needed!
60
+ <SidebarItem to="/dashboard" />;
61
+ // Renders as: Dashboard
62
+ ```
63
+
64
+ For the root path (`/` or `""`), when no `meta.title` is set, the title falls back to the localized string `"Home"` (English) or `"ホーム"` (Japanese).
65
+
66
+ ### Icon Resolution
67
+
68
+ Icons are resolved from the module's `meta.icon`:
69
+
70
+ ```tsx
71
+ import { Home, Package } from "lucide-react";
72
+
73
+ const modules = [
74
+ defineModule({
75
+ path: "dashboard",
76
+ meta: {
77
+ title: "Dashboard",
78
+ icon: <Home />, // ← Automatically used in sidebar
79
+ },
80
+ }),
81
+ defineModule({
82
+ path: "products",
83
+ meta: {
84
+ title: "Products",
85
+ icon: <Package />,
86
+ },
87
+ }),
88
+ ];
89
+
90
+ <DefaultSidebar>
91
+ <SidebarItem to="/dashboard" /> {/* Shows Home icon */}
92
+ <SidebarItem to="/products" /> {/* Shows Package icon */}
93
+ </DefaultSidebar>;
94
+ ```
95
+
96
+ ## Manual Override
97
+
98
+ ### Override Title
99
+
100
+ ```tsx
101
+ <SidebarItem
102
+ to="/dashboard"
103
+ title="My Dashboard" // Override auto-resolved title
104
+ />
105
+ ```
106
+
107
+ ### Localized Override
108
+
109
+ Pass a `LocalizedString`, such as a value from `defineI18nLabels`, to resolve the override using the current AppShell locale:
110
+
111
+ ```tsx
112
+ <SidebarItem to="/dashboard" title={labels.t("dashboard")} />
113
+ ```
114
+
115
+ ### Override Icon
116
+
117
+ ```tsx
118
+ import { Home } from "lucide-react";
119
+
120
+ <SidebarItem
121
+ to="/dashboard"
122
+ icon={<Home />} // Override auto-resolved icon
123
+ />;
124
+ ```
125
+
126
+ ### Both Title and Icon
127
+
128
+ ```tsx
129
+ import { Settings } from "lucide-react";
130
+
131
+ <SidebarItem to="/settings" title="Settings" icon={<Settings />} />;
132
+ ```
133
+
134
+ ## External Links
135
+
136
+ Open links in a new tab with an external link icon:
137
+
138
+ ```tsx
139
+ import { ExternalLink } from "lucide-react";
140
+
141
+ <SidebarItem
142
+ to="https://docs.example.com"
143
+ title="Documentation"
144
+ icon={<ExternalLink />}
145
+ external
146
+ />;
147
+ ```
148
+
149
+ The external link icon is automatically added to the end of the item.
150
+
151
+ ## Active State Matching
152
+
153
+ Control how the active state is determined:
154
+
155
+ ### Prefix Matching (Default)
156
+
157
+ Highlights when the current path **starts with** the `to` path:
158
+
159
+ ```tsx
160
+ <SidebarItem to="/products" activeMatch="prefix" />
161
+
162
+ // Active when:
163
+ // - /products
164
+ // - /products/123
165
+ // - /products/categories
166
+ ```
167
+
168
+ ### Exact Matching
169
+
170
+ Highlights only when the current path **exactly matches** the `to` path:
171
+
172
+ ```tsx
173
+ <SidebarItem to="/products" activeMatch="exact" />
174
+
175
+ // Active when:
176
+ // - /products (only)
177
+
178
+ // NOT active when:
179
+ // - /products/123
180
+ // - /products/categories
181
+ ```
182
+
183
+ ## Custom Rendering
184
+
185
+ For full control, use the `render` prop:
186
+
187
+ ```tsx
188
+ <SidebarItem
189
+ to="/notifications"
190
+ render={({ title, icon, isActive }) => (
191
+ <div className="flex items-center gap-2">
192
+ {icon}
193
+ <span>{title}</span>
194
+ {isActive && <Badge>New</Badge>}
195
+ <Badge variant="error">5</Badge>
196
+ </div>
197
+ )}
198
+ />
199
+ ```
200
+
201
+ The render function receives:
202
+
203
+ ```typescript
204
+ type SidebarItemRenderProps = {
205
+ title: string; // Auto-resolved or overridden
206
+ url: string; // The `to` prop value
207
+ icon?: ReactNode; // Auto-resolved or overridden
208
+ isActive: boolean; // Whether this item matches the current route
209
+ };
210
+ ```
211
+
212
+ ## Examples
213
+
214
+ ### Basic Sidebar
215
+
216
+ ```tsx
217
+ <DefaultSidebar>
218
+ <SidebarItem to="/dashboard" />
219
+ <SidebarItem to="/products" />
220
+ <SidebarItem to="/orders" />
221
+ <SidebarItem to="/customers" />
222
+ </DefaultSidebar>
223
+ ```
224
+
225
+ ### With Manual Overrides
226
+
227
+ ```tsx
228
+ import { Home, Package, ShoppingCart, Users } from "lucide-react";
229
+
230
+ <DefaultSidebar>
231
+ <SidebarItem to="/" title="Home" icon={<Home />} />
232
+ <SidebarItem to="/products" title="Products" icon={<Package />} />
233
+ <SidebarItem to="/orders" title="Orders" icon={<ShoppingCart />} />
234
+ <SidebarItem to="/customers" title="Customers" icon={<Users />} />
235
+ </DefaultSidebar>;
236
+ ```
237
+
238
+ ### With External Links
239
+
240
+ ```tsx
241
+ import { HelpCircle, FileText, ExternalLink } from "lucide-react";
242
+
243
+ <DefaultSidebar>
244
+ <SidebarItem to="/dashboard" />
245
+ <SidebarItem to="/products" />
246
+
247
+ <SidebarSeparator />
248
+
249
+ <SidebarItem to="https://docs.example.com" title="Documentation" icon={<FileText />} external />
250
+ <SidebarItem to="https://support.example.com" title="Support" icon={<HelpCircle />} external />
251
+ </DefaultSidebar>;
252
+ ```
253
+
254
+ ### With Notification Badge
255
+
256
+ ```tsx
257
+ <SidebarItem
258
+ to="/notifications"
259
+ render={({ title, icon, isActive }) => (
260
+ <>
261
+ {icon}
262
+ <span>{title}</span>
263
+ <Badge variant="error">12</Badge>
264
+ </>
265
+ )}
266
+ />
267
+ ```
268
+
269
+ ### With Active Indicator
270
+
271
+ ```tsx
272
+ <SidebarItem
273
+ to="/messages"
274
+ render={({ title, icon, isActive }) => (
275
+ <>
276
+ {icon}
277
+ <span className={isActive ? "font-bold" : undefined}>{title}</span>
278
+ {isActive && <span className="ml-auto">•</span>}
279
+ </>
280
+ )}
281
+ />
282
+ ```
283
+
284
+ ### Exact Match for Root
285
+
286
+ ```tsx
287
+ <DefaultSidebar>
288
+ <SidebarItem to="/" activeMatch="exact" />
289
+ <SidebarItem to="/dashboard" />
290
+ <SidebarItem to="/products" />
291
+ </DefaultSidebar>
292
+ ```
293
+
294
+ Without `activeMatch="exact"`, the root item would be active on all pages since every path starts with `/`.
295
+
296
+ ### Conditional Rendering with Guards
297
+
298
+ ```tsx
299
+ import { WithGuard } from "@tailor-platform/app-shell";
300
+
301
+ const isAdmin = ({ context }) => (context.currentUser?.role === "admin" ? pass() : hidden());
302
+
303
+ <DefaultSidebar>
304
+ <SidebarItem to="/dashboard" />
305
+ <SidebarItem to="/products" />
306
+
307
+ <WithGuard guards={[isAdmin]}>
308
+ <SidebarItem to="/admin" title="Admin Panel" />
309
+ </WithGuard>
310
+ </DefaultSidebar>;
311
+ ```
312
+
313
+ ### In SidebarGroup
314
+
315
+ ```tsx
316
+ import { SidebarGroup, SidebarItem } from "@tailor-platform/app-shell";
317
+ import { Package } from "lucide-react";
318
+
319
+ <SidebarGroup title="Products" icon={<Package />}>
320
+ <SidebarItem to="/products/all" />
321
+ <SidebarItem to="/products/categories" />
322
+ <SidebarItem to="/products/brands" />
323
+ </SidebarGroup>;
324
+ ```
325
+
326
+ ## Styling
327
+
328
+ ### Active State
329
+
330
+ Active items pick up the sidebar accent background automatically. The class carrying it is internal to the library — don't target it. Override the token instead:
331
+
332
+ ```css
333
+ :root {
334
+ --sidebar-accent: oklch(0.95 0.02 260);
335
+ }
336
+ ```
337
+
338
+ ### Custom Styling
339
+
340
+ Add custom classes via the `render` prop:
341
+
342
+ ```tsx
343
+ <SidebarItem
344
+ to="/special"
345
+ render={({ title, icon, isActive }) => (
346
+ <div className={cn("flex items-center gap-2", isActive && "border-l-4 border-primary")}>
347
+ {icon}
348
+ {title}
349
+ </div>
350
+ )}
351
+ />
352
+ ```
353
+
354
+ ## Accessibility
355
+
356
+ - Semantic `<a>` tag for links
357
+ - Proper `href` attribute
358
+ - Active state announced to screen readers
359
+ - External links open in new tab with `rel="noopener noreferrer"`
360
+ - Keyboard navigation support (Tab, Enter)
361
+
362
+ ## Best Practices
363
+
364
+ ### Do:
365
+
366
+ - ✅ Let AppShell auto-resolve title/icon when possible
367
+ - ✅ Use `external` for links outside your app
368
+ - ✅ Use `exact` match for root routes
369
+ - ✅ Group related items with `SidebarGroup`
370
+ - ✅ Keep item labels short (1-2 words)
371
+
372
+ ### Don't:
373
+
374
+ - ❌ Hardcode titles that exist in resource meta
375
+ - ❌ Forget `external` for external links
376
+ - ❌ Use prefix match for root route (`/`)
377
+ - ❌ Mix internal and external links without visual distinction
378
+ - ❌ Create deeply nested navigation (use breadcrumbs instead)
379
+
380
+ ## Comparison: Auto vs Manual
381
+
382
+ | Aspect | Auto-Resolved | Manual Override |
383
+ | --------------- | -------------------------- | ---------------------------- |
384
+ | **Title** | From resource `meta.title` | Specify `title` prop |
385
+ | **Icon** | From module `meta.icon` | Specify `icon` prop |
386
+ | **Effort** | Less code, DRY | More flexible |
387
+ | **Maintenance** | Single source of truth | Must update in 2 places |
388
+ | **Use When** | Standard navigation | Custom items, external links |
389
+
390
+ ## TypeScript
391
+
392
+ Full type safety:
393
+
394
+ ```typescript
395
+ import { type SidebarItemProps, type SidebarItemRenderProps } from "@tailor-platform/app-shell";
396
+
397
+ // Type-safe props
398
+ const itemProps: SidebarItemProps = {
399
+ to: "/dashboard",
400
+ title: "Dashboard",
401
+ activeMatch: "prefix",
402
+ };
403
+
404
+ // Type-safe render function
405
+ const customRender = (props: SidebarItemRenderProps) => {
406
+ // props.title, props.icon, props.isActive are all typed
407
+ return <div>{props.title}</div>;
408
+ };
409
+ ```
410
+
411
+ ## Troubleshooting
412
+
413
+ ### Title/Icon not showing
414
+
415
+ **Problem:** SidebarItem doesn't display title or icon
416
+
417
+ **Solutions:**
418
+
419
+ 1. Check that the resource has `meta.title` defined
420
+ 2. Verify the `to` prop matches the resource path exactly
421
+ 3. Ensure the module has `meta.icon` for icon display
422
+ 4. Try manually specifying `title` and `icon` props
423
+
424
+ ### Active state not working
425
+
426
+ **Problem:** Item isn't highlighted when on that page
427
+
428
+ **Solutions:**
429
+
430
+ 1. Check that the `to` prop matches the current route
431
+ 2. Use `exact` match for root routes (`/`)
432
+ 3. Use `prefix` match for parent routes with children
433
+ 4. Verify you're using React Router's `<Link>` correctly
434
+
435
+ ### External link not opening in new tab
436
+
437
+ **Problem:** External link opens in same tab
438
+
439
+ **Solution:** Add `external` prop:
440
+
441
+ ```tsx
442
+ <SidebarItem to="https://..." external />
443
+ ```
444
+
445
+ ## Related Components
446
+
447
+ - [SidebarGroup](./sidebar-group.md) - Group multiple items
448
+ - [DefaultSidebar](./sidebar-layout.md) - Container for sidebar items
449
+ - [WithGuard](./with-guard.md) - Conditional rendering
450
+
451
+ ## Related Concepts
452
+
453
+ - [Sidebar Navigation](../concepts/sidebar-navigation.md) - Sidebar customization guide
454
+ - [Modules and Resources](../concepts/modules-and-resources.md) - Define routes and meta
455
+
456
+ ## API Reference
457
+
458
+ - [usePageMeta](../api/use-page-meta.md) - Hook for resolving page metadata