@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.
Files changed (101) hide show
  1. package/LICENSE.md +21 -0
  2. package/dist/app-shell-core.css +1 -1
  3. package/dist/app-shell.d.ts +1203 -316
  4. package/dist/app-shell.js +4562 -3307
  5. package/dist/{appshell-CtS8Y3LW.js → appshell-B0wh5Lq0.js} +850 -549
  6. package/dist/style-entry.d.ts +118 -98
  7. package/dist/testing.d.ts +118 -98
  8. package/dist/testing.js +1 -1
  9. package/dist/themes/_template.css +1 -1
  10. package/dist/vite-plugin.d.ts +118 -98
  11. package/package.json +13 -13
  12. package/skills/app-shell-patterns/SKILL.md +108 -24
  13. package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
  14. package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
  15. package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
  16. package/skills/app-shell-patterns/references/api/define-module.md +247 -0
  17. package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
  18. package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
  19. package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
  20. package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
  21. package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
  22. package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
  23. package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
  24. package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
  25. package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
  26. package/skills/app-shell-patterns/references/api/use-app-shell-config.md +126 -0
  27. package/skills/app-shell-patterns/references/api/use-app-shell-data.md +146 -0
  28. package/skills/app-shell-patterns/references/api/use-app-shell.md +143 -0
  29. package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
  30. package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
  31. package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
  32. package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
  33. package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
  34. package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
  35. package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
  36. package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
  37. package/skills/app-shell-patterns/references/api/use-toast.md +107 -0
  38. package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
  39. package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
  40. package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
  41. package/skills/app-shell-patterns/references/components/alert.md +202 -0
  42. package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
  43. package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
  44. package/skills/app-shell-patterns/references/components/attachment.md +138 -0
  45. package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
  46. package/skills/app-shell-patterns/references/components/avatar.md +80 -0
  47. package/skills/app-shell-patterns/references/components/badge.md +309 -0
  48. package/skills/app-shell-patterns/references/components/button.md +164 -0
  49. package/skills/app-shell-patterns/references/components/card.md +109 -0
  50. package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
  51. package/skills/app-shell-patterns/references/components/combobox.md +318 -0
  52. package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
  53. package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
  54. package/skills/app-shell-patterns/references/components/data-table.md +953 -0
  55. package/skills/app-shell-patterns/references/components/date-picker.md +248 -0
  56. package/skills/app-shell-patterns/references/components/default-header.md +75 -0
  57. package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
  58. package/skills/app-shell-patterns/references/components/description-card.md +569 -0
  59. package/skills/app-shell-patterns/references/components/dialog.md +164 -0
  60. package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
  61. package/skills/app-shell-patterns/references/components/form.md +378 -0
  62. package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
  63. package/skills/app-shell-patterns/references/components/grid.md +184 -0
  64. package/skills/app-shell-patterns/references/components/input.md +83 -0
  65. package/skills/app-shell-patterns/references/components/layout.md +539 -0
  66. package/skills/app-shell-patterns/references/components/menu.md +218 -0
  67. package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
  68. package/skills/app-shell-patterns/references/components/select.md +283 -0
  69. package/skills/app-shell-patterns/references/components/sheet.md +237 -0
  70. package/skills/app-shell-patterns/references/components/sidebar-group.md +466 -0
  71. package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
  72. package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
  73. package/skills/app-shell-patterns/references/components/spinner.md +81 -0
  74. package/skills/app-shell-patterns/references/components/table.md +188 -0
  75. package/skills/app-shell-patterns/references/components/tabs.md +158 -0
  76. package/skills/app-shell-patterns/references/components/textarea.md +122 -0
  77. package/skills/app-shell-patterns/references/components/timeline.md +317 -0
  78. package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
  79. package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
  80. package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
  81. package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
  82. package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
  83. package/skills/app-shell-patterns/references/concepts/file-based-routing.md +350 -0
  84. package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +11 -4
  85. package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
  86. package/skills/app-shell-patterns/references/concepts/routing-navigation.md +387 -0
  87. package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +388 -0
  88. package/skills/app-shell-patterns/references/{fundamental/design-system.md → concepts/styling-theming.md} +260 -105
  89. package/skills/app-shell-patterns/references/migrations.md +34 -0
  90. package/skills/app-shell-patterns/references/pages/document-detail.md +1125 -0
  91. package/skills/app-shell-patterns/references/patterns/form-composer.md +44 -46
  92. package/skills/app-shell-patterns/references/patterns/form-modal.md +39 -100
  93. package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
  94. package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
  95. package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
  96. package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
  97. package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +14 -28
  98. package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
  99. package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +11 -86
  100. package/skills/app-shell-patterns/references/fundamental/components.md +0 -981
  101. package/skills/app-shell-patterns/references/patterns/detail-hero-with-actions.md +0 -201
