@furystack/shades 12.3.0 → 12.4.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/CHANGELOG.md +53 -0
- package/esm/components/lazy-load.d.ts +2 -0
- package/esm/components/lazy-load.d.ts.map +1 -1
- package/esm/components/lazy-load.js +8 -3
- package/esm/components/lazy-load.js.map +1 -1
- package/esm/components/lazy-load.spec.js +59 -1
- package/esm/components/lazy-load.spec.js.map +1 -1
- package/esm/components/nested-router.d.ts +20 -0
- package/esm/components/nested-router.d.ts.map +1 -1
- package/esm/components/nested-router.js +34 -12
- package/esm/components/nested-router.js.map +1 -1
- package/esm/components/nested-router.spec.js +167 -1
- package/esm/components/nested-router.spec.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/view-transition.d.ts +38 -0
- package/esm/view-transition.d.ts.map +1 -0
- package/esm/view-transition.js +50 -0
- package/esm/view-transition.js.map +1 -0
- package/esm/view-transition.spec.d.ts +2 -0
- package/esm/view-transition.spec.d.ts.map +1 -0
- package/esm/view-transition.spec.js +184 -0
- package/esm/view-transition.spec.js.map +1 -0
- package/package.json +1 -1
- package/src/components/lazy-load.spec.tsx +78 -1
- package/src/components/lazy-load.tsx +10 -3
- package/src/components/nested-router.spec.tsx +249 -0
- package/src/components/nested-router.tsx +57 -12
- package/src/index.ts +1 -0
- package/src/view-transition.spec.ts +218 -0
- package/src/view-transition.ts +66 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [12.4.0] - 2026-03-05
|
|
4
|
+
|
|
5
|
+
### ✨ Features
|
|
6
|
+
|
|
7
|
+
### View Transition API support in NestedRouter
|
|
8
|
+
|
|
9
|
+
The `NestedRouter` component now integrates with the [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API) to animate route changes with browser-native transitions.
|
|
10
|
+
|
|
11
|
+
Enable globally at the router level with a single prop:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<NestedRouter routes={appRoutes} viewTransition />
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or configure transition types for CSS targeting via `:active-view-transition-type()`:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
<NestedRouter routes={appRoutes} viewTransition={{ types: ['slide'] }} />
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Individual routes can opt out or override the router-level config:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
'/about': {
|
|
27
|
+
component: () => <AboutPage />,
|
|
28
|
+
viewTransition: false, // disables transitions for this route
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The feature is a progressive enhancement — non-supporting browsers fall back to instant page changes with zero additional code.
|
|
33
|
+
|
|
34
|
+
### View Transition API support in LazyLoad
|
|
35
|
+
|
|
36
|
+
The `LazyLoad` component now accepts a `viewTransition` prop to animate the swap from loader placeholder to loaded content:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<LazyLoad viewTransition loader={<Skeleton />} component={async () => <MyPage />} />
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Shared `maybeViewTransition()` utility
|
|
43
|
+
|
|
44
|
+
Added and exported a `maybeViewTransition(config, update)` helper that wraps a synchronous DOM update in `document.startViewTransition()` when the API is available and `config` is truthy, falling back to a direct call otherwise. This utility is used internally by `NestedRouter` and `LazyLoad`, and is available for external consumers.
|
|
45
|
+
|
|
46
|
+
### 📚 Documentation
|
|
47
|
+
|
|
48
|
+
- Added JSDoc descriptions for `onVisit` and `onLeave` lifecycle hooks on `NestedRoute`, clarifying their timing relative to view transitions
|
|
49
|
+
|
|
50
|
+
### 🧪 Tests
|
|
51
|
+
|
|
52
|
+
- Added unit tests for `resolveViewTransition()` covering router-level defaults, per-route overrides, type merging, and opt-out behavior
|
|
53
|
+
- Added integration tests verifying `NestedRouter` calls `document.startViewTransition()` when enabled, passes transition types, respects per-route `viewTransition: false`, and falls back gracefully when the API is unavailable
|
|
54
|
+
- Added tests for `LazyLoad` verifying `startViewTransition` is called when `viewTransition` is enabled and skipped when not set
|
|
55
|
+
|
|
3
56
|
## [12.3.0] - 2026-03-04
|
|
4
57
|
|
|
5
58
|
### ✨ Features
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { ViewTransitionConfig } from '../view-transition.js';
|
|
1
2
|
export interface LazyLoadProps {
|
|
2
3
|
loader: JSX.Element;
|
|
3
4
|
error?: (error: unknown, retry: () => Promise<void>) => JSX.Element;
|
|
4
5
|
component: () => Promise<JSX.Element>;
|
|
6
|
+
viewTransition?: boolean | ViewTransitionConfig;
|
|
5
7
|
}
|
|
6
8
|
export declare const LazyLoad: (props: LazyLoadProps & Omit<Partial<HTMLElement>, "style"> & {
|
|
7
9
|
style?: Partial<CSSStyleDeclaration>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-load.d.ts","sourceRoot":"","sources":["../../src/components/lazy-load.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lazy-load.d.ts","sourceRoot":"","sources":["../../src/components/lazy-load.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAGjE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,GAAG,CAAC,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;IACnE,SAAS,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACrC,cAAc,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAA;CAChD;AAED,eAAO,MAAM,QAAQ;;;;gEAwEnB,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Shade } from '../shade.js';
|
|
2
|
+
import { maybeViewTransition } from '../view-transition.js';
|
|
2
3
|
export const LazyLoad = Shade({
|
|
3
4
|
shadowDomName: 'lazy-load',
|
|
4
5
|
render: ({ props, useState, useDisposable }) => {
|
|
@@ -21,8 +22,10 @@ export const LazyLoad = Shade({
|
|
|
21
22
|
factory()
|
|
22
23
|
.then((loaded) => {
|
|
23
24
|
if (tracker.active && tracker.factory === factory) {
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
void maybeViewTransition(props.viewTransition, () => {
|
|
26
|
+
setError(undefined);
|
|
27
|
+
setComponent(loaded);
|
|
28
|
+
});
|
|
26
29
|
}
|
|
27
30
|
})
|
|
28
31
|
.catch((err) => {
|
|
@@ -43,7 +46,9 @@ export const LazyLoad = Shade({
|
|
|
43
46
|
setComponent(undefined);
|
|
44
47
|
const loaded = await factory();
|
|
45
48
|
if (tracker.active && tracker.factory === factory) {
|
|
46
|
-
|
|
49
|
+
void maybeViewTransition(props.viewTransition, () => {
|
|
50
|
+
setComponent(loaded);
|
|
51
|
+
});
|
|
47
52
|
}
|
|
48
53
|
}
|
|
49
54
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-load.js","sourceRoot":"","sources":["../../src/components/lazy-load.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"lazy-load.js","sourceRoot":"","sources":["../../src/components/lazy-load.tsx"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@ describe('Lazy Load', () => {
|
|
|
11
11
|
});
|
|
12
12
|
afterEach(() => {
|
|
13
13
|
document.body.innerHTML = '';
|
|
14
|
+
delete document.startViewTransition;
|
|
14
15
|
});
|
|
15
16
|
it('Shuld display the loader and completed state', async () => {
|
|
16
17
|
await usingAsync(new Injector(), async (injector) => {
|
|
@@ -49,7 +50,7 @@ describe('Lazy Load', () => {
|
|
|
49
50
|
expect(load).toBeCalledTimes(2);
|
|
50
51
|
});
|
|
51
52
|
});
|
|
52
|
-
it('
|
|
53
|
+
it('Should succeed on retry after initial failure', async () => {
|
|
53
54
|
await usingAsync(new Injector(), async (injector) => {
|
|
54
55
|
const rootElement = document.getElementById('root');
|
|
55
56
|
let counter = 0;
|
|
@@ -76,5 +77,62 @@ describe('Lazy Load', () => {
|
|
|
76
77
|
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>success</div></lazy-load></div>');
|
|
77
78
|
});
|
|
78
79
|
});
|
|
80
|
+
it('should call startViewTransition when viewTransition is enabled and component loads', async () => {
|
|
81
|
+
const startViewTransitionSpy = vi.fn((optionsOrCallback) => {
|
|
82
|
+
const update = typeof optionsOrCallback === 'function' ? optionsOrCallback : optionsOrCallback.update;
|
|
83
|
+
update?.();
|
|
84
|
+
return {
|
|
85
|
+
finished: Promise.resolve(),
|
|
86
|
+
ready: Promise.resolve(),
|
|
87
|
+
updateCallbackDone: Promise.resolve(),
|
|
88
|
+
skipTransition: vi.fn(),
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
document.startViewTransition = startViewTransitionSpy;
|
|
92
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
93
|
+
const rootElement = document.getElementById('root');
|
|
94
|
+
initializeShadeRoot({
|
|
95
|
+
injector,
|
|
96
|
+
rootElement,
|
|
97
|
+
jsxElement: (createComponent(LazyLoad, { viewTransition: true, loader: createComponent("div", null, "Loading..."), component: async () => {
|
|
98
|
+
await sleepAsync(50);
|
|
99
|
+
return createComponent("div", null, "Loaded");
|
|
100
|
+
} })),
|
|
101
|
+
});
|
|
102
|
+
await flushUpdates();
|
|
103
|
+
expect(document.body.innerHTML).toContain('Loading...');
|
|
104
|
+
await sleepAsync(100);
|
|
105
|
+
expect(startViewTransitionSpy).toHaveBeenCalledTimes(1);
|
|
106
|
+
expect(document.body.innerHTML).toContain('Loaded');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
it('should not call startViewTransition when viewTransition is not set', async () => {
|
|
110
|
+
const startViewTransitionSpy = vi.fn((optionsOrCallback) => {
|
|
111
|
+
const update = typeof optionsOrCallback === 'function' ? optionsOrCallback : optionsOrCallback.update;
|
|
112
|
+
update?.();
|
|
113
|
+
return {
|
|
114
|
+
finished: Promise.resolve(),
|
|
115
|
+
ready: Promise.resolve(),
|
|
116
|
+
updateCallbackDone: Promise.resolve(),
|
|
117
|
+
skipTransition: vi.fn(),
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
document.startViewTransition = startViewTransitionSpy;
|
|
121
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
122
|
+
const rootElement = document.getElementById('root');
|
|
123
|
+
initializeShadeRoot({
|
|
124
|
+
injector,
|
|
125
|
+
rootElement,
|
|
126
|
+
jsxElement: (createComponent(LazyLoad, { loader: createComponent("div", null, "Loading..."), component: async () => {
|
|
127
|
+
await sleepAsync(50);
|
|
128
|
+
return createComponent("div", null, "Loaded");
|
|
129
|
+
} })),
|
|
130
|
+
});
|
|
131
|
+
await flushUpdates();
|
|
132
|
+
await sleepAsync(100);
|
|
133
|
+
expect(startViewTransitionSpy).not.toHaveBeenCalled();
|
|
134
|
+
expect(document.body.innerHTML).toContain('Loaded');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
79
137
|
});
|
|
80
138
|
//# sourceMappingURL=lazy-load.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-load.spec.js","sourceRoot":"","sources":["../../src/components/lazy-load.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,uBAAuB,CAAA;IACnD,CAAC,CAAC,CAAA;IACF,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"lazy-load.spec.js","sourceRoot":"","sources":["../../src/components/lazy-load.spec.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Injector } from '@furystack/inject';
|
|
2
2
|
import type { MatchOptions, MatchResult } from 'path-to-regexp';
|
|
3
3
|
import type { RenderOptions } from '../models/render-options.js';
|
|
4
|
+
import type { ViewTransitionConfig } from '../view-transition.js';
|
|
4
5
|
/**
|
|
5
6
|
* Options passed to a dynamic title resolver function.
|
|
6
7
|
* @typeParam TMatchResult - The type of matched URL parameters
|
|
@@ -46,13 +47,25 @@ export type NestedRoute<TMatchResult = unknown> = {
|
|
|
46
47
|
outlet?: JSX.Element;
|
|
47
48
|
}) => JSX.Element;
|
|
48
49
|
routingOptions?: MatchOptions;
|
|
50
|
+
/**
|
|
51
|
+
* Called after the route's DOM has been mounted. When view transitions are enabled,
|
|
52
|
+
* this runs after the transition's update callback has completed and the new DOM is in place.
|
|
53
|
+
* Use for imperative side effects like data fetching or focus management — not for visual
|
|
54
|
+
* animations, which are handled by the View Transition API when `viewTransition` is enabled.
|
|
55
|
+
*/
|
|
49
56
|
onVisit?: (options: RenderOptions<unknown> & {
|
|
50
57
|
element: JSX.Element;
|
|
51
58
|
}) => Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Called before the route's DOM is removed (and before the view transition starts, if enabled).
|
|
61
|
+
* Use for cleanup or teardown logic — not for exit animations, which are handled by the
|
|
62
|
+
* View Transition API when `viewTransition` is enabled.
|
|
63
|
+
*/
|
|
52
64
|
onLeave?: (options: RenderOptions<unknown> & {
|
|
53
65
|
element: JSX.Element;
|
|
54
66
|
}) => Promise<void>;
|
|
55
67
|
children?: Record<string, NestedRoute<any>>;
|
|
68
|
+
viewTransition?: boolean | ViewTransitionConfig;
|
|
56
69
|
};
|
|
57
70
|
/**
|
|
58
71
|
* Props for the NestedRouter component.
|
|
@@ -61,6 +74,7 @@ export type NestedRoute<TMatchResult = unknown> = {
|
|
|
61
74
|
export type NestedRouterProps = {
|
|
62
75
|
routes: Record<string, NestedRoute<any>>;
|
|
63
76
|
notFound?: JSX.Element;
|
|
77
|
+
viewTransition?: boolean | ViewTransitionConfig;
|
|
64
78
|
};
|
|
65
79
|
/**
|
|
66
80
|
* A single entry in a match chain, pairing a matched route with its match result.
|
|
@@ -119,6 +133,12 @@ export type RenderMatchChainResult = {
|
|
|
119
133
|
* @returns The fully composed JSX element and per-entry rendered elements
|
|
120
134
|
*/
|
|
121
135
|
export declare const renderMatchChain: (chain: MatchChainEntry[], currentUrl: string) => RenderMatchChainResult;
|
|
136
|
+
/**
|
|
137
|
+
* Resolves the effective view transition config for a navigation by merging
|
|
138
|
+
* the router-level default with the innermost (leaf) route's override.
|
|
139
|
+
* A per-route `false` disables transitions even when the router default is on.
|
|
140
|
+
*/
|
|
141
|
+
export declare const resolveViewTransition: (routerConfig: boolean | ViewTransitionConfig | undefined, newChain: MatchChainEntry[]) => ViewTransitionConfig | false;
|
|
122
142
|
/**
|
|
123
143
|
* A nested router component that supports hierarchical route definitions
|
|
124
144
|
* with parent/child relationships. Parent routes receive an `outlet` prop
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-router.d.ts","sourceRoot":"","sources":["../../src/components/nested-router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"nested-router.d.ts","sourceRoot":"","sources":["../../src/components/nested-router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAKhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAGjE;;;GAGG;AACH,MAAM,MAAM,oBAAoB,CAAC,YAAY,GAAG,OAAO,IAAI;IACzD,KAAK,EAAE,WAAW,CAAC,YAAY,SAAS,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC,CAAA;IACvE,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,eAAe,CAAC,YAAY,GAAG,OAAO;IACrD,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,oBAAoB,CAAC,YAAY,CAAC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;CAC7F;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CAAC,YAAY,GAAG,OAAO,IAAI;IAChD,IAAI,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;IACpC,SAAS,EAAE,CAAC,OAAO,EAAE;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,WAAW,CAAC,YAAY,SAAS,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC,CAAA;QACvE,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;KACrB,KAAK,GAAG,CAAC,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,YAAY,CAAA;IAC7B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG;QAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvF;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG;QAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAA;IAC3C,cAAc,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAA;CAChD,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAA;IACxC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,cAAc,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAA;CAChD,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC3B,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAC3B,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,eAAe,EAAE,GAAG,IAAI,CAAA;IACpC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAA;IAChB,aAAa,EAAE,GAAG,CAAC,OAAO,EAAE,CAAA;CAC7B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,GAC1B,QAAQ,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,EACxC,YAAY,MAAM,KACjB,eAAe,EAAE,GAAG,IAuCtB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,UAAU,eAAe,EAAE,EAAE,UAAU,eAAe,EAAE,KAAG,MAW9F,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAA;IAChB,aAAa,EAAE,GAAG,CAAC,OAAO,EAAE,CAAA;CAC7B,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,eAAe,EAAE,EAAE,YAAY,MAAM,KAAG,sBAe/E,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,cAAc,OAAO,GAAG,oBAAoB,GAAG,SAAS,EACxD,UAAU,eAAe,EAAE,KAC1B,oBAAoB,GAAG,KAazB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;;;;gEA6FvB,CAAA"}
|
|
@@ -4,6 +4,7 @@ import { LocationService } from '../services/location-service.js';
|
|
|
4
4
|
import { RouteMatchService } from '../services/route-match-service.js';
|
|
5
5
|
import { createComponent, setRenderMode } from '../shade-component.js';
|
|
6
6
|
import { Shade } from '../shade.js';
|
|
7
|
+
import { maybeViewTransition } from '../view-transition.js';
|
|
7
8
|
/**
|
|
8
9
|
* Recursively builds a match chain from outermost to innermost matched route.
|
|
9
10
|
*
|
|
@@ -93,6 +94,24 @@ export const renderMatchChain = (chain, currentUrl) => {
|
|
|
93
94
|
}
|
|
94
95
|
return { jsx: outlet, chainElements };
|
|
95
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* Resolves the effective view transition config for a navigation by merging
|
|
99
|
+
* the router-level default with the innermost (leaf) route's override.
|
|
100
|
+
* A per-route `false` disables transitions even when the router default is on.
|
|
101
|
+
*/
|
|
102
|
+
export const resolveViewTransition = (routerConfig, newChain) => {
|
|
103
|
+
if (!routerConfig && routerConfig !== undefined)
|
|
104
|
+
return false;
|
|
105
|
+
const leafRoute = newChain[newChain.length - 1]?.route;
|
|
106
|
+
const routeConfig = leafRoute?.viewTransition;
|
|
107
|
+
if (routeConfig === false)
|
|
108
|
+
return false;
|
|
109
|
+
if (!routerConfig && !routeConfig)
|
|
110
|
+
return false;
|
|
111
|
+
const baseTypes = typeof routerConfig === 'object' ? routerConfig.types : undefined;
|
|
112
|
+
const routeTypes = typeof routeConfig === 'object' ? routeConfig.types : undefined;
|
|
113
|
+
return { types: routeTypes ?? baseTypes };
|
|
114
|
+
};
|
|
96
115
|
/**
|
|
97
116
|
* A nested router component that supports hierarchical route definitions
|
|
98
117
|
* with parent/child relationships. Parent routes receive an `outlet` prop
|
|
@@ -125,7 +144,6 @@ export const NestedRouter = Shade({
|
|
|
125
144
|
lastChainEntries.length !== newChain.length;
|
|
126
145
|
if (hasChanged) {
|
|
127
146
|
const version = ++versionRef.current;
|
|
128
|
-
// Call onLeave for routes that are being left (from divergence point to end of old chain)
|
|
129
147
|
for (let i = lastChainEntries.length - 1; i >= divergeIndex; i--) {
|
|
130
148
|
await lastChainEntries[i].route.onLeave?.({ ...options, element: lastChainElements[i] });
|
|
131
149
|
if (version !== versionRef.current)
|
|
@@ -141,9 +159,12 @@ export const NestedRouter = Shade({
|
|
|
141
159
|
}
|
|
142
160
|
if (version !== versionRef.current)
|
|
143
161
|
return;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
162
|
+
const applyUpdate = () => {
|
|
163
|
+
setState({ matchChain: newChain, jsx: newResult.jsx, chainElements: newResult.chainElements });
|
|
164
|
+
injector.getInstance(RouteMatchService).currentMatchChain.setValue(newChain);
|
|
165
|
+
};
|
|
166
|
+
const vtConfig = resolveViewTransition(options.props.viewTransition, newChain);
|
|
167
|
+
await maybeViewTransition(vtConfig === false ? undefined : vtConfig, applyUpdate);
|
|
147
168
|
for (let i = divergeIndex; i < newChain.length; i++) {
|
|
148
169
|
await newChain[i].route.onVisit?.({ ...options, element: newResult.chainElements[i] });
|
|
149
170
|
if (version !== versionRef.current)
|
|
@@ -153,19 +174,20 @@ export const NestedRouter = Shade({
|
|
|
153
174
|
}
|
|
154
175
|
else if (lastChain !== null) {
|
|
155
176
|
const version = ++versionRef.current;
|
|
156
|
-
// No match found — call onLeave for all active routes and show notFound.
|
|
157
|
-
// The null sentinel prevents re-entering this block on re-render.
|
|
158
177
|
for (let i = (lastChain?.length ?? 0) - 1; i >= 0; i--) {
|
|
159
178
|
await lastChain[i].route.onLeave?.({ ...options, element: lastChainElements[i] });
|
|
160
179
|
if (version !== versionRef.current)
|
|
161
180
|
return;
|
|
162
181
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
182
|
+
const applyNotFound = () => {
|
|
183
|
+
setState({
|
|
184
|
+
matchChain: null,
|
|
185
|
+
jsx: options.props.notFound || createComponent("div", null),
|
|
186
|
+
chainElements: [],
|
|
187
|
+
});
|
|
188
|
+
injector.getInstance(RouteMatchService).currentMatchChain.setValue([]);
|
|
189
|
+
};
|
|
190
|
+
await maybeViewTransition(options.props.viewTransition, applyNotFound);
|
|
169
191
|
}
|
|
170
192
|
}
|
|
171
193
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-router.js","sourceRoot":"","sources":["../../src/components/nested-router.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAA;AAEjE,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAA;AACtE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"nested-router.js","sourceRoot":"","sources":["../../src/components/nested-router.tsx"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { initializeShadeRoot } from '../initialize.js';
|
|
|
5
5
|
import { createComponent } from '../shade-component.js';
|
|
6
6
|
import { flushUpdates } from '../shade.js';
|
|
7
7
|
import { RouteMatchService } from '../services/route-match-service.js';
|
|
8
|
-
import { buildMatchChain, findDivergenceIndex, NestedRouter, renderMatchChain, } from './nested-router.js';
|
|
8
|
+
import { buildMatchChain, findDivergenceIndex, NestedRouter, renderMatchChain, resolveViewTransition, } from './nested-router.js';
|
|
9
9
|
import { NestedRouteLink } from './nested-route-link.js';
|
|
10
10
|
describe('buildMatchChain', () => {
|
|
11
11
|
it('should match a simple leaf route', () => {
|
|
@@ -819,4 +819,170 @@ describe('NestedRouter + RouteMatchService integration', () => {
|
|
|
819
819
|
});
|
|
820
820
|
});
|
|
821
821
|
});
|
|
822
|
+
describe('resolveViewTransition', () => {
|
|
823
|
+
const makeEntry = (viewTransition) => ({
|
|
824
|
+
route: { component: () => createComponent("div", null), viewTransition },
|
|
825
|
+
match: { path: '/', params: {} },
|
|
826
|
+
});
|
|
827
|
+
it('should return false when router config is undefined and route has no override', () => {
|
|
828
|
+
expect(resolveViewTransition(undefined, [makeEntry()])).toBe(false);
|
|
829
|
+
});
|
|
830
|
+
it('should return false when router config is false', () => {
|
|
831
|
+
expect(resolveViewTransition(false, [makeEntry()])).toBe(false);
|
|
832
|
+
});
|
|
833
|
+
it('should return config when router config is true', () => {
|
|
834
|
+
expect(resolveViewTransition(true, [makeEntry()])).toEqual({ types: undefined });
|
|
835
|
+
});
|
|
836
|
+
it('should return false when router is true but leaf route opts out', () => {
|
|
837
|
+
expect(resolveViewTransition(true, [makeEntry(false)])).toBe(false);
|
|
838
|
+
});
|
|
839
|
+
it('should use router-level types when route has no override', () => {
|
|
840
|
+
expect(resolveViewTransition({ types: ['slide'] }, [makeEntry()])).toEqual({ types: ['slide'] });
|
|
841
|
+
});
|
|
842
|
+
it('should prefer route-level types over router-level types', () => {
|
|
843
|
+
expect(resolveViewTransition({ types: ['slide'] }, [makeEntry({ types: ['fade'] })])).toEqual({
|
|
844
|
+
types: ['fade'],
|
|
845
|
+
});
|
|
846
|
+
});
|
|
847
|
+
it('should enable transitions when only the leaf route enables it', () => {
|
|
848
|
+
expect(resolveViewTransition(undefined, [makeEntry(true)])).toEqual({ types: undefined });
|
|
849
|
+
});
|
|
850
|
+
it('should use types from the innermost (leaf) route in a chain', () => {
|
|
851
|
+
const parent = makeEntry({ types: ['parent-type'] });
|
|
852
|
+
const child = makeEntry({ types: ['child-type'] });
|
|
853
|
+
expect(resolveViewTransition(true, [parent, child])).toEqual({ types: ['child-type'] });
|
|
854
|
+
});
|
|
855
|
+
});
|
|
856
|
+
describe('NestedRouter view transitions', () => {
|
|
857
|
+
let startViewTransitionSpy;
|
|
858
|
+
beforeEach(() => {
|
|
859
|
+
document.body.innerHTML = '<div id="root"></div>';
|
|
860
|
+
startViewTransitionSpy = vi.fn((optionsOrCallback) => {
|
|
861
|
+
const update = typeof optionsOrCallback === 'function' ? optionsOrCallback : optionsOrCallback.update;
|
|
862
|
+
update?.();
|
|
863
|
+
return {
|
|
864
|
+
finished: Promise.resolve(),
|
|
865
|
+
ready: Promise.resolve(),
|
|
866
|
+
updateCallbackDone: Promise.resolve(),
|
|
867
|
+
skipTransition: vi.fn(),
|
|
868
|
+
};
|
|
869
|
+
});
|
|
870
|
+
document.startViewTransition = startViewTransitionSpy;
|
|
871
|
+
});
|
|
872
|
+
afterEach(() => {
|
|
873
|
+
document.body.innerHTML = '';
|
|
874
|
+
delete document.startViewTransition;
|
|
875
|
+
});
|
|
876
|
+
it('should call startViewTransition when viewTransition is enabled', async () => {
|
|
877
|
+
history.pushState(null, '', '/');
|
|
878
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
879
|
+
const rootElement = document.getElementById('root');
|
|
880
|
+
initializeShadeRoot({
|
|
881
|
+
injector,
|
|
882
|
+
rootElement,
|
|
883
|
+
jsxElement: (createComponent("div", null,
|
|
884
|
+
createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
|
|
885
|
+
createComponent(NestedRouter, { viewTransition: true, routes: {
|
|
886
|
+
'/about': { component: () => createComponent("div", { id: "content" }, "about") },
|
|
887
|
+
'/': { component: () => createComponent("div", { id: "content" }, "home") },
|
|
888
|
+
} }))),
|
|
889
|
+
});
|
|
890
|
+
await flushUpdates();
|
|
891
|
+
startViewTransitionSpy.mockClear();
|
|
892
|
+
document.getElementById('go-about')?.click();
|
|
893
|
+
await flushUpdates();
|
|
894
|
+
expect(startViewTransitionSpy).toHaveBeenCalledTimes(1);
|
|
895
|
+
expect(document.getElementById('content')?.innerHTML).toBe('about');
|
|
896
|
+
});
|
|
897
|
+
});
|
|
898
|
+
it('should not call startViewTransition when viewTransition is not set', async () => {
|
|
899
|
+
history.pushState(null, '', '/');
|
|
900
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
901
|
+
const rootElement = document.getElementById('root');
|
|
902
|
+
initializeShadeRoot({
|
|
903
|
+
injector,
|
|
904
|
+
rootElement,
|
|
905
|
+
jsxElement: (createComponent("div", null,
|
|
906
|
+
createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
|
|
907
|
+
createComponent(NestedRouter, { routes: {
|
|
908
|
+
'/about': { component: () => createComponent("div", { id: "content" }, "about") },
|
|
909
|
+
'/': { component: () => createComponent("div", { id: "content" }, "home") },
|
|
910
|
+
} }))),
|
|
911
|
+
});
|
|
912
|
+
await flushUpdates();
|
|
913
|
+
startViewTransitionSpy.mockClear();
|
|
914
|
+
document.getElementById('go-about')?.click();
|
|
915
|
+
await flushUpdates();
|
|
916
|
+
expect(startViewTransitionSpy).not.toHaveBeenCalled();
|
|
917
|
+
expect(document.getElementById('content')?.innerHTML).toBe('about');
|
|
918
|
+
});
|
|
919
|
+
});
|
|
920
|
+
it('should pass types to startViewTransition when configured', async () => {
|
|
921
|
+
history.pushState(null, '', '/');
|
|
922
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
923
|
+
const rootElement = document.getElementById('root');
|
|
924
|
+
initializeShadeRoot({
|
|
925
|
+
injector,
|
|
926
|
+
rootElement,
|
|
927
|
+
jsxElement: (createComponent("div", null,
|
|
928
|
+
createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
|
|
929
|
+
createComponent(NestedRouter, { viewTransition: { types: ['slide'] }, routes: {
|
|
930
|
+
'/about': { component: () => createComponent("div", { id: "content" }, "about") },
|
|
931
|
+
'/': { component: () => createComponent("div", { id: "content" }, "home") },
|
|
932
|
+
} }))),
|
|
933
|
+
});
|
|
934
|
+
await flushUpdates();
|
|
935
|
+
startViewTransitionSpy.mockClear();
|
|
936
|
+
document.getElementById('go-about')?.click();
|
|
937
|
+
await flushUpdates();
|
|
938
|
+
expect(startViewTransitionSpy).toHaveBeenCalledWith(expect.objectContaining({ types: ['slide'] }));
|
|
939
|
+
});
|
|
940
|
+
});
|
|
941
|
+
it('should respect per-route viewTransition: false override', async () => {
|
|
942
|
+
history.pushState(null, '', '/');
|
|
943
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
944
|
+
const rootElement = document.getElementById('root');
|
|
945
|
+
initializeShadeRoot({
|
|
946
|
+
injector,
|
|
947
|
+
rootElement,
|
|
948
|
+
jsxElement: (createComponent("div", null,
|
|
949
|
+
createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
|
|
950
|
+
createComponent(NestedRouter, { viewTransition: true, routes: {
|
|
951
|
+
'/about': {
|
|
952
|
+
component: () => createComponent("div", { id: "content" }, "about"),
|
|
953
|
+
viewTransition: false,
|
|
954
|
+
},
|
|
955
|
+
'/': { component: () => createComponent("div", { id: "content" }, "home") },
|
|
956
|
+
} }))),
|
|
957
|
+
});
|
|
958
|
+
await flushUpdates();
|
|
959
|
+
startViewTransitionSpy.mockClear();
|
|
960
|
+
document.getElementById('go-about')?.click();
|
|
961
|
+
await flushUpdates();
|
|
962
|
+
expect(startViewTransitionSpy).not.toHaveBeenCalled();
|
|
963
|
+
expect(document.getElementById('content')?.innerHTML).toBe('about');
|
|
964
|
+
});
|
|
965
|
+
});
|
|
966
|
+
it('should fall back gracefully when startViewTransition is not available', async () => {
|
|
967
|
+
delete document.startViewTransition;
|
|
968
|
+
history.pushState(null, '', '/');
|
|
969
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
970
|
+
const rootElement = document.getElementById('root');
|
|
971
|
+
initializeShadeRoot({
|
|
972
|
+
injector,
|
|
973
|
+
rootElement,
|
|
974
|
+
jsxElement: (createComponent("div", null,
|
|
975
|
+
createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
|
|
976
|
+
createComponent(NestedRouter, { viewTransition: true, routes: {
|
|
977
|
+
'/about': { component: () => createComponent("div", { id: "content" }, "about") },
|
|
978
|
+
'/': { component: () => createComponent("div", { id: "content" }, "home") },
|
|
979
|
+
} }))),
|
|
980
|
+
});
|
|
981
|
+
await flushUpdates();
|
|
982
|
+
document.getElementById('go-about')?.click();
|
|
983
|
+
await flushUpdates();
|
|
984
|
+
expect(document.getElementById('content')?.innerHTML).toBe('about');
|
|
985
|
+
});
|
|
986
|
+
});
|
|
987
|
+
});
|
|
822
988
|
//# sourceMappingURL=nested-router.spec.js.map
|