@liteforge/router 0.1.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 +21 -0
- package/README.md +296 -0
- package/dist/components.d.ts +75 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +475 -0
- package/dist/components.js.map +1 -0
- package/dist/guards.d.ts +103 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +268 -0
- package/dist/guards.js.map +1 -0
- package/dist/history.d.ts +33 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +315 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/lazy.d.ts +197 -0
- package/dist/lazy.d.ts.map +1 -0
- package/dist/lazy.js +458 -0
- package/dist/lazy.js.map +1 -0
- package/dist/middleware.d.ts +69 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +215 -0
- package/dist/middleware.js.map +1 -0
- package/dist/route-matcher.d.ts +80 -0
- package/dist/route-matcher.d.ts.map +1 -0
- package/dist/route-matcher.js +482 -0
- package/dist/route-matcher.js.map +1 -0
- package/dist/router.d.ts +26 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +393 -0
- package/dist/router.js.map +1 -0
- package/dist/types.d.ts +459 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
import { effect } from '@liteforge/core';
|
|
2
|
+
import { use, pushContext, popContext, isComponentFactory } from '@liteforge/runtime';
|
|
3
|
+
import { isPathActive } from './route-matcher.js';
|
|
4
|
+
import { isLazyComponent, getLazyDelay, getLazyLoading, getLazyError } from './lazy.js';
|
|
5
|
+
/**
|
|
6
|
+
* RouterOutlet renders the component for the current matched route.
|
|
7
|
+
*
|
|
8
|
+
* For nested routes, each RouterOutlet tracks its depth and renders
|
|
9
|
+
* the appropriate level of the route match chain.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Basic usage
|
|
14
|
+
* const outlet = RouterOutlet();
|
|
15
|
+
*
|
|
16
|
+
* // With fallback for no match
|
|
17
|
+
* const outlet = RouterOutlet({ fallback: () => document.createTextNode('Not Found') });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function RouterOutlet(config = {}) {
|
|
21
|
+
const { fallback } = config;
|
|
22
|
+
// Get router from context
|
|
23
|
+
let router;
|
|
24
|
+
try {
|
|
25
|
+
router = use('router');
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new Error('RouterOutlet requires a router in context. Make sure to use createApp with a router.');
|
|
29
|
+
}
|
|
30
|
+
// Get current outlet depth (default 0 for top-level)
|
|
31
|
+
let depth;
|
|
32
|
+
try {
|
|
33
|
+
depth = use('router:outlet-depth') ?? 0;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
depth = 0;
|
|
37
|
+
}
|
|
38
|
+
// Create a container for the outlet
|
|
39
|
+
const container = document.createDocumentFragment();
|
|
40
|
+
// Placeholder comment node for positioning
|
|
41
|
+
const placeholder = document.createComment(`router-outlet:${depth}`);
|
|
42
|
+
container.appendChild(placeholder);
|
|
43
|
+
// Track current mounted component/node
|
|
44
|
+
let currentInstance = null;
|
|
45
|
+
let currentNode = null;
|
|
46
|
+
let parentNode = null;
|
|
47
|
+
// Track current route to avoid remounting same component on child navigation
|
|
48
|
+
// We compare routes (not components) because compiled routes are stable references
|
|
49
|
+
let currentRoute = null;
|
|
50
|
+
// Cleanup function for effect
|
|
51
|
+
let cleanupEffect = null;
|
|
52
|
+
// Navigation ID for race condition handling
|
|
53
|
+
let navigationId = 0;
|
|
54
|
+
// Delay timer ID
|
|
55
|
+
let delayTimerId = null;
|
|
56
|
+
/**
|
|
57
|
+
* Clear delay timer if active
|
|
58
|
+
*/
|
|
59
|
+
function clearDelayTimer() {
|
|
60
|
+
if (delayTimerId !== null) {
|
|
61
|
+
clearTimeout(delayTimerId);
|
|
62
|
+
delayTimerId = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Unmount current content
|
|
67
|
+
* Note: Does NOT reset currentComponent - that's managed by renderComponent()
|
|
68
|
+
*/
|
|
69
|
+
function unmountCurrent() {
|
|
70
|
+
clearDelayTimer();
|
|
71
|
+
if (currentInstance) {
|
|
72
|
+
currentInstance.unmount();
|
|
73
|
+
currentInstance = null;
|
|
74
|
+
}
|
|
75
|
+
if (currentNode && currentNode.parentNode) {
|
|
76
|
+
currentNode.parentNode.removeChild(currentNode);
|
|
77
|
+
currentNode = null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Mount a node at the outlet position
|
|
82
|
+
*/
|
|
83
|
+
function mountNode(node) {
|
|
84
|
+
parentNode = placeholder.parentNode;
|
|
85
|
+
if (!parentNode)
|
|
86
|
+
return;
|
|
87
|
+
// Remove current node if any (without full unmount)
|
|
88
|
+
if (currentNode && currentNode.parentNode) {
|
|
89
|
+
currentNode.parentNode.removeChild(currentNode);
|
|
90
|
+
}
|
|
91
|
+
parentNode.insertBefore(node, placeholder.nextSibling);
|
|
92
|
+
currentNode = node;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Render a sync route component
|
|
96
|
+
*/
|
|
97
|
+
function renderSyncComponent(component, props) {
|
|
98
|
+
unmountCurrent();
|
|
99
|
+
parentNode = placeholder.parentNode;
|
|
100
|
+
if (!parentNode)
|
|
101
|
+
return;
|
|
102
|
+
// Check if it's a ComponentFactory
|
|
103
|
+
if (isComponentFactory(component)) {
|
|
104
|
+
pushContext({ 'router:outlet-depth': depth + 1 });
|
|
105
|
+
try {
|
|
106
|
+
currentInstance = component(props);
|
|
107
|
+
const tempContainer = document.createElement('div');
|
|
108
|
+
currentInstance.mount(tempContainer);
|
|
109
|
+
const mountedNode = tempContainer.firstChild;
|
|
110
|
+
if (mountedNode) {
|
|
111
|
+
parentNode.insertBefore(mountedNode, placeholder.nextSibling);
|
|
112
|
+
currentNode = mountedNode;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
popContext();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (typeof component === 'function') {
|
|
120
|
+
pushContext({ 'router:outlet-depth': depth + 1 });
|
|
121
|
+
try {
|
|
122
|
+
// Call with props - some components expect them
|
|
123
|
+
const result = component(props);
|
|
124
|
+
currentNode = result;
|
|
125
|
+
parentNode.insertBefore(currentNode, placeholder.nextSibling);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
popContext();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Render a route component (sync or lazy)
|
|
134
|
+
*/
|
|
135
|
+
function renderComponent(route, component, props) {
|
|
136
|
+
// Same route as currently rendered → don't remount
|
|
137
|
+
// This is critical for nested routes: when navigating /dashboard → /dashboard/users,
|
|
138
|
+
// the parent layout (depth 0) stays mounted, only the child outlet (depth 1) updates
|
|
139
|
+
// We compare routes (not components) because compiled routes are stable references
|
|
140
|
+
if (route === currentRoute) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
currentRoute = route;
|
|
144
|
+
// Increment navigation ID to invalidate any pending loads
|
|
145
|
+
// This must happen AFTER the route check, so same-route calls don't invalidate
|
|
146
|
+
navigationId++;
|
|
147
|
+
const thisNavigationId = navigationId;
|
|
148
|
+
// Check if it's a lazy component
|
|
149
|
+
if (isLazyComponent(component)) {
|
|
150
|
+
// Check if already loaded - use SYNCHRONOUS getLoaded() to avoid microtask race
|
|
151
|
+
const loadedComponent = component.getLoaded();
|
|
152
|
+
if (loadedComponent) {
|
|
153
|
+
// Already loaded - render SYNCHRONOUSLY (no .then(), no microtask)
|
|
154
|
+
renderSyncComponent(loadedComponent, props);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Not loaded yet - handle lazy loading with delay
|
|
158
|
+
handleLazyComponent(component, props, thisNavigationId);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Check if it's a ComponentFactory (from createComponent)
|
|
162
|
+
if (isComponentFactory(component)) {
|
|
163
|
+
renderSyncComponent(component, props);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// It's a plain function (either sync or lazy loader without our wrapper)
|
|
167
|
+
if (typeof component === 'function') {
|
|
168
|
+
pushContext({ 'router:outlet-depth': depth + 1 });
|
|
169
|
+
try {
|
|
170
|
+
// Call with props - component may expect them
|
|
171
|
+
const result = component(props);
|
|
172
|
+
if (result instanceof Promise) {
|
|
173
|
+
popContext();
|
|
174
|
+
// Plain lazy loader - handle without delay features
|
|
175
|
+
handlePlainLazyComponent(result, props, thisNavigationId);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
unmountCurrent();
|
|
179
|
+
parentNode = placeholder.parentNode;
|
|
180
|
+
if (parentNode) {
|
|
181
|
+
currentNode = result;
|
|
182
|
+
parentNode.insertBefore(currentNode, placeholder.nextSibling);
|
|
183
|
+
}
|
|
184
|
+
popContext();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
popContext();
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Handle lazy-loaded component with delay behavior
|
|
195
|
+
*/
|
|
196
|
+
function handleLazyComponent(lazyComponent, props, navId) {
|
|
197
|
+
const delay = getLazyDelay(lazyComponent);
|
|
198
|
+
const loadingFn = getLazyLoading(lazyComponent);
|
|
199
|
+
const errorFn = getLazyError(lazyComponent);
|
|
200
|
+
// Set up delay timer for showing loading state
|
|
201
|
+
if (delay > 0 && loadingFn) {
|
|
202
|
+
clearDelayTimer();
|
|
203
|
+
delayTimerId = setTimeout(() => {
|
|
204
|
+
if (navigationId !== navId)
|
|
205
|
+
return; // Stale navigation
|
|
206
|
+
// Show loading state after delay
|
|
207
|
+
const loadingNode = loadingFn();
|
|
208
|
+
mountNode(loadingNode);
|
|
209
|
+
}, delay);
|
|
210
|
+
}
|
|
211
|
+
else if (delay === 0 && loadingFn) {
|
|
212
|
+
// Show loading immediately (delay = 0)
|
|
213
|
+
unmountCurrent();
|
|
214
|
+
parentNode = placeholder.parentNode;
|
|
215
|
+
if (parentNode) {
|
|
216
|
+
const loadingNode = loadingFn();
|
|
217
|
+
parentNode.insertBefore(loadingNode, placeholder.nextSibling);
|
|
218
|
+
currentNode = loadingNode;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Start loading the component
|
|
222
|
+
lazyComponent().then(module => {
|
|
223
|
+
clearDelayTimer();
|
|
224
|
+
if (navigationId !== navId)
|
|
225
|
+
return; // Stale navigation
|
|
226
|
+
const loadedComponent = 'default' in module ? module.default : module;
|
|
227
|
+
renderSyncComponent(loadedComponent, props);
|
|
228
|
+
}).catch((error) => {
|
|
229
|
+
clearDelayTimer();
|
|
230
|
+
if (navigationId !== navId)
|
|
231
|
+
return; // Stale navigation
|
|
232
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
233
|
+
console.error('Failed to load lazy component:', err);
|
|
234
|
+
if (errorFn) {
|
|
235
|
+
// Show error state with retry
|
|
236
|
+
const retry = () => {
|
|
237
|
+
lazyComponent.reset();
|
|
238
|
+
handleLazyComponent(lazyComponent, props, navigationId);
|
|
239
|
+
};
|
|
240
|
+
unmountCurrent();
|
|
241
|
+
parentNode = placeholder.parentNode;
|
|
242
|
+
if (parentNode) {
|
|
243
|
+
const errorNode = errorFn(err, retry);
|
|
244
|
+
parentNode.insertBefore(errorNode, placeholder.nextSibling);
|
|
245
|
+
currentNode = errorNode;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Handle plain lazy component (without our wrapper)
|
|
252
|
+
*/
|
|
253
|
+
async function handlePlainLazyComponent(promise, props, navId) {
|
|
254
|
+
try {
|
|
255
|
+
const module = await promise;
|
|
256
|
+
if (navigationId !== navId)
|
|
257
|
+
return; // Stale navigation
|
|
258
|
+
const component = 'default' in module ? module.default : module;
|
|
259
|
+
renderSyncComponent(component, props);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (navigationId !== navId)
|
|
263
|
+
return; // Stale navigation
|
|
264
|
+
console.error('Failed to load lazy component:', error);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Render fallback content
|
|
269
|
+
*/
|
|
270
|
+
function renderFallback() {
|
|
271
|
+
unmountCurrent();
|
|
272
|
+
if (fallback) {
|
|
273
|
+
parentNode = placeholder.parentNode;
|
|
274
|
+
if (parentNode) {
|
|
275
|
+
currentNode = fallback();
|
|
276
|
+
parentNode.insertBefore(currentNode, placeholder.nextSibling);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Set up effect to watch route changes
|
|
281
|
+
// We need to defer this until the placeholder is in the DOM
|
|
282
|
+
const originalPlaceholder = placeholder;
|
|
283
|
+
// Use MutationObserver to detect when we're added to DOM
|
|
284
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
285
|
+
const observer = new MutationObserver(() => {
|
|
286
|
+
if (originalPlaceholder.parentNode) {
|
|
287
|
+
observer.disconnect();
|
|
288
|
+
setupRouteWatcher();
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
// Observe the document for changes
|
|
292
|
+
observer.observe(document, { childList: true, subtree: true });
|
|
293
|
+
// Also check immediately in case we're already in DOM
|
|
294
|
+
if (originalPlaceholder.parentNode) {
|
|
295
|
+
observer.disconnect();
|
|
296
|
+
// Use setTimeout to ensure context is properly set up
|
|
297
|
+
setTimeout(setupRouteWatcher, 0);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// Fallback for environments without MutationObserver
|
|
302
|
+
setTimeout(setupRouteWatcher, 0);
|
|
303
|
+
}
|
|
304
|
+
function setupRouteWatcher() {
|
|
305
|
+
cleanupEffect = effect(() => {
|
|
306
|
+
const matched = router.matched();
|
|
307
|
+
const preloadedData = router.preloadedData();
|
|
308
|
+
const params = router.params();
|
|
309
|
+
const query = router.query();
|
|
310
|
+
// Get the match at our depth level
|
|
311
|
+
const matchAtDepth = matched[depth];
|
|
312
|
+
if (!matchAtDepth) {
|
|
313
|
+
// No match at this depth
|
|
314
|
+
renderFallback();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const { route } = matchAtDepth;
|
|
318
|
+
const component = route.component;
|
|
319
|
+
if (!component) {
|
|
320
|
+
// Route has no component (might be redirect-only)
|
|
321
|
+
renderFallback();
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
// Build props for the route component
|
|
325
|
+
const componentProps = {
|
|
326
|
+
params,
|
|
327
|
+
query,
|
|
328
|
+
preloaded: preloadedData,
|
|
329
|
+
};
|
|
330
|
+
renderComponent(route, component, componentProps);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
// Return a node that cleans up when removed
|
|
334
|
+
// We wrap the placeholder in a custom behavior
|
|
335
|
+
const result = placeholder;
|
|
336
|
+
// Store cleanup function on the node for later access
|
|
337
|
+
result.__cleanup = () => {
|
|
338
|
+
if (cleanupEffect) {
|
|
339
|
+
cleanupEffect();
|
|
340
|
+
cleanupEffect = null;
|
|
341
|
+
}
|
|
342
|
+
unmountCurrent();
|
|
343
|
+
};
|
|
344
|
+
return result;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Link creates an anchor element with client-side navigation.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* ```ts
|
|
351
|
+
* // Basic link
|
|
352
|
+
* const link = Link({ href: '/about', children: 'About Us' });
|
|
353
|
+
*
|
|
354
|
+
* // With active class
|
|
355
|
+
* const navLink = Link({
|
|
356
|
+
* href: '/users',
|
|
357
|
+
* children: 'Users',
|
|
358
|
+
* activeClass: 'nav-active',
|
|
359
|
+
* exactActiveClass: 'nav-exact',
|
|
360
|
+
* });
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
export function Link(config) {
|
|
364
|
+
const { href, children, activeClass = 'active', exactActiveClass = 'exact-active', exact = false, class: className, replace = false, target, attrs = {}, preload, } = config;
|
|
365
|
+
// Get router from context
|
|
366
|
+
let router;
|
|
367
|
+
try {
|
|
368
|
+
router = use('router');
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
throw new Error('Link requires a router in context. Make sure to use createApp with a router.');
|
|
372
|
+
}
|
|
373
|
+
// Create anchor element
|
|
374
|
+
const anchor = document.createElement('a');
|
|
375
|
+
anchor.href = href;
|
|
376
|
+
// Set children
|
|
377
|
+
if (typeof children === 'string') {
|
|
378
|
+
anchor.textContent = children;
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
anchor.appendChild(children);
|
|
382
|
+
}
|
|
383
|
+
// Set static class
|
|
384
|
+
if (className) {
|
|
385
|
+
anchor.className = className;
|
|
386
|
+
}
|
|
387
|
+
// Set target
|
|
388
|
+
if (target) {
|
|
389
|
+
anchor.target = target;
|
|
390
|
+
}
|
|
391
|
+
// Set additional attributes
|
|
392
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
393
|
+
anchor.setAttribute(key, value);
|
|
394
|
+
}
|
|
395
|
+
// Track if preload has been triggered (only do it once)
|
|
396
|
+
let preloadTriggered = false;
|
|
397
|
+
// Handle preload on hover
|
|
398
|
+
if (preload) {
|
|
399
|
+
anchor.addEventListener('mouseenter', () => {
|
|
400
|
+
if (preloadTriggered)
|
|
401
|
+
return;
|
|
402
|
+
preloadTriggered = true;
|
|
403
|
+
// If preload is a LazyComponent, prefetch it directly
|
|
404
|
+
if (preload !== true && isLazyComponent(preload)) {
|
|
405
|
+
preload.prefetch();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
// If preload is true, try to find the route's lazy component
|
|
409
|
+
const resolved = router.resolve(href);
|
|
410
|
+
const routeComponent = resolved.route?.component;
|
|
411
|
+
if (routeComponent && isLazyComponent(routeComponent)) {
|
|
412
|
+
routeComponent.prefetch();
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
// Handle click for client-side navigation
|
|
417
|
+
anchor.addEventListener('click', (event) => {
|
|
418
|
+
// Don't handle if modifier keys are pressed (allow new tab)
|
|
419
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
// Don't handle if target is _blank
|
|
423
|
+
if (anchor.target === '_blank') {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
// Don't handle external links
|
|
427
|
+
if (anchor.origin !== window.location.origin) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
// Prevent default browser navigation
|
|
431
|
+
event.preventDefault();
|
|
432
|
+
// Navigate using router
|
|
433
|
+
if (replace) {
|
|
434
|
+
router.replace(href);
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
router.navigate(href);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
// Set up effect to manage active classes
|
|
441
|
+
const disposeEffect = effect(() => {
|
|
442
|
+
const currentPath = router.path();
|
|
443
|
+
// Check for exact match
|
|
444
|
+
const isExactActive = isPathActive(currentPath, href, true);
|
|
445
|
+
// Check for active match (exact if `exact` prop is true, otherwise prefix match)
|
|
446
|
+
const isActive = exact
|
|
447
|
+
? isExactActive
|
|
448
|
+
: isPathActive(currentPath, href, false);
|
|
449
|
+
// Manage exact active class
|
|
450
|
+
if (isExactActive) {
|
|
451
|
+
anchor.classList.add(exactActiveClass);
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
anchor.classList.remove(exactActiveClass);
|
|
455
|
+
}
|
|
456
|
+
// Manage active class
|
|
457
|
+
if (isActive) {
|
|
458
|
+
anchor.classList.add(activeClass);
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
anchor.classList.remove(activeClass);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
// Store cleanup function on the element
|
|
465
|
+
anchor.__cleanup = disposeEffect;
|
|
466
|
+
return anchor;
|
|
467
|
+
}
|
|
468
|
+
// =============================================================================
|
|
469
|
+
// NavLink (Convenience Alias)
|
|
470
|
+
// =============================================================================
|
|
471
|
+
/**
|
|
472
|
+
* NavLink is an alias for Link with navigation-focused defaults.
|
|
473
|
+
*/
|
|
474
|
+
export const NavLink = Link;
|
|
475
|
+
//# sourceMappingURL=components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.js","sourceRoot":"","sources":["../src/components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGtF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAexF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,YAAY,CAAC,SAA6B,EAAE;IAC1D,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAE5B,0BAA0B;IAC1B,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAS,QAAQ,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sFAAsF,CAAC,CAAC;IAC1G,CAAC;IAED,qDAAqD;IACrD,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,GAAG,CAAS,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC;IAED,oCAAoC;IACpC,MAAM,SAAS,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;IAEpD,2CAA2C;IAC3C,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,iBAAiB,KAAK,EAAE,CAAC,CAAC;IACrE,SAAS,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IAEnC,uCAAuC;IACvC,IAAI,eAAe,GAA6B,IAAI,CAAC;IACrD,IAAI,WAAW,GAAgB,IAAI,CAAC;IACpC,IAAI,UAAU,GAAgB,IAAI,CAAC;IAEnC,6EAA6E;IAC7E,mFAAmF;IACnF,IAAI,YAAY,GAAyB,IAAI,CAAC;IAE9C,8BAA8B;IAC9B,IAAI,aAAa,GAAwB,IAAI,CAAC;IAE9C,4CAA4C;IAC5C,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,iBAAiB;IACjB,IAAI,YAAY,GAAyC,IAAI,CAAC;IAE9D;;OAEG;IACH,SAAS,eAAe;QACtB,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YAC1B,YAAY,CAAC,YAAY,CAAC,CAAC;YAC3B,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,SAAS,cAAc;QACrB,eAAe,EAAE,CAAC;QAClB,IAAI,eAAe,EAAE,CAAC;YACpB,eAAe,CAAC,OAAO,EAAE,CAAC;YAC1B,eAAe,GAAG,IAAI,CAAC;QACzB,CAAC;QACD,IAAI,WAAW,IAAI,WAAW,CAAC,UAAU,EAAE,CAAC;YAC1C,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;YAChD,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS,SAAS,CAAC,IAAU;QAC3B,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,oDAAoD;QACpD,IAAI,WAAW,IAAI,WAAW,CAAC,UAAU,EAAE,CAAC;YAC1C,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAClD,CAAC;QAED,UAAU,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;QACvD,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,SAAS,mBAAmB,CAC1B,SAAyB,EACzB,KAA8B;QAE9B,cAAc,EAAE,CAAC;QACjB,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,mCAAmC;QACnC,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,WAAW,CAAC,EAAE,qBAAqB,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;YAElD,IAAI,CAAC;gBACH,eAAe,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;gBACnC,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBACpD,eAAe,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;gBAErC,MAAM,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC;gBAC7C,IAAI,WAAW,EAAE,CAAC;oBAChB,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;oBAC9D,WAAW,GAAG,WAAW,CAAC;gBAC5B,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,UAAU,EAAE,CAAC;YACf,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;YAC3C,WAAW,CAAC,EAAE,qBAAqB,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;YAElD,IAAI,CAAC;gBACH,gDAAgD;gBAChD,MAAM,MAAM,GAAI,SAAkD,CAAC,KAAK,CAAC,CAAC;gBAC1E,WAAW,GAAG,MAAM,CAAC;gBACrB,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;YAChE,CAAC;oBAAS,CAAC;gBACT,UAAU,EAAE,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS,eAAe,CACtB,KAAoB,EACpB,SAAyC,EACzC,KAA8B;QAE9B,mDAAmD;QACnD,qFAAqF;QACrF,qFAAqF;QACrF,mFAAmF;QACnF,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QACD,YAAY,GAAG,KAAK,CAAC;QAErB,0DAA0D;QAC1D,+EAA+E;QAC/E,YAAY,EAAE,CAAC;QACf,MAAM,gBAAgB,GAAG,YAAY,CAAC;QAEtC,iCAAiC;QACjC,IAAI,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,gFAAgF;YAChF,MAAM,eAAe,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;YAC9C,IAAI,eAAe,EAAE,CAAC;gBACpB,mEAAmE;gBACnE,mBAAmB,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YAED,kDAAkD;YAClD,mBAAmB,CAAC,SAAS,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QAED,0DAA0D;QAC1D,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,yEAAyE;QACzE,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;YACpC,WAAW,CAAC,EAAE,qBAAqB,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;YAElD,IAAI,CAAC;gBACH,8CAA8C;gBAC9C,MAAM,MAAM,GAAI,SAA0G,CAAC,KAAK,CAAC,CAAC;gBAElI,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;oBAC9B,UAAU,EAAE,CAAC;oBACb,oDAAoD;oBACpD,wBAAwB,CAAC,MAAM,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;gBAC5D,CAAC;qBAAM,CAAC;oBACN,cAAc,EAAE,CAAC;oBACjB,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;oBACpC,IAAI,UAAU,EAAE,CAAC;wBACf,WAAW,GAAG,MAAM,CAAC;wBACrB,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;oBAChE,CAAC;oBACD,UAAU,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,UAAU,EAAE,CAAC;gBACb,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS,mBAAmB,CAC1B,aAAuC,EACvC,KAA8B,EAC9B,KAAa;QAEb,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;QAE5C,+CAA+C;QAC/C,IAAI,KAAK,GAAG,CAAC,IAAI,SAAS,EAAE,CAAC;YAC3B,eAAe,EAAE,CAAC;YAClB,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC7B,IAAI,YAAY,KAAK,KAAK;oBAAE,OAAO,CAAC,mBAAmB;gBAEvD,iCAAiC;gBACjC,MAAM,WAAW,GAAG,SAAS,EAAE,CAAC;gBAChC,SAAS,CAAC,WAAW,CAAC,CAAC;YACzB,CAAC,EAAE,KAAK,CAAC,CAAC;QACZ,CAAC;aAAM,IAAI,KAAK,KAAK,CAAC,IAAI,SAAS,EAAE,CAAC;YACpC,uCAAuC;YACvC,cAAc,EAAE,CAAC;YACjB,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;YACpC,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,WAAW,GAAG,SAAS,EAAE,CAAC;gBAChC,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;gBAC9D,WAAW,GAAG,WAAW,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,8BAA8B;QAC9B,aAAa,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YAC5B,eAAe,EAAE,CAAC;YAElB,IAAI,YAAY,KAAK,KAAK;gBAAE,OAAO,CAAC,mBAAmB;YAEvD,MAAM,eAAe,GAAG,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;YACtE,mBAAmB,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YAC1B,eAAe,EAAE,CAAC;YAElB,IAAI,YAAY,KAAK,KAAK;gBAAE,OAAO,CAAC,mBAAmB;YAEvD,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACtE,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;YAErD,IAAI,OAAO,EAAE,CAAC;gBACZ,8BAA8B;gBAC9B,MAAM,KAAK,GAAG,GAAG,EAAE;oBACjB,aAAa,CAAC,KAAK,EAAE,CAAC;oBACtB,mBAAmB,CAAC,aAAa,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;gBAC1D,CAAC,CAAC;gBAEF,cAAc,EAAE,CAAC;gBACjB,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;gBACpC,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;oBACtC,UAAU,CAAC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;oBAC5D,WAAW,GAAG,SAAS,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,UAAU,wBAAwB,CACrC,OAA8D,EAC9D,KAA8B,EAC9B,KAAa;QAEb,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;YAE7B,IAAI,YAAY,KAAK,KAAK;gBAAE,OAAO,CAAC,mBAAmB;YAEvD,MAAM,SAAS,GAAG,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;YAChE,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,YAAY,KAAK,KAAK;gBAAE,OAAO,CAAC,mBAAmB;YACvD,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS,cAAc;QACrB,cAAc,EAAE,CAAC;QAEjB,IAAI,QAAQ,EAAE,CAAC;YACb,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;YACpC,IAAI,UAAU,EAAE,CAAC;gBACf,WAAW,GAAG,QAAQ,EAAE,CAAC;gBACzB,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,4DAA4D;IAC5D,MAAM,mBAAmB,GAAG,WAAW,CAAC;IAExC,yDAAyD;IACzD,IAAI,OAAO,gBAAgB,KAAK,WAAW,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE;YACzC,IAAI,mBAAmB,CAAC,UAAU,EAAE,CAAC;gBACnC,QAAQ,CAAC,UAAU,EAAE,CAAC;gBACtB,iBAAiB,EAAE,CAAC;YACtB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,mCAAmC;QACnC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/D,sDAAsD;QACtD,IAAI,mBAAmB,CAAC,UAAU,EAAE,CAAC;YACnC,QAAQ,CAAC,UAAU,EAAE,CAAC;YACtB,sDAAsD;YACtD,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;SAAM,CAAC;QACN,qDAAqD;QACrD,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,SAAS,iBAAiB;QACxB,aAAa,GAAG,MAAM,CAAC,GAAG,EAAE;YAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;YAE7B,mCAAmC;YACnC,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAEpC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,yBAAyB;gBACzB,cAAc,EAAE,CAAC;gBACjB,OAAO;YACT,CAAC;YAED,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC;YAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;YAElC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,kDAAkD;gBAClD,cAAc,EAAE,CAAC;gBACjB,OAAO;YACT,CAAC;YAED,sCAAsC;YACtC,MAAM,cAAc,GAAG;gBACrB,MAAM;gBACN,KAAK;gBACL,SAAS,EAAE,aAAa;aACzB,CAAC;YAEF,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,4CAA4C;IAC5C,+CAA+C;IAC/C,MAAM,MAAM,GAAG,WAAW,CAAC;IAE3B,sDAAsD;IACrD,MAA4C,CAAC,SAAS,GAAG,GAAG,EAAE;QAC7D,IAAI,aAAa,EAAE,CAAC;YAClB,aAAa,EAAE,CAAC;YAChB,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;QACD,cAAc,EAAE,CAAC;IACnB,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAmCD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,IAAI,CAAC,MAAkB;IACrC,MAAM,EACJ,IAAI,EACJ,QAAQ,EACR,WAAW,GAAG,QAAQ,EACtB,gBAAgB,GAAG,cAAc,EACjC,KAAK,GAAG,KAAK,EACb,KAAK,EAAE,SAAS,EAChB,OAAO,GAAG,KAAK,EACf,MAAM,EACN,KAAK,GAAG,EAAE,EACV,OAAO,GACR,GAAG,MAAM,CAAC;IAEX,0BAA0B;IAC1B,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAS,QAAQ,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAClG,CAAC;IAED,wBAAwB;IACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;IAEnB,eAAe;IACf,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED,mBAAmB;IACnB,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;IAED,aAAa;IACb,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED,4BAA4B;IAC5B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,wDAAwD;IACxD,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,0BAA0B;IAC1B,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,GAAG,EAAE;YACzC,IAAI,gBAAgB;gBAAE,OAAO;YAC7B,gBAAgB,GAAG,IAAI,CAAC;YAExB,sDAAsD;YACtD,IAAI,OAAO,KAAK,IAAI,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjD,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,6DAA6D;YAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,cAAc,GAAG,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;YAEjD,IAAI,cAAc,IAAI,eAAe,CAAC,cAAc,CAAC,EAAE,CAAC;gBACtD,cAAc,CAAC,QAAQ,EAAE,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,0CAA0C;IAC1C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAiB,EAAE,EAAE;QACrD,4DAA4D;QAC5D,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACrE,OAAO;QACT,CAAC;QAED,mCAAmC;QACnC,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,8BAA8B;QAC9B,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,qCAAqC;QACrC,KAAK,CAAC,cAAc,EAAE,CAAC;QAEvB,wBAAwB;QACxB,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,EAAE;QAChC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAElC,wBAAwB;QACxB,MAAM,aAAa,GAAG,YAAY,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAE5D,iFAAiF;QACjF,MAAM,QAAQ,GAAG,KAAK;YACpB,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAE3C,4BAA4B;QAC5B,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC5C,CAAC;QAED,sBAAsB;QACtB,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,wCAAwC;IACvC,MAAyD,CAAC,SAAS,GAAG,aAAa,CAAC;IAErF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gFAAgF;AAChF,8BAA8B;AAC9B,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC"}
|
package/dist/guards.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { RouteGuard, GuardFunction, GuardContext, GuardResult, CompiledRoute, NavigationTarget } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Define a named route guard
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const authGuard = defineGuard('auth', ({ to, from, use }) => {
|
|
8
|
+
* const auth = use('auth');
|
|
9
|
+
* if (!auth.isAuthenticated()) {
|
|
10
|
+
* return `/login?redirect=${encodeURIComponent(to.path)}`;
|
|
11
|
+
* }
|
|
12
|
+
* return true;
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* // Parameterized guard
|
|
16
|
+
* const roleGuard = defineGuard('role', ({ use, param }) => {
|
|
17
|
+
* return use('auth').hasRole(param) || '/unauthorized';
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function defineGuard(name: string, handler: GuardFunction): RouteGuard;
|
|
22
|
+
/**
|
|
23
|
+
* Guard registry for managing named guards
|
|
24
|
+
*/
|
|
25
|
+
export declare class GuardRegistry {
|
|
26
|
+
private guards;
|
|
27
|
+
/**
|
|
28
|
+
* Register a guard
|
|
29
|
+
*/
|
|
30
|
+
register(guard: RouteGuard): void;
|
|
31
|
+
/**
|
|
32
|
+
* Register multiple guards
|
|
33
|
+
*/
|
|
34
|
+
registerAll(guards: RouteGuard[]): void;
|
|
35
|
+
/**
|
|
36
|
+
* Get a guard by name
|
|
37
|
+
*/
|
|
38
|
+
get(name: string): RouteGuard | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a guard exists
|
|
41
|
+
*/
|
|
42
|
+
has(name: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Unregister a guard
|
|
45
|
+
*/
|
|
46
|
+
unregister(name: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Get all guard names
|
|
49
|
+
*/
|
|
50
|
+
names(): string[];
|
|
51
|
+
/**
|
|
52
|
+
* Clear all guards
|
|
53
|
+
*/
|
|
54
|
+
clear(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Get the internal map (for route compilation)
|
|
57
|
+
*/
|
|
58
|
+
getMap(): Map<string, RouteGuard>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Normalize guard result to a consistent format
|
|
62
|
+
*/
|
|
63
|
+
export declare function normalizeGuardResult(result: GuardResult): {
|
|
64
|
+
allowed: boolean;
|
|
65
|
+
redirect?: NavigationTarget;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Run all guards for a route match
|
|
69
|
+
* Guards are run in order; first failing guard stops execution
|
|
70
|
+
*/
|
|
71
|
+
export declare function runGuards(guards: RouteGuard[], context: Omit<GuardContext, 'param'>): Promise<{
|
|
72
|
+
allowed: boolean;
|
|
73
|
+
redirect?: NavigationTarget;
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Resolve guards from guard specification using the registry
|
|
77
|
+
* This is called at navigation time to support dynamic guard registration
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveGuardsFromSpec(guardSpec: CompiledRoute['guardSpec'], registry: GuardRegistry): RouteGuard[];
|
|
80
|
+
/**
|
|
81
|
+
* Collect all guards for a matched route chain
|
|
82
|
+
* (including parent route guards for nested routes)
|
|
83
|
+
* Resolves string guards from the registry at runtime
|
|
84
|
+
*/
|
|
85
|
+
export declare function collectRouteGuards(route: CompiledRoute, registry?: GuardRegistry): RouteGuard[];
|
|
86
|
+
/**
|
|
87
|
+
* Create a simple authentication guard
|
|
88
|
+
*/
|
|
89
|
+
export declare function createAuthGuard(isAuthenticated: () => boolean, loginPath?: string): RouteGuard;
|
|
90
|
+
/**
|
|
91
|
+
* Create a role-based guard
|
|
92
|
+
* Usage: guard: 'role:admin' or guard: 'role:editor'
|
|
93
|
+
*/
|
|
94
|
+
export declare function createRoleGuard(hasRole: (role: string) => boolean, unauthorizedPath?: string): RouteGuard;
|
|
95
|
+
/**
|
|
96
|
+
* Create a confirmation guard that can be used for unsaved changes
|
|
97
|
+
*/
|
|
98
|
+
export declare function createConfirmGuard(shouldConfirm: () => boolean, message?: string): RouteGuard;
|
|
99
|
+
/**
|
|
100
|
+
* Create a guest-only guard (redirects authenticated users)
|
|
101
|
+
*/
|
|
102
|
+
export declare function createGuestGuard(isAuthenticated: () => boolean, homePath?: string): RouteGuard;
|
|
103
|
+
//# sourceMappingURL=guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,YAAY,EACZ,WAAW,EACX,aAAa,EACb,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAMpB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,UAAU,CAE5E;AAMD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAiC;IAE/C;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAOjC;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI;IAMvC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIzC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;OAEG;IACH,KAAK,IAAI,MAAM,EAAE;IAIjB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;CAGlC;AAmCD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,GAClB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAWnD;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,GACnC,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAC,CAS5D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,EACrC,QAAQ,EAAE,aAAa,GACtB,UAAU,EAAE,CAiCd;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,UAAU,EAAE,CAgC/F;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,OAAO,EAC9B,SAAS,GAAE,MAAiB,GAC3B,UAAU,CASZ;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,EAClC,gBAAgB,GAAE,MAAwB,GACzC,UAAU,CAQZ;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,OAAO,EAC5B,OAAO,GAAE,MAAoE,GAC5E,UAAU,CAYZ;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,OAAO,EAC9B,QAAQ,GAAE,MAAY,GACrB,UAAU,CAOZ"}
|