toiljs 0.0.15 → 0.0.19
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/.babelrc +13 -13
- package/.gitattributes +2 -2
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
- package/.github/ISSUE_TEMPLATE/bug_report.yml +90 -90
- package/.github/ISSUE_TEMPLATE/config.yml +8 -8
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/PULL_REQUEST_TEMPLATE.md +43 -43
- package/.github/changelog-config.json +45 -45
- package/.github/dependabot.yml +27 -27
- package/.github/workflows/ci.yml +191 -191
- package/.prettierrc.json +11 -11
- package/.vscode/settings.json +9 -9
- package/CHANGELOG.md +116 -5
- package/LICENSE +187 -187
- package/README.md +524 -315
- package/as-pect.asconfig.json +34 -34
- package/as-pect.config.js +65 -65
- package/assets/logo.svg +36 -36
- package/build/backend/.tsbuildinfo +1 -1
- package/build/backend/index.d.ts +1 -0
- package/build/backend/index.js +20 -1
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/index.js +1320 -696
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/dev/devtools.d.ts +6 -0
- package/build/client/dev/devtools.js +479 -0
- package/build/client/dev/error-overlay.d.ts +9 -0
- package/build/client/dev/error-overlay.js +19 -4
- package/build/client/errors.d.ts +1 -0
- package/build/client/errors.js +3 -0
- package/build/client/index.d.ts +2 -0
- package/build/client/index.js +2 -0
- package/build/client/navigation/prefetch.d.ts +1 -0
- package/build/client/navigation/prefetch.js +35 -0
- package/build/client/routing/Router.js +1 -1
- package/build/client/routing/hooks.js +6 -2
- package/build/client/routing/loader.d.ts +23 -0
- package/build/client/routing/loader.js +53 -7
- package/build/client/routing/mount.js +4 -3
- package/build/client/rpc.d.ts +1 -0
- package/build/client/rpc.js +37 -0
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/config.d.ts +16 -0
- package/build/compiler/config.js +9 -0
- package/build/compiler/docs.js +78 -21
- package/build/compiler/generate.js +5 -4
- package/build/compiler/index.d.ts +3 -2
- package/build/compiler/index.js +2 -2
- package/build/compiler/plugin.js +228 -0
- package/build/compiler/prerender.d.ts +1 -0
- package/build/compiler/prerender.js +1 -1
- package/build/compiler/seo.d.ts +1 -1
- package/build/compiler/seo.js +20 -5
- package/build/compiler/ssg.js +39 -2
- package/build/compiler/vite.js +25 -0
- package/build/io/.tsbuildinfo +1 -1
- package/build/io/codec.d.ts +54 -0
- package/build/io/codec.js +143 -0
- package/build/io/index.d.ts +1 -2
- package/build/io/index.js +1 -2
- package/build/logger/.tsbuildinfo +1 -1
- package/build/shared/.tsbuildinfo +1 -1
- package/eslint.config.js +48 -48
- package/examples/basic/client/404.tsx +11 -11
- package/examples/basic/client/components/.gitkeep +1 -1
- package/examples/basic/client/global-error.tsx +13 -13
- package/examples/basic/client/layout.tsx +25 -25
- package/examples/basic/client/public/images/.gitkeep +1 -1
- package/examples/basic/client/public/images/logo.svg +36 -36
- package/examples/basic/client/public/robots.txt +2 -2
- package/examples/basic/client/routes/docs/[...slug].tsx +12 -12
- package/examples/basic/client/routes/features/error/error.tsx +16 -16
- package/examples/basic/client/routes/features/index.tsx +1 -1
- package/examples/basic/client/routes/features/template/b.tsx +14 -14
- package/examples/basic/client/routes/files/[[...slug]].tsx +21 -21
- package/examples/basic/client/routes/gallery/layout.tsx +13 -13
- package/examples/basic/client/routes/io.tsx +23 -24
- package/examples/basic/client/routes/loader-demo/loading.tsx +13 -13
- package/examples/basic/client/routes/rest.tsx +74 -0
- package/examples/basic/client/routes/rpc.tsx +43 -0
- package/examples/basic/client/routes/search.tsx +61 -61
- package/examples/basic/client/toil.tsx +5 -5
- package/package.json +167 -148
- package/presets/eslint.js +88 -88
- package/presets/no-uint8array-tostring.js +200 -200
- package/presets/prettier-plugin.js +51 -0
- package/presets/prettier.json +19 -18
- package/presets/tsconfig.json +37 -37
- package/server/runtime/README.md +97 -0
- package/server/runtime/abort/abort.ts +27 -0
- package/server/runtime/env/Server.ts +61 -0
- package/server/runtime/envelope.ts +191 -0
- package/server/runtime/exports/index.ts +52 -0
- package/server/runtime/handlers/ToilHandler.ts +34 -0
- package/server/runtime/index.ts +26 -0
- package/server/runtime/lang/Potential.ts +5 -0
- package/server/runtime/memory.ts +81 -0
- package/server/runtime/request.ts +55 -0
- package/server/runtime/response.ts +86 -0
- package/server/runtime/rest/Rest.ts +39 -0
- package/server/runtime/rest/RestHandler.ts +20 -0
- package/server/runtime/rest/RouteContext.ts +82 -0
- package/server/runtime/rest/match.ts +48 -0
- package/server/runtime/tsconfig.json +7 -0
- package/src/backend/index.ts +202 -160
- package/src/cli/create.ts +15 -5
- package/src/cli/diagnostics.ts +81 -0
- package/src/cli/doctor.ts +384 -7
- package/src/cli/index.ts +11 -2
- package/src/cli/proc.ts +50 -50
- package/src/cli/updates.ts +69 -69
- package/src/cli/validate.ts +31 -31
- package/src/client/channel/channel.ts +146 -146
- package/src/client/components/Form.tsx +65 -65
- package/src/client/components/Script.tsx +113 -113
- package/src/client/components/Slot.tsx +21 -21
- package/src/client/dev/devtools.tsx +1018 -0
- package/src/client/dev/error-overlay.tsx +30 -4
- package/src/client/errors.ts +11 -0
- package/src/client/head/head.ts +167 -167
- package/src/client/head/metadata.ts +112 -112
- package/src/client/index.ts +91 -89
- package/src/client/navigation/NavLink.tsx +86 -86
- package/src/client/navigation/navigation.ts +235 -235
- package/src/client/navigation/prefetch.ts +169 -130
- package/src/client/navigation/scroll.ts +53 -53
- package/src/client/routing/Router.tsx +8 -2
- package/src/client/routing/action.ts +122 -122
- package/src/client/routing/error-boundary.tsx +43 -43
- package/src/client/routing/hooks.ts +21 -6
- package/src/client/routing/loader.ts +325 -235
- package/src/client/routing/match.ts +47 -47
- package/src/client/routing/mount.tsx +54 -52
- package/src/client/routing/params-context.ts +10 -10
- package/src/client/routing/slot-context.ts +7 -7
- package/src/client/rpc.ts +64 -0
- package/src/client/search/search.ts +189 -189
- package/src/client/search/use-page-search.ts +73 -73
- package/src/client/types.ts +73 -73
- package/src/compiler/config.ts +221 -182
- package/src/compiler/docs.ts +285 -228
- package/src/compiler/generate.ts +395 -394
- package/src/compiler/index.ts +66 -57
- package/src/compiler/pages.ts +70 -70
- package/src/compiler/plugin.ts +258 -2
- package/src/compiler/prerender.ts +156 -156
- package/src/compiler/seo.ts +417 -390
- package/src/compiler/ssg.ts +171 -126
- package/src/compiler/vite.ts +34 -0
- package/src/io/FastMap.ts +151 -127
- package/src/io/FastSet.ts +15 -1
- package/src/io/codec.ts +217 -0
- package/src/io/index.ts +10 -11
- package/src/io/lengths.ts +14 -14
- package/src/io/types.ts +19 -18
- package/src/logger/index.ts +22 -22
- package/src/shared/index.ts +10 -10
- package/std/client/index.d.ts +15 -15
- package/std/client/package.json +3 -3
- package/test/assembly/example.spec.ts +17 -7
- package/test/channel.test.ts +21 -21
- package/test/doctor.test.ts +65 -0
- package/test/dom/Link.test.tsx +47 -47
- package/test/dom/NavLink.test.tsx +37 -37
- package/test/dom/error-overlay.test.tsx +44 -44
- package/test/dom/loader.test.tsx +121 -121
- package/test/dom/navigation.test.ts +59 -59
- package/test/dom/revalidate.test.tsx +38 -38
- package/test/dom/route-head.test.tsx +78 -78
- package/test/dom/router-loading.test.tsx +44 -44
- package/test/dom/scroll.test.ts +56 -56
- package/test/dom/use-metadata.test.tsx +58 -58
- package/test/errors.test.ts +21 -0
- package/test/io.test.ts +117 -93
- package/test/navlink.test.ts +28 -28
- package/test/placeholder.test.ts +9 -9
- package/test/prettier-plugin.test.ts +46 -0
- package/test/routes.test.ts +76 -76
- package/test/rpc.test.ts +50 -0
- package/test/seo.test.ts +175 -164
- package/test/slot-layouts.test.ts +69 -69
- package/test/ssg.test.ts +36 -36
- package/test/update.test.ts +44 -44
- package/test/validate.test.ts +42 -42
- package/tests/data-parity/generated-parity.ts +99 -0
- package/tests/data-parity/parity.ts +80 -0
- package/tests/data-parity/spec.ts +46 -0
- package/toil-routes.d.ts +7 -0
- package/tsconfig.backend.json +13 -13
- package/tsconfig.base.json +35 -35
- package/tsconfig.cli.json +13 -13
- package/tsconfig.client.json +14 -14
- package/tsconfig.compiler.json +13 -13
- package/tsconfig.io.json +12 -12
- package/tsconfig.json +22 -22
- package/tsconfig.logger.json +12 -12
- package/tsconfig.server.json +10 -10
- package/tsconfig.shared.json +12 -12
- package/vitest.config.ts +26 -26
- package/.idea/codeStyles/Project.xml +0 -54
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/prettier.xml +0 -7
- package/.idea/toiljs.iml +0 -8
- package/.idea/vcs.xml +0 -6
- package/.toil/entry.tsx +0 -9
- package/.toil/index.html +0 -12
- package/.toil/routes.ts +0 -9
- package/build/cli/configure.d.ts +0 -16
- package/build/cli/configure.js +0 -272
- package/build/cli/create.d.ts +0 -16
- package/build/cli/create.js +0 -420
- package/build/cli/diagnostics.d.ts +0 -55
- package/build/cli/diagnostics.js +0 -333
- package/build/cli/doctor.d.ts +0 -6
- package/build/cli/doctor.js +0 -249
- package/build/cli/features.d.ts +0 -25
- package/build/cli/features.js +0 -107
- package/build/cli/index.d.ts +0 -2
- package/build/cli/proc.d.ts +0 -6
- package/build/cli/proc.js +0 -31
- package/build/cli/ui.d.ts +0 -9
- package/build/cli/ui.js +0 -75
- package/build/cli/update.d.ts +0 -7
- package/build/cli/update.js +0 -117
- package/build/cli/updates.d.ts +0 -10
- package/build/cli/updates.js +0 -45
- package/build/cli/validate.d.ts +0 -4
- package/build/cli/validate.js +0 -19
- package/build/client/Link.d.ts +0 -8
- package/build/client/Link.js +0 -44
- package/build/client/NavLink.d.ts +0 -14
- package/build/client/NavLink.js +0 -37
- package/build/client/Router.d.ts +0 -7
- package/build/client/Router.js +0 -55
- package/build/client/channel.d.ts +0 -23
- package/build/client/channel.js +0 -94
- package/build/client/error-boundary.d.ts +0 -16
- package/build/client/error-boundary.js +0 -19
- package/build/client/head.d.ts +0 -26
- package/build/client/head.js +0 -87
- package/build/client/hooks.d.ts +0 -17
- package/build/client/hooks.js +0 -48
- package/build/client/lazy.d.ts +0 -16
- package/build/client/lazy.js +0 -53
- package/build/client/match.d.ts +0 -2
- package/build/client/match.js +0 -32
- package/build/client/mount.d.ts +0 -2
- package/build/client/mount.js +0 -13
- package/build/client/navigation.d.ts +0 -13
- package/build/client/navigation.js +0 -97
- package/build/client/params-context.d.ts +0 -2
- package/build/client/params-context.js +0 -2
- package/build/client/prefetch.d.ts +0 -11
- package/build/client/prefetch.js +0 -100
- package/build/client/runtime.d.ts +0 -31
- package/build/client/runtime.js +0 -112
- package/build/client/scroll.d.ts +0 -8
- package/build/client/scroll.js +0 -36
- package/build/io/BinaryReader.d.ts +0 -44
- package/build/io/BinaryReader.js +0 -244
- package/build/io/BinaryWriter.d.ts +0 -44
- package/build/io/BinaryWriter.js +0 -297
- package/build/server/release.wasm +0 -0
- package/build/server/release.wat +0 -9
- package/src/io/BinaryReader.ts +0 -340
- package/src/io/BinaryWriter.ts +0 -385
- package/src/server/index.ts +0 -10
- package/src/server/main.ts +0 -13
- package/src/server/tsconfig.json +0 -4
- package/toil-env.d.ts +0 -16
- package/toilconfig.json +0 -30
|
@@ -1,113 +1,113 @@
|
|
|
1
|
-
import { useEffect, type ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* When a {@link Script} is injected, relative to the app becoming interactive:
|
|
5
|
-
* - `afterInteractive` (default), on mount, once the app is running. Good for analytics, widgets.
|
|
6
|
-
* - `lazyOnload`, deferred until the browser is idle (after `window.load`). For low-priority scripts.
|
|
7
|
-
* - `beforeInteractive`, as early as possible. In a client-only SPA there is no SSR, so this still
|
|
8
|
-
* runs after hydration, but synchronously on first mount with high fetch priority.
|
|
9
|
-
*/
|
|
10
|
-
export type ScriptStrategy = 'beforeInteractive' | 'afterInteractive' | 'lazyOnload';
|
|
11
|
-
|
|
12
|
-
/** Props for {@link Script}. Provide either `src` (external) or inline `children` (script body). */
|
|
13
|
-
export interface ScriptProps {
|
|
14
|
-
/** URL of an external script. Omit when providing an inline script body via `children`. */
|
|
15
|
-
src?: string;
|
|
16
|
-
/** When to load the script. Default `'afterInteractive'`. */
|
|
17
|
-
strategy?: ScriptStrategy;
|
|
18
|
-
/** Stable identity for dedup (required for inline scripts; defaults to `src` for external ones). */
|
|
19
|
-
id?: string;
|
|
20
|
-
/** `type` attribute (e.g. `'module'`, `'application/json'`). */
|
|
21
|
-
type?: string;
|
|
22
|
-
/** Fired once the script has loaded (external) or been inserted (inline). */
|
|
23
|
-
onLoad?: () => void;
|
|
24
|
-
/** Fired after load, and on every later mount once the script is already loaded. */
|
|
25
|
-
onReady?: () => void;
|
|
26
|
-
/** Fired if an external script fails to load. */
|
|
27
|
-
onError?: (error: unknown) => void;
|
|
28
|
-
/** Inline script body. Mutually exclusive with `src`. */
|
|
29
|
-
children?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
type LoadState = 'loading' | 'ready';
|
|
33
|
-
/** Module-level registry so a given script is injected/executed at most once across the app. */
|
|
34
|
-
const registry = new Map<string, LoadState>();
|
|
35
|
-
|
|
36
|
-
function inject(props: ScriptProps, key: string): void {
|
|
37
|
-
const { src, type, onLoad, onReady, onError, children } = props;
|
|
38
|
-
const el = document.createElement('script');
|
|
39
|
-
el.dataset.toilScript = key;
|
|
40
|
-
if (type !== undefined) el.type = type;
|
|
41
|
-
|
|
42
|
-
if (src !== undefined) {
|
|
43
|
-
el.src = src;
|
|
44
|
-
el.async = true;
|
|
45
|
-
el.addEventListener('load', () => {
|
|
46
|
-
registry.set(key, 'ready');
|
|
47
|
-
onLoad?.();
|
|
48
|
-
onReady?.();
|
|
49
|
-
});
|
|
50
|
-
el.addEventListener('error', (event) => {
|
|
51
|
-
registry.delete(key); // allow a later remount to retry
|
|
52
|
-
onError?.(event);
|
|
53
|
-
});
|
|
54
|
-
document.head.appendChild(el);
|
|
55
|
-
} else {
|
|
56
|
-
el.textContent = children ?? '';
|
|
57
|
-
document.head.appendChild(el);
|
|
58
|
-
registry.set(key, 'ready');
|
|
59
|
-
onLoad?.();
|
|
60
|
-
onReady?.();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Loads an external or inline `<script>` with a load `strategy`, deduplicated across the app so the
|
|
66
|
-
* same script never executes twice. Renders nothing. Mirrors the ergonomics of Next.js `next/script`
|
|
67
|
-
* for a client-only SPA.
|
|
68
|
-
*/
|
|
69
|
-
export function Script(props: ScriptProps): ReactNode {
|
|
70
|
-
const { src, id, strategy = 'afterInteractive', onReady } = props;
|
|
71
|
-
const key = id ?? src;
|
|
72
|
-
|
|
73
|
-
useEffect(() => {
|
|
74
|
-
if (key === undefined) {
|
|
75
|
-
// No id and no src: nothing to dedup or load (an inline script needs at least an id).
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const state = registry.get(key);
|
|
80
|
-
if (state === 'ready') {
|
|
81
|
-
onReady?.();
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
if (state === 'loading') {
|
|
85
|
-
return; // another instance is already injecting it
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
registry.set(key, 'loading');
|
|
89
|
-
const run = (): void => {
|
|
90
|
-
inject(props, key);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
if (strategy === 'lazyOnload') {
|
|
94
|
-
if (document.readyState === 'complete') {
|
|
95
|
-
const idle = window.requestIdleCallback?.bind(window);
|
|
96
|
-
if (idle) idle(run);
|
|
97
|
-
else setTimeout(run, 0);
|
|
98
|
-
} else {
|
|
99
|
-
window.addEventListener('load', run, { once: true });
|
|
100
|
-
}
|
|
101
|
-
return () => {
|
|
102
|
-
window.removeEventListener('load', run);
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// beforeInteractive + afterInteractive: inject now (on mount).
|
|
107
|
-
run();
|
|
108
|
-
// Intentionally keyed on identity only: inject once per script key; later prop changes
|
|
109
|
-
// (handlers, body) are read at inject time and must not re-run/re-inject the script.
|
|
110
|
-
}, [key, strategy]);
|
|
111
|
-
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
1
|
+
import { useEffect, type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* When a {@link Script} is injected, relative to the app becoming interactive:
|
|
5
|
+
* - `afterInteractive` (default), on mount, once the app is running. Good for analytics, widgets.
|
|
6
|
+
* - `lazyOnload`, deferred until the browser is idle (after `window.load`). For low-priority scripts.
|
|
7
|
+
* - `beforeInteractive`, as early as possible. In a client-only SPA there is no SSR, so this still
|
|
8
|
+
* runs after hydration, but synchronously on first mount with high fetch priority.
|
|
9
|
+
*/
|
|
10
|
+
export type ScriptStrategy = 'beforeInteractive' | 'afterInteractive' | 'lazyOnload';
|
|
11
|
+
|
|
12
|
+
/** Props for {@link Script}. Provide either `src` (external) or inline `children` (script body). */
|
|
13
|
+
export interface ScriptProps {
|
|
14
|
+
/** URL of an external script. Omit when providing an inline script body via `children`. */
|
|
15
|
+
src?: string;
|
|
16
|
+
/** When to load the script. Default `'afterInteractive'`. */
|
|
17
|
+
strategy?: ScriptStrategy;
|
|
18
|
+
/** Stable identity for dedup (required for inline scripts; defaults to `src` for external ones). */
|
|
19
|
+
id?: string;
|
|
20
|
+
/** `type` attribute (e.g. `'module'`, `'application/json'`). */
|
|
21
|
+
type?: string;
|
|
22
|
+
/** Fired once the script has loaded (external) or been inserted (inline). */
|
|
23
|
+
onLoad?: () => void;
|
|
24
|
+
/** Fired after load, and on every later mount once the script is already loaded. */
|
|
25
|
+
onReady?: () => void;
|
|
26
|
+
/** Fired if an external script fails to load. */
|
|
27
|
+
onError?: (error: unknown) => void;
|
|
28
|
+
/** Inline script body. Mutually exclusive with `src`. */
|
|
29
|
+
children?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type LoadState = 'loading' | 'ready';
|
|
33
|
+
/** Module-level registry so a given script is injected/executed at most once across the app. */
|
|
34
|
+
const registry = new Map<string, LoadState>();
|
|
35
|
+
|
|
36
|
+
function inject(props: ScriptProps, key: string): void {
|
|
37
|
+
const { src, type, onLoad, onReady, onError, children } = props;
|
|
38
|
+
const el = document.createElement('script');
|
|
39
|
+
el.dataset.toilScript = key;
|
|
40
|
+
if (type !== undefined) el.type = type;
|
|
41
|
+
|
|
42
|
+
if (src !== undefined) {
|
|
43
|
+
el.src = src;
|
|
44
|
+
el.async = true;
|
|
45
|
+
el.addEventListener('load', () => {
|
|
46
|
+
registry.set(key, 'ready');
|
|
47
|
+
onLoad?.();
|
|
48
|
+
onReady?.();
|
|
49
|
+
});
|
|
50
|
+
el.addEventListener('error', (event) => {
|
|
51
|
+
registry.delete(key); // allow a later remount to retry
|
|
52
|
+
onError?.(event);
|
|
53
|
+
});
|
|
54
|
+
document.head.appendChild(el);
|
|
55
|
+
} else {
|
|
56
|
+
el.textContent = children ?? '';
|
|
57
|
+
document.head.appendChild(el);
|
|
58
|
+
registry.set(key, 'ready');
|
|
59
|
+
onLoad?.();
|
|
60
|
+
onReady?.();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Loads an external or inline `<script>` with a load `strategy`, deduplicated across the app so the
|
|
66
|
+
* same script never executes twice. Renders nothing. Mirrors the ergonomics of Next.js `next/script`
|
|
67
|
+
* for a client-only SPA.
|
|
68
|
+
*/
|
|
69
|
+
export function Script(props: ScriptProps): ReactNode {
|
|
70
|
+
const { src, id, strategy = 'afterInteractive', onReady } = props;
|
|
71
|
+
const key = id ?? src;
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (key === undefined) {
|
|
75
|
+
// No id and no src: nothing to dedup or load (an inline script needs at least an id).
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const state = registry.get(key);
|
|
80
|
+
if (state === 'ready') {
|
|
81
|
+
onReady?.();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (state === 'loading') {
|
|
85
|
+
return; // another instance is already injecting it
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
registry.set(key, 'loading');
|
|
89
|
+
const run = (): void => {
|
|
90
|
+
inject(props, key);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if (strategy === 'lazyOnload') {
|
|
94
|
+
if (document.readyState === 'complete') {
|
|
95
|
+
const idle = window.requestIdleCallback?.bind(window);
|
|
96
|
+
if (idle) idle(run);
|
|
97
|
+
else setTimeout(run, 0);
|
|
98
|
+
} else {
|
|
99
|
+
window.addEventListener('load', run, { once: true });
|
|
100
|
+
}
|
|
101
|
+
return () => {
|
|
102
|
+
window.removeEventListener('load', run);
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// beforeInteractive + afterInteractive: inject now (on mount).
|
|
107
|
+
run();
|
|
108
|
+
// Intentionally keyed on identity only: inject once per script key; later prop changes
|
|
109
|
+
// (handlers, body) are read at inject time and must not re-run/re-inject the script.
|
|
110
|
+
}, [key, strategy]);
|
|
111
|
+
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { useContext, type ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
import { SlotContext } from '../routing/slot-context.js';
|
|
4
|
-
|
|
5
|
-
/** Props for {@link Slot}. */
|
|
6
|
-
export interface SlotProps {
|
|
7
|
-
/** The parallel-slot name, the `@name` directory under `routes/` (without the `@`). */
|
|
8
|
-
name: string;
|
|
9
|
-
/** Rendered when the slot has no match for the current URL. Default `null`. */
|
|
10
|
-
fallback?: ReactNode;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Renders the parallel-route slot named `name` for the current URL. Place it in a layout or page to
|
|
15
|
-
* show an `@name` route tree alongside the main content (e.g. a persistent sidebar, or a modal that
|
|
16
|
-
* an intercepting route fills). Renders `fallback` (default nothing) when no slot route matches.
|
|
17
|
-
*/
|
|
18
|
-
export function Slot({ name, fallback = null }: SlotProps): ReactNode {
|
|
19
|
-
const slots = useContext(SlotContext);
|
|
20
|
-
return slots[name] ?? fallback;
|
|
21
|
-
}
|
|
1
|
+
import { useContext, type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { SlotContext } from '../routing/slot-context.js';
|
|
4
|
+
|
|
5
|
+
/** Props for {@link Slot}. */
|
|
6
|
+
export interface SlotProps {
|
|
7
|
+
/** The parallel-slot name, the `@name` directory under `routes/` (without the `@`). */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Rendered when the slot has no match for the current URL. Default `null`. */
|
|
10
|
+
fallback?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Renders the parallel-route slot named `name` for the current URL. Place it in a layout or page to
|
|
15
|
+
* show an `@name` route tree alongside the main content (e.g. a persistent sidebar, or a modal that
|
|
16
|
+
* an intercepting route fills). Renders `fallback` (default nothing) when no slot route matches.
|
|
17
|
+
*/
|
|
18
|
+
export function Slot({ name, fallback = null }: SlotProps): ReactNode {
|
|
19
|
+
const slots = useContext(SlotContext);
|
|
20
|
+
return slots[name] ?? fallback;
|
|
21
|
+
}
|