@flight-framework/router 0.0.8 → 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/dist/preact/index.d.ts +77 -0
- package/dist/preact/index.js +220 -0
- package/dist/solid/index.d.ts +107 -0
- package/dist/solid/index.js +191 -0
- package/dist/svelte/index.d.ts +118 -0
- package/dist/svelte/index.js +161 -0
- package/dist/vue/index.d.ts +147 -0
- package/dist/vue/index.js +224 -0
- package/package.json +46 -6
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { P as PrefetchStrategy, b as RouterProviderProps, a as RouterContextValue } from '../prefetch-CMmeei6-.js';
|
|
2
|
+
export { L as LinkProps, N as NavigateOptions, d as PrefetchOptions, c as PrefetchPriority, R as RouteParams, S as SearchParams, w as clearPrefetchCache, l as findRoute, o as generatePath, B as getRouterContext, D as initRouter, q as isActive, v as isPrefetched, m as matchRoute, n as navigate, x as observeForPrefetch, p as parseParams, s as prefetch, t as prefetchAll, z as prefetchPages, A as prefetchWhenIdle, r as redirect, y as setupIntentPrefetch, C as subscribe } from '../prefetch-CMmeei6-.js';
|
|
3
|
+
import * as preact$1 from 'preact';
|
|
4
|
+
import { FunctionComponent, ComponentChildren } from 'preact';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Preact Link Component
|
|
8
|
+
*
|
|
9
|
+
* Provides client-side navigation with prefetching support for Preact.
|
|
10
|
+
* API is nearly identical to React version.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface LinkProps {
|
|
14
|
+
href: string;
|
|
15
|
+
prefetch?: boolean | PrefetchStrategy;
|
|
16
|
+
replace?: boolean;
|
|
17
|
+
scroll?: boolean;
|
|
18
|
+
class?: string;
|
|
19
|
+
className?: string;
|
|
20
|
+
target?: string;
|
|
21
|
+
rel?: string;
|
|
22
|
+
'aria-label'?: string;
|
|
23
|
+
onClick?: (e: MouseEvent) => void;
|
|
24
|
+
children?: preact.ComponentChildren;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Preact Link Component
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* <Link href="/docs" prefetch="intent">Documentation</Link>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare const Link: FunctionComponent<LinkProps>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Preact Context for router
|
|
38
|
+
*/
|
|
39
|
+
declare const RouterContext: preact$1.Context<RouterContextValue>;
|
|
40
|
+
/**
|
|
41
|
+
* Hook to access router context
|
|
42
|
+
*/
|
|
43
|
+
declare function useRouter(): RouterContextValue;
|
|
44
|
+
/**
|
|
45
|
+
* Hook to get current pathname
|
|
46
|
+
*/
|
|
47
|
+
declare function usePathname(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Hook to get current search params
|
|
50
|
+
*/
|
|
51
|
+
declare function useSearchParams(): URLSearchParams;
|
|
52
|
+
/**
|
|
53
|
+
* Hook to get route params
|
|
54
|
+
*/
|
|
55
|
+
declare function useParams(): Record<string, string>;
|
|
56
|
+
interface RouterProviderComponentProps extends Partial<RouterProviderProps> {
|
|
57
|
+
children?: ComponentChildren;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Preact Router Provider
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* import { RouterProvider } from '@flight-framework/router/preact';
|
|
65
|
+
*
|
|
66
|
+
* function App() {
|
|
67
|
+
* return (
|
|
68
|
+
* <RouterProvider initialPath="/">
|
|
69
|
+
* <YourApp />
|
|
70
|
+
* </RouterProvider>
|
|
71
|
+
* );
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare const RouterProvider: FunctionComponent<RouterProviderComponentProps>;
|
|
76
|
+
|
|
77
|
+
export { Link, PrefetchStrategy, RouterContext, RouterContextValue, RouterProvider, RouterProviderProps, useParams, usePathname, useRouter, useSearchParams };
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearPrefetchCache,
|
|
3
|
+
findRoute,
|
|
4
|
+
generatePath,
|
|
5
|
+
getRouterContext,
|
|
6
|
+
initRouter,
|
|
7
|
+
isActive,
|
|
8
|
+
isPrefetched,
|
|
9
|
+
matchRoute,
|
|
10
|
+
navigate,
|
|
11
|
+
observeForPrefetch,
|
|
12
|
+
parseParams,
|
|
13
|
+
prefetch,
|
|
14
|
+
prefetchAll,
|
|
15
|
+
prefetchPages,
|
|
16
|
+
prefetchWhenIdle,
|
|
17
|
+
redirect,
|
|
18
|
+
setupIntentPrefetch,
|
|
19
|
+
subscribe
|
|
20
|
+
} from "../chunk-MO2HMSZH.js";
|
|
21
|
+
|
|
22
|
+
// src/preact/Link.tsx
|
|
23
|
+
import { h } from "preact";
|
|
24
|
+
import { useCallback, useEffect, useRef } from "preact/hooks";
|
|
25
|
+
var isBrowser = typeof window !== "undefined";
|
|
26
|
+
function isExternalUrl(href) {
|
|
27
|
+
if (!href) return false;
|
|
28
|
+
return href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//") || href.startsWith("mailto:") || href.startsWith("tel:") || href.startsWith("javascript:") || href.startsWith("#");
|
|
29
|
+
}
|
|
30
|
+
function normalizePrefetchStrategy(prefetchProp) {
|
|
31
|
+
if (prefetchProp === true) return "intent";
|
|
32
|
+
if (prefetchProp === false || prefetchProp === void 0) return "none";
|
|
33
|
+
return prefetchProp;
|
|
34
|
+
}
|
|
35
|
+
var Link = ({
|
|
36
|
+
href,
|
|
37
|
+
children,
|
|
38
|
+
class: className,
|
|
39
|
+
className: classNameProp,
|
|
40
|
+
target,
|
|
41
|
+
rel,
|
|
42
|
+
prefetch: prefetchProp = "none",
|
|
43
|
+
replace = false,
|
|
44
|
+
scroll = true,
|
|
45
|
+
onClick,
|
|
46
|
+
"aria-label": ariaLabel,
|
|
47
|
+
...props
|
|
48
|
+
}) => {
|
|
49
|
+
const linkRef = useRef(null);
|
|
50
|
+
const isExternal = isExternalUrl(href);
|
|
51
|
+
const prefetchStrategy = normalizePrefetchStrategy(prefetchProp);
|
|
52
|
+
const handleClick = useCallback(
|
|
53
|
+
(e) => {
|
|
54
|
+
if (onClick) {
|
|
55
|
+
onClick(e);
|
|
56
|
+
if (e.defaultPrevented) return;
|
|
57
|
+
}
|
|
58
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (e.button !== 0) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (isExternal || target === "_blank") {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
const { navigate: navigate2 } = getRouterContext();
|
|
69
|
+
navigate2(href, { replace, scroll });
|
|
70
|
+
},
|
|
71
|
+
[href, isExternal, target, replace, scroll, onClick]
|
|
72
|
+
);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (isExternal || !isBrowser || prefetchStrategy === "none") {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const link = linkRef.current;
|
|
78
|
+
if (!link) return;
|
|
79
|
+
switch (prefetchStrategy) {
|
|
80
|
+
case "render":
|
|
81
|
+
prefetch(href, { priority: "low" });
|
|
82
|
+
break;
|
|
83
|
+
case "viewport":
|
|
84
|
+
return observeForPrefetch(link, href);
|
|
85
|
+
case "intent":
|
|
86
|
+
default:
|
|
87
|
+
return setupIntentPrefetch(link, href);
|
|
88
|
+
}
|
|
89
|
+
}, [href, prefetchStrategy, isExternal]);
|
|
90
|
+
const computedRel = isExternal && target === "_blank" ? rel || "noopener noreferrer" : rel;
|
|
91
|
+
const finalClassName = className || classNameProp;
|
|
92
|
+
return h("a", {
|
|
93
|
+
ref: linkRef,
|
|
94
|
+
href,
|
|
95
|
+
class: finalClassName,
|
|
96
|
+
target,
|
|
97
|
+
rel: computedRel,
|
|
98
|
+
"aria-label": ariaLabel,
|
|
99
|
+
onClick: handleClick,
|
|
100
|
+
...props
|
|
101
|
+
}, children);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// src/preact/RouterProvider.tsx
|
|
105
|
+
import { h as h2, createContext } from "preact";
|
|
106
|
+
import { useContext, useState, useEffect as useEffect2 } from "preact/hooks";
|
|
107
|
+
var isBrowser2 = typeof window !== "undefined";
|
|
108
|
+
function navigateTo(to, options = {}) {
|
|
109
|
+
if (!isBrowser2) return;
|
|
110
|
+
const { replace = false, scroll = true, state } = options;
|
|
111
|
+
if (replace) {
|
|
112
|
+
window.history.replaceState(state ?? null, "", to);
|
|
113
|
+
} else {
|
|
114
|
+
window.history.pushState(state ?? null, "", to);
|
|
115
|
+
}
|
|
116
|
+
if (scroll) {
|
|
117
|
+
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
var defaultContext = {
|
|
121
|
+
path: "/",
|
|
122
|
+
searchParams: new URLSearchParams(),
|
|
123
|
+
navigate: navigateTo,
|
|
124
|
+
back: () => isBrowser2 && window.history.back(),
|
|
125
|
+
forward: () => isBrowser2 && window.history.forward()
|
|
126
|
+
};
|
|
127
|
+
var RouterContext = createContext(defaultContext);
|
|
128
|
+
function useRouter() {
|
|
129
|
+
return useContext(RouterContext);
|
|
130
|
+
}
|
|
131
|
+
function usePathname() {
|
|
132
|
+
const { path } = useContext(RouterContext);
|
|
133
|
+
return path;
|
|
134
|
+
}
|
|
135
|
+
function useSearchParams() {
|
|
136
|
+
const { searchParams } = useContext(RouterContext);
|
|
137
|
+
return searchParams;
|
|
138
|
+
}
|
|
139
|
+
function useParams() {
|
|
140
|
+
return {};
|
|
141
|
+
}
|
|
142
|
+
var RouterProvider = ({
|
|
143
|
+
children,
|
|
144
|
+
initialPath,
|
|
145
|
+
basePath = ""
|
|
146
|
+
}) => {
|
|
147
|
+
const [routerState, setRouterState] = useState(() => {
|
|
148
|
+
const path = isBrowser2 ? window.location.pathname : initialPath || "/";
|
|
149
|
+
const searchParams = isBrowser2 ? new URLSearchParams(window.location.search) : new URLSearchParams();
|
|
150
|
+
let normalizedPath = path;
|
|
151
|
+
if (basePath && path.startsWith(basePath)) {
|
|
152
|
+
normalizedPath = path.slice(basePath.length) || "/";
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
path: normalizedPath,
|
|
156
|
+
searchParams,
|
|
157
|
+
navigate: navigateTo,
|
|
158
|
+
back: () => isBrowser2 && window.history.back(),
|
|
159
|
+
forward: () => isBrowser2 && window.history.forward()
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
useEffect2(() => {
|
|
163
|
+
if (!isBrowser2) return;
|
|
164
|
+
const handlePopState = () => {
|
|
165
|
+
let path = window.location.pathname;
|
|
166
|
+
if (basePath && path.startsWith(basePath)) {
|
|
167
|
+
path = path.slice(basePath.length) || "/";
|
|
168
|
+
}
|
|
169
|
+
setRouterState((prev) => ({
|
|
170
|
+
...prev,
|
|
171
|
+
path,
|
|
172
|
+
searchParams: new URLSearchParams(window.location.search)
|
|
173
|
+
}));
|
|
174
|
+
};
|
|
175
|
+
window.addEventListener("popstate", handlePopState);
|
|
176
|
+
const unsubscribe = subscribe((ctx) => {
|
|
177
|
+
let path = ctx.path;
|
|
178
|
+
if (basePath && path.startsWith(basePath)) {
|
|
179
|
+
path = path.slice(basePath.length) || "/";
|
|
180
|
+
}
|
|
181
|
+
setRouterState((prev) => ({
|
|
182
|
+
...prev,
|
|
183
|
+
path,
|
|
184
|
+
searchParams: ctx.searchParams
|
|
185
|
+
}));
|
|
186
|
+
});
|
|
187
|
+
return () => {
|
|
188
|
+
window.removeEventListener("popstate", handlePopState);
|
|
189
|
+
unsubscribe();
|
|
190
|
+
};
|
|
191
|
+
}, [basePath]);
|
|
192
|
+
return h2(RouterContext.Provider, { value: routerState }, children);
|
|
193
|
+
};
|
|
194
|
+
export {
|
|
195
|
+
Link,
|
|
196
|
+
RouterContext,
|
|
197
|
+
RouterProvider,
|
|
198
|
+
clearPrefetchCache,
|
|
199
|
+
findRoute,
|
|
200
|
+
generatePath,
|
|
201
|
+
getRouterContext,
|
|
202
|
+
initRouter,
|
|
203
|
+
isActive,
|
|
204
|
+
isPrefetched,
|
|
205
|
+
matchRoute,
|
|
206
|
+
navigate,
|
|
207
|
+
observeForPrefetch,
|
|
208
|
+
parseParams,
|
|
209
|
+
prefetch,
|
|
210
|
+
prefetchAll,
|
|
211
|
+
prefetchPages,
|
|
212
|
+
prefetchWhenIdle,
|
|
213
|
+
redirect,
|
|
214
|
+
setupIntentPrefetch,
|
|
215
|
+
subscribe,
|
|
216
|
+
useParams,
|
|
217
|
+
usePathname,
|
|
218
|
+
useRouter,
|
|
219
|
+
useSearchParams
|
|
220
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { P as PrefetchStrategy, b as RouterProviderProps, a as RouterContextValue } from '../prefetch-CMmeei6-.js';
|
|
2
|
+
export { L as LinkProps, N as NavigateOptions, d as PrefetchOptions, c as PrefetchPriority, R as RouteParams, S as SearchParams, w as clearPrefetchCache, l as findRoute, o as generatePath, B as getRouterContext, D as initRouter, q as isActive, v as isPrefetched, m as matchRoute, n as navigate, x as observeForPrefetch, p as parseParams, s as prefetch, t as prefetchAll, z as prefetchPages, A as prefetchWhenIdle, r as redirect, y as setupIntentPrefetch, C as subscribe } from '../prefetch-CMmeei6-.js';
|
|
3
|
+
import * as solid_js from 'solid-js';
|
|
4
|
+
import { JSX, Accessor } from 'solid-js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* SolidJS Link Component
|
|
8
|
+
*
|
|
9
|
+
* Provides client-side navigation with prefetching support for SolidJS.
|
|
10
|
+
* Uses functional component pattern without JSX to avoid type conflicts.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface LinkProps {
|
|
14
|
+
href: string;
|
|
15
|
+
prefetch?: boolean | PrefetchStrategy;
|
|
16
|
+
replace?: boolean;
|
|
17
|
+
scroll?: boolean;
|
|
18
|
+
class?: string;
|
|
19
|
+
target?: string;
|
|
20
|
+
rel?: string;
|
|
21
|
+
'aria-label'?: string;
|
|
22
|
+
onClick?: (e: MouseEvent) => void;
|
|
23
|
+
children?: JSX.Element;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create props for a Link anchor element
|
|
27
|
+
* Use this with spread operator on an <a> element
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* const linkProps = createLinkProps({ href: '/docs', prefetch: 'intent' });
|
|
32
|
+
* <a {...linkProps}>Docs</a>
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
declare function createLinkProps(props: LinkProps): {
|
|
36
|
+
href: string;
|
|
37
|
+
class: string | undefined;
|
|
38
|
+
target: string | undefined;
|
|
39
|
+
rel: string | undefined;
|
|
40
|
+
'aria-label': string | undefined;
|
|
41
|
+
onClick: (e: MouseEvent) => void;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Solid Link action for use with ref
|
|
45
|
+
*/
|
|
46
|
+
declare function linkAction(node: HTMLAnchorElement, props: Accessor<{
|
|
47
|
+
href: string;
|
|
48
|
+
prefetch?: boolean | PrefetchStrategy;
|
|
49
|
+
}>): void;
|
|
50
|
+
/**
|
|
51
|
+
* Link component for SolidJS
|
|
52
|
+
* Re-export createLinkProps for component-like usage
|
|
53
|
+
*/
|
|
54
|
+
declare const Link: {
|
|
55
|
+
createProps: typeof createLinkProps;
|
|
56
|
+
action: typeof linkAction;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* SolidJS Context for router
|
|
61
|
+
*/
|
|
62
|
+
declare const RouterContext: solid_js.Context<Accessor<RouterContextValue>>;
|
|
63
|
+
/**
|
|
64
|
+
* Hook to access router context
|
|
65
|
+
*/
|
|
66
|
+
declare function useRouter(): RouterContextValue;
|
|
67
|
+
/**
|
|
68
|
+
* Hook to get current pathname as a signal accessor
|
|
69
|
+
*/
|
|
70
|
+
declare function usePathname(): Accessor<string>;
|
|
71
|
+
/**
|
|
72
|
+
* Hook to get current search params
|
|
73
|
+
*/
|
|
74
|
+
declare function useSearchParams(): Accessor<URLSearchParams>;
|
|
75
|
+
/**
|
|
76
|
+
* Hook to get route params
|
|
77
|
+
*/
|
|
78
|
+
declare function useParams(): Accessor<Record<string, string>>;
|
|
79
|
+
/**
|
|
80
|
+
* Create a router provider for SolidJS
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* import { createRouterProvider } from '@flight-framework/router/solid';
|
|
85
|
+
*
|
|
86
|
+
* const { Provider, useRouter } = createRouterProvider();
|
|
87
|
+
*
|
|
88
|
+
* function App() {
|
|
89
|
+
* return (
|
|
90
|
+
* <Provider>
|
|
91
|
+
* <YourApp />
|
|
92
|
+
* </Provider>
|
|
93
|
+
* );
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
declare function createRouterProvider(options?: Partial<RouterProviderProps>): {
|
|
98
|
+
Context: solid_js.Context<Accessor<RouterContextValue>>;
|
|
99
|
+
getContext: () => RouterContextValue;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* RouterProvider for Solid - use with JSX
|
|
103
|
+
* This is a simplified version that works with Solid's context
|
|
104
|
+
*/
|
|
105
|
+
declare const RouterProvider: typeof createRouterProvider;
|
|
106
|
+
|
|
107
|
+
export { Link, PrefetchStrategy, RouterContext, RouterContextValue, RouterProvider, RouterProviderProps, createLinkProps, createRouterProvider, linkAction, useParams, usePathname, useRouter, useSearchParams };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearPrefetchCache,
|
|
3
|
+
findRoute,
|
|
4
|
+
generatePath,
|
|
5
|
+
getRouterContext,
|
|
6
|
+
initRouter,
|
|
7
|
+
isActive,
|
|
8
|
+
isPrefetched,
|
|
9
|
+
matchRoute,
|
|
10
|
+
navigate,
|
|
11
|
+
observeForPrefetch,
|
|
12
|
+
parseParams,
|
|
13
|
+
prefetch,
|
|
14
|
+
prefetchAll,
|
|
15
|
+
prefetchPages,
|
|
16
|
+
prefetchWhenIdle,
|
|
17
|
+
redirect,
|
|
18
|
+
setupIntentPrefetch,
|
|
19
|
+
subscribe
|
|
20
|
+
} from "../chunk-MO2HMSZH.js";
|
|
21
|
+
|
|
22
|
+
// src/solid/Link.ts
|
|
23
|
+
import { onCleanup } from "solid-js";
|
|
24
|
+
var isBrowser = typeof window !== "undefined";
|
|
25
|
+
function isExternalUrl(href) {
|
|
26
|
+
if (!href) return false;
|
|
27
|
+
return href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//") || href.startsWith("mailto:") || href.startsWith("tel:") || href.startsWith("javascript:") || href.startsWith("#");
|
|
28
|
+
}
|
|
29
|
+
function normalizePrefetchStrategy(prefetchProp) {
|
|
30
|
+
if (prefetchProp === true) return "intent";
|
|
31
|
+
if (prefetchProp === false || prefetchProp === void 0) return "none";
|
|
32
|
+
return prefetchProp;
|
|
33
|
+
}
|
|
34
|
+
function createLinkProps(props) {
|
|
35
|
+
const isExternal = isExternalUrl(props.href);
|
|
36
|
+
const handleClick = (e) => {
|
|
37
|
+
if (props.onClick) {
|
|
38
|
+
props.onClick(e);
|
|
39
|
+
if (e.defaultPrevented) return;
|
|
40
|
+
}
|
|
41
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (e.button !== 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (isExternal || props.target === "_blank") {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
const { navigate: navigate2 } = getRouterContext();
|
|
52
|
+
navigate2(props.href, {
|
|
53
|
+
replace: props.replace ?? false,
|
|
54
|
+
scroll: props.scroll ?? true
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const computedRel = isExternal && props.target === "_blank" ? props.rel || "noopener noreferrer" : props.rel;
|
|
58
|
+
return {
|
|
59
|
+
href: props.href,
|
|
60
|
+
class: props.class,
|
|
61
|
+
target: props.target,
|
|
62
|
+
rel: computedRel,
|
|
63
|
+
"aria-label": props["aria-label"],
|
|
64
|
+
onClick: handleClick
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function linkAction(node, props) {
|
|
68
|
+
const { href, prefetch: prefetchProp } = props();
|
|
69
|
+
const isExternal = isExternalUrl(href);
|
|
70
|
+
const prefetchStrategy = normalizePrefetchStrategy(prefetchProp);
|
|
71
|
+
let cleanup;
|
|
72
|
+
if (!isExternal && isBrowser && prefetchStrategy !== "none") {
|
|
73
|
+
switch (prefetchStrategy) {
|
|
74
|
+
case "render":
|
|
75
|
+
prefetch(href, { priority: "low" });
|
|
76
|
+
break;
|
|
77
|
+
case "viewport":
|
|
78
|
+
cleanup = observeForPrefetch(node, href);
|
|
79
|
+
break;
|
|
80
|
+
case "intent":
|
|
81
|
+
default:
|
|
82
|
+
cleanup = setupIntentPrefetch(node, href);
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
onCleanup(() => cleanup?.());
|
|
87
|
+
}
|
|
88
|
+
var Link = {
|
|
89
|
+
createProps: createLinkProps,
|
|
90
|
+
action: linkAction
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/solid/RouterProvider.ts
|
|
94
|
+
import { createContext, useContext, createSignal as createSignal2 } from "solid-js";
|
|
95
|
+
var isBrowser2 = typeof window !== "undefined";
|
|
96
|
+
function navigateTo(to, options = {}) {
|
|
97
|
+
if (!isBrowser2) return;
|
|
98
|
+
const { replace = false, scroll = true, state } = options;
|
|
99
|
+
if (replace) {
|
|
100
|
+
window.history.replaceState(state ?? null, "", to);
|
|
101
|
+
} else {
|
|
102
|
+
window.history.pushState(state ?? null, "", to);
|
|
103
|
+
}
|
|
104
|
+
if (scroll) {
|
|
105
|
+
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
var defaultContext = {
|
|
109
|
+
path: "/",
|
|
110
|
+
searchParams: new URLSearchParams(),
|
|
111
|
+
navigate: navigateTo,
|
|
112
|
+
back: () => isBrowser2 && window.history.back(),
|
|
113
|
+
forward: () => isBrowser2 && window.history.forward()
|
|
114
|
+
};
|
|
115
|
+
var RouterContext = createContext(() => defaultContext);
|
|
116
|
+
function useRouter() {
|
|
117
|
+
const getContext = useContext(RouterContext);
|
|
118
|
+
return getContext();
|
|
119
|
+
}
|
|
120
|
+
function usePathname() {
|
|
121
|
+
const getContext = useContext(RouterContext);
|
|
122
|
+
return () => getContext().path;
|
|
123
|
+
}
|
|
124
|
+
function useSearchParams() {
|
|
125
|
+
const getContext = useContext(RouterContext);
|
|
126
|
+
return () => getContext().searchParams;
|
|
127
|
+
}
|
|
128
|
+
function useParams() {
|
|
129
|
+
return () => ({});
|
|
130
|
+
}
|
|
131
|
+
function createRouterProvider(options = {}) {
|
|
132
|
+
const [path, setPath] = createSignal2(
|
|
133
|
+
isBrowser2 ? window.location.pathname : options.initialPath || "/"
|
|
134
|
+
);
|
|
135
|
+
const [searchParams, setSearchParams] = createSignal2(
|
|
136
|
+
isBrowser2 ? new URLSearchParams(window.location.search) : new URLSearchParams()
|
|
137
|
+
);
|
|
138
|
+
const getRouterContext2 = () => ({
|
|
139
|
+
path: path(),
|
|
140
|
+
searchParams: searchParams(),
|
|
141
|
+
navigate: navigateTo,
|
|
142
|
+
back: () => isBrowser2 && window.history.back(),
|
|
143
|
+
forward: () => isBrowser2 && window.history.forward()
|
|
144
|
+
});
|
|
145
|
+
if (isBrowser2) {
|
|
146
|
+
const handlePopState = () => {
|
|
147
|
+
setPath(window.location.pathname);
|
|
148
|
+
setSearchParams(new URLSearchParams(window.location.search));
|
|
149
|
+
};
|
|
150
|
+
window.addEventListener("popstate", handlePopState);
|
|
151
|
+
subscribe((ctx) => {
|
|
152
|
+
setPath(ctx.path);
|
|
153
|
+
setSearchParams(ctx.searchParams);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
Context: RouterContext,
|
|
158
|
+
getContext: getRouterContext2
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
var RouterProvider = createRouterProvider;
|
|
162
|
+
export {
|
|
163
|
+
Link,
|
|
164
|
+
RouterContext,
|
|
165
|
+
RouterProvider,
|
|
166
|
+
clearPrefetchCache,
|
|
167
|
+
createLinkProps,
|
|
168
|
+
createRouterProvider,
|
|
169
|
+
findRoute,
|
|
170
|
+
generatePath,
|
|
171
|
+
getRouterContext,
|
|
172
|
+
initRouter,
|
|
173
|
+
isActive,
|
|
174
|
+
isPrefetched,
|
|
175
|
+
linkAction,
|
|
176
|
+
matchRoute,
|
|
177
|
+
navigate,
|
|
178
|
+
observeForPrefetch,
|
|
179
|
+
parseParams,
|
|
180
|
+
prefetch,
|
|
181
|
+
prefetchAll,
|
|
182
|
+
prefetchPages,
|
|
183
|
+
prefetchWhenIdle,
|
|
184
|
+
redirect,
|
|
185
|
+
setupIntentPrefetch,
|
|
186
|
+
subscribe,
|
|
187
|
+
useParams,
|
|
188
|
+
usePathname,
|
|
189
|
+
useRouter,
|
|
190
|
+
useSearchParams
|
|
191
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { P as PrefetchStrategy, a as RouterContextValue } from '../prefetch-CMmeei6-.js';
|
|
2
|
+
export { L as LinkProps, N as NavigateOptions, d as PrefetchOptions, c as PrefetchPriority, R as RouteParams, b as RouterProviderProps, S as SearchParams, w as clearPrefetchCache, l as findRoute, o as generatePath, B as getRouterContext, D as initRouter, q as isActive, v as isPrefetched, m as matchRoute, n as navigate, x as observeForPrefetch, p as parseParams, s as prefetch, t as prefetchAll, z as prefetchPages, A as prefetchWhenIdle, r as redirect, y as setupIntentPrefetch, C as subscribe } from '../prefetch-CMmeei6-.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Svelte Link Component
|
|
6
|
+
*
|
|
7
|
+
* Provides client-side navigation with prefetching support for Svelte 5.
|
|
8
|
+
* Uses Svelte 5 runes ($props) for reactive properties.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a Link component action for Svelte.
|
|
13
|
+
* Use this with Svelte's `use:` directive for full control.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```svelte
|
|
17
|
+
* <script>
|
|
18
|
+
* import { linkAction } from '@flight-framework/router/svelte';
|
|
19
|
+
* </script>
|
|
20
|
+
*
|
|
21
|
+
* <a href="/docs" use:linkAction={{ prefetch: 'intent' }}>Docs</a>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function linkAction(node: HTMLAnchorElement, options?: {
|
|
25
|
+
prefetch?: boolean | PrefetchStrategy;
|
|
26
|
+
replace?: boolean;
|
|
27
|
+
scroll?: boolean;
|
|
28
|
+
}): {
|
|
29
|
+
destroy(): void;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Link component factory for Svelte.
|
|
33
|
+
* Returns props to spread on an anchor element.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```svelte
|
|
37
|
+
* <script>
|
|
38
|
+
* import { createLinkProps } from '@flight-framework/router/svelte';
|
|
39
|
+
*
|
|
40
|
+
* const linkProps = createLinkProps('/docs', { prefetch: 'intent' });
|
|
41
|
+
* </script>
|
|
42
|
+
*
|
|
43
|
+
* <a {...linkProps}>Documentation</a>
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare function createLinkProps(href: string, options?: {
|
|
47
|
+
prefetch?: boolean | PrefetchStrategy;
|
|
48
|
+
replace?: boolean;
|
|
49
|
+
scroll?: boolean;
|
|
50
|
+
}): {
|
|
51
|
+
href: string;
|
|
52
|
+
onclick: (e: MouseEvent) => void;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Simple Link function component.
|
|
56
|
+
* For Svelte 5, use $props() in your .svelte file instead.
|
|
57
|
+
* This provides the core logic that can be used in a .svelte wrapper.
|
|
58
|
+
*/
|
|
59
|
+
declare const Link: {
|
|
60
|
+
createProps: typeof createLinkProps;
|
|
61
|
+
action: typeof linkAction;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Svelte Stores for Router
|
|
66
|
+
*
|
|
67
|
+
* Provides Svelte stores for reactive router state.
|
|
68
|
+
* Compatible with Svelte 4 and Svelte 5.
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Router store - provides reactive access to router context
|
|
73
|
+
*/
|
|
74
|
+
declare const routerStore: {
|
|
75
|
+
subscribe(callback: (value: RouterContextValue) => void): () => boolean;
|
|
76
|
+
set(newValue: RouterContextValue): void;
|
|
77
|
+
get(): RouterContextValue;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Pathname store - provides reactive access to current pathname
|
|
81
|
+
*/
|
|
82
|
+
declare const pathnameStore: {
|
|
83
|
+
subscribe(callback: (value: string) => void): () => boolean;
|
|
84
|
+
set(newValue: string): void;
|
|
85
|
+
get(): string;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Get current router context (non-reactive for SSR)
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```svelte
|
|
92
|
+
* <script>
|
|
93
|
+
* import { getRouter } from '@flight-framework/router/svelte';
|
|
94
|
+
*
|
|
95
|
+
* const { navigate, back, forward } = getRouter();
|
|
96
|
+
* </script>
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare function getRouter(): RouterContextValue;
|
|
100
|
+
/**
|
|
101
|
+
* Get current pathname (non-reactive for SSR)
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```svelte
|
|
105
|
+
* <script>
|
|
106
|
+
* import { getPathname } from '@flight-framework/router/svelte';
|
|
107
|
+
*
|
|
108
|
+
* const pathname = getPathname();
|
|
109
|
+
* </script>
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
declare function getPathname(): string;
|
|
113
|
+
/**
|
|
114
|
+
* Get current search params (non-reactive for SSR)
|
|
115
|
+
*/
|
|
116
|
+
declare function getSearchParams(): URLSearchParams;
|
|
117
|
+
|
|
118
|
+
export { Link, PrefetchStrategy, RouterContextValue, getPathname, getRouter, getSearchParams, pathnameStore, routerStore };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearPrefetchCache,
|
|
3
|
+
findRoute,
|
|
4
|
+
generatePath,
|
|
5
|
+
getRouterContext,
|
|
6
|
+
initRouter,
|
|
7
|
+
isActive,
|
|
8
|
+
isPrefetched,
|
|
9
|
+
matchRoute,
|
|
10
|
+
navigate,
|
|
11
|
+
observeForPrefetch,
|
|
12
|
+
parseParams,
|
|
13
|
+
prefetch,
|
|
14
|
+
prefetchAll,
|
|
15
|
+
prefetchPages,
|
|
16
|
+
prefetchWhenIdle,
|
|
17
|
+
redirect,
|
|
18
|
+
setupIntentPrefetch,
|
|
19
|
+
subscribe
|
|
20
|
+
} from "../chunk-MO2HMSZH.js";
|
|
21
|
+
|
|
22
|
+
// src/svelte/Link.ts
|
|
23
|
+
var isBrowser = typeof window !== "undefined";
|
|
24
|
+
function isExternalUrl(href) {
|
|
25
|
+
if (!href) return false;
|
|
26
|
+
return href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//") || href.startsWith("mailto:") || href.startsWith("tel:") || href.startsWith("javascript:") || href.startsWith("#");
|
|
27
|
+
}
|
|
28
|
+
function normalizePrefetchStrategy(prefetchProp) {
|
|
29
|
+
if (prefetchProp === true) return "intent";
|
|
30
|
+
if (prefetchProp === false || prefetchProp === void 0) return "none";
|
|
31
|
+
return prefetchProp;
|
|
32
|
+
}
|
|
33
|
+
function linkAction(node, options = {}) {
|
|
34
|
+
const { prefetch: prefetchProp = "none", replace = false, scroll = true } = options;
|
|
35
|
+
const href = node.getAttribute("href") || "";
|
|
36
|
+
const isExternal = isExternalUrl(href);
|
|
37
|
+
const prefetchStrategy = normalizePrefetchStrategy(prefetchProp);
|
|
38
|
+
let cleanup;
|
|
39
|
+
const handleClick = (e) => {
|
|
40
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
41
|
+
if (e.button !== 0) return;
|
|
42
|
+
if (isExternal || node.target === "_blank") return;
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
const { navigate: navigate2 } = getRouterContext();
|
|
45
|
+
navigate2(href, { replace, scroll });
|
|
46
|
+
};
|
|
47
|
+
node.addEventListener("click", handleClick);
|
|
48
|
+
if (!isExternal && prefetchStrategy !== "none" && isBrowser) {
|
|
49
|
+
switch (prefetchStrategy) {
|
|
50
|
+
case "render":
|
|
51
|
+
prefetch(href, { priority: "low" });
|
|
52
|
+
break;
|
|
53
|
+
case "viewport":
|
|
54
|
+
cleanup = observeForPrefetch(node, href);
|
|
55
|
+
break;
|
|
56
|
+
case "intent":
|
|
57
|
+
default:
|
|
58
|
+
cleanup = setupIntentPrefetch(node, href);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
destroy() {
|
|
64
|
+
node.removeEventListener("click", handleClick);
|
|
65
|
+
cleanup?.();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function createLinkProps(href, options = {}) {
|
|
70
|
+
const { replace = false, scroll = true } = options;
|
|
71
|
+
const isExternal = isExternalUrl(href);
|
|
72
|
+
return {
|
|
73
|
+
href,
|
|
74
|
+
onclick: (e) => {
|
|
75
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
76
|
+
if (e.button !== 0) return;
|
|
77
|
+
if (isExternal) return;
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
const { navigate: navigate2 } = getRouterContext();
|
|
80
|
+
navigate2(href, { replace, scroll });
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
var Link = {
|
|
85
|
+
createProps: createLinkProps,
|
|
86
|
+
action: linkAction
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/svelte/stores.ts
|
|
90
|
+
var isBrowser2 = typeof window !== "undefined";
|
|
91
|
+
function createStore(initialValue) {
|
|
92
|
+
let value = initialValue;
|
|
93
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
94
|
+
return {
|
|
95
|
+
subscribe(callback) {
|
|
96
|
+
subscribers.add(callback);
|
|
97
|
+
callback(value);
|
|
98
|
+
return () => subscribers.delete(callback);
|
|
99
|
+
},
|
|
100
|
+
set(newValue) {
|
|
101
|
+
value = newValue;
|
|
102
|
+
subscribers.forEach((cb) => cb(value));
|
|
103
|
+
},
|
|
104
|
+
get() {
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
var routerStore = createStore(getRouterContext());
|
|
110
|
+
var pathnameStore = createStore(
|
|
111
|
+
isBrowser2 ? window.location.pathname : "/"
|
|
112
|
+
);
|
|
113
|
+
var searchParamsStore = createStore(
|
|
114
|
+
isBrowser2 ? new URLSearchParams(window.location.search) : new URLSearchParams()
|
|
115
|
+
);
|
|
116
|
+
if (isBrowser2) {
|
|
117
|
+
subscribe((ctx) => {
|
|
118
|
+
routerStore.set(ctx);
|
|
119
|
+
pathnameStore.set(ctx.path);
|
|
120
|
+
searchParamsStore.set(ctx.searchParams);
|
|
121
|
+
});
|
|
122
|
+
window.addEventListener("popstate", () => {
|
|
123
|
+
pathnameStore.set(window.location.pathname);
|
|
124
|
+
searchParamsStore.set(new URLSearchParams(window.location.search));
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function getRouter() {
|
|
128
|
+
return routerStore.get();
|
|
129
|
+
}
|
|
130
|
+
function getPathname() {
|
|
131
|
+
return pathnameStore.get();
|
|
132
|
+
}
|
|
133
|
+
function getSearchParams() {
|
|
134
|
+
return searchParamsStore.get();
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
Link,
|
|
138
|
+
clearPrefetchCache,
|
|
139
|
+
findRoute,
|
|
140
|
+
generatePath,
|
|
141
|
+
getPathname,
|
|
142
|
+
getRouter,
|
|
143
|
+
getRouterContext,
|
|
144
|
+
getSearchParams,
|
|
145
|
+
initRouter,
|
|
146
|
+
isActive,
|
|
147
|
+
isPrefetched,
|
|
148
|
+
matchRoute,
|
|
149
|
+
navigate,
|
|
150
|
+
observeForPrefetch,
|
|
151
|
+
parseParams,
|
|
152
|
+
pathnameStore,
|
|
153
|
+
prefetch,
|
|
154
|
+
prefetchAll,
|
|
155
|
+
prefetchPages,
|
|
156
|
+
prefetchWhenIdle,
|
|
157
|
+
redirect,
|
|
158
|
+
routerStore,
|
|
159
|
+
setupIntentPrefetch,
|
|
160
|
+
subscribe
|
|
161
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { P as PrefetchStrategy, b as RouterProviderProps, a as RouterContextValue } from '../prefetch-CMmeei6-.js';
|
|
2
|
+
export { L as LinkProps, N as NavigateOptions, d as PrefetchOptions, c as PrefetchPriority, R as RouteParams, S as SearchParams, w as clearPrefetchCache, l as findRoute, o as generatePath, B as getRouterContext, D as initRouter, q as isActive, v as isPrefetched, m as matchRoute, n as navigate, x as observeForPrefetch, p as parseParams, s as prefetch, t as prefetchAll, z as prefetchPages, A as prefetchWhenIdle, r as redirect, y as setupIntentPrefetch, C as subscribe } from '../prefetch-CMmeei6-.js';
|
|
3
|
+
import * as vue from 'vue';
|
|
4
|
+
import { PropType, Ref } from 'vue';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Vue Link Component
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```vue
|
|
11
|
+
* <template>
|
|
12
|
+
* <Link href="/docs" prefetch="intent">Documentation</Link>
|
|
13
|
+
* </template>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare const Link: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
17
|
+
href: {
|
|
18
|
+
type: StringConstructor;
|
|
19
|
+
required: true;
|
|
20
|
+
};
|
|
21
|
+
prefetch: {
|
|
22
|
+
type: PropType<boolean | PrefetchStrategy>;
|
|
23
|
+
default: string;
|
|
24
|
+
};
|
|
25
|
+
replace: {
|
|
26
|
+
type: BooleanConstructor;
|
|
27
|
+
default: boolean;
|
|
28
|
+
};
|
|
29
|
+
scroll: {
|
|
30
|
+
type: BooleanConstructor;
|
|
31
|
+
default: boolean;
|
|
32
|
+
};
|
|
33
|
+
class: {
|
|
34
|
+
type: StringConstructor;
|
|
35
|
+
default: undefined;
|
|
36
|
+
};
|
|
37
|
+
target: {
|
|
38
|
+
type: StringConstructor;
|
|
39
|
+
default: undefined;
|
|
40
|
+
};
|
|
41
|
+
rel: {
|
|
42
|
+
type: StringConstructor;
|
|
43
|
+
default: undefined;
|
|
44
|
+
};
|
|
45
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
46
|
+
[key: string]: any;
|
|
47
|
+
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
48
|
+
href: {
|
|
49
|
+
type: StringConstructor;
|
|
50
|
+
required: true;
|
|
51
|
+
};
|
|
52
|
+
prefetch: {
|
|
53
|
+
type: PropType<boolean | PrefetchStrategy>;
|
|
54
|
+
default: string;
|
|
55
|
+
};
|
|
56
|
+
replace: {
|
|
57
|
+
type: BooleanConstructor;
|
|
58
|
+
default: boolean;
|
|
59
|
+
};
|
|
60
|
+
scroll: {
|
|
61
|
+
type: BooleanConstructor;
|
|
62
|
+
default: boolean;
|
|
63
|
+
};
|
|
64
|
+
class: {
|
|
65
|
+
type: StringConstructor;
|
|
66
|
+
default: undefined;
|
|
67
|
+
};
|
|
68
|
+
target: {
|
|
69
|
+
type: StringConstructor;
|
|
70
|
+
default: undefined;
|
|
71
|
+
};
|
|
72
|
+
rel: {
|
|
73
|
+
type: StringConstructor;
|
|
74
|
+
default: undefined;
|
|
75
|
+
};
|
|
76
|
+
}>> & Readonly<{}>, {
|
|
77
|
+
replace: boolean;
|
|
78
|
+
scroll: boolean;
|
|
79
|
+
prefetch: boolean | PrefetchStrategy;
|
|
80
|
+
class: string;
|
|
81
|
+
target: string;
|
|
82
|
+
rel: string;
|
|
83
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Vue Composables for Router
|
|
87
|
+
*
|
|
88
|
+
* Provides Vue 3 composition API composables for routing.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Vue RouterProvider component for composition API
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```vue
|
|
96
|
+
* <script setup>
|
|
97
|
+
* import { RouterProvider } from '@flight-framework/router/vue';
|
|
98
|
+
* </script>
|
|
99
|
+
*
|
|
100
|
+
* <template>
|
|
101
|
+
* <RouterProvider initial-path="/">
|
|
102
|
+
* <App />
|
|
103
|
+
* </RouterProvider>
|
|
104
|
+
* </template>
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function RouterProvider(props: RouterProviderProps, { slots }: {
|
|
108
|
+
slots: {
|
|
109
|
+
default?: () => unknown;
|
|
110
|
+
};
|
|
111
|
+
}): unknown;
|
|
112
|
+
/**
|
|
113
|
+
* Composable to access router functions
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```vue
|
|
117
|
+
* <script setup>
|
|
118
|
+
* import { useRouter } from '@flight-framework/router/vue';
|
|
119
|
+
*
|
|
120
|
+
* const { navigate, back, forward } = useRouter();
|
|
121
|
+
* </script>
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
declare function useRouter(): RouterContextValue;
|
|
125
|
+
/**
|
|
126
|
+
* Composable to get current pathname
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```vue
|
|
130
|
+
* <script setup>
|
|
131
|
+
* import { usePathname } from '@flight-framework/router/vue';
|
|
132
|
+
*
|
|
133
|
+
* const pathname = usePathname();
|
|
134
|
+
* </script>
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
declare function usePathname(): Ref<string>;
|
|
138
|
+
/**
|
|
139
|
+
* Composable to get current search params
|
|
140
|
+
*/
|
|
141
|
+
declare function useSearchParams(): Ref<URLSearchParams>;
|
|
142
|
+
/**
|
|
143
|
+
* Composable to get route params
|
|
144
|
+
*/
|
|
145
|
+
declare function useParams(): Ref<Record<string, string>>;
|
|
146
|
+
|
|
147
|
+
export { Link, PrefetchStrategy, RouterContextValue, RouterProvider, RouterProviderProps, useParams, usePathname, useRouter, useSearchParams };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearPrefetchCache,
|
|
3
|
+
findRoute,
|
|
4
|
+
generatePath,
|
|
5
|
+
getRouterContext,
|
|
6
|
+
initRouter,
|
|
7
|
+
isActive,
|
|
8
|
+
isPrefetched,
|
|
9
|
+
matchRoute,
|
|
10
|
+
navigate,
|
|
11
|
+
observeForPrefetch,
|
|
12
|
+
parseParams,
|
|
13
|
+
prefetch,
|
|
14
|
+
prefetchAll,
|
|
15
|
+
prefetchPages,
|
|
16
|
+
prefetchWhenIdle,
|
|
17
|
+
redirect,
|
|
18
|
+
setupIntentPrefetch,
|
|
19
|
+
subscribe
|
|
20
|
+
} from "../chunk-MO2HMSZH.js";
|
|
21
|
+
|
|
22
|
+
// src/vue/Link.ts
|
|
23
|
+
import { defineComponent, ref, onMounted, onUnmounted, h } from "vue";
|
|
24
|
+
var isBrowser = typeof window !== "undefined";
|
|
25
|
+
function isExternalUrl(href) {
|
|
26
|
+
if (!href) return false;
|
|
27
|
+
return href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//") || href.startsWith("mailto:") || href.startsWith("tel:") || href.startsWith("javascript:") || href.startsWith("#");
|
|
28
|
+
}
|
|
29
|
+
function normalizePrefetchStrategy(prefetchProp) {
|
|
30
|
+
if (prefetchProp === true) return "intent";
|
|
31
|
+
if (prefetchProp === false || prefetchProp === void 0) return "none";
|
|
32
|
+
return prefetchProp;
|
|
33
|
+
}
|
|
34
|
+
var Link = defineComponent({
|
|
35
|
+
name: "FlightLink",
|
|
36
|
+
props: {
|
|
37
|
+
href: {
|
|
38
|
+
type: String,
|
|
39
|
+
required: true
|
|
40
|
+
},
|
|
41
|
+
prefetch: {
|
|
42
|
+
type: [Boolean, String],
|
|
43
|
+
default: "none"
|
|
44
|
+
},
|
|
45
|
+
replace: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
default: false
|
|
48
|
+
},
|
|
49
|
+
scroll: {
|
|
50
|
+
type: Boolean,
|
|
51
|
+
default: true
|
|
52
|
+
},
|
|
53
|
+
class: {
|
|
54
|
+
type: String,
|
|
55
|
+
default: void 0
|
|
56
|
+
},
|
|
57
|
+
target: {
|
|
58
|
+
type: String,
|
|
59
|
+
default: void 0
|
|
60
|
+
},
|
|
61
|
+
rel: {
|
|
62
|
+
type: String,
|
|
63
|
+
default: void 0
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
setup(props, { slots }) {
|
|
67
|
+
const linkRef = ref(null);
|
|
68
|
+
const isExternal = isExternalUrl(props.href);
|
|
69
|
+
const prefetchStrategy = normalizePrefetchStrategy(props.prefetch);
|
|
70
|
+
let cleanup;
|
|
71
|
+
onMounted(() => {
|
|
72
|
+
if (isExternal || !isBrowser || prefetchStrategy === "none") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const link = linkRef.value;
|
|
76
|
+
if (!link) return;
|
|
77
|
+
switch (prefetchStrategy) {
|
|
78
|
+
case "render":
|
|
79
|
+
prefetch(props.href, { priority: "low" });
|
|
80
|
+
break;
|
|
81
|
+
case "viewport":
|
|
82
|
+
cleanup = observeForPrefetch(link, props.href);
|
|
83
|
+
break;
|
|
84
|
+
case "intent":
|
|
85
|
+
default:
|
|
86
|
+
cleanup = setupIntentPrefetch(link, props.href);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
onUnmounted(() => {
|
|
91
|
+
cleanup?.();
|
|
92
|
+
});
|
|
93
|
+
const handleClick = (e) => {
|
|
94
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (e.button !== 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (isExternal || props.target === "_blank") {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
const { navigate: navigate2 } = getRouterContext();
|
|
105
|
+
navigate2(props.href, { replace: props.replace, scroll: props.scroll });
|
|
106
|
+
};
|
|
107
|
+
const computedRel = isExternal && props.target === "_blank" ? props.rel || "noopener noreferrer" : props.rel;
|
|
108
|
+
return () => h("a", {
|
|
109
|
+
ref: linkRef,
|
|
110
|
+
href: props.href,
|
|
111
|
+
class: props.class,
|
|
112
|
+
target: props.target,
|
|
113
|
+
rel: computedRel,
|
|
114
|
+
onClick: handleClick
|
|
115
|
+
}, slots.default?.());
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// src/vue/composables.ts
|
|
120
|
+
import { ref as ref2, provide, inject, onMounted as onMounted2, onUnmounted as onUnmounted2 } from "vue";
|
|
121
|
+
var isBrowser2 = typeof window !== "undefined";
|
|
122
|
+
var RouterKey = /* @__PURE__ */ Symbol("FlightRouter");
|
|
123
|
+
function navigateTo(to, options = {}) {
|
|
124
|
+
if (!isBrowser2) return;
|
|
125
|
+
const { replace = false, scroll = true, state } = options;
|
|
126
|
+
if (replace) {
|
|
127
|
+
window.history.replaceState(state ?? null, "", to);
|
|
128
|
+
} else {
|
|
129
|
+
window.history.pushState(state ?? null, "", to);
|
|
130
|
+
}
|
|
131
|
+
if (scroll) {
|
|
132
|
+
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function RouterProvider(props, { slots }) {
|
|
136
|
+
const path = ref2(isBrowser2 ? window.location.pathname : props.initialPath || "/");
|
|
137
|
+
const searchParams = ref2(isBrowser2 ? new URLSearchParams(window.location.search) : new URLSearchParams());
|
|
138
|
+
const routerState = ref2({
|
|
139
|
+
path: path.value,
|
|
140
|
+
searchParams: searchParams.value,
|
|
141
|
+
navigate: navigateTo,
|
|
142
|
+
back: () => isBrowser2 && window.history.back(),
|
|
143
|
+
forward: () => isBrowser2 && window.history.forward()
|
|
144
|
+
});
|
|
145
|
+
provide(RouterKey, routerState);
|
|
146
|
+
if (isBrowser2) {
|
|
147
|
+
onMounted2(() => {
|
|
148
|
+
const handlePopState = () => {
|
|
149
|
+
path.value = window.location.pathname;
|
|
150
|
+
searchParams.value = new URLSearchParams(window.location.search);
|
|
151
|
+
routerState.value = {
|
|
152
|
+
...routerState.value,
|
|
153
|
+
path: path.value,
|
|
154
|
+
searchParams: searchParams.value
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
window.addEventListener("popstate", handlePopState);
|
|
158
|
+
const unsubscribe = subscribe((ctx) => {
|
|
159
|
+
path.value = ctx.path;
|
|
160
|
+
searchParams.value = ctx.searchParams;
|
|
161
|
+
routerState.value = {
|
|
162
|
+
...routerState.value,
|
|
163
|
+
path: ctx.path,
|
|
164
|
+
searchParams: ctx.searchParams
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
onUnmounted2(() => {
|
|
168
|
+
window.removeEventListener("popstate", handlePopState);
|
|
169
|
+
unsubscribe();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return slots.default?.();
|
|
174
|
+
}
|
|
175
|
+
function useRouter() {
|
|
176
|
+
const routerState = inject(RouterKey);
|
|
177
|
+
if (routerState) {
|
|
178
|
+
return routerState.value;
|
|
179
|
+
}
|
|
180
|
+
return getRouterContext();
|
|
181
|
+
}
|
|
182
|
+
function usePathname() {
|
|
183
|
+
const routerState = inject(RouterKey);
|
|
184
|
+
if (routerState) {
|
|
185
|
+
return ref2(routerState.value.path);
|
|
186
|
+
}
|
|
187
|
+
return ref2(isBrowser2 ? window.location.pathname : "/");
|
|
188
|
+
}
|
|
189
|
+
function useSearchParams() {
|
|
190
|
+
const routerState = inject(RouterKey);
|
|
191
|
+
if (routerState) {
|
|
192
|
+
return ref2(routerState.value.searchParams);
|
|
193
|
+
}
|
|
194
|
+
return ref2(isBrowser2 ? new URLSearchParams(window.location.search) : new URLSearchParams());
|
|
195
|
+
}
|
|
196
|
+
function useParams() {
|
|
197
|
+
return ref2({});
|
|
198
|
+
}
|
|
199
|
+
export {
|
|
200
|
+
Link,
|
|
201
|
+
RouterProvider,
|
|
202
|
+
clearPrefetchCache,
|
|
203
|
+
findRoute,
|
|
204
|
+
generatePath,
|
|
205
|
+
getRouterContext,
|
|
206
|
+
initRouter,
|
|
207
|
+
isActive,
|
|
208
|
+
isPrefetched,
|
|
209
|
+
matchRoute,
|
|
210
|
+
navigate,
|
|
211
|
+
observeForPrefetch,
|
|
212
|
+
parseParams,
|
|
213
|
+
prefetch,
|
|
214
|
+
prefetchAll,
|
|
215
|
+
prefetchPages,
|
|
216
|
+
prefetchWhenIdle,
|
|
217
|
+
redirect,
|
|
218
|
+
setupIntentPrefetch,
|
|
219
|
+
subscribe,
|
|
220
|
+
useParams,
|
|
221
|
+
usePathname,
|
|
222
|
+
useRouter,
|
|
223
|
+
useSearchParams
|
|
224
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flight-framework/router",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Agnostic client-side routing primitives for Flight Framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,21 +14,42 @@
|
|
|
14
14
|
"./react": {
|
|
15
15
|
"types": "./dist/react/index.d.ts",
|
|
16
16
|
"import": "./dist/react/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./vue": {
|
|
19
|
+
"types": "./dist/vue/index.d.ts",
|
|
20
|
+
"import": "./dist/vue/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./svelte": {
|
|
23
|
+
"types": "./dist/svelte/index.d.ts",
|
|
24
|
+
"import": "./dist/svelte/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./solid": {
|
|
27
|
+
"types": "./dist/solid/index.d.ts",
|
|
28
|
+
"import": "./dist/solid/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./preact": {
|
|
31
|
+
"types": "./dist/preact/index.d.ts",
|
|
32
|
+
"import": "./dist/preact/index.js"
|
|
17
33
|
}
|
|
18
34
|
},
|
|
19
35
|
"files": [
|
|
20
36
|
"dist"
|
|
21
37
|
],
|
|
22
38
|
"scripts": {
|
|
23
|
-
"build": "tsup src/index.ts src/react/index.ts --format esm --dts --clean",
|
|
24
|
-
"dev": "tsup src/index.ts src/react/index.ts --format esm --dts --watch"
|
|
39
|
+
"build": "tsup src/index.ts src/react/index.ts src/vue/index.ts src/svelte/index.ts src/solid/index.ts src/preact/index.ts --format esm --dts --clean",
|
|
40
|
+
"dev": "tsup src/index.ts src/react/index.ts src/vue/index.ts src/svelte/index.ts src/solid/index.ts src/preact/index.ts --format esm --dts --watch"
|
|
25
41
|
},
|
|
26
42
|
"keywords": [
|
|
27
43
|
"flight",
|
|
28
44
|
"router",
|
|
29
45
|
"spa",
|
|
30
46
|
"navigation",
|
|
31
|
-
"ssr"
|
|
47
|
+
"ssr",
|
|
48
|
+
"react",
|
|
49
|
+
"vue",
|
|
50
|
+
"svelte",
|
|
51
|
+
"solid",
|
|
52
|
+
"preact"
|
|
32
53
|
],
|
|
33
54
|
"author": "Flight Framework",
|
|
34
55
|
"license": "MIT",
|
|
@@ -39,15 +60,34 @@
|
|
|
39
60
|
},
|
|
40
61
|
"devDependencies": {
|
|
41
62
|
"@types/react": "^19.0.0",
|
|
63
|
+
"preact": "^10.19.0",
|
|
64
|
+
"solid-js": "^1.8.0",
|
|
42
65
|
"tsup": "^8.0.0",
|
|
43
|
-
"typescript": "^5.3.0"
|
|
66
|
+
"typescript": "^5.3.0",
|
|
67
|
+
"vue": "^3.4.0"
|
|
44
68
|
},
|
|
45
69
|
"peerDependencies": {
|
|
46
|
-
"
|
|
70
|
+
"preact": ">=10.0.0",
|
|
71
|
+
"react": ">=18.0.0",
|
|
72
|
+
"solid-js": ">=1.0.0",
|
|
73
|
+
"svelte": ">=4.0.0",
|
|
74
|
+
"vue": ">=3.0.0"
|
|
47
75
|
},
|
|
48
76
|
"peerDependenciesMeta": {
|
|
49
77
|
"react": {
|
|
50
78
|
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"vue": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"svelte": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"solid-js": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"preact": {
|
|
90
|
+
"optional": true
|
|
51
91
|
}
|
|
52
92
|
}
|
|
53
93
|
}
|