@tanstack/vue-router 0.0.1 → 1.140.1
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 +66 -45
- package/dist/esm/Asset.d.ts +2 -0
- package/dist/esm/Asset.js +33 -0
- package/dist/esm/Asset.js.map +1 -0
- package/dist/esm/CatchBoundary.d.ts +19 -0
- package/dist/esm/CatchBoundary.js +135 -0
- package/dist/esm/CatchBoundary.js.map +1 -0
- package/dist/esm/ClientOnly.d.ts +67 -0
- package/dist/esm/HeadContent.d.ts +10 -0
- package/dist/esm/HeadContent.js +116 -0
- package/dist/esm/HeadContent.js.map +1 -0
- package/dist/esm/Match.d.ts +25 -0
- package/dist/esm/Match.js +262 -0
- package/dist/esm/Match.js.map +1 -0
- package/dist/esm/Matches.d.ts +39 -0
- package/dist/esm/Matches.js +186 -0
- package/dist/esm/Matches.js.map +1 -0
- package/dist/esm/RouterProvider.d.ts +33 -0
- package/dist/esm/RouterProvider.js +65 -0
- package/dist/esm/RouterProvider.js.map +1 -0
- package/dist/esm/SafeFragment.d.ts +4 -0
- package/dist/esm/ScriptOnce.d.ts +5 -0
- package/dist/esm/ScriptOnce.js +21 -0
- package/dist/esm/ScriptOnce.js.map +1 -0
- package/dist/esm/Scripts.d.ts +1 -0
- package/dist/esm/Scripts.js +46 -0
- package/dist/esm/Scripts.js.map +1 -0
- package/dist/esm/ScrollRestoration.d.ts +14 -0
- package/dist/esm/ScrollRestoration.js +36 -0
- package/dist/esm/ScrollRestoration.js.map +1 -0
- package/dist/esm/Transitioner.d.ts +2 -0
- package/dist/esm/Transitioner.js +154 -0
- package/dist/esm/Transitioner.js.map +1 -0
- package/dist/esm/awaited.d.ts +12 -0
- package/dist/esm/awaited.js +40 -0
- package/dist/esm/awaited.js.map +1 -0
- package/dist/esm/fileRoute.d.ts +54 -0
- package/dist/esm/fileRoute.js +103 -0
- package/dist/esm/fileRoute.js.map +1 -0
- package/dist/esm/history.d.ts +8 -0
- package/dist/esm/index.d.ts +51 -0
- package/dist/esm/index.js +138 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lazyRouteComponent.d.ts +8 -0
- package/dist/esm/lazyRouteComponent.js +106 -0
- package/dist/esm/lazyRouteComponent.js.map +1 -0
- package/dist/esm/link.d.ts +61 -0
- package/dist/esm/link.js +376 -0
- package/dist/esm/link.js.map +1 -0
- package/dist/esm/matchContext.d.ts +20 -0
- package/dist/esm/matchContext.js +16 -0
- package/dist/esm/matchContext.js.map +1 -0
- package/dist/esm/not-found.d.ts +12 -0
- package/dist/esm/not-found.js +45 -0
- package/dist/esm/not-found.js.map +1 -0
- package/dist/esm/renderRouteNotFound.d.ts +11 -0
- package/dist/esm/renderRouteNotFound.js +19 -0
- package/dist/esm/renderRouteNotFound.js.map +1 -0
- package/dist/esm/route.d.ts +96 -0
- package/dist/esm/route.js +176 -0
- package/dist/esm/route.js.map +1 -0
- package/dist/esm/router.d.ts +69 -0
- package/dist/esm/router.js +14 -0
- package/dist/esm/router.js.map +1 -0
- package/dist/esm/routerContext.d.ts +21 -0
- package/dist/esm/routerContext.js +21 -0
- package/dist/esm/routerContext.js.map +1 -0
- package/dist/esm/scroll-restoration.d.ts +1 -0
- package/dist/esm/scroll-restoration.js +21 -0
- package/dist/esm/scroll-restoration.js.map +1 -0
- package/dist/esm/typePrimitives.d.ts +10 -0
- package/dist/esm/useBlocker.d.ts +66 -0
- package/dist/esm/useBlocker.js +295 -0
- package/dist/esm/useBlocker.js.map +1 -0
- package/dist/esm/useCanGoBack.d.ts +1 -0
- package/dist/esm/useCanGoBack.js +8 -0
- package/dist/esm/useCanGoBack.js.map +1 -0
- package/dist/esm/useLoaderData.d.ts +8 -0
- package/dist/esm/useLoaderData.js +14 -0
- package/dist/esm/useLoaderData.js.map +1 -0
- package/dist/esm/useLoaderDeps.d.ts +7 -0
- package/dist/esm/useLoaderDeps.js +17 -0
- package/dist/esm/useLoaderDeps.js.map +1 -0
- package/dist/esm/useLocation.d.ts +7 -0
- package/dist/esm/useLocation.js +10 -0
- package/dist/esm/useLocation.js.map +1 -0
- package/dist/esm/useMatch.d.ts +10 -0
- package/dist/esm/useMatch.js +39 -0
- package/dist/esm/useMatch.js.map +1 -0
- package/dist/esm/useNavigate.d.ts +5 -0
- package/dist/esm/useNavigate.js +29 -0
- package/dist/esm/useNavigate.js.map +1 -0
- package/dist/esm/useParams.d.ts +9 -0
- package/dist/esm/useParams.js +15 -0
- package/dist/esm/useParams.js.map +1 -0
- package/dist/esm/useRouteContext.d.ts +4 -0
- package/dist/esm/useRouteContext.js +11 -0
- package/dist/esm/useRouteContext.js.map +1 -0
- package/dist/esm/useRouter.d.ts +4 -0
- package/dist/esm/useRouter.js +12 -0
- package/dist/esm/useRouter.js.map +1 -0
- package/dist/esm/useRouterState.d.ts +8 -0
- package/dist/esm/useRouterState.js +20 -0
- package/dist/esm/useRouterState.js.map +1 -0
- package/dist/esm/useSearch.d.ts +9 -0
- package/dist/esm/useSearch.js +15 -0
- package/dist/esm/useSearch.js.map +1 -0
- package/dist/esm/utils.d.ts +40 -0
- package/dist/esm/utils.js +44 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/source/Asset.d.ts +2 -0
- package/dist/source/Asset.jsx +22 -0
- package/dist/source/Asset.jsx.map +1 -0
- package/dist/source/CatchBoundary.d.ts +19 -0
- package/dist/source/CatchBoundary.jsx +134 -0
- package/dist/source/CatchBoundary.jsx.map +1 -0
- package/dist/source/ClientOnly.d.ts +67 -0
- package/dist/source/ClientOnly.jsx +63 -0
- package/dist/source/ClientOnly.jsx.map +1 -0
- package/dist/source/HeadContent.d.ts +10 -0
- package/dist/source/HeadContent.jsx +133 -0
- package/dist/source/HeadContent.jsx.map +1 -0
- package/dist/source/Match.d.ts +25 -0
- package/dist/source/Match.jsx +316 -0
- package/dist/source/Match.jsx.map +1 -0
- package/dist/source/Matches.d.ts +39 -0
- package/dist/source/Matches.jsx +191 -0
- package/dist/source/Matches.jsx.map +1 -0
- package/dist/source/RouterProvider.d.ts +33 -0
- package/dist/source/RouterProvider.jsx +63 -0
- package/dist/source/RouterProvider.jsx.map +1 -0
- package/dist/source/SafeFragment.d.ts +4 -0
- package/dist/source/SafeFragment.jsx +10 -0
- package/dist/source/SafeFragment.jsx.map +1 -0
- package/dist/source/ScriptOnce.d.ts +5 -0
- package/dist/source/ScriptOnce.jsx +17 -0
- package/dist/source/ScriptOnce.jsx.map +1 -0
- package/dist/source/Scripts.d.ts +1 -0
- package/dist/source/Scripts.jsx +49 -0
- package/dist/source/Scripts.jsx.map +1 -0
- package/dist/source/ScrollRestoration.d.ts +14 -0
- package/dist/source/ScrollRestoration.jsx +37 -0
- package/dist/source/ScrollRestoration.jsx.map +1 -0
- package/dist/source/Transitioner.d.ts +2 -0
- package/dist/source/Transitioner.jsx +181 -0
- package/dist/source/Transitioner.jsx.map +1 -0
- package/dist/source/awaited.d.ts +12 -0
- package/dist/source/awaited.jsx +38 -0
- package/dist/source/awaited.jsx.map +1 -0
- package/dist/source/fileRoute.d.ts +54 -0
- package/dist/source/fileRoute.js +98 -0
- package/dist/source/fileRoute.js.map +1 -0
- package/dist/source/history.d.ts +8 -0
- package/dist/source/history.js +2 -0
- package/dist/source/history.js.map +1 -0
- package/dist/source/index.d.ts +51 -0
- package/dist/source/index.jsx +40 -0
- package/dist/source/index.jsx.map +1 -0
- package/dist/source/lazyRouteComponent.d.ts +8 -0
- package/dist/source/lazyRouteComponent.jsx +135 -0
- package/dist/source/lazyRouteComponent.jsx.map +1 -0
- package/dist/source/link.d.ts +61 -0
- package/dist/source/link.jsx +495 -0
- package/dist/source/link.jsx.map +1 -0
- package/dist/source/matchContext.d.ts +20 -0
- package/dist/source/matchContext.jsx +32 -0
- package/dist/source/matchContext.jsx.map +1 -0
- package/dist/source/not-found.d.ts +12 -0
- package/dist/source/not-found.jsx +48 -0
- package/dist/source/not-found.jsx.map +1 -0
- package/dist/source/renderRouteNotFound.d.ts +11 -0
- package/dist/source/renderRouteNotFound.jsx +24 -0
- package/dist/source/renderRouteNotFound.jsx.map +1 -0
- package/dist/source/route.d.ts +97 -0
- package/dist/source/route.js +167 -0
- package/dist/source/route.js.map +1 -0
- package/dist/source/router.d.ts +70 -0
- package/dist/source/router.js +10 -0
- package/dist/source/router.js.map +1 -0
- package/dist/source/routerContext.d.ts +21 -0
- package/dist/source/routerContext.jsx +37 -0
- package/dist/source/routerContext.jsx.map +1 -0
- package/dist/source/scroll-restoration.d.ts +1 -0
- package/dist/source/scroll-restoration.jsx +16 -0
- package/dist/source/scroll-restoration.jsx.map +1 -0
- package/dist/source/typePrimitives.d.ts +10 -0
- package/dist/source/typePrimitives.js +2 -0
- package/dist/source/typePrimitives.js.map +1 -0
- package/dist/source/useBlocker.d.ts +66 -0
- package/dist/source/useBlocker.jsx +308 -0
- package/dist/source/useBlocker.jsx.map +1 -0
- package/dist/source/useCanGoBack.d.ts +1 -0
- package/dist/source/useCanGoBack.js +5 -0
- package/dist/source/useCanGoBack.js.map +1 -0
- package/dist/source/useLoaderData.d.ts +8 -0
- package/dist/source/useLoaderData.jsx +11 -0
- package/dist/source/useLoaderData.jsx.map +1 -0
- package/dist/source/useLoaderDeps.d.ts +7 -0
- package/dist/source/useLoaderDeps.jsx +11 -0
- package/dist/source/useLoaderDeps.jsx.map +1 -0
- package/dist/source/useLocation.d.ts +7 -0
- package/dist/source/useLocation.jsx +7 -0
- package/dist/source/useLocation.jsx.map +1 -0
- package/dist/source/useMatch.d.ts +10 -0
- package/dist/source/useMatch.jsx +46 -0
- package/dist/source/useMatch.jsx.map +1 -0
- package/dist/source/useNavigate.d.ts +5 -0
- package/dist/source/useNavigate.jsx +18 -0
- package/dist/source/useNavigate.jsx.map +1 -0
- package/dist/source/useParams.d.ts +9 -0
- package/dist/source/useParams.jsx +12 -0
- package/dist/source/useParams.jsx.map +1 -0
- package/dist/source/useRouteContext.d.ts +4 -0
- package/dist/source/useRouteContext.js +8 -0
- package/dist/source/useRouteContext.js.map +1 -0
- package/dist/source/useRouter.d.ts +4 -0
- package/dist/source/useRouter.jsx +9 -0
- package/dist/source/useRouter.jsx.map +1 -0
- package/dist/source/useRouterState.d.ts +8 -0
- package/dist/source/useRouterState.jsx +19 -0
- package/dist/source/useRouterState.jsx.map +1 -0
- package/dist/source/useSearch.d.ts +9 -0
- package/dist/source/useSearch.jsx +12 -0
- package/dist/source/useSearch.jsx.map +1 -0
- package/dist/source/utils.d.ts +40 -0
- package/dist/source/utils.js +78 -0
- package/dist/source/utils.js.map +1 -0
- package/package.json +77 -7
- package/src/Asset.tsx +23 -0
- package/src/CatchBoundary.tsx +186 -0
- package/src/ClientOnly.tsx +75 -0
- package/src/HeadContent.tsx +159 -0
- package/src/Match.tsx +415 -0
- package/src/Matches.tsx +349 -0
- package/src/RouterProvider.tsx +117 -0
- package/src/SafeFragment.tsx +10 -0
- package/src/ScriptOnce.tsx +30 -0
- package/src/Scripts.tsx +65 -0
- package/src/ScrollRestoration.tsx +69 -0
- package/src/Transitioner.tsx +213 -0
- package/src/awaited.tsx +54 -0
- package/src/fileRoute.ts +271 -0
- package/src/history.ts +9 -0
- package/src/index.tsx +346 -0
- package/src/lazyRouteComponent.tsx +173 -0
- package/src/link.tsx +765 -0
- package/src/matchContext.tsx +41 -0
- package/src/not-found.tsx +55 -0
- package/src/renderRouteNotFound.tsx +35 -0
- package/src/route.ts +658 -0
- package/src/router.ts +103 -0
- package/src/routerContext.tsx +53 -0
- package/src/scroll-restoration.tsx +29 -0
- package/src/typePrimitives.ts +74 -0
- package/src/useBlocker.tsx +501 -0
- package/src/useCanGoBack.ts +5 -0
- package/src/useLoaderData.tsx +50 -0
- package/src/useLoaderDeps.tsx +46 -0
- package/src/useLocation.tsx +30 -0
- package/src/useMatch.tsx +127 -0
- package/src/useNavigate.tsx +40 -0
- package/src/useParams.tsx +71 -0
- package/src/useRouteContext.ts +31 -0
- package/src/useRouter.tsx +15 -0
- package/src/useRouterState.tsx +43 -0
- package/src/useSearch.tsx +71 -0
- package/src/utils.ts +111 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useMatch } from './useMatch';
|
|
2
|
+
export function useSearch(opts) {
|
|
3
|
+
return useMatch({
|
|
4
|
+
from: opts.from,
|
|
5
|
+
strict: opts.strict,
|
|
6
|
+
shouldThrow: opts.shouldThrow,
|
|
7
|
+
select: (match) => {
|
|
8
|
+
return opts.select ? opts.select(match.search) : match.search;
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=useSearch.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSearch.jsx","sourceRoot":"","sources":["../../src/useSearch.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AA6CrC,MAAM,UAAU,SAAS,CAOvB,IAMC;IAID,OAAO,QAAQ,CAAC;QACd,IAAI,EAAE,IAAI,CAAC,IAAK;QAChB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM,EAAE,CAAC,KAAU,EAAE,EAAE;YACrB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAA;QAC/D,CAAC;KACF,CAAQ,CAAA;AACX,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as Vue from 'vue';
|
|
2
|
+
export declare const useLayoutEffect: typeof Vue.effect;
|
|
3
|
+
export declare const usePrevious: (fn: () => boolean) => Vue.ComputedRef<{
|
|
4
|
+
current: boolean | null;
|
|
5
|
+
previous: boolean | null;
|
|
6
|
+
}>;
|
|
7
|
+
/**
|
|
8
|
+
* React hook to wrap `IntersectionObserver`.
|
|
9
|
+
*
|
|
10
|
+
* This hook will create an `IntersectionObserver` and observe the ref passed to it.
|
|
11
|
+
*
|
|
12
|
+
* When the intersection changes, the callback will be called with the `IntersectionObserverEntry`.
|
|
13
|
+
*
|
|
14
|
+
* @param ref - The ref to observe
|
|
15
|
+
* @param intersectionObserverOptions - The options to pass to the IntersectionObserver
|
|
16
|
+
* @param options - The options to pass to the hook
|
|
17
|
+
* @param callback - The callback to call when the intersection changes
|
|
18
|
+
* @returns The IntersectionObserver instance
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const MyComponent = () => {
|
|
22
|
+
* const ref = React.useRef<HTMLDivElement>(null)
|
|
23
|
+
* useIntersectionObserver(
|
|
24
|
+
* ref,
|
|
25
|
+
* (entry) => { doSomething(entry) },
|
|
26
|
+
* { rootMargin: '10px' },
|
|
27
|
+
* { disabled: false }
|
|
28
|
+
* )
|
|
29
|
+
* return <div ref={ref} />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function useIntersectionObserver<T extends Element>(ref: Vue.Ref<T | null>, callback: (entry: IntersectionObserverEntry | undefined) => void, intersectionObserverOptions?: IntersectionObserverInit, options?: {
|
|
33
|
+
disabled?: boolean | (() => boolean);
|
|
34
|
+
}): Vue.Ref<IntersectionObserver | null>;
|
|
35
|
+
export declare function splitProps<T extends Record<string, any>>(props: T, keys: Array<keyof T>): Vue.ComputedRef<{
|
|
36
|
+
[k: string]: unknown;
|
|
37
|
+
}>[];
|
|
38
|
+
export type ParentProps<T = {}> = T & {
|
|
39
|
+
children?: Vue.VNode | Array<Vue.VNode> | string;
|
|
40
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as Vue from 'vue';
|
|
2
|
+
export const useLayoutEffect = typeof window !== 'undefined' ? Vue.effect : Vue.effect;
|
|
3
|
+
export const usePrevious = (fn) => {
|
|
4
|
+
return Vue.computed((prev = {
|
|
5
|
+
current: null,
|
|
6
|
+
previous: null,
|
|
7
|
+
}) => {
|
|
8
|
+
const current = fn();
|
|
9
|
+
if (prev.current !== current) {
|
|
10
|
+
prev.previous = prev.current;
|
|
11
|
+
prev.current = current;
|
|
12
|
+
}
|
|
13
|
+
return prev;
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* React hook to wrap `IntersectionObserver`.
|
|
18
|
+
*
|
|
19
|
+
* This hook will create an `IntersectionObserver` and observe the ref passed to it.
|
|
20
|
+
*
|
|
21
|
+
* When the intersection changes, the callback will be called with the `IntersectionObserverEntry`.
|
|
22
|
+
*
|
|
23
|
+
* @param ref - The ref to observe
|
|
24
|
+
* @param intersectionObserverOptions - The options to pass to the IntersectionObserver
|
|
25
|
+
* @param options - The options to pass to the hook
|
|
26
|
+
* @param callback - The callback to call when the intersection changes
|
|
27
|
+
* @returns The IntersectionObserver instance
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* const MyComponent = () => {
|
|
31
|
+
* const ref = React.useRef<HTMLDivElement>(null)
|
|
32
|
+
* useIntersectionObserver(
|
|
33
|
+
* ref,
|
|
34
|
+
* (entry) => { doSomething(entry) },
|
|
35
|
+
* { rootMargin: '10px' },
|
|
36
|
+
* { disabled: false }
|
|
37
|
+
* )
|
|
38
|
+
* return <div ref={ref} />
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function useIntersectionObserver(ref, callback, intersectionObserverOptions = {}, options = {}) {
|
|
42
|
+
const isIntersectionObserverAvailable = typeof IntersectionObserver === 'function';
|
|
43
|
+
const observerRef = Vue.ref(null);
|
|
44
|
+
// Use watchEffect with cleanup to properly manage the observer lifecycle
|
|
45
|
+
Vue.watchEffect((onCleanup) => {
|
|
46
|
+
const r = ref.value;
|
|
47
|
+
// Support both static boolean and function for disabled check
|
|
48
|
+
const isDisabled = typeof options.disabled === 'function'
|
|
49
|
+
? options.disabled()
|
|
50
|
+
: options.disabled;
|
|
51
|
+
if (!r || !isIntersectionObserverAvailable || isDisabled) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
55
|
+
callback(entry);
|
|
56
|
+
}, intersectionObserverOptions);
|
|
57
|
+
observerRef.value = observer;
|
|
58
|
+
observer.observe(r);
|
|
59
|
+
onCleanup(() => {
|
|
60
|
+
observer.disconnect();
|
|
61
|
+
observerRef.value = null;
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
return observerRef;
|
|
65
|
+
}
|
|
66
|
+
export function splitProps(props, keys) {
|
|
67
|
+
// Get the specified props
|
|
68
|
+
const selectedProps = Vue.computed(() => {
|
|
69
|
+
return Object.fromEntries(keys.map((key) => [key, props[key]]));
|
|
70
|
+
});
|
|
71
|
+
// Get remaining props as attrs
|
|
72
|
+
const remainingAttrs = Vue.computed(() => {
|
|
73
|
+
const attrs = Vue.useAttrs();
|
|
74
|
+
return Object.fromEntries(Object.entries(attrs).filter(([key]) => !keys.includes(key)));
|
|
75
|
+
});
|
|
76
|
+
return [selectedProps, remainingAttrs];
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,80 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/vue-router",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.140.1",
|
|
4
|
+
"description": "Modern and scalable routing for Vue applications",
|
|
5
|
+
"author": "Tanner Linsley",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/TanStack/router.git",
|
|
10
|
+
"directory": "packages/vue-router"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://tanstack.com/router",
|
|
13
|
+
"funding": {
|
|
14
|
+
"type": "github",
|
|
15
|
+
"url": "https://github.com/sponsors/tannerlinsley"
|
|
16
|
+
},
|
|
5
17
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
18
|
+
"vue",
|
|
19
|
+
"location",
|
|
20
|
+
"router",
|
|
21
|
+
"routing",
|
|
22
|
+
"async",
|
|
23
|
+
"async router",
|
|
24
|
+
"typescript"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"types": "dist/esm/index.d.ts",
|
|
28
|
+
"module": "dist/esm/index.js",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/esm/index.d.ts",
|
|
33
|
+
"default": "./dist/esm/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"src"
|
|
42
|
+
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=12"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@tanstack/vue-store": "^0.8.0",
|
|
48
|
+
"jsesc": "^3.0.2",
|
|
49
|
+
"tiny-invariant": "^1.3.3",
|
|
50
|
+
"tiny-warning": "^1.0.3",
|
|
51
|
+
"@tanstack/history": "1.140.0",
|
|
52
|
+
"@tanstack/router-core": "1.140.1"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
56
|
+
"@testing-library/vue": "^8.1.0",
|
|
57
|
+
"@types/jsesc": "^3.0.3",
|
|
58
|
+
"@vitejs/plugin-vue": "^5.2.3",
|
|
59
|
+
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
|
60
|
+
"combinate": "^1.1.11",
|
|
61
|
+
"vue": "^3.5.25",
|
|
62
|
+
"zod": "^3.23.8"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"vue": "^3.3.0"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"clean": "rimraf ./dist && rimraf ./coverage",
|
|
69
|
+
"test": "pnpm run test:unit",
|
|
70
|
+
"test:eslint": "eslint",
|
|
71
|
+
"test:types": "pnpm run test:unit .test-d.ts",
|
|
72
|
+
"test:unit": "vitest",
|
|
73
|
+
"test:unit:ui": "vitest --ui --watch",
|
|
74
|
+
"test:unit:dev": "pnpm run test:unit --watch --hideSkippedTests",
|
|
75
|
+
"test:perf": "vitest bench",
|
|
76
|
+
"test:perf:dev": "pnpm run test:perf --watch --hideSkippedTests",
|
|
77
|
+
"test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
|
|
78
|
+
"build": "vite build && tsc -p tsconfig.build.json"
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/Asset.tsx
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { RouterManagedTag } from '@tanstack/router-core'
|
|
2
|
+
|
|
3
|
+
export function Asset({ tag, attrs, children }: RouterManagedTag): any {
|
|
4
|
+
switch (tag) {
|
|
5
|
+
case 'title':
|
|
6
|
+
return <title {...attrs}>{children}</title>
|
|
7
|
+
case 'meta':
|
|
8
|
+
return <meta {...attrs} />
|
|
9
|
+
case 'link':
|
|
10
|
+
return <link {...attrs} />
|
|
11
|
+
case 'style':
|
|
12
|
+
return <style {...attrs} innerHTML={children} />
|
|
13
|
+
case 'script':
|
|
14
|
+
if ((attrs as any) && (attrs as any).src) {
|
|
15
|
+
return <script {...attrs} />
|
|
16
|
+
}
|
|
17
|
+
if (typeof children === 'string')
|
|
18
|
+
return <script {...attrs} innerHTML={children} />
|
|
19
|
+
return null
|
|
20
|
+
default:
|
|
21
|
+
return null
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import * as Vue from 'vue'
|
|
2
|
+
import type { ErrorRouteComponent } from './route'
|
|
3
|
+
|
|
4
|
+
// Define the error component props interface
|
|
5
|
+
interface ErrorComponentProps {
|
|
6
|
+
error: Error
|
|
7
|
+
reset: () => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Create a Vue error boundary component
|
|
11
|
+
const VueErrorBoundary = Vue.defineComponent({
|
|
12
|
+
name: 'VueErrorBoundary',
|
|
13
|
+
props: {
|
|
14
|
+
onError: Function,
|
|
15
|
+
resetKey: [String, Number],
|
|
16
|
+
},
|
|
17
|
+
emits: ['catch'],
|
|
18
|
+
setup(props, { slots }) {
|
|
19
|
+
const error = Vue.ref<Error | null>(null)
|
|
20
|
+
const resetFn = Vue.ref<(() => void) | null>(null)
|
|
21
|
+
|
|
22
|
+
const reset = () => {
|
|
23
|
+
error.value = null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Watch for changes in the reset key
|
|
27
|
+
Vue.watch(
|
|
28
|
+
() => props.resetKey,
|
|
29
|
+
(newKey, oldKey) => {
|
|
30
|
+
if (newKey !== oldKey && error.value) {
|
|
31
|
+
reset()
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
// Capture errors from child components
|
|
37
|
+
Vue.onErrorCaptured((err: Error) => {
|
|
38
|
+
// If the error is a Promise (thrown for Suspense), don't treat it as an error
|
|
39
|
+
// Just ignore it - Suspense will handle it
|
|
40
|
+
if (
|
|
41
|
+
err instanceof Promise ||
|
|
42
|
+
(err && typeof (err as any).then === 'function')
|
|
43
|
+
) {
|
|
44
|
+
return false // Prevent from propagating as an error, but don't set error state
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
error.value = err
|
|
48
|
+
resetFn.value = reset
|
|
49
|
+
|
|
50
|
+
// Call the onError callback if provided
|
|
51
|
+
if (props.onError) {
|
|
52
|
+
props.onError(err)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Prevent the error from propagating further
|
|
56
|
+
return false
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
// If there's an error, render the fallback
|
|
61
|
+
if (error.value && slots.fallback) {
|
|
62
|
+
return slots.fallback({
|
|
63
|
+
error: error.value,
|
|
64
|
+
reset,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Otherwise render the default slot
|
|
69
|
+
return slots.default && slots.default()
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Main CatchBoundary component
|
|
75
|
+
export function CatchBoundary(props: {
|
|
76
|
+
getResetKey: () => number | string
|
|
77
|
+
children: Vue.VNode
|
|
78
|
+
errorComponent?: ErrorRouteComponent
|
|
79
|
+
onCatch?: (error: Error) => void
|
|
80
|
+
}) {
|
|
81
|
+
// Create a component to use in the template
|
|
82
|
+
const CatchBoundaryWrapper = Vue.defineComponent({
|
|
83
|
+
name: 'CatchBoundaryWrapper',
|
|
84
|
+
inheritAttrs: false,
|
|
85
|
+
setup() {
|
|
86
|
+
const resetKey = Vue.computed(() => props.getResetKey())
|
|
87
|
+
|
|
88
|
+
return () => {
|
|
89
|
+
// Always use our default component as a safe fallback
|
|
90
|
+
const defaultErrorComponent = ErrorComponent
|
|
91
|
+
|
|
92
|
+
return Vue.h(
|
|
93
|
+
VueErrorBoundary,
|
|
94
|
+
{
|
|
95
|
+
resetKey: resetKey.value,
|
|
96
|
+
onError: props.onCatch,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
default: () => props.children,
|
|
100
|
+
fallback: ({ error, reset }: ErrorComponentProps) => {
|
|
101
|
+
// Safely render the error component - either the provided one or the default
|
|
102
|
+
if (props.errorComponent) {
|
|
103
|
+
// Use the provided error component
|
|
104
|
+
return Vue.h(props.errorComponent, { error, reset })
|
|
105
|
+
} else {
|
|
106
|
+
// Use the default error component
|
|
107
|
+
return Vue.h(defaultErrorComponent, { error, reset })
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
return Vue.h(CatchBoundaryWrapper)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Error component
|
|
120
|
+
export const ErrorComponent = Vue.defineComponent({
|
|
121
|
+
name: 'ErrorComponent',
|
|
122
|
+
props: {
|
|
123
|
+
error: Object,
|
|
124
|
+
reset: Function,
|
|
125
|
+
},
|
|
126
|
+
setup(props) {
|
|
127
|
+
const show = Vue.ref(process.env.NODE_ENV !== 'production')
|
|
128
|
+
|
|
129
|
+
const toggleShow = () => {
|
|
130
|
+
show.value = !show.value
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return () =>
|
|
134
|
+
Vue.h('div', { style: { padding: '.5rem', maxWidth: '100%' } }, [
|
|
135
|
+
Vue.h(
|
|
136
|
+
'div',
|
|
137
|
+
{ style: { display: 'flex', alignItems: 'center', gap: '.5rem' } },
|
|
138
|
+
[
|
|
139
|
+
Vue.h(
|
|
140
|
+
'strong',
|
|
141
|
+
{ style: { fontSize: '1rem' } },
|
|
142
|
+
'Something went wrong!',
|
|
143
|
+
),
|
|
144
|
+
Vue.h(
|
|
145
|
+
'button',
|
|
146
|
+
{
|
|
147
|
+
style: {
|
|
148
|
+
appearance: 'none',
|
|
149
|
+
fontSize: '.6em',
|
|
150
|
+
border: '1px solid currentColor',
|
|
151
|
+
padding: '.1rem .2rem',
|
|
152
|
+
fontWeight: 'bold',
|
|
153
|
+
borderRadius: '.25rem',
|
|
154
|
+
},
|
|
155
|
+
onClick: toggleShow,
|
|
156
|
+
},
|
|
157
|
+
show.value ? 'Hide Error' : 'Show Error',
|
|
158
|
+
),
|
|
159
|
+
],
|
|
160
|
+
),
|
|
161
|
+
Vue.h('div', { style: { height: '.25rem' } }),
|
|
162
|
+
show.value
|
|
163
|
+
? Vue.h('div', {}, [
|
|
164
|
+
Vue.h(
|
|
165
|
+
'pre',
|
|
166
|
+
{
|
|
167
|
+
style: {
|
|
168
|
+
fontSize: '.7em',
|
|
169
|
+
border: '1px solid red',
|
|
170
|
+
borderRadius: '.25rem',
|
|
171
|
+
padding: '.3rem',
|
|
172
|
+
color: 'red',
|
|
173
|
+
overflow: 'auto',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
[
|
|
177
|
+
props.error?.message
|
|
178
|
+
? Vue.h('code', {}, props.error.message)
|
|
179
|
+
: null,
|
|
180
|
+
],
|
|
181
|
+
),
|
|
182
|
+
])
|
|
183
|
+
: null,
|
|
184
|
+
])
|
|
185
|
+
},
|
|
186
|
+
})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as Vue from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface ClientOnlyProps {
|
|
4
|
+
/**
|
|
5
|
+
* The children to render when the JS is loaded.
|
|
6
|
+
*/
|
|
7
|
+
children?: Vue.VNode
|
|
8
|
+
/**
|
|
9
|
+
* The fallback component to render if the JS is not yet loaded.
|
|
10
|
+
*/
|
|
11
|
+
fallback?: Vue.VNode
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Render the children only after the JS has loaded client-side. Use an optional
|
|
16
|
+
* fallback component if the JS is not yet loaded.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* Render a Chart component if JS loads, renders a simple FakeChart
|
|
20
|
+
* component server-side or if there is no JS. The FakeChart can have only the
|
|
21
|
+
* UI without the behavior or be a loading spinner or skeleton.
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* return (
|
|
25
|
+
* <ClientOnly fallback={<FakeChart />}>
|
|
26
|
+
* <Chart />
|
|
27
|
+
* </ClientOnly>
|
|
28
|
+
* )
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export const ClientOnly = Vue.defineComponent({
|
|
32
|
+
name: 'ClientOnly',
|
|
33
|
+
props: {
|
|
34
|
+
fallback: {
|
|
35
|
+
type: Object as Vue.PropType<Vue.VNode>,
|
|
36
|
+
default: null,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
setup(props, { slots }) {
|
|
40
|
+
const hydrated = useHydrated()
|
|
41
|
+
return () => {
|
|
42
|
+
if (hydrated.value) {
|
|
43
|
+
return slots.default?.()
|
|
44
|
+
}
|
|
45
|
+
return props.fallback ?? null
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Return a boolean indicating if the JS has been hydrated already.
|
|
52
|
+
* When doing Server-Side Rendering, the result will always be false.
|
|
53
|
+
* When doing Client-Side Rendering, the result will always be false on the
|
|
54
|
+
* first render and true from then on. Even if a new component renders it will
|
|
55
|
+
* always start with true.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* // Disable a button that needs JS to work.
|
|
60
|
+
* const hydrated = useHydrated()
|
|
61
|
+
* return (
|
|
62
|
+
* <button type="button" disabled={!hydrated.value} onClick={doSomethingCustom}>
|
|
63
|
+
* Click me
|
|
64
|
+
* </button>
|
|
65
|
+
* )
|
|
66
|
+
* ```
|
|
67
|
+
* @returns True if the JS has been hydrated already, false otherwise.
|
|
68
|
+
*/
|
|
69
|
+
export function useHydrated(): Vue.Ref<boolean> {
|
|
70
|
+
const hydrated = Vue.ref(false)
|
|
71
|
+
Vue.onMounted(() => {
|
|
72
|
+
hydrated.value = true
|
|
73
|
+
})
|
|
74
|
+
return hydrated
|
|
75
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as Vue from 'vue'
|
|
2
|
+
|
|
3
|
+
import { Asset } from './Asset'
|
|
4
|
+
import { useRouter } from './useRouter'
|
|
5
|
+
import { useRouterState } from './useRouterState'
|
|
6
|
+
import type { RouterManagedTag } from '@tanstack/router-core'
|
|
7
|
+
|
|
8
|
+
export const useTags = () => {
|
|
9
|
+
const router = useRouter()
|
|
10
|
+
|
|
11
|
+
const routeMeta = useRouterState({
|
|
12
|
+
select: (state) => {
|
|
13
|
+
return state.matches.map((match) => match.meta!).filter(Boolean)
|
|
14
|
+
},
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const meta: Vue.Ref<Array<RouterManagedTag>> = Vue.computed(() => {
|
|
18
|
+
const resultMeta: Array<RouterManagedTag> = []
|
|
19
|
+
const metaByAttribute: Record<string, true> = {}
|
|
20
|
+
let title: RouterManagedTag | undefined
|
|
21
|
+
;[...routeMeta.value].reverse().forEach((metas) => {
|
|
22
|
+
;[...metas].reverse().forEach((m) => {
|
|
23
|
+
if (!m) return
|
|
24
|
+
|
|
25
|
+
if (m.title) {
|
|
26
|
+
if (!title) {
|
|
27
|
+
title = {
|
|
28
|
+
tag: 'title',
|
|
29
|
+
children: m.title,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
const attribute = m.name ?? m.property
|
|
34
|
+
if (attribute) {
|
|
35
|
+
if (metaByAttribute[attribute]) {
|
|
36
|
+
return
|
|
37
|
+
} else {
|
|
38
|
+
metaByAttribute[attribute] = true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
resultMeta.push({
|
|
43
|
+
tag: 'meta',
|
|
44
|
+
attrs: {
|
|
45
|
+
...m,
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (title) {
|
|
53
|
+
resultMeta.push(title)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
resultMeta.reverse()
|
|
57
|
+
|
|
58
|
+
return resultMeta
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const links = useRouterState({
|
|
62
|
+
select: (state) =>
|
|
63
|
+
state.matches
|
|
64
|
+
.map((match) => match.links!)
|
|
65
|
+
.filter(Boolean)
|
|
66
|
+
.flat(1)
|
|
67
|
+
.map((link) => ({
|
|
68
|
+
tag: 'link',
|
|
69
|
+
attrs: {
|
|
70
|
+
...link,
|
|
71
|
+
},
|
|
72
|
+
})) as Array<RouterManagedTag>,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const preloadMeta = useRouterState({
|
|
76
|
+
select: (state) => {
|
|
77
|
+
const preloadMeta: Array<RouterManagedTag> = []
|
|
78
|
+
|
|
79
|
+
state.matches
|
|
80
|
+
.map((match) => router.looseRoutesById[match.routeId]!)
|
|
81
|
+
.forEach((route) =>
|
|
82
|
+
router.ssr?.manifest?.routes[route.id]?.preloads
|
|
83
|
+
?.filter(Boolean)
|
|
84
|
+
.forEach((preload) => {
|
|
85
|
+
preloadMeta.push({
|
|
86
|
+
tag: 'link',
|
|
87
|
+
attrs: {
|
|
88
|
+
rel: 'modulepreload',
|
|
89
|
+
href: preload,
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
}),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return preloadMeta
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const headScripts = useRouterState({
|
|
100
|
+
select: (state) =>
|
|
101
|
+
(
|
|
102
|
+
state.matches
|
|
103
|
+
.map((match) => match.headScripts!)
|
|
104
|
+
.flat(1)
|
|
105
|
+
.filter(Boolean) as Array<RouterManagedTag>
|
|
106
|
+
).map(({ children, ...script }) => ({
|
|
107
|
+
tag: 'script',
|
|
108
|
+
attrs: {
|
|
109
|
+
...script,
|
|
110
|
+
},
|
|
111
|
+
children,
|
|
112
|
+
})),
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return () =>
|
|
116
|
+
uniqBy(
|
|
117
|
+
[
|
|
118
|
+
...meta.value,
|
|
119
|
+
...preloadMeta.value,
|
|
120
|
+
...links.value,
|
|
121
|
+
...headScripts.value,
|
|
122
|
+
] as Array<RouterManagedTag>,
|
|
123
|
+
(d) => {
|
|
124
|
+
return JSON.stringify(d)
|
|
125
|
+
},
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
|
|
131
|
+
* It should be rendered in the `<head>` of your document.
|
|
132
|
+
*/
|
|
133
|
+
export const HeadContent = Vue.defineComponent({
|
|
134
|
+
name: 'HeadContent',
|
|
135
|
+
setup() {
|
|
136
|
+
const tags = useTags()
|
|
137
|
+
|
|
138
|
+
return () => {
|
|
139
|
+
return tags().map((tag) =>
|
|
140
|
+
Vue.h(Asset, {
|
|
141
|
+
...tag,
|
|
142
|
+
key: `tsr-meta-${JSON.stringify(tag)}`,
|
|
143
|
+
}),
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
function uniqBy<T>(arr: Array<T>, fn: (item: T) => string) {
|
|
150
|
+
const seen = new Set<string>()
|
|
151
|
+
return arr.filter((item) => {
|
|
152
|
+
const key = fn(item)
|
|
153
|
+
if (seen.has(key)) {
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
seen.add(key)
|
|
157
|
+
return true
|
|
158
|
+
})
|
|
159
|
+
}
|