@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,120 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.view-transitions",
|
|
4
|
+
"title": "View Transitions API Integration",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"ViewTransitionPreset","stability":"experimental","signature":"type ViewTransitionPreset"} */
|
|
9
|
+
/**
|
|
10
|
+
* Built-in transition presets
|
|
11
|
+
* These transitions work globally without requiring additional parameters.
|
|
12
|
+
*/
|
|
13
|
+
export type ViewTransitionPreset = 'slide' | 'fade' | 'none';
|
|
14
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"ViewTransitionType","stability":"experimental","signature":"type ViewTransitionType"} */
|
|
15
|
+
/**
|
|
16
|
+
* View transition types
|
|
17
|
+
* Includes built-in presets plus 'custom' for element-specific transitions.
|
|
18
|
+
* The 'custom' type requires a transition name via data-transition-name attribute.
|
|
19
|
+
*/
|
|
20
|
+
export type ViewTransitionType = ViewTransitionPreset | 'custom';
|
|
21
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"ViewTransitionConfig","stability":"experimental","signature":"interface ViewTransitionConfig"} */
|
|
22
|
+
/**
|
|
23
|
+
* View transition configuration
|
|
24
|
+
* Controls global view transition behavior for the router.
|
|
25
|
+
* Browser support required: Chrome 111+, Edge 111+
|
|
26
|
+
*/
|
|
27
|
+
export interface ViewTransitionConfig {
|
|
28
|
+
/** Whether to enable view transitions */
|
|
29
|
+
enabled?: boolean;
|
|
30
|
+
/** Default transition preset (cannot be 'custom' as it requires a name parameter) */
|
|
31
|
+
defaultTransition?: ViewTransitionPreset;
|
|
32
|
+
/** Custom transition duration (ms) */
|
|
33
|
+
duration?: number;
|
|
34
|
+
/** Easing function for transitions */
|
|
35
|
+
easing?: string;
|
|
36
|
+
}
|
|
37
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"ViewTransitionOptions","stability":"experimental","signature":"interface ViewTransitionOptions"} */
|
|
38
|
+
/**
|
|
39
|
+
* View transition options for individual navigations
|
|
40
|
+
* Allows per-navigation customization of transition behavior.
|
|
41
|
+
*/
|
|
42
|
+
export interface ViewTransitionOptions {
|
|
43
|
+
/** Transition type to use */
|
|
44
|
+
type?: ViewTransitionType | undefined;
|
|
45
|
+
/** Whether to skip transition for this navigation */
|
|
46
|
+
skipTransition?: boolean | undefined;
|
|
47
|
+
/** Custom transition name */
|
|
48
|
+
name?: string | undefined;
|
|
49
|
+
}
|
|
50
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"ViewTransitionManager","stability":"experimental","signature":"class ViewTransitionManager"} */
|
|
51
|
+
/**
|
|
52
|
+
* View transition manager for enhanced navigation UX
|
|
53
|
+
* Integrates the browser's View Transitions API for smooth route changes.
|
|
54
|
+
* Provides slide, fade, and custom animations with graceful fallback for unsupported browsers.
|
|
55
|
+
*/
|
|
56
|
+
export declare class ViewTransitionManager {
|
|
57
|
+
private config;
|
|
58
|
+
constructor(config?: ViewTransitionConfig);
|
|
59
|
+
/**
|
|
60
|
+
* Check if View Transitions API is supported (dynamic check for testing)
|
|
61
|
+
*/
|
|
62
|
+
private isSupported;
|
|
63
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"isAvailable","stability":"experimental","signature":"() => boolean"} */
|
|
64
|
+
/**
|
|
65
|
+
* Check if view transitions are supported and enabled
|
|
66
|
+
* Returns true only if both browser support exists AND transitions are enabled in config.
|
|
67
|
+
*/
|
|
68
|
+
isAvailable(): boolean;
|
|
69
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"executeTransition","stability":"experimental","signature":"<T>(updateCallback: () => Promise<T> | T, options?: ViewTransitionOptions) => Promise<T>"} */
|
|
70
|
+
/**
|
|
71
|
+
* Execute a view transition for navigation
|
|
72
|
+
* Wraps the DOM update callback with View Transitions API animation.
|
|
73
|
+
* Gracefully falls back to immediate execution if unsupported or disabled.
|
|
74
|
+
*/
|
|
75
|
+
executeTransition<T>(updateCallback: () => Promise<T> | T, options?: ViewTransitionOptions): Promise<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Apply custom transition styles
|
|
78
|
+
*/
|
|
79
|
+
private applyTransitionStyles;
|
|
80
|
+
/**
|
|
81
|
+
* Clear transition styles
|
|
82
|
+
*/
|
|
83
|
+
private clearTransitionStyles;
|
|
84
|
+
/**
|
|
85
|
+
* Get transition options from element attributes
|
|
86
|
+
* Reads data-transition and data-transition-name attributes to configure transitions.
|
|
87
|
+
* If no element is provided, returns default transition options from config.
|
|
88
|
+
* @internal Used internally by the router during navigation
|
|
89
|
+
*/
|
|
90
|
+
getTransitionOptionsFromElement(element?: Element | null): ViewTransitionOptions | null;
|
|
91
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"updateConfig","stability":"experimental","signature":"(config: Partial<ViewTransitionConfig>) => void"} */
|
|
92
|
+
/**
|
|
93
|
+
* Update configuration
|
|
94
|
+
* Allows runtime configuration changes for view transitions.
|
|
95
|
+
*/
|
|
96
|
+
updateConfig(config: Partial<ViewTransitionConfig>): void;
|
|
97
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"cleanup","stability":"experimental","signature":"() => void"} */
|
|
98
|
+
/**
|
|
99
|
+
* Cleanup transition styles and resources
|
|
100
|
+
* Removes injected transition styles from the document.
|
|
101
|
+
*/
|
|
102
|
+
cleanup(): void;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Global view transition manager instance
|
|
106
|
+
* Singleton instance used by the router for view transition management.
|
|
107
|
+
* @internal Used internally by the router; users should configure via RouterConfig
|
|
108
|
+
*/
|
|
109
|
+
export declare const viewTransitionManager: ViewTransitionManager;
|
|
110
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"useViewTransitions","stability":"experimental","signature":"(config?: ViewTransitionConfig) => ViewTransitionManager"} */
|
|
111
|
+
/**
|
|
112
|
+
* View transition utilities
|
|
113
|
+
*/
|
|
114
|
+
export declare function useViewTransitions(config?: ViewTransitionConfig): ViewTransitionManager;
|
|
115
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"supportsViewTransitions","stability":"stable","signature":"() => boolean"} */
|
|
116
|
+
/**
|
|
117
|
+
* Check if view transitions are supported in the current environment
|
|
118
|
+
*/
|
|
119
|
+
export declare function supportsViewTransitions(): boolean;
|
|
120
|
+
//# sourceMappingURL=transitions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transitions.d.ts","sourceRoot":"","sources":["../../../../src/router/features/ux/transitions.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,4JAA4J;AAC5J;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7D,wJAAwJ;AACxJ;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,oBAAoB,GAAG,QAAQ,CAAC;AAEjE,iKAAiK;AACjK;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qFAAqF;IACrF,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;IACzC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mKAAmK;AACnK;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,6BAA6B;IAC7B,IAAI,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACtC,qDAAqD;IACrD,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,+JAA+J;AAC/J;;;;GAIG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAiC;gBAEnC,MAAM,GAAE,oBAAyB;IAU7C;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB,uIAAuI;IACvI;;;OAGG;IACH,WAAW,IAAI,OAAO;IAItB,wNAAwN;IACxN;;;;OAIG;IACG,iBAAiB,CAAC,CAAC,EACvB,cAAc,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EACpC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,CAAC,CAAC;IA+Cb;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA4E7B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAW7B;;;;;OAKG;IACH,+BAA+B,CAC7B,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,GACvB,qBAAqB,GAAG,IAAI;IA4B/B,0KAA0K;IAC1K;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI;IAIzD,gIAAgI;IAChI;;;OAGG;IACH,OAAO,IAAI,IAAI;CAGhB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,uBAA8B,CAAC;AAEjE,yLAAyL;AACzL;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,CAAC,EAAE,oBAAoB,GAC5B,qBAAqB,CAKvB;AAED,6IAA6I;AAC7I;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.view-transitions",
|
|
4
|
+
"title": "View Transitions API Integration",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"ViewTransitionManager","stability":"experimental","signature":"class ViewTransitionManager"} */
|
|
9
|
+
/**
|
|
10
|
+
* View transition manager for enhanced navigation UX
|
|
11
|
+
* Integrates the browser's View Transitions API for smooth route changes.
|
|
12
|
+
* Provides slide, fade, and custom animations with graceful fallback for unsupported browsers.
|
|
13
|
+
*/
|
|
14
|
+
export class ViewTransitionManager {
|
|
15
|
+
constructor(config = {}) {
|
|
16
|
+
this.config = {
|
|
17
|
+
enabled: true,
|
|
18
|
+
defaultTransition: 'fade',
|
|
19
|
+
duration: 400,
|
|
20
|
+
easing: 'ease-in-out',
|
|
21
|
+
...config,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if View Transitions API is supported (dynamic check for testing)
|
|
26
|
+
*/
|
|
27
|
+
isSupported() {
|
|
28
|
+
return typeof document !== 'undefined' && 'startViewTransition' in document;
|
|
29
|
+
}
|
|
30
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"isAvailable","stability":"experimental","signature":"() => boolean"} */
|
|
31
|
+
/**
|
|
32
|
+
* Check if view transitions are supported and enabled
|
|
33
|
+
* Returns true only if both browser support exists AND transitions are enabled in config.
|
|
34
|
+
*/
|
|
35
|
+
isAvailable() {
|
|
36
|
+
return this.isSupported() && this.config.enabled;
|
|
37
|
+
}
|
|
38
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"executeTransition","stability":"experimental","signature":"<T>(updateCallback: () => Promise<T> | T, options?: ViewTransitionOptions) => Promise<T>"} */
|
|
39
|
+
/**
|
|
40
|
+
* Execute a view transition for navigation
|
|
41
|
+
* Wraps the DOM update callback with View Transitions API animation.
|
|
42
|
+
* Gracefully falls back to immediate execution if unsupported or disabled.
|
|
43
|
+
*/
|
|
44
|
+
async executeTransition(updateCallback, options) {
|
|
45
|
+
// If transitions are not available or disabled, just run the callback
|
|
46
|
+
if (!this.isAvailable() || options?.skipTransition) {
|
|
47
|
+
return await updateCallback();
|
|
48
|
+
}
|
|
49
|
+
// Apply custom transition styles BEFORE starting transition
|
|
50
|
+
if (options?.type && options.type !== 'none') {
|
|
51
|
+
this.applyTransitionStyles(options.type, options.name);
|
|
52
|
+
}
|
|
53
|
+
// Use the native View Transitions API
|
|
54
|
+
if (document.startViewTransition) {
|
|
55
|
+
return await new Promise((resolve, reject) => {
|
|
56
|
+
const transition = document.startViewTransition(async () => {
|
|
57
|
+
try {
|
|
58
|
+
const result = await updateCallback();
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
reject(error);
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// Handle transition completion
|
|
67
|
+
transition.finished
|
|
68
|
+
.then(() => {
|
|
69
|
+
// Transition completed successfully
|
|
70
|
+
})
|
|
71
|
+
.catch(error => {
|
|
72
|
+
console.warn('View transition failed:', error);
|
|
73
|
+
// Continue with the result even if transition failed
|
|
74
|
+
});
|
|
75
|
+
// The result will be available when the callback completes
|
|
76
|
+
transition.ready
|
|
77
|
+
.then(result => {
|
|
78
|
+
resolve(result);
|
|
79
|
+
})
|
|
80
|
+
.catch(reject);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// Fallback for browsers without View Transitions API
|
|
84
|
+
return await updateCallback();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Apply custom transition styles
|
|
88
|
+
*/
|
|
89
|
+
applyTransitionStyles(type, name) {
|
|
90
|
+
if (typeof document === 'undefined')
|
|
91
|
+
return;
|
|
92
|
+
// Remove existing transition styles
|
|
93
|
+
this.clearTransitionStyles();
|
|
94
|
+
const style = document.createElement('style');
|
|
95
|
+
style.id = 'pithy-view-transition-styles';
|
|
96
|
+
let css = '';
|
|
97
|
+
switch (type) {
|
|
98
|
+
case 'slide':
|
|
99
|
+
css = `
|
|
100
|
+
::view-transition-old(root) {
|
|
101
|
+
animation: slide-out ${this.config.duration}ms ${this.config.easing} both;
|
|
102
|
+
}
|
|
103
|
+
::view-transition-new(root) {
|
|
104
|
+
animation: slide-in ${this.config.duration}ms ${this.config.easing} both;
|
|
105
|
+
}
|
|
106
|
+
@keyframes slide-out {
|
|
107
|
+
from { transform: translateX(0); }
|
|
108
|
+
to { transform: translateX(-100%); }
|
|
109
|
+
}
|
|
110
|
+
@keyframes slide-in {
|
|
111
|
+
from { transform: translateX(100%); }
|
|
112
|
+
to { transform: translateX(0); }
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
break;
|
|
116
|
+
case 'fade':
|
|
117
|
+
css = `
|
|
118
|
+
::view-transition-old(root) {
|
|
119
|
+
animation: fade-out ${this.config.duration}ms ${this.config.easing} both;
|
|
120
|
+
}
|
|
121
|
+
::view-transition-new(root) {
|
|
122
|
+
animation: fade-in ${this.config.duration}ms ${this.config.easing} both;
|
|
123
|
+
}
|
|
124
|
+
@keyframes fade-out {
|
|
125
|
+
from { opacity: 1; }
|
|
126
|
+
to { opacity: 0; }
|
|
127
|
+
}
|
|
128
|
+
@keyframes fade-in {
|
|
129
|
+
from { opacity: 0; }
|
|
130
|
+
to { opacity: 1; }
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
break;
|
|
134
|
+
case 'custom':
|
|
135
|
+
if (name) {
|
|
136
|
+
css = `
|
|
137
|
+
::view-transition-old(${name}) {
|
|
138
|
+
animation: custom-out ${this.config.duration}ms ${this.config.easing} both;
|
|
139
|
+
}
|
|
140
|
+
::view-transition-new(${name}) {
|
|
141
|
+
animation: custom-in ${this.config.duration}ms ${this.config.easing} both;
|
|
142
|
+
}
|
|
143
|
+
@keyframes custom-out {
|
|
144
|
+
from { opacity: 1; transform: scale(1); }
|
|
145
|
+
to { opacity: 0.8; transform: scale(0.95); }
|
|
146
|
+
}
|
|
147
|
+
@keyframes custom-in {
|
|
148
|
+
from { opacity: 0.8; transform: scale(0.95); }
|
|
149
|
+
to { opacity: 1; transform: scale(1); }
|
|
150
|
+
}
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
style.textContent = css;
|
|
156
|
+
document.head.appendChild(style);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Clear transition styles
|
|
160
|
+
*/
|
|
161
|
+
clearTransitionStyles() {
|
|
162
|
+
if (typeof document === 'undefined')
|
|
163
|
+
return;
|
|
164
|
+
const existingStyle = document.getElementById('pithy-view-transition-styles');
|
|
165
|
+
if (existingStyle) {
|
|
166
|
+
existingStyle.remove();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get transition options from element attributes
|
|
171
|
+
* Reads data-transition and data-transition-name attributes to configure transitions.
|
|
172
|
+
* If no element is provided, returns default transition options from config.
|
|
173
|
+
* @internal Used internally by the router during navigation
|
|
174
|
+
*/
|
|
175
|
+
getTransitionOptionsFromElement(element) {
|
|
176
|
+
// If no element provided, use default transition from config
|
|
177
|
+
if (!element) {
|
|
178
|
+
return {
|
|
179
|
+
type: this.config.defaultTransition,
|
|
180
|
+
name: undefined,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const skipTransition = element.hasAttribute('data-no-transition') ||
|
|
184
|
+
element.closest('[data-no-transition]') !== null;
|
|
185
|
+
if (skipTransition) {
|
|
186
|
+
return { skipTransition: true };
|
|
187
|
+
}
|
|
188
|
+
const transitionType = element.getAttribute('data-transition');
|
|
189
|
+
const transitionName = element.getAttribute('data-transition-name');
|
|
190
|
+
return {
|
|
191
|
+
type: transitionType || this.config.defaultTransition,
|
|
192
|
+
name: transitionName || undefined,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"updateConfig","stability":"experimental","signature":"(config: Partial<ViewTransitionConfig>) => void"} */
|
|
196
|
+
/**
|
|
197
|
+
* Update configuration
|
|
198
|
+
* Allows runtime configuration changes for view transitions.
|
|
199
|
+
*/
|
|
200
|
+
updateConfig(config) {
|
|
201
|
+
this.config = { ...this.config, ...config };
|
|
202
|
+
}
|
|
203
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"cleanup","stability":"experimental","signature":"() => void"} */
|
|
204
|
+
/**
|
|
205
|
+
* Cleanup transition styles and resources
|
|
206
|
+
* Removes injected transition styles from the document.
|
|
207
|
+
*/
|
|
208
|
+
cleanup() {
|
|
209
|
+
this.clearTransitionStyles();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Global view transition manager instance
|
|
214
|
+
* Singleton instance used by the router for view transition management.
|
|
215
|
+
* @internal Used internally by the router; users should configure via RouterConfig
|
|
216
|
+
*/
|
|
217
|
+
export const viewTransitionManager = new ViewTransitionManager();
|
|
218
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"useViewTransitions","stability":"experimental","signature":"(config?: ViewTransitionConfig) => ViewTransitionManager"} */
|
|
219
|
+
/**
|
|
220
|
+
* View transition utilities
|
|
221
|
+
*/
|
|
222
|
+
export function useViewTransitions(config) {
|
|
223
|
+
if (config) {
|
|
224
|
+
viewTransitionManager.updateConfig(config);
|
|
225
|
+
}
|
|
226
|
+
return viewTransitionManager;
|
|
227
|
+
}
|
|
228
|
+
/** @codexApi {"parent":"pithy.router.view-transitions","name":"supportsViewTransitions","stability":"stable","signature":"() => boolean"} */
|
|
229
|
+
/**
|
|
230
|
+
* Check if view transitions are supported in the current environment
|
|
231
|
+
*/
|
|
232
|
+
export function supportsViewTransitions() {
|
|
233
|
+
return typeof document !== 'undefined' && 'startViewTransition' in document;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=transitions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transitions.js","sourceRoot":"","sources":["../../../../src/router/features/ux/transitions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.directive-binding",
|
|
4
|
+
"title": "Router Directive Binding System",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import type { Router } from '../core/router';
|
|
9
|
+
/** @codexApi {"parent":"pithy.router.directive-binding","name":"setGlobalRouter","stability":"stable","signature":"(router: Router) => void"} */
|
|
10
|
+
/**
|
|
11
|
+
* Set the global router instance for directive binding.
|
|
12
|
+
* Also registers the directive binder with core and scans for unbound links.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setGlobalRouter(router: Router): void;
|
|
15
|
+
/** @codexApi {"parent":"pithy.router.directive-binding","name":"getGlobalRouter","stability":"stable","signature":"() => Router | null"} */
|
|
16
|
+
/**
|
|
17
|
+
* Get the global router instance
|
|
18
|
+
*/
|
|
19
|
+
export declare function getGlobalRouter(): Router | null;
|
|
20
|
+
//# sourceMappingURL=directive-binder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directive-binder.d.ts","sourceRoot":"","sources":["../../../src/router/integration/directive-binder.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAiBF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AA8I7C,iJAAiJ;AACjJ;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CASpD;AAED,4IAA4I;AAC5I;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/C"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.directive-binding",
|
|
4
|
+
"title": "Router Directive Binding System",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Router Directive Binder
|
|
10
|
+
*
|
|
11
|
+
* Handles binding of router directives (@routerOutlet, @routerLink) in templates.
|
|
12
|
+
* Registers with core's directive registry to integrate with template compilation.
|
|
13
|
+
*
|
|
14
|
+
* @module router/integration/directive-binder
|
|
15
|
+
*/
|
|
16
|
+
import { registerDirectiveBinder } from '@pithyjs/core';
|
|
17
|
+
import { routerLink, routerOutlet } from './directives';
|
|
18
|
+
import { PREFETCH_STRATEGIES, } from '../features/prefetch';
|
|
19
|
+
function resolvePrefetchAttr(value) {
|
|
20
|
+
if (value === null)
|
|
21
|
+
return 'none';
|
|
22
|
+
if (PREFETCH_STRATEGIES.includes(value)) {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
if (import.meta.env?.DEV) {
|
|
26
|
+
console.warn(`[@routerLink] invalid data-prefetch="${value}" — expected one of ${PREFETCH_STRATEGIES.join(', ')}; falling back to "none".`);
|
|
27
|
+
}
|
|
28
|
+
return 'none';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Global router instance - will be set by the router when it mounts
|
|
32
|
+
*/
|
|
33
|
+
let globalRouter = null;
|
|
34
|
+
/**
|
|
35
|
+
* Bind existing router links that were rendered before the router was available
|
|
36
|
+
* Looks for @routerLink elements that don't have cleanup functions attached yet
|
|
37
|
+
*/
|
|
38
|
+
function bindExistingRouterLinks(router) {
|
|
39
|
+
const unboundLinks = document.querySelectorAll('a[data-router-link]:not([data-router-bound])');
|
|
40
|
+
unboundLinks.forEach(el => {
|
|
41
|
+
const element = el;
|
|
42
|
+
// Mark as bound to avoid double-binding
|
|
43
|
+
element.setAttribute('data-router-bound', 'true');
|
|
44
|
+
const prefetchStrategy = resolvePrefetchAttr(element.getAttribute('data-prefetch'));
|
|
45
|
+
// Extract other router link options
|
|
46
|
+
const activeClass = element.getAttribute('active-class') || 'router-link-active';
|
|
47
|
+
const exactMatch = element.hasAttribute('exact-match');
|
|
48
|
+
const replace = element.hasAttribute('replace');
|
|
49
|
+
const options = {
|
|
50
|
+
activeClass,
|
|
51
|
+
exactMatch,
|
|
52
|
+
prefetch: prefetchStrategy,
|
|
53
|
+
replace,
|
|
54
|
+
};
|
|
55
|
+
routerLink(element, router, options);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Binds router directives (@routerOutlet, @routerLink) within the DOM tree
|
|
60
|
+
* This integrates the router directives into the core template compilation system
|
|
61
|
+
*/
|
|
62
|
+
const bindRouterDirectives = (root, _context, disposers) => {
|
|
63
|
+
if (!globalRouter) {
|
|
64
|
+
// Router not yet initialized, skip binding
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Type narrowing: router is non-null after the check above
|
|
68
|
+
const router = globalRouter;
|
|
69
|
+
// Find all elements with router directives
|
|
70
|
+
const elements = root.querySelectorAll('*');
|
|
71
|
+
elements.forEach(el => {
|
|
72
|
+
const element = el;
|
|
73
|
+
// Handle @routerOutlet directive
|
|
74
|
+
if (element.hasAttribute('data-router-outlet')) {
|
|
75
|
+
routerOutlet(element, router);
|
|
76
|
+
// Add cleanup
|
|
77
|
+
disposers.push(() => {
|
|
78
|
+
const target = element;
|
|
79
|
+
const cleanup = target.__routerOutletCleanup;
|
|
80
|
+
if (cleanup) {
|
|
81
|
+
cleanup();
|
|
82
|
+
delete target.__routerOutletCleanup;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// Handle @routerLink directive
|
|
87
|
+
if (element.hasAttribute('data-router-link') && element.tagName === 'A') {
|
|
88
|
+
const anchorElement = element;
|
|
89
|
+
// Skip if already bound (to avoid double-binding)
|
|
90
|
+
if (anchorElement.hasAttribute('data-router-bound')) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Mark as bound to avoid double-binding
|
|
94
|
+
anchorElement.setAttribute('data-router-bound', 'true');
|
|
95
|
+
const prefetchStrategy = resolvePrefetchAttr(element.getAttribute('data-prefetch'));
|
|
96
|
+
// Extract other router link options
|
|
97
|
+
const activeClass = element.getAttribute('active-class') || 'router-link-active';
|
|
98
|
+
const exactMatch = element.hasAttribute('exact-match');
|
|
99
|
+
const replace = element.hasAttribute('replace');
|
|
100
|
+
const options = {
|
|
101
|
+
activeClass,
|
|
102
|
+
exactMatch,
|
|
103
|
+
prefetch: prefetchStrategy,
|
|
104
|
+
replace,
|
|
105
|
+
};
|
|
106
|
+
routerLink(anchorElement, router, options);
|
|
107
|
+
// Add cleanup
|
|
108
|
+
disposers.push(() => {
|
|
109
|
+
const target = anchorElement;
|
|
110
|
+
const cleanup = target.__routerLinkCleanup;
|
|
111
|
+
if (cleanup) {
|
|
112
|
+
cleanup();
|
|
113
|
+
delete target.__routerLinkCleanup;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
/** @codexApi {"parent":"pithy.router.directive-binding","name":"setGlobalRouter","stability":"stable","signature":"(router: Router) => void"} */
|
|
120
|
+
/**
|
|
121
|
+
* Set the global router instance for directive binding.
|
|
122
|
+
* Also registers the directive binder with core and scans for unbound links.
|
|
123
|
+
*/
|
|
124
|
+
export function setGlobalRouter(router) {
|
|
125
|
+
globalRouter = router;
|
|
126
|
+
// Register our directive binder with core (idempotent - won't double-register)
|
|
127
|
+
registerDirectiveBinder(bindRouterDirectives);
|
|
128
|
+
// Scan the DOM for any unbound router links and bind them
|
|
129
|
+
// This handles the case where links were rendered before the router was mounted
|
|
130
|
+
bindExistingRouterLinks(router);
|
|
131
|
+
}
|
|
132
|
+
/** @codexApi {"parent":"pithy.router.directive-binding","name":"getGlobalRouter","stability":"stable","signature":"() => Router | null"} */
|
|
133
|
+
/**
|
|
134
|
+
* Get the global router instance
|
|
135
|
+
*/
|
|
136
|
+
export function getGlobalRouter() {
|
|
137
|
+
return globalRouter;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=directive-binder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directive-binder.js","sourceRoot":"","sources":["../../../src/router/integration/directive-binder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.directives",
|
|
4
|
+
"title": "Router Directives (@routerOutlet, @routerLink)",
|
|
5
|
+
"category": "directive"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import type { Router } from '../core/router';
|
|
9
|
+
import { type PrefetchStrategy } from '../features/prefetch';
|
|
10
|
+
/** @codexApi {"parent":"pithy.router.directives","name":"routerOutlet","stability":"experimental","signature":"(element: HTMLElement, router: Router) => void"} */
|
|
11
|
+
/**
|
|
12
|
+
* Router outlet directive - marks where child routes should be rendered
|
|
13
|
+
*
|
|
14
|
+
* NOTE: This directive only marks the outlet element. The actual route component
|
|
15
|
+
* rendering is handled by OutletManager.mountSegments() when router.mount() is called.
|
|
16
|
+
*/
|
|
17
|
+
export declare function routerOutlet(element: HTMLElement, _router: Router): void;
|
|
18
|
+
/** @codexApi {"parent":"pithy.router.directives","name":"routerLink","stability":"stable","signature":"(element: HTMLAnchorElement, router: Router, options?: RouterLinkOptions) => void"} */
|
|
19
|
+
/**
|
|
20
|
+
* Router link directive - enhances anchor tags with client-side navigation
|
|
21
|
+
* Fixed to prevent URL changes when guards deny navigation
|
|
22
|
+
*/
|
|
23
|
+
export declare function routerLink(element: HTMLAnchorElement, router: Router, options?: RouterLinkOptions): void;
|
|
24
|
+
/**
|
|
25
|
+
* Router link options
|
|
26
|
+
*/
|
|
27
|
+
export interface RouterLinkOptions {
|
|
28
|
+
/** CSS class to apply when link is active */
|
|
29
|
+
activeClass?: string;
|
|
30
|
+
/** Whether to match the exact path or allow partial matches */
|
|
31
|
+
exactMatch?: boolean;
|
|
32
|
+
/** Prefetch strategy */
|
|
33
|
+
prefetch?: PrefetchStrategy;
|
|
34
|
+
/** Replace current history entry instead of pushing a new one */
|
|
35
|
+
replace?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** @codexApi {"parent":"pithy.router.directives","name":"cleanupRouterDirectives","stability":"experimental","signature":"(element: HTMLElement) => void"} */
|
|
38
|
+
/**
|
|
39
|
+
* Cleanup router directive subscriptions
|
|
40
|
+
*/
|
|
41
|
+
export declare function cleanupRouterDirectives(element: HTMLElement): void;
|
|
42
|
+
//# sourceMappingURL=directives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../../../src/router/integration/directives.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAG9B,mKAAmK;AACnK;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAUxE;AAED,8LAA8L;AAC9L;;;GAGG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,iBAAsB,GAC9B,IAAI,CAsEN;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,8JAA8J;AAC9J;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAuBlE"}
|