@flight-framework/router 0.0.7 → 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.
@@ -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.7",
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
- "react": ">=18.0.0"
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
  }