@askrjs/askr 0.3.0 → 0.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 +874 -0
- package/README.md +61 -29
- package/capabilities.json +19 -9
- package/dist/actions/index.js +56 -12
- package/dist/benchmark.js +10 -15
- package/dist/boot/index.d.ts +3 -2
- package/dist/boot/index.js +1 -1
- package/dist/boot-DaoTYoCw.js +3989 -0
- package/dist/browser-activity-CB8e-V4f.js +220 -0
- package/dist/components/index.d.ts +8 -1
- package/dist/components/index.js +1 -43
- package/dist/{aria-hKjThHcp.js → compose-ref-DWzdbxsD.js} +41 -4
- package/dist/control/index.d.ts +2 -0
- package/dist/control/index.js +1 -1
- package/dist/control-nfpT2fbK.js +209 -0
- package/dist/core.d.ts +5 -9
- package/dist/csp-nonce-DwGw1A6Q.js +35 -0
- package/dist/data/index.js +3 -3
- package/dist/{data-2edW0jhF.js → data-BCwClJiF.js} +283 -94
- package/dist/data-runtime-C1bFAlba.js +242 -0
- package/dist/{deferred-CbgNhf67.js → deferred-bEEHHvic.js} +42 -20
- package/dist/domains/actions.d.ts +8 -3
- package/dist/domains/component.d.ts +1 -107
- package/dist/domains/context.d.ts +0 -15
- package/dist/domains/control.d.ts +36 -249
- package/dist/domains/data.d.ts +31 -13
- package/dist/domains/diagnostics.d.ts +1 -2
- package/dist/domains/lifecycle.d.ts +2 -5
- package/dist/domains/refs.d.ts +0 -2
- package/dist/domains/routing.d.ts +43 -8
- package/dist/domains/scheduler.d.ts +1 -76
- package/dist/domains/server.d.ts +5 -2
- package/dist/domains/state.d.ts +2 -5
- package/dist/domains/telemetry.d.ts +0 -2
- package/dist/elements.d.ts +214 -51
- package/dist/error-boundary-Bpwofwps.js +293 -0
- package/dist/foundations/icon/index.d.ts +0 -58
- package/dist/foundations/icon/index.js +2 -2
- package/dist/foundations/index.js +2 -1
- package/dist/foundations/interactions/index.js +1 -1
- package/dist/foundations/state/index.d.ts +3 -3
- package/dist/foundations/state/index.js +5 -3
- package/dist/foundations/structures/index.js +2 -1
- package/dist/foundations/utilities/index.d.ts +2 -0
- package/dist/foundations/utilities/index.js +1 -2
- package/dist/fx/index.d.ts +31 -58
- package/dist/fx/index.js +313 -195
- package/dist/hooks-BimKStr4.js +202 -0
- package/dist/index.d.ts +11 -74
- package/dist/index.js +8 -447
- package/dist/instance-BAnfmXOR.js +988 -0
- package/dist/{interactions-CTeACdT_.js → interactions-D2BoREb-.js} +3 -2
- package/dist/jsx-dev-runtime.d.ts +41 -18
- package/dist/jsx-dev-runtime.js +1 -6
- package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
- package/dist/jsx-runtime.js +1 -1
- package/dist/jsx.d.ts +61 -37
- package/dist/{manifest-D1P3UNWV.js → manifest-CW9gyNBY.js} +3 -3
- package/dist/{navigate-prC5V8XV.js → navigate-CP_0Zy5U.js} +454 -87
- package/dist/navigation.d.ts +12 -3
- package/dist/peer-types.d.ts +8 -0
- package/dist/portal-DuOKfnLa.js +349 -0
- package/dist/promise-Dz8iIHAm.js +16 -0
- package/dist/query-registry-WMCN0BJL.js +320 -0
- package/dist/readable-DFWOsTac.js +21 -0
- package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
- package/dist/render-sync-IC5lMFpq.js +1240 -0
- package/dist/resolution-Cx82-xjW.js +1244 -0
- package/dist/resource-CLjB7RBQ.js +377 -0
- package/dist/resources/index.d.ts +21 -11
- package/dist/resources/index.js +45 -244
- package/dist/router/index.d.ts +14 -5
- package/dist/router/index.js +22 -53
- package/dist/scope-CwpVSHVf.js +55 -0
- package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
- package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
- package/dist/ssg/index.d.ts +1 -2
- package/dist/ssg/index.js +5 -13
- package/dist/ssr/index.d.ts +26 -28
- package/dist/ssr/index.js +4 -4
- package/dist/{ssr-CiNm6Vzl.js → ssr-BJ8ug7zH.js} +133 -122
- package/dist/ssr-DoV-vJ-5.js +229 -0
- package/dist/state-DWO1KzkX.js +232 -0
- package/dist/structures-D4dDMqHX.js +231 -0
- package/dist/testing/index.d.ts +8 -4
- package/dist/testing/index.js +29 -34
- package/dist/url-CnbfpX0K.js +185 -0
- package/dist/utilities.d.ts +48 -2
- package/dist/verify-hydration-DpVaDnqz.js +152 -0
- package/package.json +19 -9
- package/dist/access-CEA2pOry.js +0 -1046
- package/dist/activity-oy2YFTFF.js +0 -201
- package/dist/boot-BMBMWUGI.js +0 -1084
- package/dist/capabilities-Bbf0mlp9.js +0 -42
- package/dist/compose-ref-v0qGlHoN.js +0 -26
- package/dist/control-BR_mrX__.js +0 -173
- package/dist/control-C-ApnFs1.js +0 -20
- package/dist/csp-nonce-BfFWcd0w.js +0 -173
- package/dist/data-runtime-CxoY98lX.js +0 -149
- package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
- package/dist/dom-renderer.d.ts +0 -77
- package/dist/domains/renderer.d.ts +0 -127
- package/dist/eager-control.d.ts +0 -8
- package/dist/effect-C3Zsc1k6.js +0 -292
- package/dist/for-state-BDykeOJL.js +0 -1753
- package/dist/instance-VAFYVJOa.js +0 -1027
- package/dist/notify-DxxuDPeY.js +0 -266
- package/dist/portal-w3oQ6oQU.js +0 -29
- package/dist/query-registry-LrYpQsDJ.js +0 -83
- package/dist/render-resolved-BC0W7_5b.js +0 -1123
- package/dist/renderer-CT0HeY58.js +0 -8623
- package/dist/resolution-3DskUkjG.js +0 -577
- package/dist/resource-18-sFRl9.js +0 -344
- package/dist/route-matching-CUzZ31gT.js +0 -551
- package/dist/router-internal-7nuNEHfG.js +0 -36
- package/dist/scope-Cq_iYbTR.js +0 -403
- package/dist/selector-BSPVkjKP.js +0 -311
- package/dist/ssr-EPjwJH5R.js +0 -29
- package/dist/state-BXJfudq1.js +0 -91
- package/dist/structures-CjEzfj4h.js +0 -654
- package/dist/timer-C7uqnJVt.js +0 -85
- package/dist/verify-hydration-ikaxotf7.js +0 -27
- package/dist/vnode-D24p6IW2.js +0 -7
package/dist/navigation.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import './core.js';
|
|
1
|
+
import { RouteDestination } from './core.js';
|
|
2
2
|
/** Scroll behavior for programmatic navigations (`navigate()`). */
|
|
3
3
|
type NavigationScrollBehavior = 'top' | 'preserve';
|
|
4
4
|
/** Scroll behavior for browser back/forward (popstate) navigations. */
|
|
@@ -16,8 +16,17 @@ type NavigateOptions = {
|
|
|
16
16
|
/** Entry-local browser history state. It is not serialized into the URL or sent to the server. */
|
|
17
17
|
state?: unknown;
|
|
18
18
|
};
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Navigate the client-side router using the History API.
|
|
21
|
+
*
|
|
22
|
+
* A string is a logical path: a root-relative path gains the registry
|
|
23
|
+
* `basePath`. A typed destination from `to()` already carries its public href.
|
|
24
|
+
* A target on another origin is handed to the browser.
|
|
25
|
+
*/
|
|
26
|
+
declare function navigate(
|
|
27
|
+
target: string | RouteDestination,
|
|
28
|
+
options?: NavigateOptions
|
|
29
|
+
): void;
|
|
21
30
|
export {
|
|
22
31
|
ScrollRestorationOptions,
|
|
23
32
|
NavigationScrollBehavior,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @askrjs/auth and @askrjs/schema are optional, type-only peers. Every
|
|
2
|
+
// published declaration reaches them through this module so an app that never
|
|
3
|
+
// installs them still typechecks with `skipLibCheck: false`; their types
|
|
4
|
+
// degrade to `any` until the app installs the peer it uses.
|
|
5
|
+
// @ts-ignore -- optional peer: resolves only when @askrjs/auth is installed.
|
|
6
|
+
export type { AuthContext, AuthRequirement } from '@askrjs/auth';
|
|
7
|
+
// @ts-ignore -- optional peer: resolves only when @askrjs/schema is installed.
|
|
8
|
+
export type { InferSchema, ObjectSchema } from '@askrjs/schema';
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { M as getOwner, T as Signal, d as recordUndo, o as getRenderHost } from "./instance-BAnfmXOR.js";
|
|
2
|
+
import { t as ELEMENT_TYPE } from "./jsx-DRS-qjiN.js";
|
|
3
|
+
import { i as currentComponent, m as deliverToBoundary } from "./hooks-BimKStr4.js";
|
|
4
|
+
import { n as getActiveRenderContext } from "./render-context-DGHnEveC.js";
|
|
5
|
+
import { i as OWNED_TYPE, n as holdUntilBoundaryRecovers, r as nearestErrorBoundary, t as ErrorBoundary } from "./error-boundary-Bpwofwps.js";
|
|
6
|
+
//#region src/common/portal.ts
|
|
7
|
+
/**
|
|
8
|
+
* Internal marker used to defer server portal host output until all writes in
|
|
9
|
+
* the current render root are known.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
const SSR_PORTAL_HOST = Symbol.for("askr.ssr-portal-host");
|
|
14
|
+
/** Compare writer positions in their owner trees, independent of activation order. */
|
|
15
|
+
function comparePortalWriterOrder(left, right, leftSourceOrder, rightSourceOrder) {
|
|
16
|
+
if (leftSourceOrder !== void 0 && rightSourceOrder !== void 0) return leftSourceOrder - rightSourceOrder;
|
|
17
|
+
const leftPath = portalWriterOrder(left);
|
|
18
|
+
const rightPath = portalWriterOrder(right);
|
|
19
|
+
const length = Math.min(leftPath.length, rightPath.length);
|
|
20
|
+
for (let index = 0; index < length; index++) if (leftPath[index] !== rightPath[index]) return leftPath[index] - rightPath[index];
|
|
21
|
+
return leftPath.length - rightPath.length;
|
|
22
|
+
}
|
|
23
|
+
function portalWriterOrder(owner) {
|
|
24
|
+
if (!owner) return [-1];
|
|
25
|
+
const path = [];
|
|
26
|
+
for (let current = owner; current; current = current.parent) path.push(current.ownedIndex);
|
|
27
|
+
return path.reverse();
|
|
28
|
+
}
|
|
29
|
+
const SSR_PORTAL_HOST_PREFIX = "askr-portal:";
|
|
30
|
+
const SSR_PORTAL_ANCHOR_PREFIX = "askr-portal-anchor:";
|
|
31
|
+
function createSSRPortalHostToken(id) {
|
|
32
|
+
return `<!--${SSR_PORTAL_HOST_PREFIX}${id}-->`;
|
|
33
|
+
}
|
|
34
|
+
function createSSRPortalAnchorToken(id) {
|
|
35
|
+
return `<!--${SSR_PORTAL_ANCHOR_PREFIX}${id}-->`;
|
|
36
|
+
}
|
|
37
|
+
function isSSRPortalMarkerData(data, prefix) {
|
|
38
|
+
if (!data.startsWith(prefix)) return false;
|
|
39
|
+
const id = data.slice(prefix.length);
|
|
40
|
+
return id.length > 0 && Array.from(id).every((char) => char >= "0" && char <= "9");
|
|
41
|
+
}
|
|
42
|
+
function isSSRPortalHydrationAnchor(node) {
|
|
43
|
+
if (typeof node !== "object" || node === null || node.nodeType !== 8) return false;
|
|
44
|
+
const data = node.data;
|
|
45
|
+
return typeof data === "string" && (isSSRPortalMarkerData(data, SSR_PORTAL_HOST_PREFIX) || isSSRPortalMarkerData(data, SSR_PORTAL_ANCHOR_PREFIX));
|
|
46
|
+
}
|
|
47
|
+
function isSSRPortalWriterAnchor(node) {
|
|
48
|
+
return isSSRPortalHydrationAnchor(node) && node.data.startsWith(SSR_PORTAL_ANCHOR_PREFIX);
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/common/ssr-portals.ts
|
|
52
|
+
const DEFAULT_SSR_PORTAL_KEY = {};
|
|
53
|
+
const IMPERATIVE_WRITER = {};
|
|
54
|
+
function getSSRPortalSlot(key) {
|
|
55
|
+
const context = getActiveRenderContext();
|
|
56
|
+
if (context?.mode !== "ssr") return null;
|
|
57
|
+
let slot = context.ssrPortals.slots.get(key);
|
|
58
|
+
if (!slot) {
|
|
59
|
+
slot = {
|
|
60
|
+
hasValue: false,
|
|
61
|
+
value: void 0,
|
|
62
|
+
writers: /* @__PURE__ */ new Map(),
|
|
63
|
+
hosts: []
|
|
64
|
+
};
|
|
65
|
+
context.ssrPortals.slots.set(key, slot);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
context,
|
|
69
|
+
slot
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function createSSRPortalHost(key, automatic, defaultPortal = false) {
|
|
73
|
+
const current = getSSRPortalSlot(key);
|
|
74
|
+
if (!current) return null;
|
|
75
|
+
const token = createSSRPortalHostToken(current.context.ssrPortals.nextHostId++);
|
|
76
|
+
current.slot.hosts.push({
|
|
77
|
+
token,
|
|
78
|
+
automatic,
|
|
79
|
+
defaultPortal
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
$$typeof: ELEMENT_TYPE,
|
|
83
|
+
type: SSR_PORTAL_HOST,
|
|
84
|
+
props: { token }
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function writeSSRPortal(key, children, owner) {
|
|
88
|
+
const current = getSSRPortalSlot(key);
|
|
89
|
+
if (!current) return false;
|
|
90
|
+
const writer = owner ?? IMPERATIVE_WRITER;
|
|
91
|
+
const previous = current.slot.writers.get(writer);
|
|
92
|
+
const entry = {
|
|
93
|
+
owner: owner ?? null,
|
|
94
|
+
value: children,
|
|
95
|
+
order: previous?.order ?? current.context.ssrPortals.nextWriteOrder++
|
|
96
|
+
};
|
|
97
|
+
current.slot.writers.set(writer, entry);
|
|
98
|
+
current.slot.hasValue = true;
|
|
99
|
+
current.slot.value = children;
|
|
100
|
+
current.slot.owner = owner;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/core/api/portal.ts
|
|
105
|
+
/**
|
|
106
|
+
* Portals: content written in one place and rendered at a host elsewhere.
|
|
107
|
+
*
|
|
108
|
+
* A channel holds ordered writer records. Each writer's content commits to
|
|
109
|
+
* its own record and renders at the host's position, owned by that writer, so
|
|
110
|
+
* the content lives and dies with the writer and reads the writer's scopes.
|
|
111
|
+
*
|
|
112
|
+
* Each application root provides a default channel; `<Portal>` writes to it
|
|
113
|
+
* and `<DefaultPortal>` (or the automatic host a root appends) renders it.
|
|
114
|
+
*/
|
|
115
|
+
let nextWriteId = 0;
|
|
116
|
+
function createWrite(owner, children) {
|
|
117
|
+
return {
|
|
118
|
+
owner,
|
|
119
|
+
id: ++nextWriteId,
|
|
120
|
+
children: new Signal(children)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function createPortalChannel() {
|
|
124
|
+
return {
|
|
125
|
+
writes: new Signal([]),
|
|
126
|
+
explicitHosts: new Signal(0)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function renderWrite(writes) {
|
|
130
|
+
return [...writes].sort(compareWrites).map((write) => ({
|
|
131
|
+
$$typeof: ELEMENT_TYPE,
|
|
132
|
+
type: OWNED_TYPE,
|
|
133
|
+
props: {
|
|
134
|
+
owner: write.owner,
|
|
135
|
+
children: {
|
|
136
|
+
$$typeof: ELEMENT_TYPE,
|
|
137
|
+
type: PortalLayer,
|
|
138
|
+
props: { write }
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
key: `portal:${write.id}`
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
function PortalLayer(props) {
|
|
145
|
+
const children = props.write.children.read();
|
|
146
|
+
return {
|
|
147
|
+
$$typeof: ELEMENT_TYPE,
|
|
148
|
+
type: ErrorBoundary,
|
|
149
|
+
props: {
|
|
150
|
+
children,
|
|
151
|
+
fallback: (error) => {
|
|
152
|
+
if (deliverToBoundary(props.write.owner, error)) return null;
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/** Record `children` as `channel`'s content once the current render commits. */
|
|
159
|
+
function writeChannel(channel, children) {
|
|
160
|
+
if (writeSSRPortal(ssrKey(channel), children, getOwner())) return;
|
|
161
|
+
const instance = currentComponent();
|
|
162
|
+
if (!instance) {
|
|
163
|
+
let write = imperativeWriters.get(channel);
|
|
164
|
+
if (!write) {
|
|
165
|
+
write = createWrite(null, children);
|
|
166
|
+
imperativeWriters.set(channel, write);
|
|
167
|
+
addWrite(channel, write);
|
|
168
|
+
} else write.children.write(children);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (instance.server) return;
|
|
172
|
+
let owned = writers.get(instance);
|
|
173
|
+
if (!owned) writers.set(instance, owned = /* @__PURE__ */ new Map());
|
|
174
|
+
let write = owned.get(channel);
|
|
175
|
+
const created = !write;
|
|
176
|
+
const previousChildren = write?.children.peek();
|
|
177
|
+
if (!write) {
|
|
178
|
+
write = createWrite(instance, children);
|
|
179
|
+
owned.set(channel, write);
|
|
180
|
+
}
|
|
181
|
+
const record = write;
|
|
182
|
+
const apply = () => {
|
|
183
|
+
addWrite(channel, record);
|
|
184
|
+
record.children.write(children);
|
|
185
|
+
};
|
|
186
|
+
if (getRenderHost()?.isHydrating()) {
|
|
187
|
+
apply();
|
|
188
|
+
recordUndo(() => {
|
|
189
|
+
if (created) {
|
|
190
|
+
removeWrite(channel, record);
|
|
191
|
+
owned.delete(channel);
|
|
192
|
+
} else record.children.write(previousChildren);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (created) instance.onCleanup(() => {
|
|
196
|
+
owned.delete(channel);
|
|
197
|
+
removeWrite(channel, record);
|
|
198
|
+
});
|
|
199
|
+
instance.onCommitSync(() => {
|
|
200
|
+
apply();
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
const writers = /* @__PURE__ */ new WeakMap();
|
|
204
|
+
const imperativeWriters = /* @__PURE__ */ new WeakMap();
|
|
205
|
+
function addWrite(channel, write) {
|
|
206
|
+
if (channel.writes.peek().some((item) => item === write)) return;
|
|
207
|
+
channel.writes.write([...channel.writes.peek(), write].sort(compareWrites));
|
|
208
|
+
}
|
|
209
|
+
function compareWrites(left, right) {
|
|
210
|
+
const leftPosition = sourcePosition(left.owner);
|
|
211
|
+
const rightPosition = sourcePosition(right.owner);
|
|
212
|
+
if (leftPosition && rightPosition) {
|
|
213
|
+
if (leftPosition.container === rightPosition.container) {
|
|
214
|
+
const length = Math.min(leftPosition.path.length, rightPosition.path.length);
|
|
215
|
+
for (let index = 0; index < length; index++) if (leftPosition.path[index] !== rightPosition.path[index]) return leftPosition.path[index] - rightPosition.path[index];
|
|
216
|
+
if (leftPosition.path.length !== rightPosition.path.length) return leftPosition.path.length - rightPosition.path.length;
|
|
217
|
+
} else {
|
|
218
|
+
const relation = leftPosition.container.compareDocumentPosition(rightPosition.container);
|
|
219
|
+
if (relation & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
|
|
220
|
+
if (relation & Node.DOCUMENT_POSITION_PRECEDING) return 1;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return comparePortalWriterOrder(left.owner, right.owner);
|
|
224
|
+
}
|
|
225
|
+
function sourcePosition(owner) {
|
|
226
|
+
if (!owner || typeof Node === "undefined") return null;
|
|
227
|
+
let node = owner.view;
|
|
228
|
+
const path = [];
|
|
229
|
+
while (node?.parent) {
|
|
230
|
+
const parent = node.parent;
|
|
231
|
+
if ("children" in parent && Array.isArray(parent.children)) path.unshift(parent.children.indexOf(node));
|
|
232
|
+
if ("el" in parent && parent.el instanceof Element) return {
|
|
233
|
+
container: parent.el,
|
|
234
|
+
path
|
|
235
|
+
};
|
|
236
|
+
node = parent;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
function removeWrite(channel, write) {
|
|
241
|
+
const writes = channel.writes.peek();
|
|
242
|
+
if (!writes.includes(write)) return;
|
|
243
|
+
channel.writes.write(writes.filter((item) => item !== write));
|
|
244
|
+
}
|
|
245
|
+
function definePortal() {
|
|
246
|
+
const channel = createPortalChannel();
|
|
247
|
+
function PortalHost() {
|
|
248
|
+
const ssr = createSSRPortalHost(channel, false);
|
|
249
|
+
if (ssr) return ssr;
|
|
250
|
+
deferWhileHydrating();
|
|
251
|
+
return renderWrite(channel.writes.read());
|
|
252
|
+
}
|
|
253
|
+
PortalHost.render = (props) => {
|
|
254
|
+
writeChannel(channel, props.children);
|
|
255
|
+
return null;
|
|
256
|
+
};
|
|
257
|
+
portalChannels.set(PortalHost, channel);
|
|
258
|
+
return PortalHost;
|
|
259
|
+
}
|
|
260
|
+
const portalChannels = /* @__PURE__ */ new WeakMap();
|
|
261
|
+
const DEFAULT_CHANNEL = Symbol("askr.default-portal");
|
|
262
|
+
let fallbackChannel = null;
|
|
263
|
+
let fallbackAdoptable = false;
|
|
264
|
+
const rootChannels = /* @__PURE__ */ new Map();
|
|
265
|
+
/** Give everything rendered under `owner` its own default portal. */
|
|
266
|
+
function provideDefaultPortal(owner, root) {
|
|
267
|
+
const channel = root && rootChannels.size === 0 && fallbackAdoptable && fallbackChannel ? fallbackChannel : createPortalChannel();
|
|
268
|
+
if (root) {
|
|
269
|
+
rootChannels.set(root, channel);
|
|
270
|
+
fallbackChannel = null;
|
|
271
|
+
fallbackAdoptable = false;
|
|
272
|
+
owner.onCleanup(() => {
|
|
273
|
+
if (rootChannels.get(root) === channel) rootChannels.delete(root);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
(owner.context ??= /* @__PURE__ */ new Map()).set(DEFAULT_CHANNEL, channel);
|
|
277
|
+
return channel;
|
|
278
|
+
}
|
|
279
|
+
/** Server renders collect default-portal writes under one key. */
|
|
280
|
+
function ssrKey(channel) {
|
|
281
|
+
return channel === serverDefaultChannel ? DEFAULT_SSR_PORTAL_KEY : channel;
|
|
282
|
+
}
|
|
283
|
+
const serverDefaultChannel = createPortalChannel();
|
|
284
|
+
function defaultChannel() {
|
|
285
|
+
if (currentComponent()?.server) return serverDefaultChannel;
|
|
286
|
+
const provided = getOwner()?.lookup(DEFAULT_CHANNEL);
|
|
287
|
+
if (provided) return provided;
|
|
288
|
+
let connected = null;
|
|
289
|
+
for (const [root, channel] of rootChannels) {
|
|
290
|
+
if (!root.isConnected) continue;
|
|
291
|
+
if (connected) {
|
|
292
|
+
fallbackAdoptable = false;
|
|
293
|
+
return fallbackChannel ?? (fallbackChannel = createPortalChannel());
|
|
294
|
+
}
|
|
295
|
+
connected = channel;
|
|
296
|
+
}
|
|
297
|
+
if (connected) return connected;
|
|
298
|
+
fallbackAdoptable = rootChannels.size === 0;
|
|
299
|
+
return fallbackChannel ?? (fallbackChannel = createPortalChannel());
|
|
300
|
+
}
|
|
301
|
+
/** Write `children` to the default portal. */
|
|
302
|
+
function Portal(props) {
|
|
303
|
+
writeChannel(defaultChannel(), props.children);
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
/** Render the default portal's content here. */
|
|
307
|
+
function DefaultPortal(props) {
|
|
308
|
+
const automatic = props?.__askrAutoDefaultPortal === true;
|
|
309
|
+
if (currentComponent()?.server) return createSSRPortalHost(DEFAULT_SSR_PORTAL_KEY, automatic, true);
|
|
310
|
+
const channel = defaultChannel();
|
|
311
|
+
if (automatic) {
|
|
312
|
+
if (channel.explicitHosts.read() > 0) return null;
|
|
313
|
+
deferWhileHydrating();
|
|
314
|
+
return renderWrite(channel.writes.read());
|
|
315
|
+
}
|
|
316
|
+
const instance = currentComponent();
|
|
317
|
+
if (instance && !instance.server && !explicitHosts.has(instance)) {
|
|
318
|
+
explicitHosts.add(instance);
|
|
319
|
+
channel.explicitHosts.write(channel.explicitHosts.peek() + 1);
|
|
320
|
+
let counted = true;
|
|
321
|
+
recordUndo(() => {
|
|
322
|
+
counted = false;
|
|
323
|
+
explicitHosts.delete(instance);
|
|
324
|
+
channel.explicitHosts.write(channel.explicitHosts.peek() - 1);
|
|
325
|
+
});
|
|
326
|
+
const boundary = nearestErrorBoundary(instance);
|
|
327
|
+
instance.onCleanup(() => {
|
|
328
|
+
if (!counted) return;
|
|
329
|
+
counted = false;
|
|
330
|
+
const release = () => channel.explicitHosts.write(channel.explicitHosts.peek() - 1);
|
|
331
|
+
if (!boundary || !holdUntilBoundaryRecovers(boundary, release)) release();
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
deferWhileHydrating();
|
|
335
|
+
return renderWrite(channel.writes.read());
|
|
336
|
+
}
|
|
337
|
+
const explicitHosts = /* @__PURE__ */ new WeakSet();
|
|
338
|
+
/** A host rendered before its content: claim the server content later. */
|
|
339
|
+
function deferWhileHydrating() {
|
|
340
|
+
const instance = currentComponent();
|
|
341
|
+
if (instance?.mounted === false) getRenderHost()?.deferHydration(instance);
|
|
342
|
+
}
|
|
343
|
+
/** `DefaultPortal.render()` writes to the default portal, like `<Portal>`. */
|
|
344
|
+
DefaultPortal.render = (props) => {
|
|
345
|
+
writeChannel(defaultChannel(), props.children);
|
|
346
|
+
return null;
|
|
347
|
+
};
|
|
348
|
+
//#endregion
|
|
349
|
+
export { SSR_PORTAL_HOST as a, isSSRPortalHydrationAnchor as c, provideDefaultPortal as i, isSSRPortalWriterAnchor as l, Portal as n, comparePortalWriterOrder as o, definePortal as r, createSSRPortalAnchorToken as s, DefaultPortal as t };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/common/promise.ts
|
|
2
|
+
function isPromiseLike(value) {
|
|
3
|
+
return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Components must return synchronously; async work belongs in `resource()`.
|
|
7
|
+
*
|
|
8
|
+
* The rule was previously enforced by ten hand-written throws carrying three
|
|
9
|
+
* different messages. It is one rule, so it has one message and one guard.
|
|
10
|
+
*/
|
|
11
|
+
const ASYNC_COMPONENT_MESSAGE = "Async components are not supported. Use resource() for async work.";
|
|
12
|
+
function assertSyncComponentResult(result) {
|
|
13
|
+
if (isPromiseLike(result)) throw new Error(ASYNC_COMPONENT_MESSAGE);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { isPromiseLike as n, assertSyncComponentResult as t };
|