@@ -0,0 +1,307 @@
1
+ ---
2
+ title: redirectTo
3
+ description: Guard function that redirects to another page
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/hooks/guards/redirect-to.docs.outline.md — do not edit by hand. -->
7
+
8
+ # redirectTo
9
+
10
+ Returns a guard result that redirects the user to a different URL. Used primarily for authentication flows and access control redirection.
11
+
12
+ ## Signature
13
+
14
+ ```typescript
15
+ function redirectTo(to: string): GuardResult;
16
+ ```
17
+
18
+ ## Parameters
19
+
20
+ ### `to`
21
+
22
+ - **Type:** `string`
23
+ - **Required:** Yes
24
+ - **Description:** Target URL path to redirect to
25
+
26
+ ## Return Type
27
+
28
+ ```typescript
29
+ {
30
+ type: "redirect";
31
+ to: string;
32
+ }
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ```typescript
38
+ import { redirectTo, type Guard } from "@tailor-platform/app-shell";
39
+
40
+ const redirectToLogin: Guard = () => {
41
+ return redirectTo("/login");
42
+ };
43
+ ```
44
+
45
+ ## When to Use
46
+
47
+ Use `redirectTo()` when:
48
+
49
+ - ✅ User needs authentication (redirect to login)
50
+ - ✅ User needs to complete setup (redirect to onboarding)
51
+ - ✅ Access denied but you want to show why (redirect to error page)
52
+ - ✅ You want explicit navigation vs silent denial
53
+
54
+ ## Examples
55
+
56
+ ### Require Authentication
57
+
58
+ ```typescript
59
+ const requireAuth: Guard = ({ context }) => {
60
+ if (!context.currentUser) {
61
+ return redirectTo("/login");
62
+ }
63
+ return pass();
64
+ };
65
+ ```
66
+
67
+ ### Subscription Required
68
+
69
+ ```typescript
70
+ const requirePremium: Guard = ({ context }) => {
71
+ if (context.currentUser?.plan !== "premium") {
72
+ return redirectTo("/upgrade");
73
+ }
74
+ return pass();
75
+ };
76
+ ```
77
+
78
+ ### Complete Profile
79
+
80
+ ```typescript
81
+ const requireProfile: Guard = ({ context }) => {
82
+ if (!context.currentUser?.profileComplete) {
83
+ return redirectTo("/complete-profile");
84
+ }
85
+ return pass();
86
+ };
87
+ ```
88
+
89
+ ### Email Verification
90
+
91
+ ```typescript
92
+ const requireVerifiedEmail: Guard = ({ context }) => {
93
+ if (!context.currentUser?.emailVerified) {
94
+ return redirectTo("/verify-email");
95
+ }
96
+ return pass();
97
+ };
98
+ ```
99
+
100
+ ### Terms Acceptance
101
+
102
+ ```typescript
103
+ const requireTerms: Guard = ({ context }) => {
104
+ if (!context.currentUser?.termsAccepted) {
105
+ return redirectTo("/accept-terms");
106
+ }
107
+ return pass();
108
+ };
109
+ ```
110
+
111
+ ### Role-Based Redirect
112
+
113
+ ```typescript
114
+ const redirectNonAdmins: Guard = ({ context }) => {
115
+ if (context.currentUser?.role !== "admin") {
116
+ return redirectTo("/access-denied");
117
+ }
118
+ return pass();
119
+ };
120
+ ```
121
+
122
+ ### Conditional Redirect
123
+
124
+ ```typescript
125
+ const conditionalRedirect: Guard = ({ context }) => {
126
+ const user = context.currentUser;
127
+
128
+ if (!user) {
129
+ return redirectTo("/login");
130
+ }
131
+
132
+ if (user.suspended) {
133
+ return redirectTo("/account-suspended");
134
+ }
135
+
136
+ if (!user.onboardingComplete) {
137
+ return redirectTo("/onboarding");
138
+ }
139
+
140
+ return pass();
141
+ };
142
+ ```
143
+
144
+ ### Async Redirect
145
+
146
+ ```typescript
147
+ const asyncRedirect: Guard = async ({ context }) => {
148
+ const status = await fetch("/api/user-status");
149
+ const { active } = await status.json();
150
+
151
+ if (!active) {
152
+ return redirectTo("/reactivate");
153
+ }
154
+
155
+ return pass();
156
+ };
157
+ ```
158
+
159
+ ## vs hidden()
160
+
161
+ | Aspect | redirectTo() | hidden() |
162
+ | --------------------- | ------------------------ | ----------------------- |
163
+ | **Result** | Redirect to URL | 404 Not Found |
164
+ | **User Experience** | Clear (shows why denied) | Silent (no explanation) |
165
+ | **URL Changes** | Yes | No |
166
+ | **Navigation Impact** | No effect | Hides from navigation |
167
+ | **Use Case** | Login flows, errors | Permission hiding |
168
+
169
+ ### Example: When to Use Each
170
+
171
+ ```typescript
172
+ // Use redirectTo() - User needs to take action
173
+ const requireAuth: Guard = ({ context }) => {
174
+ if (!context.currentUser) {
175
+ return redirectTo("/login"); // Clear: "You need to log in"
176
+ }
177
+ return pass();
178
+ };
179
+
180
+ // Use hidden() - Feature doesn't exist for user
181
+ const adminFeature: Guard = ({ context }) => {
182
+ if (!isAdmin(context)) {
183
+ return hidden(); // Silent: User doesn't even know this exists
184
+ }
185
+ return pass();
186
+ };
187
+ ```
188
+
189
+ ## Redirect Chains
190
+
191
+ Guards can create redirect chains:
192
+
193
+ ```typescript
194
+ const guards = [
195
+ // 1. Check authentication
196
+ ({ context }) => {
197
+ if (!context.currentUser) {
198
+ return redirectTo("/login");
199
+ }
200
+ return pass();
201
+ },
202
+ // 2. Check onboarding (only runs if authenticated)
203
+ ({ context }) => {
204
+ if (!context.currentUser?.onboardingComplete) {
205
+ return redirectTo("/onboarding");
206
+ }
207
+ return pass();
208
+ },
209
+ // 3. Check permissions (only runs if onboarded)
210
+ ({ context }) => {
211
+ if (!context.currentUser?.hasAccess) {
212
+ return redirectTo("/upgrade");
213
+ }
214
+ return pass();
215
+ },
216
+ ];
217
+ ```
218
+
219
+ ## Module vs Resource Redirects
220
+
221
+ ### Module-Level
222
+
223
+ ```typescript
224
+ const dashboardModule = defineModule({
225
+ path: "dashboard",
226
+ component: DashboardPage,
227
+ guards: [
228
+ ({ context }) => {
229
+ if (!context.currentUser) {
230
+ return redirectTo("/login");
231
+ }
232
+ return pass();
233
+ },
234
+ ],
235
+ });
236
+
237
+ // Accessing /dashboard without auth → Redirects to /login
238
+ ```
239
+
240
+ ### Resource-Level
241
+
242
+ ```typescript
243
+ const settingsResource = defineResource({
244
+ path: "settings",
245
+ component: SettingsPage,
246
+ guards: [
247
+ ({ context }) => {
248
+ if (!context.currentUser?.emailVerified) {
249
+ return redirectTo("/verify-email");
250
+ }
251
+ return pass();
252
+ },
253
+ ],
254
+ });
255
+
256
+ // Accessing /settings without verified email → Redirects to /verify-email
257
+ ```
258
+
259
+ ## Limitations
260
+
261
+ ### Not Supported in WithGuard
262
+
263
+ `redirectTo()` does **NOT** work with the `WithGuard` component:
264
+
265
+ ```typescript
266
+ // ❌ NOT SUPPORTED
267
+ <WithGuard
268
+ guards={[
269
+ () => redirectTo("/login") // This won't work!
270
+ ]}
271
+ >
272
+ <Content />
273
+ </WithGuard>
274
+
275
+ // ✅ Use hidden() with fallback instead
276
+ <WithGuard
277
+ guards={[() => hidden()]}
278
+ fallback={<Navigate to="/login" />}
279
+ >
280
+ <Content />
281
+ </WithGuard>
282
+ ```
283
+
284
+ ## Preserving Original URL
285
+
286
+ To preserve the original URL after redirect:
287
+
288
+ ```typescript
289
+ const requireAuth: Guard = ({ context }) => {
290
+ if (!context.currentUser) {
291
+ const currentPath = window.location.pathname;
292
+ return redirectTo(`/login?redirect=${encodeURIComponent(currentPath)}`);
293
+ }
294
+ return pass();
295
+ };
296
+
297
+ // After login, redirect back:
298
+ // const redirect = searchParams.get('redirect');
299
+ // if (redirect) navigate(redirect);
300
+ ```
301
+
302
+ ## Related
303
+
304
+ - [pass()](./pass.md) - Allow access and continue
305
+ - [hidden()](./hidden.md) - Deny access and return 404
306
+ - [Guards Overview](./overview.md) - Complete guard system guide
307
+ - [WithGuard Component](../../components/with-guard.md) - Component-level guards (doesn't support redirectTo)
@@ -0,0 +1,240 @@
1
+ ---
2
+ title: useLocation
3
+ description: Hook to access current location object with pathname, search, and state
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/hooks/router/use-location.docs.outline.md — do not edit by hand. -->
7
+
8
+ # useLocation
9
+
10
+ React Router hook to access the current location object. Re-exported from `react-router` for convenience.
11
+
12
+ ## Signature
13
+
14
+ ```typescript
15
+ const useLocation: () => Location;
16
+ ```
17
+
18
+ ## Return Type
19
+
20
+ ```typescript
21
+ interface Location {
22
+ pathname: string; // Current path: "/products/123"
23
+ search: string; // Query string: "?sort=name&page=2"
24
+ hash: string; // Hash: "#details"
25
+ state: any; // State passed via navigate()
26
+ key: string; // Unique key for this location
27
+ }
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ### Access Current Path
33
+
34
+ ```typescript
35
+ import { useLocation } from "@tailor-platform/app-shell";
36
+
37
+ function Breadcrumb() {
38
+ const location = useLocation();
39
+
40
+ return <div>Current path: {location.pathname}</div>;
41
+ }
42
+ ```
43
+
44
+ ### Check Active Route
45
+
46
+ ```typescript
47
+ function NavItem({ path, label }: { path: string; label: string }) {
48
+ const location = useLocation();
49
+ const isActive = location.pathname === path;
50
+
51
+ return (
52
+ <a
53
+ href={path}
54
+ className={isActive ? "active" : ""}
55
+ >
56
+ {label}
57
+ </a>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ### Access Query Parameters
63
+
64
+ ```typescript
65
+ function ProductsList() {
66
+ const location = useLocation();
67
+ const searchParams = new URLSearchParams(location.search);
68
+
69
+ const sort = searchParams.get("sort"); // "name"
70
+ const page = searchParams.get("page"); // "2"
71
+
72
+ return <div>Sort: {sort}, Page: {page}</div>;
73
+ }
74
+
75
+ // URL: /products?sort=name&page=2
76
+ ```
77
+
78
+ ### Access Navigation State
79
+
80
+ ```typescript
81
+ // Navigate with state
82
+ function ProductsList() {
83
+ const navigate = useNavigate();
84
+
85
+ const selectProduct = (id: string) => {
86
+ navigate(`/products/${id}`, {
87
+ state: { from: "list", scrollPosition: window.scrollY },
88
+ });
89
+ };
90
+ }
91
+
92
+ // Access state in target component
93
+ function ProductDetail() {
94
+ const location = useLocation();
95
+ const from = location.state?.from; // "list"
96
+ const scrollPos = location.state?.scrollPosition; // 450
97
+
98
+ return <div>Came from: {from}</div>;
99
+ }
100
+ ```
101
+
102
+ ### Track Route Changes
103
+
104
+ ```typescript
105
+ function AnalyticsTracker() {
106
+ const location = useLocation();
107
+
108
+ useEffect(() => {
109
+ // Track page view
110
+ analytics.pageView(location.pathname);
111
+ }, [location.pathname]);
112
+
113
+ return null;
114
+ }
115
+ ```
116
+
117
+ ### Preserve Query Params on Navigation
118
+
119
+ ```typescript
120
+ function FilterButton({ filter }: { filter: string }) {
121
+ const location = useLocation();
122
+ const navigate = useNavigate();
123
+
124
+ const applyFilter = () => {
125
+ const params = new URLSearchParams(location.search);
126
+ params.set("filter", filter);
127
+ navigate(`${location.pathname}?${params}`);
128
+ };
129
+
130
+ return <button onClick={applyFilter}>Apply Filter</button>;
131
+ }
132
+ ```
133
+
134
+ ## Common Patterns
135
+
136
+ ### Check Prefix Match
137
+
138
+ ```typescript
139
+ function isActiveRoute(pathname: string, prefix: string) {
140
+ return pathname.startsWith(prefix);
141
+ }
142
+
143
+ function NavItem({ path }: { path: string }) {
144
+ const location = useLocation();
145
+ const isActive = isActiveRoute(location.pathname, path);
146
+
147
+ return <a className={isActive ? "active" : ""}>{path}</a>;
148
+ }
149
+ ```
150
+
151
+ ### Scroll to Hash
152
+
153
+ ```typescript
154
+ function ScrollToHash() {
155
+ const location = useLocation();
156
+
157
+ useEffect(() => {
158
+ if (location.hash) {
159
+ const element = document.querySelector(location.hash);
160
+ element?.scrollIntoView({ behavior: "smooth" });
161
+ }
162
+ }, [location.hash]);
163
+
164
+ return null;
165
+ }
166
+ ```
167
+
168
+ ### Preserve Scroll Position
169
+
170
+ ```typescript
171
+ function Layout() {
172
+ const location = useLocation();
173
+ const scrollPositions = useRef<Record<string, number>>({});
174
+
175
+ useEffect(() => {
176
+ // Save scroll position
177
+ scrollPositions.current[location.key] = window.scrollY;
178
+
179
+ // Restore scroll position
180
+ const savedPosition = scrollPositions.current[location.key];
181
+ if (savedPosition !== undefined) {
182
+ window.scrollTo(0, savedPosition);
183
+ }
184
+ }, [location]);
185
+
186
+ return <Outlet />;
187
+ }
188
+ ```
189
+
190
+ ## useSearchParams Alternative
191
+
192
+ For easier query parameter handling, use `useSearchParams`:
193
+
194
+ ```typescript
195
+ import { useSearchParams } from "@tailor-platform/app-shell";
196
+
197
+ function ProductsList() {
198
+ const [searchParams, setSearchParams] = useSearchParams();
199
+
200
+ const sort = searchParams.get("sort");
201
+ const page = searchParams.get("page");
202
+
203
+ const updateSort = (newSort: string) => {
204
+ setSearchParams({ sort: newSort, page });
205
+ };
206
+
207
+ return <div>...</div>;
208
+ }
209
+ ```
210
+
211
+ ## Important Notes
212
+
213
+ ### Always Import from AppShell
214
+
215
+ ```typescript
216
+ // ✅ Correct
217
+ import { useLocation } from "@tailor-platform/app-shell";
218
+
219
+ // ❌ Wrong - won't work with AppShell's router
220
+ import { useLocation } from "react-router";
221
+ ```
222
+
223
+ ### Location is Immutable
224
+
225
+ The location object is immutable. Don't try to modify it:
226
+
227
+ ```typescript
228
+ // ❌ Wrong
229
+ location.pathname = "/new-path";
230
+
231
+ // ✅ Correct - use navigate
232
+ navigate("/new-path");
233
+ ```
234
+
235
+ ## Related
236
+
237
+ - [useNavigate](./use-navigate.md) - Programmatic navigation
238
+ - [useParams](./use-params.md) - Access route parameters
239
+ - [useSearchParams](./use-navigate.md) - Query parameter management
240
+ - [Routing & Navigation](../../concepts/routing-navigation.md) - Navigation guide
@@ -0,0 +1,138 @@
1
+ ---
2
+ title: useNavigate
3
+ description: Hook for programmatic navigation between routes
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/hooks/router/use-navigate.docs.outline.md — do not edit by hand. -->
7
+
8
+ # useNavigate
9
+
10
+ React Router hook for programmatic navigation. Re-exported from `react-router` for convenience.
11
+
12
+ ## Signature
13
+
14
+ ```typescript
15
+ const useNavigate: () => (to: string | number, options?: NavigateOptions) => void;
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### Navigate to Path
21
+
22
+ ```typescript
23
+ import { useNavigate } from "@tailor-platform/app-shell";
24
+
25
+ function MyComponent() {
26
+ const navigate = useNavigate();
27
+
28
+ const goToProducts = () => {
29
+ navigate("/products");
30
+ };
31
+
32
+ return <button onClick={goToProducts}>View Products</button>;
33
+ }
34
+ ```
35
+
36
+ ### Navigate with Dynamic Parameters
37
+
38
+ ```typescript
39
+ function ProductCard({ id }: { id: string }) {
40
+ const navigate = useNavigate();
41
+
42
+ const viewDetails = () => {
43
+ navigate(`/products/${id}`);
44
+ };
45
+
46
+ return <button onClick={viewDetails}>Details</button>;
47
+ }
48
+ ```
49
+
50
+ ### Navigate Back
51
+
52
+ ```typescript
53
+ function BackButton() {
54
+ const navigate = useNavigate();
55
+
56
+ return <button onClick={() => navigate(-1)}>Back</button>;
57
+ }
58
+ ```
59
+
60
+ ### Navigate Forward
61
+
62
+ ```typescript
63
+ function ForwardButton() {
64
+ const navigate = useNavigate();
65
+
66
+ return <button onClick={() => navigate(1)}>Forward</button>;
67
+ }
68
+ ```
69
+
70
+ ### Replace Current Entry
71
+
72
+ ```typescript
73
+ function LoginSuccess() {
74
+ const navigate = useNavigate();
75
+
76
+ useEffect(() => {
77
+ // Replace current history entry (user can't go back to login)
78
+ navigate("/dashboard", { replace: true });
79
+ }, []);
80
+
81
+ return <div>Redirecting...</div>;
82
+ }
83
+ ```
84
+
85
+ ### Navigate with State
86
+
87
+ ```typescript
88
+ function ProductsList() {
89
+ const navigate = useNavigate();
90
+
91
+ const selectProduct = (product: Product) => {
92
+ navigate(`/products/${product.id}`, {
93
+ state: { from: "list" },
94
+ });
95
+ };
96
+
97
+ return <ProductList onSelect={selectProduct} />;
98
+ }
99
+
100
+ // Access state in target component
101
+ function ProductDetail() {
102
+ const location = useLocation();
103
+ const from = location.state?.from; // "list"
104
+ }
105
+ ```
106
+
107
+ ## NavigateOptions
108
+
109
+ ```typescript
110
+ interface NavigateOptions {
111
+ replace?: boolean; // Replace current entry instead of pushing
112
+ state?: any; // Pass state to target route
113
+ preventScrollReset?: boolean;
114
+ relative?: "route" | "path";
115
+ }
116
+ ```
117
+
118
+ ## Important Notes
119
+
120
+ ### Import from AppShell
121
+
122
+ Always import from `@tailor-platform/app-shell`, not `react-router`:
123
+
124
+ ```typescript
125
+ // ✅ Correct
126
+ import { useNavigate } from "@tailor-platform/app-shell";
127
+
128
+ // ❌ Wrong - won't work with AppShell's router
129
+ import { useNavigate } from "react-router";
130
+ ```
131
+
132
+ This ensures you're using AppShell's router instance.
133
+
134
+ ## Related
135
+
136
+ - [useParams](./use-params.md) - Access route parameters
137
+ - [useLocation](./use-location.md) - Access current location
138
+ - [Routing & Navigation](../../concepts/routing-navigation.md) - Navigation guide, including the `Navigate` component for declarative redirects