@pithyjs/router 0.1.0-beta.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 +621 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/router/core/config.d.ts +22 -0
- package/dist/router/core/config.d.ts.map +1 -0
- package/dist/router/core/config.js +54 -0
- package/dist/router/core/config.js.map +1 -0
- package/dist/router/core/constants.d.ts +89 -0
- package/dist/router/core/constants.d.ts.map +1 -0
- package/dist/router/core/constants.js +95 -0
- package/dist/router/core/constants.js.map +1 -0
- package/dist/router/core/history.d.ts +54 -0
- package/dist/router/core/history.d.ts.map +1 -0
- package/dist/router/core/history.js +89 -0
- package/dist/router/core/history.js.map +1 -0
- package/dist/router/core/matcher.d.ts +43 -0
- package/dist/router/core/matcher.d.ts.map +1 -0
- package/dist/router/core/matcher.js +242 -0
- package/dist/router/core/matcher.js.map +1 -0
- package/dist/router/core/params.d.ts +88 -0
- package/dist/router/core/params.d.ts.map +1 -0
- package/dist/router/core/params.js +150 -0
- package/dist/router/core/params.js.map +1 -0
- package/dist/router/core/pipeline.d.ts +90 -0
- package/dist/router/core/pipeline.d.ts.map +1 -0
- package/dist/router/core/pipeline.js +323 -0
- package/dist/router/core/pipeline.js.map +1 -0
- package/dist/router/core/route-tree.d.ts +76 -0
- package/dist/router/core/route-tree.d.ts.map +1 -0
- package/dist/router/core/route-tree.js +143 -0
- package/dist/router/core/route-tree.js.map +1 -0
- package/dist/router/core/router.d.ts +229 -0
- package/dist/router/core/router.d.ts.map +1 -0
- package/dist/router/core/router.js +762 -0
- package/dist/router/core/router.js.map +1 -0
- package/dist/router/core/types.d.ts +387 -0
- package/dist/router/core/types.d.ts.map +1 -0
- package/dist/router/core/types.js +22 -0
- package/dist/router/core/types.js.map +1 -0
- package/dist/router/core/utils.d.ts +66 -0
- package/dist/router/core/utils.d.ts.map +1 -0
- package/dist/router/core/utils.js +152 -0
- package/dist/router/core/utils.js.map +1 -0
- package/dist/router/features/coordinator.d.ts +75 -0
- package/dist/router/features/coordinator.d.ts.map +1 -0
- package/dist/router/features/coordinator.js +203 -0
- package/dist/router/features/coordinator.js.map +1 -0
- package/dist/router/features/errors/error-codes.d.ts +107 -0
- package/dist/router/features/errors/error-codes.d.ts.map +1 -0
- package/dist/router/features/errors/error-codes.js +247 -0
- package/dist/router/features/errors/error-codes.js.map +1 -0
- package/dist/router/features/errors/error-resolution.d.ts +31 -0
- package/dist/router/features/errors/error-resolution.d.ts.map +1 -0
- package/dist/router/features/errors/error-resolution.js +47 -0
- package/dist/router/features/errors/error-resolution.js.map +1 -0
- package/dist/router/features/errors/error-types.d.ts +60 -0
- package/dist/router/features/errors/error-types.d.ts.map +1 -0
- package/dist/router/features/errors/error-types.js +57 -0
- package/dist/router/features/errors/error-types.js.map +1 -0
- package/dist/router/features/errors/global-error-fallback.d.ts +33 -0
- package/dist/router/features/errors/global-error-fallback.d.ts.map +1 -0
- package/dist/router/features/errors/global-error-fallback.js +182 -0
- package/dist/router/features/errors/global-error-fallback.js.map +1 -0
- package/dist/router/features/errors/index.d.ts +15 -0
- package/dist/router/features/errors/index.d.ts.map +1 -0
- package/dist/router/features/errors/index.js +18 -0
- package/dist/router/features/errors/index.js.map +1 -0
- package/dist/router/features/errors/router-errors.d.ts +44 -0
- package/dist/router/features/errors/router-errors.d.ts.map +1 -0
- package/dist/router/features/errors/router-errors.js +53 -0
- package/dist/router/features/errors/router-errors.js.map +1 -0
- package/dist/router/features/guards/engine.d.ts +40 -0
- package/dist/router/features/guards/engine.d.ts.map +1 -0
- package/dist/router/features/guards/engine.js +67 -0
- package/dist/router/features/guards/engine.js.map +1 -0
- package/dist/router/features/guards/index.d.ts +52 -0
- package/dist/router/features/guards/index.d.ts.map +1 -0
- package/dist/router/features/guards/index.js +95 -0
- package/dist/router/features/guards/index.js.map +1 -0
- package/dist/router/features/loaders/cache.d.ts +60 -0
- package/dist/router/features/loaders/cache.d.ts.map +1 -0
- package/dist/router/features/loaders/cache.js +80 -0
- package/dist/router/features/loaders/cache.js.map +1 -0
- package/dist/router/features/loaders/engine.d.ts +17 -0
- package/dist/router/features/loaders/engine.d.ts.map +1 -0
- package/dist/router/features/loaders/engine.js +27 -0
- package/dist/router/features/loaders/engine.js.map +1 -0
- package/dist/router/features/loaders/index.d.ts +49 -0
- package/dist/router/features/loaders/index.d.ts.map +1 -0
- package/dist/router/features/loaders/index.js +112 -0
- package/dist/router/features/loaders/index.js.map +1 -0
- package/dist/router/features/loading-ui-manager.d.ts +69 -0
- package/dist/router/features/loading-ui-manager.d.ts.map +1 -0
- package/dist/router/features/loading-ui-manager.js +209 -0
- package/dist/router/features/loading-ui-manager.js.map +1 -0
- package/dist/router/features/module-loader.d.ts +50 -0
- package/dist/router/features/module-loader.d.ts.map +1 -0
- package/dist/router/features/module-loader.js +121 -0
- package/dist/router/features/module-loader.js.map +1 -0
- package/dist/router/features/outlet/errors.d.ts +24 -0
- package/dist/router/features/outlet/errors.d.ts.map +1 -0
- package/dist/router/features/outlet/errors.js +96 -0
- package/dist/router/features/outlet/errors.js.map +1 -0
- package/dist/router/features/outlet/index.d.ts +45 -0
- package/dist/router/features/outlet/index.d.ts.map +1 -0
- package/dist/router/features/outlet/index.js +95 -0
- package/dist/router/features/outlet/index.js.map +1 -0
- package/dist/router/features/outlet/mount.d.ts +38 -0
- package/dist/router/features/outlet/mount.d.ts.map +1 -0
- package/dist/router/features/outlet/mount.js +301 -0
- package/dist/router/features/outlet/mount.js.map +1 -0
- package/dist/router/features/outlet/segment-chain.d.ts +16 -0
- package/dist/router/features/outlet/segment-chain.d.ts.map +1 -0
- package/dist/router/features/outlet/segment-chain.js +62 -0
- package/dist/router/features/outlet/segment-chain.js.map +1 -0
- package/dist/router/features/prefetch/index.d.ts +97 -0
- package/dist/router/features/prefetch/index.d.ts.map +1 -0
- package/dist/router/features/prefetch/index.js +345 -0
- package/dist/router/features/prefetch/index.js.map +1 -0
- package/dist/router/features/ux/focus.d.ts +62 -0
- package/dist/router/features/ux/focus.d.ts.map +1 -0
- package/dist/router/features/ux/focus.js +136 -0
- package/dist/router/features/ux/focus.js.map +1 -0
- package/dist/router/features/ux/live-region.d.ts +81 -0
- package/dist/router/features/ux/live-region.d.ts.map +1 -0
- package/dist/router/features/ux/live-region.js +166 -0
- package/dist/router/features/ux/live-region.js.map +1 -0
- package/dist/router/features/ux/scroll-focus.d.ts +105 -0
- package/dist/router/features/ux/scroll-focus.d.ts.map +1 -0
- package/dist/router/features/ux/scroll-focus.js +111 -0
- package/dist/router/features/ux/scroll-focus.js.map +1 -0
- package/dist/router/features/ux/scroll.d.ts +71 -0
- package/dist/router/features/ux/scroll.d.ts.map +1 -0
- package/dist/router/features/ux/scroll.js +137 -0
- package/dist/router/features/ux/scroll.js.map +1 -0
- package/dist/router/features/ux/transitions.d.ts +120 -0
- package/dist/router/features/ux/transitions.d.ts.map +1 -0
- package/dist/router/features/ux/transitions.js +235 -0
- package/dist/router/features/ux/transitions.js.map +1 -0
- package/dist/router/integration/directive-binder.d.ts +20 -0
- package/dist/router/integration/directive-binder.d.ts.map +1 -0
- package/dist/router/integration/directive-binder.js +139 -0
- package/dist/router/integration/directive-binder.js.map +1 -0
- package/dist/router/integration/directives.d.ts +42 -0
- package/dist/router/integration/directives.d.ts.map +1 -0
- package/dist/router/integration/directives.js +109 -0
- package/dist/router/integration/directives.js.map +1 -0
- package/dist/router/integration/history-adapter.d.ts +76 -0
- package/dist/router/integration/history-adapter.d.ts.map +1 -0
- package/dist/router/integration/history-adapter.js +157 -0
- package/dist/router/integration/history-adapter.js.map +1 -0
- package/dist/router/integration/hmr.d.ts +83 -0
- package/dist/router/integration/hmr.d.ts.map +1 -0
- package/dist/router/integration/hmr.js +160 -0
- package/dist/router/integration/hmr.js.map +1 -0
- package/dist/router/integration/link-interceptor.d.ts +49 -0
- package/dist/router/integration/link-interceptor.d.ts.map +1 -0
- package/dist/router/integration/link-interceptor.js +94 -0
- package/dist/router/integration/link-interceptor.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.prefetch",
|
|
4
|
+
"title": "Enhanced Prefetch System with Intelligent Heuristics",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import { PREFETCH_DEFAULTS } from '../../core/constants';
|
|
9
|
+
import { DEFAULT_VISIBILITY_MARGIN, observeVisibilityOnce, } from '@pithyjs/shared';
|
|
10
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"PREFETCH_STRATEGIES","stability":"stable","signature":"readonly PrefetchStrategy[]","description":"Runtime list of valid PrefetchStrategy values for enum validation"} */
|
|
11
|
+
export const PREFETCH_STRATEGIES = [
|
|
12
|
+
'none',
|
|
13
|
+
'hover',
|
|
14
|
+
'visible',
|
|
15
|
+
'intent',
|
|
16
|
+
];
|
|
17
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"PrefetchManager","stability":"stable","signature":"class PrefetchManager","description":"Intelligent resource prefetching with enhanced heuristics"} */
|
|
18
|
+
/**
|
|
19
|
+
* Prefetch manager for intelligent resource prefetching
|
|
20
|
+
* Implements enhanced prefetch policy & cache layer from architectural improvements
|
|
21
|
+
*/
|
|
22
|
+
export class PrefetchManager {
|
|
23
|
+
constructor(config = {}) {
|
|
24
|
+
this.activeRequests = new Map();
|
|
25
|
+
this.hoverTimers = new Map();
|
|
26
|
+
this.intentTracking = new Map();
|
|
27
|
+
/** Track when each route was last prefetched with its TTL to avoid repeated prefetches */
|
|
28
|
+
this.prefetchedAt = new Map();
|
|
29
|
+
this.config = {
|
|
30
|
+
hoverDelay: config.hoverDelay ?? PREFETCH_DEFAULTS.HOVER_DELAY,
|
|
31
|
+
visibleMargin: config.visibleMargin ?? DEFAULT_VISIBILITY_MARGIN,
|
|
32
|
+
cacheTTL: config.cacheTTL ?? PREFETCH_DEFAULTS.CACHE_TTL,
|
|
33
|
+
intentVelocityThreshold: config.intentVelocityThreshold ??
|
|
34
|
+
PREFETCH_DEFAULTS.INTENT_VELOCITY_THRESHOLD,
|
|
35
|
+
intentDirectionSamples: config.intentDirectionSamples ??
|
|
36
|
+
PREFETCH_DEFAULTS.INTENT_DIRECTION_SAMPLES,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"registerLink","stability":"stable","signature":"(element: HTMLElement, strategy: PrefetchStrategy) => void","description":"Register a link element for prefetching with a given strategy"} */
|
|
40
|
+
/**
|
|
41
|
+
* Register a link for prefetching with specified strategy
|
|
42
|
+
*/
|
|
43
|
+
registerLink(element, strategy) {
|
|
44
|
+
const href = element.getAttribute('href');
|
|
45
|
+
if (!href || strategy === 'none') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
switch (strategy) {
|
|
49
|
+
case 'hover':
|
|
50
|
+
this.setupHoverPrefetch(element, href);
|
|
51
|
+
break;
|
|
52
|
+
case 'visible':
|
|
53
|
+
this.setupVisiblePrefetch(element);
|
|
54
|
+
break;
|
|
55
|
+
case 'intent':
|
|
56
|
+
this.setupIntentPrefetch(element, href);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"unregisterLink","stability":"stable","signature":"(element: HTMLElement) => void","description":"Unregister a link and clean up its prefetch listeners"} */
|
|
61
|
+
/**
|
|
62
|
+
* Unregister a link from prefetching
|
|
63
|
+
*/
|
|
64
|
+
unregisterLink(element) {
|
|
65
|
+
const href = element.getAttribute('href');
|
|
66
|
+
if (href) {
|
|
67
|
+
this.cancelPrefetch(href);
|
|
68
|
+
}
|
|
69
|
+
// Clean up hover timer
|
|
70
|
+
const timer = this.hoverTimers.get(element);
|
|
71
|
+
if (timer) {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
this.hoverTimers.delete(element);
|
|
74
|
+
}
|
|
75
|
+
// Clean up intent tracking
|
|
76
|
+
this.intentTracking.delete(element);
|
|
77
|
+
// Call element-specific cleanup (removes event listeners and visibility observer)
|
|
78
|
+
const target = element;
|
|
79
|
+
const cleanup = target.__prefetchCleanup;
|
|
80
|
+
if (cleanup) {
|
|
81
|
+
cleanup();
|
|
82
|
+
delete target.__prefetchCleanup;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Setup hover-based prefetching with intent delay
|
|
87
|
+
*/
|
|
88
|
+
setupHoverPrefetch(element, href) {
|
|
89
|
+
const handleMouseEnter = () => {
|
|
90
|
+
const timer = setTimeout(() => {
|
|
91
|
+
this.prefetchRoute(href, 'hover');
|
|
92
|
+
this.hoverTimers.delete(element);
|
|
93
|
+
}, this.config.hoverDelay);
|
|
94
|
+
this.hoverTimers.set(element, timer);
|
|
95
|
+
};
|
|
96
|
+
const handleMouseLeave = () => {
|
|
97
|
+
// Only clear the hover timer, but DON'T cancel in-flight prefetch requests
|
|
98
|
+
// This is important because mouseleave fires before click, so canceling
|
|
99
|
+
// would abort requests that navigation needs
|
|
100
|
+
const timer = this.hoverTimers.get(element);
|
|
101
|
+
if (timer) {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
this.hoverTimers.delete(element);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
element.addEventListener('mouseenter', handleMouseEnter);
|
|
107
|
+
element.addEventListener('mouseleave', handleMouseLeave);
|
|
108
|
+
// Store cleanup functions
|
|
109
|
+
element.__prefetchCleanup = () => {
|
|
110
|
+
element.removeEventListener('mouseenter', handleMouseEnter);
|
|
111
|
+
element.removeEventListener('mouseleave', handleMouseLeave);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Setup visibility-based prefetching using shared observer pool from @pithyjs/shared
|
|
116
|
+
*/
|
|
117
|
+
setupVisiblePrefetch(element) {
|
|
118
|
+
const href = element.getAttribute('href');
|
|
119
|
+
if (!href)
|
|
120
|
+
return;
|
|
121
|
+
// Use shared IntersectionObserver pool
|
|
122
|
+
const cleanup = observeVisibilityOnce(element, () => this.prefetchRoute(href, 'visible'), { rootMargin: this.config.visibleMargin });
|
|
123
|
+
// Store cleanup for unregisterLink
|
|
124
|
+
element.__prefetchCleanup = cleanup;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Setup intent-based prefetching with pointer tracking
|
|
128
|
+
*/
|
|
129
|
+
setupIntentPrefetch(element, href) {
|
|
130
|
+
const tracker = new PointerTracker(this.config.intentVelocityThreshold, this.config.intentDirectionSamples);
|
|
131
|
+
// Define proximity threshold (distance from link to start tracking)
|
|
132
|
+
const proximityThreshold = 200; // pixels
|
|
133
|
+
const handleMouseMove = (event) => {
|
|
134
|
+
const rect = element.getBoundingClientRect();
|
|
135
|
+
const centerX = rect.left + rect.width / 2;
|
|
136
|
+
const centerY = rect.top + rect.height / 2;
|
|
137
|
+
// Calculate distance from cursor to link center
|
|
138
|
+
const distanceToLink = Math.sqrt(Math.pow(event.clientX - centerX, 2) +
|
|
139
|
+
Math.pow(event.clientY - centerY, 2));
|
|
140
|
+
// Only track intent if cursor is within proximity threshold
|
|
141
|
+
if (distanceToLink > proximityThreshold) {
|
|
142
|
+
return; // Too far away, ignore
|
|
143
|
+
}
|
|
144
|
+
const isMovingToward = tracker.update(event.clientX, event.clientY, centerX, centerY);
|
|
145
|
+
if (isMovingToward) {
|
|
146
|
+
this.prefetchRoute(href, 'intent');
|
|
147
|
+
// Remove listener after successful prefetch to avoid repeated triggers
|
|
148
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
// Listen on document for global mouse movement
|
|
152
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
153
|
+
this.intentTracking.set(element, tracker);
|
|
154
|
+
// Store cleanup function
|
|
155
|
+
element.__prefetchCleanup = () => {
|
|
156
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"prefetchRoute","stability":"stable","signature":"(href: string, strategy: PrefetchStrategy) => Promise<void>","description":"Prefetch a route with priority handling and deduplication"} */
|
|
160
|
+
/**
|
|
161
|
+
* Prefetch a route with priority handling
|
|
162
|
+
*/
|
|
163
|
+
async prefetchRoute(href, _strategy) {
|
|
164
|
+
// Don't prefetch if already in progress
|
|
165
|
+
if (this.activeRequests.has(href)) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Don't prefetch if we're already on this route
|
|
169
|
+
const router = globalThis.router;
|
|
170
|
+
if (router) {
|
|
171
|
+
const currentPath = router.state?.()?.path || window.location.pathname;
|
|
172
|
+
const targetPath = new URL(href, window.location.origin).pathname;
|
|
173
|
+
if (currentPath === targetPath) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Don't prefetch if we've recently prefetched this route (within its cache TTL)
|
|
178
|
+
const lastPrefetch = this.prefetchedAt.get(href);
|
|
179
|
+
if (lastPrefetch &&
|
|
180
|
+
Date.now() - lastPrefetch.timestamp < lastPrefetch.ttl) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const controller = new AbortController();
|
|
185
|
+
this.activeRequests.set(href, controller);
|
|
186
|
+
// Prefetch module code and loader data in parallel for faster loading
|
|
187
|
+
await Promise.all([
|
|
188
|
+
this.prefetchModuleCode(href, controller.signal),
|
|
189
|
+
this.prefetchLoaderData(href, controller.signal),
|
|
190
|
+
]);
|
|
191
|
+
// Record successful prefetch time with route-specific TTL
|
|
192
|
+
if (!controller.signal.aborted) {
|
|
193
|
+
// Get route's cache TTL if available, otherwise use default
|
|
194
|
+
let ttl = this.config.cacheTTL;
|
|
195
|
+
const router = globalThis.router;
|
|
196
|
+
if (router?.getRouteCacheTTL) {
|
|
197
|
+
const routeTTL = await router.getRouteCacheTTL(href);
|
|
198
|
+
if (routeTTL !== undefined) {
|
|
199
|
+
ttl = routeTTL;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
this.prefetchedAt.set(href, { timestamp: Date.now(), ttl });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
if (error instanceof Error && error.name !== 'AbortError') {
|
|
207
|
+
console.warn('[Router] Prefetch failed:', error);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
this.activeRequests.delete(href);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"cancelPrefetch","stability":"stable","signature":"(href: string) => void","description":"Cancel an in-flight prefetch for a specific route"} */
|
|
215
|
+
/**
|
|
216
|
+
* Cancel prefetch for a specific route
|
|
217
|
+
*/
|
|
218
|
+
cancelPrefetch(href) {
|
|
219
|
+
const controller = this.activeRequests.get(href);
|
|
220
|
+
if (controller) {
|
|
221
|
+
controller.abort();
|
|
222
|
+
this.activeRequests.delete(href);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Prefetch module code (dynamic imports)
|
|
227
|
+
*/
|
|
228
|
+
async prefetchModuleCode(href, signal) {
|
|
229
|
+
if (signal.aborted)
|
|
230
|
+
return;
|
|
231
|
+
// Get the global router instance to access route manifest
|
|
232
|
+
const router = globalThis.router;
|
|
233
|
+
if (!router || !router.prefetchRoute) {
|
|
234
|
+
return; // No router or prefetch method available
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
await router.prefetchRoute(href, signal);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Silently fail - not critical
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Prefetch loader data
|
|
245
|
+
*/
|
|
246
|
+
async prefetchLoaderData(href, signal) {
|
|
247
|
+
if (signal.aborted)
|
|
248
|
+
return;
|
|
249
|
+
// Get the global router instance to access loader system
|
|
250
|
+
const router = globalThis.router;
|
|
251
|
+
if (!router || !router.prefetchLoader) {
|
|
252
|
+
return; // No router or prefetch loader method available
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
await router.prefetchLoader(href, signal);
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Silently fail - not critical
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"dispose","stability":"stable","signature":"() => void","description":"Clean up all prefetch resources, requests, and timers"} */
|
|
262
|
+
/**
|
|
263
|
+
* Cleanup all prefetch resources
|
|
264
|
+
*/
|
|
265
|
+
dispose() {
|
|
266
|
+
// Cancel all active requests
|
|
267
|
+
for (const controller of this.activeRequests.values()) {
|
|
268
|
+
controller.abort();
|
|
269
|
+
}
|
|
270
|
+
this.activeRequests.clear();
|
|
271
|
+
// Clear all timers
|
|
272
|
+
for (const timer of this.hoverTimers.values()) {
|
|
273
|
+
clearTimeout(timer);
|
|
274
|
+
}
|
|
275
|
+
this.hoverTimers.clear();
|
|
276
|
+
// Clear intent tracking
|
|
277
|
+
this.intentTracking.clear();
|
|
278
|
+
// Clear prefetch timestamps
|
|
279
|
+
this.prefetchedAt.clear();
|
|
280
|
+
// Note: Visibility observers are cleaned up via __prefetchCleanup when elements are unregistered
|
|
281
|
+
// The shared observer pool in @pithyjs/core handles its own lifecycle
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Pointer tracker for intent-based prefetching
|
|
286
|
+
*/
|
|
287
|
+
class PointerTracker {
|
|
288
|
+
constructor(velocityThreshold, sampleCount) {
|
|
289
|
+
this.positions = [];
|
|
290
|
+
this.velocityThreshold = velocityThreshold;
|
|
291
|
+
this.sampleCount = sampleCount;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Update pointer position and check if moving toward target
|
|
295
|
+
*/
|
|
296
|
+
update(x, y, targetX, targetY) {
|
|
297
|
+
const now = Date.now();
|
|
298
|
+
// Add current position
|
|
299
|
+
this.positions.push({ x, y, time: now });
|
|
300
|
+
// Keep only recent samples
|
|
301
|
+
if (this.positions.length > this.sampleCount) {
|
|
302
|
+
this.positions.shift();
|
|
303
|
+
}
|
|
304
|
+
// Need at least 2 positions to calculate velocity
|
|
305
|
+
if (this.positions.length < 2) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
// Calculate velocity and direction
|
|
309
|
+
const recent = this.positions[this.positions.length - 1];
|
|
310
|
+
const previous = this.positions[this.positions.length - 2];
|
|
311
|
+
if (!recent || !previous)
|
|
312
|
+
return false;
|
|
313
|
+
const deltaTime = recent.time - previous.time;
|
|
314
|
+
if (deltaTime === 0)
|
|
315
|
+
return false;
|
|
316
|
+
const deltaX = recent.x - previous.x;
|
|
317
|
+
const deltaY = recent.y - previous.y;
|
|
318
|
+
const velocity = (Math.sqrt(deltaX * deltaX + deltaY * deltaY) / deltaTime) * 1000; // px/second
|
|
319
|
+
// Check if velocity meets threshold
|
|
320
|
+
if (velocity < this.velocityThreshold) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
// Check if moving toward target
|
|
324
|
+
const toTargetX = targetX - recent.x;
|
|
325
|
+
const toTargetY = targetY - recent.y;
|
|
326
|
+
const dotProduct = deltaX * toTargetX + deltaY * toTargetY;
|
|
327
|
+
return dotProduct > 0; // Moving toward target
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Global prefetch manager instance (lazy-initialized to avoid TDZ issues
|
|
332
|
+
* with cross-chunk constants during bundled module evaluation).
|
|
333
|
+
*/
|
|
334
|
+
let globalPrefetchManager = null;
|
|
335
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"getPrefetchManager","stability":"stable","signature":"() => PrefetchManager","description":"Get the lazy-initialized global prefetch manager"} */
|
|
336
|
+
/**
|
|
337
|
+
* Get the global prefetch manager
|
|
338
|
+
*/
|
|
339
|
+
export function getPrefetchManager() {
|
|
340
|
+
if (!globalPrefetchManager) {
|
|
341
|
+
globalPrefetchManager = new PrefetchManager();
|
|
342
|
+
}
|
|
343
|
+
return globalPrefetchManager;
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/router/features/prefetch/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.ux.focus",
|
|
4
|
+
"title": "A11y Focus Management",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Focus management configuration
|
|
10
|
+
*/
|
|
11
|
+
export interface FocusConfig {
|
|
12
|
+
/** Focus selector priority (highest to lowest) */
|
|
13
|
+
focusSelectors?: string[];
|
|
14
|
+
/** Whether to manage focus automatically */
|
|
15
|
+
autoFocus?: boolean;
|
|
16
|
+
/** Fallback element for focus when no targets found */
|
|
17
|
+
focusFallback?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Required version of focus configuration
|
|
21
|
+
*/
|
|
22
|
+
export type RequiredFocusConfig = Required<FocusConfig>;
|
|
23
|
+
/**
|
|
24
|
+
* Focus manager for enhanced accessibility
|
|
25
|
+
*/
|
|
26
|
+
export declare class FocusManager {
|
|
27
|
+
private config;
|
|
28
|
+
constructor(config?: FocusConfig);
|
|
29
|
+
/**
|
|
30
|
+
* Manage focus after navigation
|
|
31
|
+
*/
|
|
32
|
+
manageFocus(options?: {
|
|
33
|
+
preventScroll?: boolean;
|
|
34
|
+
}): void;
|
|
35
|
+
/**
|
|
36
|
+
* Ensure element is programmatically focusable
|
|
37
|
+
*/
|
|
38
|
+
private ensureFocusable;
|
|
39
|
+
/**
|
|
40
|
+
* Check if element is visible
|
|
41
|
+
*/
|
|
42
|
+
private isVisible;
|
|
43
|
+
/**
|
|
44
|
+
* Check if user is currently focused on an interactive element
|
|
45
|
+
* Prevents focus stealing during navigation
|
|
46
|
+
*/
|
|
47
|
+
private isUserOnInteractiveElement;
|
|
48
|
+
/**
|
|
49
|
+
* Update focus configuration
|
|
50
|
+
*/
|
|
51
|
+
updateConfig(config: Partial<FocusConfig>): void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Global focus manager instance
|
|
55
|
+
*/
|
|
56
|
+
export declare const focusManager: FocusManager;
|
|
57
|
+
/** @codexApi {"parent":"pithy.router.ux.focus","name":"useFocus","stability":"stable","signature":"(config?: FocusConfig) => FocusManager"} */
|
|
58
|
+
/**
|
|
59
|
+
* Focus utilities
|
|
60
|
+
*/
|
|
61
|
+
export declare function useFocus(config?: FocusConfig): FocusManager;
|
|
62
|
+
//# sourceMappingURL=focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../../../src/router/features/ux/focus.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AAExD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,GAAE,WAAgB;IAgBpC;;OAEG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAqCxD;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,SAAS;IAUjB;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAmClC;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;CAGjD;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,cAAqB,CAAC;AAE/C,+IAA+I;AAC/I;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,YAAY,CAK3D"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.ux.focus",
|
|
4
|
+
"title": "A11y Focus Management",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Focus manager for enhanced accessibility
|
|
10
|
+
*/
|
|
11
|
+
export class FocusManager {
|
|
12
|
+
constructor(config = {}) {
|
|
13
|
+
this.config = {
|
|
14
|
+
focusSelectors: [
|
|
15
|
+
'[data-focus-target]',
|
|
16
|
+
'[autofocus]',
|
|
17
|
+
'[tabindex]',
|
|
18
|
+
'h1',
|
|
19
|
+
'[role=heading]',
|
|
20
|
+
'main',
|
|
21
|
+
],
|
|
22
|
+
autoFocus: true,
|
|
23
|
+
focusFallback: '[data-router-outlet]',
|
|
24
|
+
...config,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Manage focus after navigation
|
|
29
|
+
*/
|
|
30
|
+
manageFocus(options) {
|
|
31
|
+
if (!this.config.autoFocus)
|
|
32
|
+
return;
|
|
33
|
+
// Don't steal focus if user is already on an interactive element
|
|
34
|
+
if (this.isUserOnInteractiveElement()) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Find the best focus target
|
|
38
|
+
let target = null;
|
|
39
|
+
for (const selector of this.config.focusSelectors) {
|
|
40
|
+
target = document.querySelector(selector);
|
|
41
|
+
if (target && this.isVisible(target)) {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Focus the target if found
|
|
46
|
+
if (target) {
|
|
47
|
+
const el = this.ensureFocusable(target);
|
|
48
|
+
const focusOptions = { preventScroll: true, ...(options ?? {}) };
|
|
49
|
+
el.focus(focusOptions);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Fallback to outlet if no targets found
|
|
53
|
+
if (!target) {
|
|
54
|
+
const outlet = document.querySelector(this.config.focusFallback);
|
|
55
|
+
if (outlet) {
|
|
56
|
+
const el = this.ensureFocusable(outlet);
|
|
57
|
+
el.focus({ preventScroll: true });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Ensure element is programmatically focusable
|
|
64
|
+
*/
|
|
65
|
+
ensureFocusable(el) {
|
|
66
|
+
const node = el;
|
|
67
|
+
const isNaturallyFocusable = typeof node.focus === 'function' && node.tabIndex >= 0;
|
|
68
|
+
if (!isNaturallyFocusable && !node.hasAttribute('tabindex')) {
|
|
69
|
+
node.setAttribute('tabindex', '-1');
|
|
70
|
+
node.setAttribute('data-router-tmp-tabindex', '');
|
|
71
|
+
}
|
|
72
|
+
return node;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if element is visible
|
|
76
|
+
*/
|
|
77
|
+
isVisible(element) {
|
|
78
|
+
const rect = element.getBoundingClientRect();
|
|
79
|
+
return (rect.width > 0 &&
|
|
80
|
+
rect.height > 0 &&
|
|
81
|
+
rect.top < window.innerHeight &&
|
|
82
|
+
rect.bottom > 0);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if user is currently focused on an interactive element
|
|
86
|
+
* Prevents focus stealing during navigation
|
|
87
|
+
*/
|
|
88
|
+
isUserOnInteractiveElement() {
|
|
89
|
+
const activeEl = document.activeElement;
|
|
90
|
+
if (!activeEl || activeEl === document.body) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// Check if the active element is an interactive element
|
|
94
|
+
const tagName = activeEl.tagName.toLowerCase();
|
|
95
|
+
const interactiveTags = ['input', 'textarea', 'select', 'button', 'a'];
|
|
96
|
+
// Check tag name
|
|
97
|
+
if (interactiveTags.includes(tagName)) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
// Check if element has tabindex (is focusable)
|
|
101
|
+
if (activeEl.hasAttribute('tabindex')) {
|
|
102
|
+
const tabindex = activeEl.getAttribute('tabindex');
|
|
103
|
+
// tabindex >= 0 means it's in the tab order (interactive)
|
|
104
|
+
if (tabindex !== null && parseInt(tabindex, 10) >= 0) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Check for contenteditable
|
|
109
|
+
if (activeEl.hasAttribute('contenteditable') &&
|
|
110
|
+
activeEl.getAttribute('contenteditable') !== 'false') {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Update focus configuration
|
|
117
|
+
*/
|
|
118
|
+
updateConfig(config) {
|
|
119
|
+
this.config = { ...this.config, ...config };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Global focus manager instance
|
|
124
|
+
*/
|
|
125
|
+
export const focusManager = new FocusManager();
|
|
126
|
+
/** @codexApi {"parent":"pithy.router.ux.focus","name":"useFocus","stability":"stable","signature":"(config?: FocusConfig) => FocusManager"} */
|
|
127
|
+
/**
|
|
128
|
+
* Focus utilities
|
|
129
|
+
*/
|
|
130
|
+
export function useFocus(config) {
|
|
131
|
+
if (config) {
|
|
132
|
+
focusManager.updateConfig(config);
|
|
133
|
+
}
|
|
134
|
+
return focusManager;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=focus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.js","sourceRoot":"","sources":["../../../../src/router/features/ux/focus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.ux.live-region",
|
|
4
|
+
"title": "ARIA Live Region Announcements",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Live region configuration
|
|
10
|
+
*/
|
|
11
|
+
export interface LiveRegionConfig {
|
|
12
|
+
/** Enable accessibility announcements (default: true) */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/** Whether to announce route changes (default: true) */
|
|
15
|
+
announceChanges?: boolean;
|
|
16
|
+
/** Politeness level for announcements */
|
|
17
|
+
politeness?: 'polite' | 'assertive';
|
|
18
|
+
/** Duration to keep announcement visible (ms) */
|
|
19
|
+
clearDelay?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Required version of live region configuration
|
|
23
|
+
*/
|
|
24
|
+
export type RequiredLiveRegionConfig = Required<LiveRegionConfig>;
|
|
25
|
+
/**
|
|
26
|
+
* Live region manager for screen reader announcements
|
|
27
|
+
*/
|
|
28
|
+
export declare class LiveRegionManager {
|
|
29
|
+
private announcer;
|
|
30
|
+
private config;
|
|
31
|
+
constructor(config?: LiveRegionConfig);
|
|
32
|
+
/**
|
|
33
|
+
* Announce route change for screen readers
|
|
34
|
+
*/
|
|
35
|
+
announceRouteChange(path?: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Announce custom message
|
|
38
|
+
*/
|
|
39
|
+
announce(message: string, options?: {
|
|
40
|
+
clearDelay?: number;
|
|
41
|
+
}): void;
|
|
42
|
+
/**
|
|
43
|
+
* Announce loading state
|
|
44
|
+
*/
|
|
45
|
+
announceLoading(message?: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Announce navigation error
|
|
48
|
+
*/
|
|
49
|
+
announceError(message: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Announce guard denial
|
|
52
|
+
*/
|
|
53
|
+
announceGuardDenied(message?: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* Setup screen reader announcer element
|
|
56
|
+
*/
|
|
57
|
+
private setupAnnouncer;
|
|
58
|
+
/**
|
|
59
|
+
* Update live region configuration
|
|
60
|
+
*/
|
|
61
|
+
updateConfig(config: Partial<LiveRegionConfig>): void;
|
|
62
|
+
/**
|
|
63
|
+
* Destroy announcer element
|
|
64
|
+
*/
|
|
65
|
+
destroy(): void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Global live region manager instance
|
|
69
|
+
*/
|
|
70
|
+
export declare const liveRegionManager: LiveRegionManager;
|
|
71
|
+
/** @codexApi {"parent":"pithy.router.ux.live-region","name":"useLiveRegion","stability":"stable","signature":"(config?: LiveRegionConfig) => LiveRegionManager"} */
|
|
72
|
+
/**
|
|
73
|
+
* Live region utilities
|
|
74
|
+
*/
|
|
75
|
+
export declare function useLiveRegion(config?: LiveRegionConfig): LiveRegionManager;
|
|
76
|
+
/** @codexApi {"parent":"pithy.router.ux.live-region","name":"announce","stability":"stable","signature":"(message: string) => void"} */
|
|
77
|
+
/**
|
|
78
|
+
* Announce navigation change
|
|
79
|
+
*/
|
|
80
|
+
export declare function announce(message: string): void;
|
|
81
|
+
//# sourceMappingURL=live-region.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-region.d.ts","sourceRoot":"","sources":["../../../../src/router/features/ux/live-region.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAIF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wDAAwD;IACxD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,yCAAyC;IACzC,UAAU,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IACpC,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAElE;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,MAAM,CAA2B;gBAE7B,MAAM,GAAE,gBAAqB;IAezC;;OAEG;IACH,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAiBxC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAclE;;OAEG;IACH,eAAe,CAAC,OAAO,GAAE,MAAqB,GAAG,IAAI;IAKrD;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAYpC;;OAEG;IACH,mBAAmB,CAAC,OAAO,GAAE,MAA6B,GAAG,IAAI;IAYjE;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IA0BrD;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,mBAA0B,CAAC;AAEzD,oKAAoK;AACpK;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAK1E;AAED,wIAAwI;AACxI;;GAEG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE9C"}
|