@mhmo91/schmancy 0.4.84 → 0.4.85
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/ai/area.md +72 -66
- package/dist/ai/area.md +72 -66
- package/package.json +1 -1
package/ai/area.md
CHANGED
|
@@ -27,27 +27,27 @@ Define routes declaratively with segment matching and guards.
|
|
|
27
27
|
```html
|
|
28
28
|
<!-- Simple route -->
|
|
29
29
|
<schmancy-route
|
|
30
|
-
when="
|
|
30
|
+
when="products" <!-- Matches 'products' segment in URL -->
|
|
31
31
|
component="product-list"
|
|
32
32
|
exact>
|
|
33
33
|
</schmancy-route>
|
|
34
34
|
|
|
35
|
-
<!--
|
|
35
|
+
<!-- Component tag name matching -->
|
|
36
36
|
<schmancy-route
|
|
37
|
-
when="
|
|
37
|
+
when="product-detail" <!-- Matches when component is 'product-detail' -->
|
|
38
38
|
component="product-detail">
|
|
39
39
|
</schmancy-route>
|
|
40
40
|
|
|
41
41
|
<!-- Route with guard -->
|
|
42
42
|
<schmancy-route
|
|
43
|
-
when="
|
|
43
|
+
when="admin" <!-- Matches 'admin' segment anywhere in URL -->
|
|
44
44
|
component="admin-panel"
|
|
45
45
|
.guard=${() => isAuthenticated()}>
|
|
46
46
|
</schmancy-route>
|
|
47
47
|
|
|
48
48
|
<!-- Route with default component -->
|
|
49
49
|
<schmancy-route
|
|
50
|
-
when="
|
|
50
|
+
when="dashboard"
|
|
51
51
|
component="dashboard-main"
|
|
52
52
|
default="dashboard-overview">
|
|
53
53
|
</schmancy-route>
|
|
@@ -66,7 +66,7 @@ Define routes declaratively with segment matching and guards.
|
|
|
66
66
|
|
|
67
67
|
| Property | Type | Description |
|
|
68
68
|
|----------|------|-------------|
|
|
69
|
-
| `when` | `string` | **Required**. URL segment
|
|
69
|
+
| `when` | `string` | **Required**. URL segment name OR component tag name to match. NOT a full path! |
|
|
70
70
|
| `component` | `any` | Component to render when route matches (string, constructor, element). |
|
|
71
71
|
| `exact` | `boolean` | Whether route should match exactly (default: false). |
|
|
72
72
|
| `guard` | `() => GuardResult \| Promise<GuardResult>` | Navigation guard function returning boolean, string, or redirect object. |
|
|
@@ -76,21 +76,25 @@ Define routes declaratively with segment matching and guards.
|
|
|
76
76
|
The `when` attribute supports powerful segment-based routing:
|
|
77
77
|
|
|
78
78
|
```html
|
|
79
|
-
<!--
|
|
80
|
-
<schmancy-route when="
|
|
79
|
+
<!-- Segment name matching -->
|
|
80
|
+
<schmancy-route when="home" component="home-page"></schmancy-route>
|
|
81
|
+
<!-- Matches: /home, /app/home, any URL containing 'home' segment -->
|
|
81
82
|
|
|
82
|
-
<!--
|
|
83
|
-
<schmancy-route when="
|
|
83
|
+
<!-- Component name matching -->
|
|
84
|
+
<schmancy-route when="user-profile" component="user-profile"></schmancy-route>
|
|
85
|
+
<!-- Matches when routing to 'user-profile' component -->
|
|
84
86
|
|
|
85
|
-
<!--
|
|
86
|
-
<schmancy-route when="
|
|
87
|
+
<!-- Admin section matching -->
|
|
88
|
+
<schmancy-route when="admin" component="admin-layout"></schmancy-route>
|
|
89
|
+
<!-- Matches: /admin, /admin/users, /app/admin, etc. -->
|
|
87
90
|
|
|
88
|
-
<!--
|
|
89
|
-
<schmancy-route when="
|
|
91
|
+
<!-- Product section matching -->
|
|
92
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
93
|
+
<!-- Matches: /products, /store/products, /products/123, etc. -->
|
|
90
94
|
|
|
91
|
-
<!--
|
|
92
|
-
<schmancy-route when="
|
|
93
|
-
<!-- Matches
|
|
95
|
+
<!-- About page matching -->
|
|
96
|
+
<schmancy-route when="about" component="about-page"></schmancy-route>
|
|
97
|
+
<!-- Matches: /about, /info/about, /about/team, etc. -->
|
|
94
98
|
```
|
|
95
99
|
|
|
96
100
|
### Segment Matching Rules
|
|
@@ -107,21 +111,21 @@ Guards protect routes and can redirect navigation:
|
|
|
107
111
|
```typescript
|
|
108
112
|
// Boolean guard - simple allow/deny
|
|
109
113
|
<schmancy-route
|
|
110
|
-
when="
|
|
114
|
+
when="admin"
|
|
111
115
|
component="admin-panel"
|
|
112
116
|
.guard=${() => user.isAdmin}>
|
|
113
117
|
</schmancy-route>
|
|
114
118
|
|
|
115
119
|
// String guard - redirect to path
|
|
116
120
|
<schmancy-route
|
|
117
|
-
when="
|
|
121
|
+
when="profile"
|
|
118
122
|
component="user-profile"
|
|
119
123
|
.guard=${() => isAuthenticated() || '/login'}>
|
|
120
124
|
</schmancy-route>
|
|
121
125
|
|
|
122
126
|
// Object guard - redirect with explicit syntax
|
|
123
127
|
<schmancy-route
|
|
124
|
-
when="
|
|
128
|
+
when="settings"
|
|
125
129
|
component="settings-page"
|
|
126
130
|
.guard=${() => {
|
|
127
131
|
if (!isAuthenticated()) {
|
|
@@ -136,7 +140,7 @@ Guards protect routes and can redirect navigation:
|
|
|
136
140
|
|
|
137
141
|
// Async guard - check with backend
|
|
138
142
|
<schmancy-route
|
|
139
|
-
when="
|
|
143
|
+
when="premium"
|
|
140
144
|
component="premium-content"
|
|
141
145
|
.guard=${async () => {
|
|
142
146
|
const subscription = await checkSubscription();
|
|
@@ -162,7 +166,7 @@ Create complex nested routing structures:
|
|
|
162
166
|
```html
|
|
163
167
|
<!-- Parent component with nested routes -->
|
|
164
168
|
<schmancy-route
|
|
165
|
-
when="
|
|
169
|
+
when="app" <!-- Matches 'app' segment in URL -->
|
|
166
170
|
component="app-layout"
|
|
167
171
|
default="app-dashboard">
|
|
168
172
|
|
|
@@ -170,11 +174,11 @@ Create complex nested routing structures:
|
|
|
170
174
|
<div class="app-container">
|
|
171
175
|
<nav>...</nav>
|
|
172
176
|
<schmancy-area name="app-content">
|
|
173
|
-
<!-- Nested routes -->
|
|
174
|
-
<schmancy-route when="
|
|
175
|
-
<schmancy-route when="
|
|
176
|
-
<schmancy-route when="
|
|
177
|
-
<schmancy-route when="
|
|
177
|
+
<!-- Nested routes also use segment matching -->
|
|
178
|
+
<schmancy-route when="dashboard" component="app-dashboard"></schmancy-route>
|
|
179
|
+
<schmancy-route when="users" component="user-list"></schmancy-route>
|
|
180
|
+
<schmancy-route when="user-detail" component="user-detail"></schmancy-route>
|
|
181
|
+
<schmancy-route when="settings" component="settings-layout">
|
|
178
182
|
<!-- Even deeper nesting in settings-layout -->
|
|
179
183
|
</schmancy-route>
|
|
180
184
|
</schmancy-area>
|
|
@@ -187,17 +191,17 @@ Create complex nested routing structures:
|
|
|
187
191
|
```html
|
|
188
192
|
<!-- Root level -->
|
|
189
193
|
<schmancy-area name="root">
|
|
190
|
-
<schmancy-route when="
|
|
194
|
+
<schmancy-route when="" component="app-shell" default="home-page"> <!-- Empty when = catch-all -->
|
|
191
195
|
|
|
192
196
|
<!-- Inside app-shell -->
|
|
193
197
|
<schmancy-area name="main">
|
|
194
|
-
<schmancy-route when="
|
|
198
|
+
<schmancy-route when="products" component="product-layout">
|
|
195
199
|
|
|
196
200
|
<!-- Inside product-layout -->
|
|
197
201
|
<schmancy-area name="product-content">
|
|
198
|
-
<schmancy-route when="
|
|
199
|
-
<schmancy-route when="
|
|
200
|
-
<schmancy-route when="
|
|
202
|
+
<schmancy-route when="product-list" component="product-list"></schmancy-route>
|
|
203
|
+
<schmancy-route when="product-detail" component="product-detail"></schmancy-route>
|
|
204
|
+
<schmancy-route when="reviews" component="product-reviews"></schmancy-route>
|
|
201
205
|
</schmancy-area>
|
|
202
206
|
|
|
203
207
|
</schmancy-route>
|
|
@@ -275,25 +279,26 @@ area.push({
|
|
|
275
279
|
```html
|
|
276
280
|
<schmancy-area name="main">
|
|
277
281
|
<!-- Public routes -->
|
|
278
|
-
<schmancy-route when="
|
|
279
|
-
<schmancy-route when="
|
|
282
|
+
<schmancy-route when="home" component="home-page"></schmancy-route>
|
|
283
|
+
<schmancy-route when="about" component="about-page"></schmancy-route>
|
|
280
284
|
|
|
281
285
|
<!-- Protected routes -->
|
|
282
286
|
<schmancy-route
|
|
283
|
-
when="
|
|
287
|
+
when="dashboard"
|
|
284
288
|
component="dashboard-layout"
|
|
285
289
|
.guard=${() => isAuthenticated() || '/login'}>
|
|
286
290
|
</schmancy-route>
|
|
287
291
|
|
|
288
292
|
<!-- Admin only -->
|
|
289
293
|
<schmancy-route
|
|
290
|
-
when="
|
|
294
|
+
when="admin"
|
|
291
295
|
component="admin-panel"
|
|
292
296
|
.guard=${() => hasRole('admin') || { redirect: '/unauthorized' }}>
|
|
293
297
|
</schmancy-route>
|
|
294
298
|
|
|
295
299
|
<!-- Catch-all route (should be last) -->
|
|
296
|
-
|
|
300
|
+
<!-- Note: Empty 'when' will match any route not matched above -->
|
|
301
|
+
<schmancy-route when="" component="not-found-page"></schmancy-route>
|
|
297
302
|
</schmancy-area>
|
|
298
303
|
```
|
|
299
304
|
|
|
@@ -345,16 +350,16 @@ Default components provide fallback UI when no route matches:
|
|
|
345
350
|
```html
|
|
346
351
|
<!-- Area-level default -->
|
|
347
352
|
<schmancy-area name="main" default="welcome-page">
|
|
348
|
-
<schmancy-route when="
|
|
349
|
-
<!-- Shows welcome-page when
|
|
353
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
354
|
+
<!-- Shows welcome-page when no route matches -->
|
|
350
355
|
</schmancy-area>
|
|
351
356
|
|
|
352
357
|
<!-- Route-level default for nested routing -->
|
|
353
358
|
<schmancy-route
|
|
354
|
-
when="
|
|
359
|
+
when="app"
|
|
355
360
|
component="app-layout"
|
|
356
361
|
default="app-dashboard">
|
|
357
|
-
<!-- Shows app-dashboard
|
|
362
|
+
<!-- Shows app-dashboard as default content inside app-layout -->
|
|
358
363
|
</schmancy-route>
|
|
359
364
|
```
|
|
360
365
|
|
|
@@ -365,16 +370,16 @@ Default components provide fallback UI when no route matches:
|
|
|
365
370
|
```html
|
|
366
371
|
<!-- Order routes from most specific to least specific -->
|
|
367
372
|
<schmancy-area name="main">
|
|
368
|
-
<!--
|
|
369
|
-
<schmancy-route when="
|
|
370
|
-
<schmancy-route when="
|
|
371
|
-
<schmancy-route when="
|
|
373
|
+
<!-- More specific component names first -->
|
|
374
|
+
<schmancy-route when="product-create" component="product-create"></schmancy-route>
|
|
375
|
+
<schmancy-route when="product-edit" component="product-edit"></schmancy-route>
|
|
376
|
+
<schmancy-route when="product-detail" component="product-detail"></schmancy-route>
|
|
372
377
|
|
|
373
|
-
<!-- General
|
|
374
|
-
<schmancy-route when="
|
|
378
|
+
<!-- General segment names -->
|
|
379
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
375
380
|
|
|
376
|
-
<!--
|
|
377
|
-
<schmancy-route when="
|
|
381
|
+
<!-- Catch-all (empty when) last -->
|
|
382
|
+
<schmancy-route when="" component="not-found"></schmancy-route>
|
|
378
383
|
</schmancy-area>
|
|
379
384
|
```
|
|
380
385
|
|
|
@@ -395,7 +400,7 @@ const premiumAdminGuard = () => {
|
|
|
395
400
|
};
|
|
396
401
|
|
|
397
402
|
<schmancy-route
|
|
398
|
-
when="
|
|
403
|
+
when="premium-admin"
|
|
399
404
|
component="premium-admin-panel"
|
|
400
405
|
.guard=${premiumAdminGuard}>
|
|
401
406
|
</schmancy-route>
|
|
@@ -415,8 +420,8 @@ class AppLayout extends LitElement {
|
|
|
415
420
|
</nav>
|
|
416
421
|
|
|
417
422
|
<schmancy-area name="app-content">
|
|
418
|
-
<schmancy-route when="
|
|
419
|
-
<schmancy-route when="
|
|
423
|
+
<schmancy-route when="dashboard" component="dashboard"></schmancy-route>
|
|
424
|
+
<schmancy-route when="users" component="users-module"></schmancy-route>
|
|
420
425
|
</schmancy-area>
|
|
421
426
|
</div>
|
|
422
427
|
`;
|
|
@@ -451,7 +456,7 @@ area.push({
|
|
|
451
456
|
|
|
452
457
|
// Use with declarative routes
|
|
453
458
|
<schmancy-route
|
|
454
|
-
when="
|
|
459
|
+
when="analytics"
|
|
455
460
|
.component=${LazyAnalytics}
|
|
456
461
|
.guard=${() => hasFeature('analytics') || '/upgrade'}>
|
|
457
462
|
</schmancy-route>
|
|
@@ -630,7 +635,7 @@ The traditional dynamic import method is still supported:
|
|
|
630
635
|
```typescript
|
|
631
636
|
// Direct dynamic import (without lazy helper)
|
|
632
637
|
<schmancy-route
|
|
633
|
-
when="
|
|
638
|
+
when="analytics"
|
|
634
639
|
.component=${() => import('./analytics-dashboard.js').then(m => m.AnalyticsDashboard)}
|
|
635
640
|
.guard=${() => hasFeature('analytics') || '/upgrade'}>
|
|
636
641
|
</schmancy-route>
|
|
@@ -691,8 +696,8 @@ if (path === '/products') {
|
|
|
691
696
|
```html
|
|
692
697
|
<!-- New declarative approach -->
|
|
693
698
|
<schmancy-area name="main">
|
|
694
|
-
<schmancy-route when="
|
|
695
|
-
<schmancy-route when="
|
|
699
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
700
|
+
<schmancy-route when="product-detail" component="product-detail"></schmancy-route>
|
|
696
701
|
</schmancy-area>
|
|
697
702
|
```
|
|
698
703
|
|
|
@@ -716,7 +721,7 @@ area.on('protected-area').pipe(
|
|
|
716
721
|
```html
|
|
717
722
|
<!-- Built-in guard support -->
|
|
718
723
|
<schmancy-route
|
|
719
|
-
when="
|
|
724
|
+
when="protected"
|
|
720
725
|
component="protected-content"
|
|
721
726
|
.guard=${() => isAuthenticated() || '/login'}>
|
|
722
727
|
</schmancy-route>
|
|
@@ -730,18 +735,19 @@ area.on('protected-area').pipe(
|
|
|
730
735
|
<schmancy-area name="root">
|
|
731
736
|
<!-- Tenant detection route -->
|
|
732
737
|
<schmancy-route
|
|
733
|
-
when="
|
|
738
|
+
when="tenant-app" <!-- Matches based on component tag name -->
|
|
734
739
|
component="tenant-app"
|
|
735
|
-
.guard=${async (
|
|
740
|
+
.guard=${async (params) => {
|
|
741
|
+
const tenant = params.tenant;
|
|
736
742
|
const isValid = await validateTenant(tenant);
|
|
737
743
|
return isValid || { redirect: '/invalid-tenant' };
|
|
738
744
|
}}>
|
|
739
745
|
|
|
740
746
|
<!-- Inside tenant-app -->
|
|
741
747
|
<schmancy-area name="tenant-content">
|
|
742
|
-
<schmancy-route when="
|
|
743
|
-
<schmancy-route when="
|
|
744
|
-
<schmancy-route when="
|
|
748
|
+
<schmancy-route when="dashboard" component="tenant-dashboard"></schmancy-route>
|
|
749
|
+
<schmancy-route when="users" component="tenant-users"></schmancy-route>
|
|
750
|
+
<schmancy-route when="settings" component="tenant-settings"></schmancy-route>
|
|
745
751
|
</schmancy-area>
|
|
746
752
|
|
|
747
753
|
</schmancy-route>
|
|
@@ -751,23 +757,23 @@ area.on('protected-area').pipe(
|
|
|
751
757
|
### Wizard/Step Navigation
|
|
752
758
|
|
|
753
759
|
```html
|
|
754
|
-
<schmancy-route when="
|
|
760
|
+
<schmancy-route when="onboarding" component="onboarding-wizard">
|
|
755
761
|
<!-- Inside onboarding-wizard -->
|
|
756
762
|
<schmancy-area name="wizard-step">
|
|
757
763
|
<schmancy-route
|
|
758
|
-
when="
|
|
764
|
+
when="profile"
|
|
759
765
|
component="step-profile"
|
|
760
766
|
.guard=${() => hasCompletedStep(0) || '/onboarding/welcome'}>
|
|
761
767
|
</schmancy-route>
|
|
762
768
|
|
|
763
769
|
<schmancy-route
|
|
764
|
-
when="
|
|
770
|
+
when="preferences"
|
|
765
771
|
component="step-preferences"
|
|
766
772
|
.guard=${() => hasCompletedStep(1) || '/onboarding/profile'}>
|
|
767
773
|
</schmancy-route>
|
|
768
774
|
|
|
769
775
|
<schmancy-route
|
|
770
|
-
when="
|
|
776
|
+
when="complete"
|
|
771
777
|
component="step-complete"
|
|
772
778
|
.guard=${() => hasCompletedStep(2) || '/onboarding/preferences'}>
|
|
773
779
|
</schmancy-route>
|
package/dist/ai/area.md
CHANGED
|
@@ -27,27 +27,27 @@ Define routes declaratively with segment matching and guards.
|
|
|
27
27
|
```html
|
|
28
28
|
<!-- Simple route -->
|
|
29
29
|
<schmancy-route
|
|
30
|
-
when="
|
|
30
|
+
when="products" <!-- Matches 'products' segment in URL -->
|
|
31
31
|
component="product-list"
|
|
32
32
|
exact>
|
|
33
33
|
</schmancy-route>
|
|
34
34
|
|
|
35
|
-
<!--
|
|
35
|
+
<!-- Component tag name matching -->
|
|
36
36
|
<schmancy-route
|
|
37
|
-
when="
|
|
37
|
+
when="product-detail" <!-- Matches when component is 'product-detail' -->
|
|
38
38
|
component="product-detail">
|
|
39
39
|
</schmancy-route>
|
|
40
40
|
|
|
41
41
|
<!-- Route with guard -->
|
|
42
42
|
<schmancy-route
|
|
43
|
-
when="
|
|
43
|
+
when="admin" <!-- Matches 'admin' segment anywhere in URL -->
|
|
44
44
|
component="admin-panel"
|
|
45
45
|
.guard=${() => isAuthenticated()}>
|
|
46
46
|
</schmancy-route>
|
|
47
47
|
|
|
48
48
|
<!-- Route with default component -->
|
|
49
49
|
<schmancy-route
|
|
50
|
-
when="
|
|
50
|
+
when="dashboard"
|
|
51
51
|
component="dashboard-main"
|
|
52
52
|
default="dashboard-overview">
|
|
53
53
|
</schmancy-route>
|
|
@@ -66,7 +66,7 @@ Define routes declaratively with segment matching and guards.
|
|
|
66
66
|
|
|
67
67
|
| Property | Type | Description |
|
|
68
68
|
|----------|------|-------------|
|
|
69
|
-
| `when` | `string` | **Required**. URL segment
|
|
69
|
+
| `when` | `string` | **Required**. URL segment name OR component tag name to match. NOT a full path! |
|
|
70
70
|
| `component` | `any` | Component to render when route matches (string, constructor, element). |
|
|
71
71
|
| `exact` | `boolean` | Whether route should match exactly (default: false). |
|
|
72
72
|
| `guard` | `() => GuardResult \| Promise<GuardResult>` | Navigation guard function returning boolean, string, or redirect object. |
|
|
@@ -76,21 +76,25 @@ Define routes declaratively with segment matching and guards.
|
|
|
76
76
|
The `when` attribute supports powerful segment-based routing:
|
|
77
77
|
|
|
78
78
|
```html
|
|
79
|
-
<!--
|
|
80
|
-
<schmancy-route when="
|
|
79
|
+
<!-- Segment name matching -->
|
|
80
|
+
<schmancy-route when="home" component="home-page"></schmancy-route>
|
|
81
|
+
<!-- Matches: /home, /app/home, any URL containing 'home' segment -->
|
|
81
82
|
|
|
82
|
-
<!--
|
|
83
|
-
<schmancy-route when="
|
|
83
|
+
<!-- Component name matching -->
|
|
84
|
+
<schmancy-route when="user-profile" component="user-profile"></schmancy-route>
|
|
85
|
+
<!-- Matches when routing to 'user-profile' component -->
|
|
84
86
|
|
|
85
|
-
<!--
|
|
86
|
-
<schmancy-route when="
|
|
87
|
+
<!-- Admin section matching -->
|
|
88
|
+
<schmancy-route when="admin" component="admin-layout"></schmancy-route>
|
|
89
|
+
<!-- Matches: /admin, /admin/users, /app/admin, etc. -->
|
|
87
90
|
|
|
88
|
-
<!--
|
|
89
|
-
<schmancy-route when="
|
|
91
|
+
<!-- Product section matching -->
|
|
92
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
93
|
+
<!-- Matches: /products, /store/products, /products/123, etc. -->
|
|
90
94
|
|
|
91
|
-
<!--
|
|
92
|
-
<schmancy-route when="
|
|
93
|
-
<!-- Matches
|
|
95
|
+
<!-- About page matching -->
|
|
96
|
+
<schmancy-route when="about" component="about-page"></schmancy-route>
|
|
97
|
+
<!-- Matches: /about, /info/about, /about/team, etc. -->
|
|
94
98
|
```
|
|
95
99
|
|
|
96
100
|
### Segment Matching Rules
|
|
@@ -107,21 +111,21 @@ Guards protect routes and can redirect navigation:
|
|
|
107
111
|
```typescript
|
|
108
112
|
// Boolean guard - simple allow/deny
|
|
109
113
|
<schmancy-route
|
|
110
|
-
when="
|
|
114
|
+
when="admin"
|
|
111
115
|
component="admin-panel"
|
|
112
116
|
.guard=${() => user.isAdmin}>
|
|
113
117
|
</schmancy-route>
|
|
114
118
|
|
|
115
119
|
// String guard - redirect to path
|
|
116
120
|
<schmancy-route
|
|
117
|
-
when="
|
|
121
|
+
when="profile"
|
|
118
122
|
component="user-profile"
|
|
119
123
|
.guard=${() => isAuthenticated() || '/login'}>
|
|
120
124
|
</schmancy-route>
|
|
121
125
|
|
|
122
126
|
// Object guard - redirect with explicit syntax
|
|
123
127
|
<schmancy-route
|
|
124
|
-
when="
|
|
128
|
+
when="settings"
|
|
125
129
|
component="settings-page"
|
|
126
130
|
.guard=${() => {
|
|
127
131
|
if (!isAuthenticated()) {
|
|
@@ -136,7 +140,7 @@ Guards protect routes and can redirect navigation:
|
|
|
136
140
|
|
|
137
141
|
// Async guard - check with backend
|
|
138
142
|
<schmancy-route
|
|
139
|
-
when="
|
|
143
|
+
when="premium"
|
|
140
144
|
component="premium-content"
|
|
141
145
|
.guard=${async () => {
|
|
142
146
|
const subscription = await checkSubscription();
|
|
@@ -162,7 +166,7 @@ Create complex nested routing structures:
|
|
|
162
166
|
```html
|
|
163
167
|
<!-- Parent component with nested routes -->
|
|
164
168
|
<schmancy-route
|
|
165
|
-
when="
|
|
169
|
+
when="app" <!-- Matches 'app' segment in URL -->
|
|
166
170
|
component="app-layout"
|
|
167
171
|
default="app-dashboard">
|
|
168
172
|
|
|
@@ -170,11 +174,11 @@ Create complex nested routing structures:
|
|
|
170
174
|
<div class="app-container">
|
|
171
175
|
<nav>...</nav>
|
|
172
176
|
<schmancy-area name="app-content">
|
|
173
|
-
<!-- Nested routes -->
|
|
174
|
-
<schmancy-route when="
|
|
175
|
-
<schmancy-route when="
|
|
176
|
-
<schmancy-route when="
|
|
177
|
-
<schmancy-route when="
|
|
177
|
+
<!-- Nested routes also use segment matching -->
|
|
178
|
+
<schmancy-route when="dashboard" component="app-dashboard"></schmancy-route>
|
|
179
|
+
<schmancy-route when="users" component="user-list"></schmancy-route>
|
|
180
|
+
<schmancy-route when="user-detail" component="user-detail"></schmancy-route>
|
|
181
|
+
<schmancy-route when="settings" component="settings-layout">
|
|
178
182
|
<!-- Even deeper nesting in settings-layout -->
|
|
179
183
|
</schmancy-route>
|
|
180
184
|
</schmancy-area>
|
|
@@ -187,17 +191,17 @@ Create complex nested routing structures:
|
|
|
187
191
|
```html
|
|
188
192
|
<!-- Root level -->
|
|
189
193
|
<schmancy-area name="root">
|
|
190
|
-
<schmancy-route when="
|
|
194
|
+
<schmancy-route when="" component="app-shell" default="home-page"> <!-- Empty when = catch-all -->
|
|
191
195
|
|
|
192
196
|
<!-- Inside app-shell -->
|
|
193
197
|
<schmancy-area name="main">
|
|
194
|
-
<schmancy-route when="
|
|
198
|
+
<schmancy-route when="products" component="product-layout">
|
|
195
199
|
|
|
196
200
|
<!-- Inside product-layout -->
|
|
197
201
|
<schmancy-area name="product-content">
|
|
198
|
-
<schmancy-route when="
|
|
199
|
-
<schmancy-route when="
|
|
200
|
-
<schmancy-route when="
|
|
202
|
+
<schmancy-route when="product-list" component="product-list"></schmancy-route>
|
|
203
|
+
<schmancy-route when="product-detail" component="product-detail"></schmancy-route>
|
|
204
|
+
<schmancy-route when="reviews" component="product-reviews"></schmancy-route>
|
|
201
205
|
</schmancy-area>
|
|
202
206
|
|
|
203
207
|
</schmancy-route>
|
|
@@ -275,25 +279,26 @@ area.push({
|
|
|
275
279
|
```html
|
|
276
280
|
<schmancy-area name="main">
|
|
277
281
|
<!-- Public routes -->
|
|
278
|
-
<schmancy-route when="
|
|
279
|
-
<schmancy-route when="
|
|
282
|
+
<schmancy-route when="home" component="home-page"></schmancy-route>
|
|
283
|
+
<schmancy-route when="about" component="about-page"></schmancy-route>
|
|
280
284
|
|
|
281
285
|
<!-- Protected routes -->
|
|
282
286
|
<schmancy-route
|
|
283
|
-
when="
|
|
287
|
+
when="dashboard"
|
|
284
288
|
component="dashboard-layout"
|
|
285
289
|
.guard=${() => isAuthenticated() || '/login'}>
|
|
286
290
|
</schmancy-route>
|
|
287
291
|
|
|
288
292
|
<!-- Admin only -->
|
|
289
293
|
<schmancy-route
|
|
290
|
-
when="
|
|
294
|
+
when="admin"
|
|
291
295
|
component="admin-panel"
|
|
292
296
|
.guard=${() => hasRole('admin') || { redirect: '/unauthorized' }}>
|
|
293
297
|
</schmancy-route>
|
|
294
298
|
|
|
295
299
|
<!-- Catch-all route (should be last) -->
|
|
296
|
-
|
|
300
|
+
<!-- Note: Empty 'when' will match any route not matched above -->
|
|
301
|
+
<schmancy-route when="" component="not-found-page"></schmancy-route>
|
|
297
302
|
</schmancy-area>
|
|
298
303
|
```
|
|
299
304
|
|
|
@@ -345,16 +350,16 @@ Default components provide fallback UI when no route matches:
|
|
|
345
350
|
```html
|
|
346
351
|
<!-- Area-level default -->
|
|
347
352
|
<schmancy-area name="main" default="welcome-page">
|
|
348
|
-
<schmancy-route when="
|
|
349
|
-
<!-- Shows welcome-page when
|
|
353
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
354
|
+
<!-- Shows welcome-page when no route matches -->
|
|
350
355
|
</schmancy-area>
|
|
351
356
|
|
|
352
357
|
<!-- Route-level default for nested routing -->
|
|
353
358
|
<schmancy-route
|
|
354
|
-
when="
|
|
359
|
+
when="app"
|
|
355
360
|
component="app-layout"
|
|
356
361
|
default="app-dashboard">
|
|
357
|
-
<!-- Shows app-dashboard
|
|
362
|
+
<!-- Shows app-dashboard as default content inside app-layout -->
|
|
358
363
|
</schmancy-route>
|
|
359
364
|
```
|
|
360
365
|
|
|
@@ -365,16 +370,16 @@ Default components provide fallback UI when no route matches:
|
|
|
365
370
|
```html
|
|
366
371
|
<!-- Order routes from most specific to least specific -->
|
|
367
372
|
<schmancy-area name="main">
|
|
368
|
-
<!--
|
|
369
|
-
<schmancy-route when="
|
|
370
|
-
<schmancy-route when="
|
|
371
|
-
<schmancy-route when="
|
|
373
|
+
<!-- More specific component names first -->
|
|
374
|
+
<schmancy-route when="product-create" component="product-create"></schmancy-route>
|
|
375
|
+
<schmancy-route when="product-edit" component="product-edit"></schmancy-route>
|
|
376
|
+
<schmancy-route when="product-detail" component="product-detail"></schmancy-route>
|
|
372
377
|
|
|
373
|
-
<!-- General
|
|
374
|
-
<schmancy-route when="
|
|
378
|
+
<!-- General segment names -->
|
|
379
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
375
380
|
|
|
376
|
-
<!--
|
|
377
|
-
<schmancy-route when="
|
|
381
|
+
<!-- Catch-all (empty when) last -->
|
|
382
|
+
<schmancy-route when="" component="not-found"></schmancy-route>
|
|
378
383
|
</schmancy-area>
|
|
379
384
|
```
|
|
380
385
|
|
|
@@ -395,7 +400,7 @@ const premiumAdminGuard = () => {
|
|
|
395
400
|
};
|
|
396
401
|
|
|
397
402
|
<schmancy-route
|
|
398
|
-
when="
|
|
403
|
+
when="premium-admin"
|
|
399
404
|
component="premium-admin-panel"
|
|
400
405
|
.guard=${premiumAdminGuard}>
|
|
401
406
|
</schmancy-route>
|
|
@@ -415,8 +420,8 @@ class AppLayout extends LitElement {
|
|
|
415
420
|
</nav>
|
|
416
421
|
|
|
417
422
|
<schmancy-area name="app-content">
|
|
418
|
-
<schmancy-route when="
|
|
419
|
-
<schmancy-route when="
|
|
423
|
+
<schmancy-route when="dashboard" component="dashboard"></schmancy-route>
|
|
424
|
+
<schmancy-route when="users" component="users-module"></schmancy-route>
|
|
420
425
|
</schmancy-area>
|
|
421
426
|
</div>
|
|
422
427
|
`;
|
|
@@ -451,7 +456,7 @@ area.push({
|
|
|
451
456
|
|
|
452
457
|
// Use with declarative routes
|
|
453
458
|
<schmancy-route
|
|
454
|
-
when="
|
|
459
|
+
when="analytics"
|
|
455
460
|
.component=${LazyAnalytics}
|
|
456
461
|
.guard=${() => hasFeature('analytics') || '/upgrade'}>
|
|
457
462
|
</schmancy-route>
|
|
@@ -630,7 +635,7 @@ The traditional dynamic import method is still supported:
|
|
|
630
635
|
```typescript
|
|
631
636
|
// Direct dynamic import (without lazy helper)
|
|
632
637
|
<schmancy-route
|
|
633
|
-
when="
|
|
638
|
+
when="analytics"
|
|
634
639
|
.component=${() => import('./analytics-dashboard.js').then(m => m.AnalyticsDashboard)}
|
|
635
640
|
.guard=${() => hasFeature('analytics') || '/upgrade'}>
|
|
636
641
|
</schmancy-route>
|
|
@@ -691,8 +696,8 @@ if (path === '/products') {
|
|
|
691
696
|
```html
|
|
692
697
|
<!-- New declarative approach -->
|
|
693
698
|
<schmancy-area name="main">
|
|
694
|
-
<schmancy-route when="
|
|
695
|
-
<schmancy-route when="
|
|
699
|
+
<schmancy-route when="products" component="product-list"></schmancy-route>
|
|
700
|
+
<schmancy-route when="product-detail" component="product-detail"></schmancy-route>
|
|
696
701
|
</schmancy-area>
|
|
697
702
|
```
|
|
698
703
|
|
|
@@ -716,7 +721,7 @@ area.on('protected-area').pipe(
|
|
|
716
721
|
```html
|
|
717
722
|
<!-- Built-in guard support -->
|
|
718
723
|
<schmancy-route
|
|
719
|
-
when="
|
|
724
|
+
when="protected"
|
|
720
725
|
component="protected-content"
|
|
721
726
|
.guard=${() => isAuthenticated() || '/login'}>
|
|
722
727
|
</schmancy-route>
|
|
@@ -730,18 +735,19 @@ area.on('protected-area').pipe(
|
|
|
730
735
|
<schmancy-area name="root">
|
|
731
736
|
<!-- Tenant detection route -->
|
|
732
737
|
<schmancy-route
|
|
733
|
-
when="
|
|
738
|
+
when="tenant-app" <!-- Matches based on component tag name -->
|
|
734
739
|
component="tenant-app"
|
|
735
|
-
.guard=${async (
|
|
740
|
+
.guard=${async (params) => {
|
|
741
|
+
const tenant = params.tenant;
|
|
736
742
|
const isValid = await validateTenant(tenant);
|
|
737
743
|
return isValid || { redirect: '/invalid-tenant' };
|
|
738
744
|
}}>
|
|
739
745
|
|
|
740
746
|
<!-- Inside tenant-app -->
|
|
741
747
|
<schmancy-area name="tenant-content">
|
|
742
|
-
<schmancy-route when="
|
|
743
|
-
<schmancy-route when="
|
|
744
|
-
<schmancy-route when="
|
|
748
|
+
<schmancy-route when="dashboard" component="tenant-dashboard"></schmancy-route>
|
|
749
|
+
<schmancy-route when="users" component="tenant-users"></schmancy-route>
|
|
750
|
+
<schmancy-route when="settings" component="tenant-settings"></schmancy-route>
|
|
745
751
|
</schmancy-area>
|
|
746
752
|
|
|
747
753
|
</schmancy-route>
|
|
@@ -751,23 +757,23 @@ area.on('protected-area').pipe(
|
|
|
751
757
|
### Wizard/Step Navigation
|
|
752
758
|
|
|
753
759
|
```html
|
|
754
|
-
<schmancy-route when="
|
|
760
|
+
<schmancy-route when="onboarding" component="onboarding-wizard">
|
|
755
761
|
<!-- Inside onboarding-wizard -->
|
|
756
762
|
<schmancy-area name="wizard-step">
|
|
757
763
|
<schmancy-route
|
|
758
|
-
when="
|
|
764
|
+
when="profile"
|
|
759
765
|
component="step-profile"
|
|
760
766
|
.guard=${() => hasCompletedStep(0) || '/onboarding/welcome'}>
|
|
761
767
|
</schmancy-route>
|
|
762
768
|
|
|
763
769
|
<schmancy-route
|
|
764
|
-
when="
|
|
770
|
+
when="preferences"
|
|
765
771
|
component="step-preferences"
|
|
766
772
|
.guard=${() => hasCompletedStep(1) || '/onboarding/profile'}>
|
|
767
773
|
</schmancy-route>
|
|
768
774
|
|
|
769
775
|
<schmancy-route
|
|
770
|
-
when="
|
|
776
|
+
when="complete"
|
|
771
777
|
component="step-complete"
|
|
772
778
|
.guard=${() => hasCompletedStep(2) || '/onboarding/preferences'}>
|
|
773
779
|
</schmancy-route>
|