@ssgoi/svelte 7.4.1 → 7.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -7
- package/dist/context.d.ts +26 -1
- package/dist/context.js +56 -5
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/{ssgoi-transition.svelte → legacy/ssgoi-transition.svelte} +6 -5
- package/dist/{ssgoi-transition.svelte.d.ts → legacy/ssgoi-transition.svelte.d.ts} +2 -4
- package/dist/{routers → legacy}/sveltekit/index.d.ts +4 -1
- package/dist/legacy/sveltekit/index.js +6 -0
- package/dist/legacy/sveltekit/ssgoi-route-boundary.svelte +34 -0
- package/dist/{routers → legacy}/sveltekit/ssgoi-route-boundary.svelte.d.ts +4 -1
- package/dist/{routers → legacy}/sveltekit/types.d.ts +3 -1
- package/dist/{routers/sveltekit/ssgoi-route-boundary.svelte → ssgoi-layout-boundary.svelte} +9 -22
- package/dist/ssgoi-layout-boundary.svelte.d.ts +5 -0
- package/dist/ssgoi.svelte +6 -2
- package/dist/ssgoi.svelte.d.ts +3 -0
- package/dist/types.d.ts +29 -0
- package/package.json +5 -5
- package/dist/routers/sveltekit/index.js +0 -2
- /package/dist/{routers → legacy}/sveltekit/types.js +0 -0
package/README.md
CHANGED
|
@@ -12,14 +12,13 @@ npm install @ssgoi/svelte
|
|
|
12
12
|
|
|
13
13
|
Agent setup guide: https://ssgoi.dev/llms/svelte.txt
|
|
14
14
|
|
|
15
|
-
## Router
|
|
15
|
+
## Router wiring
|
|
16
16
|
|
|
17
|
-
Install this framework package once
|
|
18
|
-
|
|
17
|
+
Install this framework package once. The root entry never imports a router:
|
|
18
|
+
pass the router members SSGOI needs through `<Ssgoi framework>`.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
| SvelteKit | `@ssgoi/svelte/sveltekit` | `SsgoiRouteBoundary` |
|
|
20
|
+
The `@ssgoi/svelte/sveltekit` subpath (`SsgoiRouteBoundary`) is deprecated.
|
|
21
|
+
Use `SsgoiLayoutBoundary` from `@ssgoi/svelte` with `framework` instead.
|
|
23
22
|
|
|
24
23
|
See the [framework guide](https://ssgoi.dev/docs/frameworks/svelte) for wiring and limits.
|
|
25
24
|
|
|
@@ -28,6 +27,8 @@ See the [framework guide](https://ssgoi.dev/docs/frameworks/svelte) for wiring a
|
|
|
28
27
|
```svelte
|
|
29
28
|
<!-- src/routes/+layout.svelte -->
|
|
30
29
|
<script lang="ts">
|
|
30
|
+
import { onNavigate } from "$app/navigation";
|
|
31
|
+
import { page } from "$app/state";
|
|
31
32
|
import { Ssgoi } from "@ssgoi/svelte";
|
|
32
33
|
import { drill } from "@ssgoi/svelte/view-transitions";
|
|
33
34
|
|
|
@@ -39,7 +40,13 @@ See the [framework guide](https://ssgoi.dev/docs/frameworks/svelte) for wiring a
|
|
|
39
40
|
</script>
|
|
40
41
|
|
|
41
42
|
<main class="ssgoi-shell">
|
|
42
|
-
<Ssgoi
|
|
43
|
+
<Ssgoi
|
|
44
|
+
{config}
|
|
45
|
+
framework={{
|
|
46
|
+
getRoute: () => ({ pathname: page.url.pathname }),
|
|
47
|
+
onNavigate,
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
43
50
|
{@render children()}
|
|
44
51
|
</Ssgoi>
|
|
45
52
|
</main>
|
|
@@ -54,6 +61,26 @@ See the [framework guide](https://ssgoi.dev/docs/frameworks/svelte) for wiring a
|
|
|
54
61
|
}
|
|
55
62
|
```
|
|
56
63
|
|
|
64
|
+
SvelteKit before 2.12 has no `$app/state`; read the store instead:
|
|
65
|
+
|
|
66
|
+
```svelte
|
|
67
|
+
<script lang="ts">
|
|
68
|
+
import { get } from "svelte/store";
|
|
69
|
+
import { onNavigate } from "$app/navigation";
|
|
70
|
+
import { page } from "$app/stores";
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<Ssgoi
|
|
74
|
+
{config}
|
|
75
|
+
framework={{
|
|
76
|
+
getRoute: () => ({ pathname: get(page).url.pathname }),
|
|
77
|
+
onNavigate,
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
{@render children()}
|
|
81
|
+
</Ssgoi>
|
|
82
|
+
```
|
|
83
|
+
|
|
57
84
|
## Route boundary
|
|
58
85
|
|
|
59
86
|
Mark each route root:
|
|
@@ -84,6 +111,59 @@ inner boundaries:
|
|
|
84
111
|
SvelteKit keeps the layout DOM during child navigation. Leaving the layout
|
|
85
112
|
uses the outer boundary; changing a child route uses the child boundary.
|
|
86
113
|
|
|
114
|
+
`SsgoiLayoutBoundary` does this for you. Declare the layout tree once in
|
|
115
|
+
`config.layouts`, and put a prop-less boundary in each layout:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const TOP_LEVEL = ["/home", "/search", "/profile"];
|
|
119
|
+
|
|
120
|
+
const config = {
|
|
121
|
+
transitions: [
|
|
122
|
+
/* ... */
|
|
123
|
+
],
|
|
124
|
+
layouts: [
|
|
125
|
+
{ paths: TOP_LEVEL },
|
|
126
|
+
{
|
|
127
|
+
paths: "/**",
|
|
128
|
+
except: TOP_LEVEL,
|
|
129
|
+
layouts: [{ paths: "/products/:category/**" }],
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```svelte
|
|
136
|
+
<!-- src/routes/+layout.svelte, inside <Ssgoi>: depth 0 -->
|
|
137
|
+
<SsgoiLayoutBoundary>
|
|
138
|
+
{@render children()}
|
|
139
|
+
</SsgoiLayoutBoundary>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```svelte
|
|
143
|
+
<!-- src/routes/(top-level)/+layout.svelte: depth 1 -->
|
|
144
|
+
<script lang="ts">
|
|
145
|
+
import { SsgoiLayoutBoundary } from "@ssgoi/svelte";
|
|
146
|
+
|
|
147
|
+
let { children } = $props();
|
|
148
|
+
</script>
|
|
149
|
+
|
|
150
|
+
<SsgoiLayoutBoundary as="section">
|
|
151
|
+
{@render children()}
|
|
152
|
+
</SsgoiLayoutBoundary>
|
|
153
|
+
<BottomNav />
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Here top-level tabs swap only the depth-1 content, while opening a detail page
|
|
157
|
+
moves the whole depth-0 boundary, bottom nav included. A boundary's depth is the
|
|
158
|
+
number of boundaries around it. At depth N it stays mounted while navigation
|
|
159
|
+
stays inside the same depth-N scope, and remounts (keeping the outgoing DOM
|
|
160
|
+
intact for the transition) when the scope changes. Siblings take the first scope
|
|
161
|
+
that matches, `except` excludes paths, and single-segment captures (`*`, `:id`,
|
|
162
|
+
`[id]`) are part of a scope instance, so `/products/shoes/1` and
|
|
163
|
+
`/products/shoes/2` share one while `/products/bags` does not. Below the
|
|
164
|
+
declared tree, or without `layouts`, a boundary remounts on every pathname
|
|
165
|
+
change. Its `data-ssgoi-transition` id is always the pathname.
|
|
166
|
+
|
|
87
167
|
Use a keyed block only when the router reuses the same DOM node and a new
|
|
88
168
|
boundary must be forced:
|
|
89
169
|
|
package/dist/context.d.ts
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
import { type Readable } from "svelte/store";
|
|
2
|
-
import type { SsgoiContext, SsgoiTransitionState } from "./types.js";
|
|
2
|
+
import type { SsgoiConfig, SsgoiContext, SsgoiFramework, SsgoiTransitionState } from "./types.js";
|
|
3
3
|
export declare function setSsgoiContext(context: SsgoiContext): void;
|
|
4
4
|
export declare function getSsgoiContext(): SsgoiContext;
|
|
5
|
+
type LayoutBoundaryState = {
|
|
6
|
+
id: string;
|
|
7
|
+
key: string | number;
|
|
8
|
+
};
|
|
9
|
+
type BoundaryAt = (depth: number) => LayoutBoundaryState;
|
|
10
|
+
/** Where a layout boundary reads its current and next `{ id, key }`. */
|
|
11
|
+
export interface LayoutRoutes {
|
|
12
|
+
current: BoundaryAt;
|
|
13
|
+
/** Registers for the calling component's lifetime. */
|
|
14
|
+
onNavigate: (listener: (next: BoundaryAt) => void | (() => void)) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolves routes once for every boundary under the provider: the id is the
|
|
18
|
+
* pathname and a depth-N boundary keys by the depth-N `layouts` scope, falling
|
|
19
|
+
* back to the pathname.
|
|
20
|
+
*/
|
|
21
|
+
export declare function setSsgoiLayoutRoutes(framework: SsgoiFramework | undefined, layouts: SsgoiConfig["layouts"]): void;
|
|
22
|
+
/** Routes for the next layout boundary only; its descendants use the provider's. */
|
|
23
|
+
export declare function setSsgoiLayoutOverride(routes: LayoutRoutes): void;
|
|
24
|
+
/** Reads a layout boundary's routes and depth, and nests its descendants. */
|
|
25
|
+
export declare function enterSsgoiLayoutBoundary(): {
|
|
26
|
+
routes: LayoutRoutes;
|
|
27
|
+
depth: number;
|
|
28
|
+
};
|
|
5
29
|
/**
|
|
6
30
|
* Store of the provider's transition lifecycle: whether a page transition is
|
|
7
31
|
* preparing or playing, and which routes it joins.
|
|
@@ -12,3 +36,4 @@ export declare function getSsgoiContext(): SsgoiContext;
|
|
|
12
36
|
* Must be called during component initialisation, under `<Ssgoi>`.
|
|
13
37
|
*/
|
|
14
38
|
export declare function getSsgoiTransition(): Readable<SsgoiTransitionState>;
|
|
39
|
+
export {};
|
package/dist/context.js
CHANGED
|
@@ -1,16 +1,67 @@
|
|
|
1
|
-
import { getContext, setContext } from "svelte";
|
|
1
|
+
import { getContext, onDestroy, setContext } from "svelte";
|
|
2
2
|
import { readable } from "svelte/store";
|
|
3
|
-
|
|
3
|
+
import { resolveLayoutChain } from "@ssgoi/core/internal";
|
|
4
|
+
const SSGOI_CONTEXT_KEY = Symbol("ssgoi");
|
|
5
|
+
const SSGOI_LAYOUT_ROUTES_KEY = Symbol("ssgoi-layout-routes");
|
|
6
|
+
const SSGOI_LAYOUT_OVERRIDE_KEY = Symbol("ssgoi-layout-override");
|
|
7
|
+
const SSGOI_LAYOUT_DEPTH_KEY = Symbol("ssgoi-layout-depth");
|
|
4
8
|
export function setSsgoiContext(context) {
|
|
5
9
|
setContext(SSGOI_CONTEXT_KEY, context);
|
|
6
10
|
}
|
|
7
11
|
export function getSsgoiContext() {
|
|
8
|
-
|
|
12
|
+
const context = getContext(SSGOI_CONTEXT_KEY);
|
|
9
13
|
if (!context) {
|
|
10
14
|
throw new Error("getSsgoiContext must be called within Ssgoi component");
|
|
11
15
|
}
|
|
12
16
|
return context;
|
|
13
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves routes once for every boundary under the provider: the id is the
|
|
20
|
+
* pathname and a depth-N boundary keys by the depth-N `layouts` scope, falling
|
|
21
|
+
* back to the pathname.
|
|
22
|
+
*/
|
|
23
|
+
export function setSsgoiLayoutRoutes(framework, layouts) {
|
|
24
|
+
if (!framework)
|
|
25
|
+
return;
|
|
26
|
+
const boundaryAt = (path) => {
|
|
27
|
+
const chain = resolveLayoutChain(layouts, path);
|
|
28
|
+
return (depth) => ({ id: path, key: chain[depth] ?? path });
|
|
29
|
+
};
|
|
30
|
+
const listeners = new Set();
|
|
31
|
+
framework.onNavigate((navigation) => {
|
|
32
|
+
if (!navigation.to)
|
|
33
|
+
return;
|
|
34
|
+
const next = boundaryAt(navigation.to.url.pathname);
|
|
35
|
+
const finish = Array.from(listeners, (listener) => listener(next));
|
|
36
|
+
return () => {
|
|
37
|
+
for (const callback of finish)
|
|
38
|
+
callback?.();
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
setContext(SSGOI_LAYOUT_ROUTES_KEY, {
|
|
42
|
+
current: (depth) => boundaryAt(framework.getRoute().pathname)(depth),
|
|
43
|
+
onNavigate: (listener) => {
|
|
44
|
+
listeners.add(listener);
|
|
45
|
+
onDestroy(() => listeners.delete(listener));
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** Routes for the next layout boundary only; its descendants use the provider's. */
|
|
50
|
+
export function setSsgoiLayoutOverride(routes) {
|
|
51
|
+
setContext(SSGOI_LAYOUT_OVERRIDE_KEY, routes);
|
|
52
|
+
}
|
|
53
|
+
/** Reads a layout boundary's routes and depth, and nests its descendants. */
|
|
54
|
+
export function enterSsgoiLayoutBoundary() {
|
|
55
|
+
const routes = getContext(SSGOI_LAYOUT_OVERRIDE_KEY) ??
|
|
56
|
+
getContext(SSGOI_LAYOUT_ROUTES_KEY);
|
|
57
|
+
if (!routes) {
|
|
58
|
+
throw new Error("SSGOI: SsgoiLayoutBoundary requires a framework. Pass it to <Ssgoi framework={{ getRoute: () => ({ pathname: page.url.pathname }), onNavigate }}>.");
|
|
59
|
+
}
|
|
60
|
+
const depth = getContext(SSGOI_LAYOUT_DEPTH_KEY) ?? 0;
|
|
61
|
+
setContext(SSGOI_LAYOUT_OVERRIDE_KEY, undefined);
|
|
62
|
+
setContext(SSGOI_LAYOUT_DEPTH_KEY, depth + 1);
|
|
63
|
+
return { routes, depth };
|
|
64
|
+
}
|
|
14
65
|
/**
|
|
15
66
|
* Store of the provider's transition lifecycle: whether a page transition is
|
|
16
67
|
* preparing or playing, and which routes it joins.
|
|
@@ -21,11 +72,11 @@ export function getSsgoiContext() {
|
|
|
21
72
|
* Must be called during component initialisation, under `<Ssgoi>`.
|
|
22
73
|
*/
|
|
23
74
|
export function getSsgoiTransition() {
|
|
24
|
-
|
|
75
|
+
const context = getContext(SSGOI_CONTEXT_KEY);
|
|
25
76
|
if (!context) {
|
|
26
77
|
throw new Error("getSsgoiTransition must be called within Ssgoi component");
|
|
27
78
|
}
|
|
28
|
-
return readable(context.getTransitionState(),
|
|
79
|
+
return readable(context.getTransitionState(), (set) => {
|
|
29
80
|
set(context.getTransitionState());
|
|
30
81
|
return context.subscribe(set);
|
|
31
82
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as Ssgoi } from "./ssgoi.svelte";
|
|
2
|
+
export { default as SsgoiLayoutBoundary } from "./ssgoi-layout-boundary.svelte";
|
|
2
3
|
export { getSsgoiTransition } from "./context.js";
|
|
3
|
-
/** @deprecated
|
|
4
|
-
export { default as SsgoiTransition } from "./ssgoi-transition.svelte";
|
|
4
|
+
/** @deprecated Will be removed in 8.0.0. */
|
|
5
|
+
export { default as SsgoiTransition } from "./legacy/ssgoi-transition.svelte";
|
|
5
6
|
export * from "./types.js";
|
|
6
7
|
export * from "@ssgoi/core";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as Ssgoi } from "./ssgoi.svelte";
|
|
2
|
+
export { default as SsgoiLayoutBoundary } from "./ssgoi-layout-boundary.svelte";
|
|
2
3
|
export { getSsgoiTransition } from "./context.js";
|
|
3
|
-
/** @deprecated
|
|
4
|
-
export { default as SsgoiTransition } from "./ssgoi-transition.svelte";
|
|
4
|
+
/** @deprecated Will be removed in 8.0.0. */
|
|
5
|
+
export { default as SsgoiTransition } from "./legacy/ssgoi-transition.svelte";
|
|
5
6
|
export * from "./types.js";
|
|
6
7
|
export * from "@ssgoi/core";
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
<!-- TODO(8.0.0): remove this entry (deprecated in 7.5.0). -->
|
|
2
|
+
<!-- @component
|
|
3
|
+
@deprecated Will be removed in 8.0.0.
|
|
4
|
+
-->
|
|
1
5
|
<script lang="ts">
|
|
2
6
|
import type { Snippet } from "svelte";
|
|
3
|
-
import { getSsgoiContext } from "
|
|
7
|
+
import { getSsgoiContext } from "../context";
|
|
4
8
|
|
|
5
|
-
/**
|
|
6
|
-
* @deprecated Set `data-ssgoi-transition` directly on the page boundary
|
|
7
|
-
* element inside `<Ssgoi>` instead.
|
|
8
|
-
*/
|
|
9
|
+
/** @deprecated Will be removed in 8.0.0. */
|
|
9
10
|
interface Props {
|
|
10
11
|
id: string;
|
|
11
12
|
children: Snippet;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
|
-
/**
|
|
3
|
-
* @deprecated Set `data-ssgoi-transition` directly on the page boundary
|
|
4
|
-
* element inside `<Ssgoi>` instead.
|
|
5
|
-
*/
|
|
2
|
+
/** @deprecated Will be removed in 8.0.0. */
|
|
6
3
|
interface Props {
|
|
7
4
|
id: string;
|
|
8
5
|
children: Snippet;
|
|
@@ -10,6 +7,7 @@ interface Props {
|
|
|
10
7
|
class?: string;
|
|
11
8
|
[key: string]: unknown;
|
|
12
9
|
}
|
|
10
|
+
/** @deprecated Will be removed in 8.0.0. */
|
|
13
11
|
declare const SsgoiTransition: import("svelte").Component<Props, {}, "">;
|
|
14
12
|
type SsgoiTransition = ReturnType<typeof SsgoiTransition>;
|
|
15
13
|
export default SsgoiTransition;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* @experimental SvelteKit route boundary.
|
|
3
|
+
* @deprecated Will be removed in 8.0.0. Use `SsgoiLayoutBoundary` from "@ssgoi/svelte" with `<Ssgoi framework={...}>` instead.
|
|
4
|
+
*/
|
|
2
5
|
export { default as SsgoiRouteBoundary } from "./ssgoi-route-boundary.svelte";
|
|
3
6
|
export type { RouteBoundaryState, SveltekitRouteLocation, SsgoiRouteBoundaryProps, } from "./types.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// TODO(8.0.0): remove this entry (deprecated in 7.5.0).
|
|
2
|
+
/**
|
|
3
|
+
* @experimental SvelteKit route boundary.
|
|
4
|
+
* @deprecated Will be removed in 8.0.0. Use `SsgoiLayoutBoundary` from "@ssgoi/svelte" with `<Ssgoi framework={...}>` instead.
|
|
5
|
+
*/
|
|
6
|
+
export { default as SsgoiRouteBoundary } from "./ssgoi-route-boundary.svelte";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!-- TODO(8.0.0): remove this entry (deprecated in 7.5.0). -->
|
|
2
|
+
<!-- @component
|
|
3
|
+
@deprecated Will be removed in 8.0.0. Use `SsgoiLayoutBoundary` from "@ssgoi/svelte" with
|
|
4
|
+
`<Ssgoi framework={...}>` instead.
|
|
5
|
+
-->
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import { onNavigate } from "$app/navigation";
|
|
8
|
+
// Stores work throughout SvelteKit 2, including releases before $app/state.
|
|
9
|
+
import { page } from "$app/stores";
|
|
10
|
+
import { setSsgoiLayoutOverride } from "../../context.js";
|
|
11
|
+
import SsgoiLayoutBoundary from "../../ssgoi-layout-boundary.svelte";
|
|
12
|
+
import type { SsgoiRouteBoundaryProps } from "./types.js";
|
|
13
|
+
|
|
14
|
+
let { resolve, routeKey, ...props }: SsgoiRouteBoundaryProps = $props();
|
|
15
|
+
|
|
16
|
+
const getBoundary = (url: URL) => {
|
|
17
|
+
const boundary = resolve?.({ pathname: url.pathname, url }) ?? {
|
|
18
|
+
id: url.pathname,
|
|
19
|
+
};
|
|
20
|
+
return { id: boundary.id, key: routeKey ?? boundary.key ?? boundary.id };
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
setSsgoiLayoutOverride({
|
|
24
|
+
current: () => getBoundary($page.url),
|
|
25
|
+
onNavigate: (listener) =>
|
|
26
|
+
onNavigate((navigation) => {
|
|
27
|
+
if (!navigation.to) return;
|
|
28
|
+
const { url } = navigation.to;
|
|
29
|
+
return listener(() => getBoundary(url));
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<SsgoiLayoutBoundary {...props} />
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { SsgoiRouteBoundaryProps } from "./types.js";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Will be removed in 8.0.0. Use `SsgoiLayoutBoundary` from "@ssgoi/svelte" with
|
|
4
|
+
* `<Ssgoi framework={...}>` instead.
|
|
5
|
+
*/
|
|
3
6
|
declare const SsgoiRouteBoundary: import("svelte").Component<SsgoiRouteBoundaryProps, {}, "">;
|
|
4
7
|
type SsgoiRouteBoundary = ReturnType<typeof SsgoiRouteBoundary>;
|
|
5
8
|
export default SsgoiRouteBoundary;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
2
|
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
/** @deprecated Will be removed in 8.0.0. Use `SsgoiLayoutBoundary` from "@ssgoi/svelte" with `<Ssgoi framework={...}>` instead. */
|
|
3
4
|
export interface RouteBoundaryState {
|
|
4
5
|
id: string;
|
|
5
6
|
key?: string | number;
|
|
6
7
|
}
|
|
8
|
+
/** @deprecated Will be removed in 8.0.0. Use `SsgoiLayoutBoundary` from "@ssgoi/svelte" with `<Ssgoi framework={...}>` instead. */
|
|
7
9
|
export interface SveltekitRouteLocation {
|
|
8
10
|
pathname: string;
|
|
9
11
|
url: URL;
|
|
10
12
|
}
|
|
11
|
-
/** @
|
|
13
|
+
/** @deprecated Will be removed in 8.0.0. Use `SsgoiLayoutBoundaryProps` from "@ssgoi/svelte" with `<Ssgoi framework={...}>` instead. */
|
|
12
14
|
export interface SsgoiRouteBoundaryProps extends HTMLAttributes<HTMLElement> {
|
|
13
15
|
children: Snippet;
|
|
14
16
|
as?: keyof HTMLElementTagNameMap;
|
|
@@ -1,29 +1,16 @@
|
|
|
1
1
|
<!-- @component
|
|
2
|
-
|
|
2
|
+
Route boundary for a layout. Keyed by `config.layouts` at its nesting depth.
|
|
3
3
|
-->
|
|
4
4
|
<script lang="ts">
|
|
5
|
-
import { onNavigate } from "$app/navigation";
|
|
6
|
-
// Stores work throughout SvelteKit 2, including releases before $app/state.
|
|
7
|
-
import { page } from "$app/stores";
|
|
8
5
|
import { flushSync, onDestroy, untrack } from "svelte";
|
|
9
|
-
import
|
|
6
|
+
import { enterSsgoiLayoutBoundary } from "./context.js";
|
|
7
|
+
import type { SsgoiLayoutBoundaryProps } from "./types.js";
|
|
10
8
|
|
|
11
|
-
let {
|
|
12
|
-
children,
|
|
13
|
-
as = "div",
|
|
14
|
-
routeKey,
|
|
15
|
-
resolve,
|
|
16
|
-
...rest
|
|
17
|
-
}: SsgoiRouteBoundaryProps = $props();
|
|
9
|
+
let { children, as = "div", ...rest }: SsgoiLayoutBoundaryProps = $props();
|
|
18
10
|
|
|
19
|
-
const
|
|
20
|
-
const boundary = resolve?.({ pathname: url.pathname, url }) ?? {
|
|
21
|
-
id: url.pathname,
|
|
22
|
-
};
|
|
23
|
-
return { id: boundary.id, key: routeKey ?? boundary.key ?? boundary.id };
|
|
24
|
-
};
|
|
11
|
+
const { routes, depth } = enterSsgoiLayoutBoundary();
|
|
25
12
|
|
|
26
|
-
let current = $state(untrack(() =>
|
|
13
|
+
let current = $state(untrack(() => routes.current(depth)));
|
|
27
14
|
let mounted = $state(true);
|
|
28
15
|
let alive = true;
|
|
29
16
|
|
|
@@ -31,9 +18,9 @@
|
|
|
31
18
|
alive = false;
|
|
32
19
|
});
|
|
33
20
|
|
|
34
|
-
onNavigate((
|
|
35
|
-
if (!alive
|
|
36
|
-
const next =
|
|
21
|
+
routes.onNavigate((boundaryAt) => {
|
|
22
|
+
if (!alive) return;
|
|
23
|
+
const next = boundaryAt(depth);
|
|
37
24
|
|
|
38
25
|
if (next.key === current.key) {
|
|
39
26
|
// A persistent shell keeps its DOM, but its outgoing id must stay current.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SsgoiLayoutBoundaryProps } from "./types.js";
|
|
2
|
+
/** Route boundary for a layout. Keyed by `config.layouts` at its nesting depth. */
|
|
3
|
+
declare const SsgoiLayoutBoundary: import("svelte").Component<SsgoiLayoutBoundaryProps, {}, "">;
|
|
4
|
+
type SsgoiLayoutBoundary = ReturnType<typeof SsgoiLayoutBoundary>;
|
|
5
|
+
export default SsgoiLayoutBoundary;
|
package/dist/ssgoi.svelte
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import type { SsgoiConfig } from "@ssgoi/core/types";
|
|
4
4
|
import type { HostAnimation } from "@ssgoi/core/internal";
|
|
5
|
-
import {
|
|
5
|
+
import type { SsgoiFramework } from "./types.js";
|
|
6
|
+
import { setSsgoiContext, setSsgoiLayoutRoutes } from "./context";
|
|
6
7
|
import {
|
|
7
8
|
createSggoiTransitionContext,
|
|
8
9
|
observeSsgoiTransitions,
|
|
@@ -12,13 +13,16 @@
|
|
|
12
13
|
interface Props {
|
|
13
14
|
config: SsgoiConfig;
|
|
14
15
|
host?: HostAnimation;
|
|
16
|
+
/** Router members for `SsgoiLayoutBoundary`. */
|
|
17
|
+
framework?: SsgoiFramework;
|
|
15
18
|
children: Snippet;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
let { config, host, children }: Props = $props();
|
|
21
|
+
let { config, host, framework, children }: Props = $props();
|
|
19
22
|
|
|
20
23
|
const contextValue = createSggoiTransitionContext(config, { host });
|
|
21
24
|
setSsgoiContext(contextValue);
|
|
25
|
+
setSsgoiLayoutRoutes(framework, config.layouts);
|
|
22
26
|
|
|
23
27
|
let root: HTMLDivElement;
|
|
24
28
|
|
package/dist/ssgoi.svelte.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
2
|
import type { SsgoiConfig } from "@ssgoi/core/types";
|
|
3
3
|
import type { HostAnimation } from "@ssgoi/core/internal";
|
|
4
|
+
import type { SsgoiFramework } from "./types.js";
|
|
4
5
|
interface Props {
|
|
5
6
|
config: SsgoiConfig;
|
|
6
7
|
host?: HostAnimation;
|
|
8
|
+
/** Router members for `SsgoiLayoutBoundary`. */
|
|
9
|
+
framework?: SsgoiFramework;
|
|
7
10
|
children: Snippet;
|
|
8
11
|
}
|
|
9
12
|
declare const Ssgoi: import("svelte").Component<Props, {}, "">;
|
package/dist/types.d.ts
CHANGED
|
@@ -1 +1,30 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
1
3
|
export * from "@ssgoi/core/types";
|
|
4
|
+
/**
|
|
5
|
+
* Router members `<Ssgoi>` reads for `SsgoiLayoutBoundary`.
|
|
6
|
+
*
|
|
7
|
+
* SvelteKit 2.12+: `{ getRoute: () => ({ pathname: page.url.pathname }),
|
|
8
|
+
* onNavigate }` from `$app/state` and `$app/navigation`. Earlier SvelteKit 2:
|
|
9
|
+
* read `get(page).url` with `page` from `$app/stores`.
|
|
10
|
+
*/
|
|
11
|
+
export interface SsgoiFramework {
|
|
12
|
+
/** The route a boundary mounts on. */
|
|
13
|
+
getRoute: () => {
|
|
14
|
+
pathname: string;
|
|
15
|
+
};
|
|
16
|
+
onNavigate: (callback: (navigation: {
|
|
17
|
+
to: {
|
|
18
|
+
url: URL;
|
|
19
|
+
} | null;
|
|
20
|
+
}) => void | (() => void)) => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A boundary's id is the pathname; at depth N (counted through enclosing
|
|
24
|
+
* boundaries) it stays mounted while navigation stays inside the same depth-N
|
|
25
|
+
* scope of `config.layouts`.
|
|
26
|
+
*/
|
|
27
|
+
export interface SsgoiLayoutBoundaryProps extends HTMLAttributes<HTMLElement> {
|
|
28
|
+
children: Snippet;
|
|
29
|
+
as?: keyof HTMLElementTagNameMap;
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ssgoi/svelte",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.5.0-beta.0",
|
|
4
4
|
"description": "Native app-like page transitions for Svelte and SvelteKit. Make a web app, PWA or WebView app feel native.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@ssgoi/core": "^7.
|
|
17
|
+
"@ssgoi/core": "^7.5.0-beta.0"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"svelte": "^5.0.0",
|
|
@@ -100,9 +100,9 @@
|
|
|
100
100
|
"import": "./dist/view-transitions.js"
|
|
101
101
|
},
|
|
102
102
|
"./sveltekit": {
|
|
103
|
-
"types": "./dist/
|
|
104
|
-
"svelte": "./dist/
|
|
105
|
-
"import": "./dist/
|
|
103
|
+
"types": "./dist/legacy/sveltekit/index.d.ts",
|
|
104
|
+
"svelte": "./dist/legacy/sveltekit/index.js",
|
|
105
|
+
"import": "./dist/legacy/sveltekit/index.js"
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
"peerDependenciesMeta": {
|
|
File without changes
|