@markless/router 0.4.0 → 0.6.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/dist/create-server-entry-DaYssO9x.js +1331 -0
- package/dist/debug-channel-CewnC9fH.js +2 -0
- package/dist/{debug-channel-CSzo-Zj8.js → debug-channel-Di6SppZv.js} +36 -17
- package/dist/index-BjxpxRL7.d.ts +248 -0
- package/dist/index.d.ts +2 -212
- package/dist/index.js +108 -40
- package/dist/protocol-constants-B4WxrZAS.js +26 -0
- package/dist/request-locals-z3rJTizs.js +90 -0
- package/dist/route-href-CGooO_g6.js +18 -0
- package/dist/route-manifest-DMizh42B.js +456 -0
- package/dist/typescript-plugin.cjs +9 -6
- package/dist/typescript-plugin.d.ts +3 -11194
- package/dist/typescript-plugin.js +9 -6
- package/dist/vite/route-href.d.ts +2 -3
- package/dist/vite/route-href.js +1 -17
- package/dist/vite/runtime/create-route-discovery.d.ts +3 -4
- package/dist/vite/runtime/create-route-discovery.js +1 -1
- package/dist/vite/runtime/create-server-entry.d.ts +27 -5
- package/dist/vite/runtime/create-server-entry.js +2 -400
- package/dist/vite/runtime/mdx-route.d.ts +1116 -17
- package/dist/vite/runtime/mdx-route.js +1097 -31
- package/dist/vite.d.ts +10 -6
- package/dist/vite.js +965 -203
- package/package.json +7 -6
- package/src/vite/entries/client-entry.ts +10 -1
- package/src/vite/entries/fragment-entry.ts +797 -0
- package/src/vite/entries/resume-entry.ts +41 -7
- package/dist/request-files-C-0LLSsx.js +0 -232
- package/dist/route-manifest-DPgGIyrS.js +0 -186
package/dist/index.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import { i as
|
|
2
|
-
import {
|
|
1
|
+
import { c as PREFETCH_ATTRIBUTE, i as HTML_ATTRIBUTES_SLOT, l as REPLACE_ATTRIBUTE, o as routeMountTarget, s as LINK_ATTRIBUTE, t as rememberRequestLocals, u as SCROLL_ATTRIBUTE } from "./request-locals-z3rJTizs.js";
|
|
2
|
+
import { a as normalizeRequestPathname, c as parseRequestFile, i as matchRouteManifest, l as transformRequestFileSource, n as buildRouteManifestFromFileIds, o as normalizeRouteFileId, s as normalizeRequestFileId } from "./route-manifest-DMizh42B.js";
|
|
3
3
|
import { createExternalDelegateStructureTokens, createExternalDelegateView } from "@markless/web/fns/external-delegate";
|
|
4
4
|
import { render } from "@markless/web/render";
|
|
5
|
-
import { MARKLESS_PENDING_MIN_VISIBLE_MS as MARKLESS_NAV_PENDING_MIN_MS, settleOrPendingDeadline } from "@markless/web";
|
|
6
|
-
//#region src/navigation-hold.ts
|
|
7
|
-
async function holdNavigationSwapUntilSettled(input) {
|
|
8
|
-
const settled = input.runtime.whenAsyncBoundariesSettled?.();
|
|
9
|
-
if (settled) {
|
|
10
|
-
if (await settleOrPendingDeadline(settled, input.clock?.wait) === "deadline") await input.runtime.holdPendingSettleCommits?.(MARKLESS_NAV_PENDING_MIN_MS);
|
|
11
|
-
}
|
|
12
|
-
if (input.signal?.aborted) return false;
|
|
13
|
-
}
|
|
14
|
-
//#endregion
|
|
5
|
+
import { MARKLESS_PENDING_MIN_VISIBLE_MS as MARKLESS_NAV_PENDING_MIN_MS, settleOrPendingDeadline } from "@markless/web/fns/pending-timing";
|
|
15
6
|
//#region src/route-state.ts
|
|
16
7
|
const MARKLESS_ROUTER_ROUTE_EVENT = "marklessrouternavigate";
|
|
8
|
+
const MARKLESS_ROUTER_RENDERED_EVENT = "marklessrouterrendered";
|
|
17
9
|
const MARKLESS_ROUTER_RENDERER_STARTED = "__marklessRouterRouteRendererStarted";
|
|
18
10
|
function routePageProps(route) {
|
|
19
11
|
const url = new URL(route.url);
|
|
@@ -31,6 +23,66 @@ function dispatchRouteUpdate(document, update) {
|
|
|
31
23
|
document.dispatchEvent(new CustomEvent(MARKLESS_ROUTER_ROUTE_EVENT, { detail: update }));
|
|
32
24
|
}
|
|
33
25
|
//#endregion
|
|
26
|
+
//#region src/navigate.ts
|
|
27
|
+
/**
|
|
28
|
+
* Navigates to `href` exactly as a click on `<Link href={href}>` would: a page of this app swaps in
|
|
29
|
+
* place, anything else loads as a document. The promise resolves once the new page is in place; a
|
|
30
|
+
* navigation that loads a new document leaves this page, so its promise never settles.
|
|
31
|
+
* Runs in the browser only.
|
|
32
|
+
*/
|
|
33
|
+
function navigate(href, options = {}) {
|
|
34
|
+
if (typeof document === "undefined") throw new Error("MARKLESS_ROUTER_NAVIGATE_SERVER: navigate() runs in the browser. Call it from an event handler or other browser code, not while the page renders on the server.");
|
|
35
|
+
const d = document;
|
|
36
|
+
const w = d.defaultView ?? window;
|
|
37
|
+
const url = new URL(href, d.baseURI);
|
|
38
|
+
const rendered = new Promise((resolve) => d.addEventListener(MARKLESS_ROUTER_RENDERED_EVENT, () => resolve(), { once: true }));
|
|
39
|
+
const anchor = d.createElement("a");
|
|
40
|
+
anchor.href = url.href;
|
|
41
|
+
anchor.hidden = true;
|
|
42
|
+
anchor.setAttribute(LINK_ATTRIBUTE, "");
|
|
43
|
+
if (options.replace) anchor.setAttribute(REPLACE_ATTRIBUTE, "");
|
|
44
|
+
if (options.scroll === false) anchor.setAttribute(SCROLL_ATTRIBUTE, "manual");
|
|
45
|
+
let reached = false;
|
|
46
|
+
let routed = false;
|
|
47
|
+
const last = (event) => {
|
|
48
|
+
if (event.target !== anchor) return;
|
|
49
|
+
reached = true;
|
|
50
|
+
routed = event.defaultPrevented;
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
};
|
|
53
|
+
w.addEventListener("click", last);
|
|
54
|
+
d.body.append(anchor);
|
|
55
|
+
try {
|
|
56
|
+
anchor.dispatchEvent(new MouseEvent("click", {
|
|
57
|
+
bubbles: true,
|
|
58
|
+
cancelable: true,
|
|
59
|
+
composed: true,
|
|
60
|
+
button: 0
|
|
61
|
+
}));
|
|
62
|
+
} finally {
|
|
63
|
+
anchor.remove();
|
|
64
|
+
w.removeEventListener("click", last);
|
|
65
|
+
}
|
|
66
|
+
if (routed || !reached) return rendered;
|
|
67
|
+
const inPage = url.hash !== "" && withoutHash(url.href) === withoutHash(w.location.href);
|
|
68
|
+
if (options.replace) w.location.replace(url.href);
|
|
69
|
+
else w.location.assign(url.href);
|
|
70
|
+
return inPage ? Promise.resolve() : new Promise(() => {});
|
|
71
|
+
}
|
|
72
|
+
function withoutHash(href) {
|
|
73
|
+
const at = href.indexOf("#");
|
|
74
|
+
return at === -1 ? href : href.slice(0, at);
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/navigation-hold.ts
|
|
78
|
+
async function holdNavigationSwapUntilSettled(input) {
|
|
79
|
+
const settled = input.runtime.whenAsyncBoundariesSettled?.();
|
|
80
|
+
if (settled) {
|
|
81
|
+
if (await settleOrPendingDeadline(settled, input.clock?.wait) === "deadline") await input.runtime.holdPendingSettleCommits?.(MARKLESS_NAV_PENDING_MIN_MS);
|
|
82
|
+
}
|
|
83
|
+
if (input.signal?.aborted) return false;
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
34
86
|
//#region src/route-renderer.ts
|
|
35
87
|
const CURRENT_ROUTE_CONTAINER = "__marklessRouterCurrentRouteContainer";
|
|
36
88
|
function startRouteUpdateRenderer(document = window.document) {
|
|
@@ -48,22 +100,26 @@ async function renderRouteUpdate(document, update) {
|
|
|
48
100
|
if (!artifact.renderData) throw new Error(`MARKLESS_ROUTER_RENDER_DATA_MISSING: Navigated route ${JSON.stringify(update.route.file)} has no linked render-data module.`);
|
|
49
101
|
const props = routePageProps(update.route);
|
|
50
102
|
const state = document;
|
|
103
|
+
const outgoing = state[CURRENT_ROUTE_CONTAINER];
|
|
51
104
|
const container = await render({
|
|
52
105
|
renderData: artifact.renderData,
|
|
53
106
|
loadSymbol: artifact.loadSymbol,
|
|
54
107
|
props
|
|
55
108
|
}, {
|
|
56
|
-
target: document
|
|
109
|
+
target: routeMountTarget(document, outgoing?.root),
|
|
57
110
|
beforeMount: async (incoming) => {
|
|
58
111
|
if (await holdNavigationSwapUntilSettled({
|
|
59
112
|
runtime: incoming.runtime,
|
|
60
113
|
signal: update.signal
|
|
61
114
|
}) === false) return false;
|
|
62
|
-
|
|
115
|
+
outgoing?.runtime?.dispose?.();
|
|
63
116
|
return true;
|
|
64
117
|
}
|
|
65
118
|
});
|
|
66
|
-
if (!update.signal?.aborted)
|
|
119
|
+
if (!update.signal?.aborted) {
|
|
120
|
+
state[CURRENT_ROUTE_CONTAINER] = container;
|
|
121
|
+
document.dispatchEvent(new CustomEvent(MARKLESS_ROUTER_RENDERED_EVENT));
|
|
122
|
+
}
|
|
67
123
|
} finally {
|
|
68
124
|
update.onRendered?.();
|
|
69
125
|
}
|
|
@@ -71,9 +127,6 @@ async function renderRouteUpdate(document, update) {
|
|
|
71
127
|
//#endregion
|
|
72
128
|
//#region src/spa-navigation.ts
|
|
73
129
|
const STARTED = "__marklessRouterSpaNavigationStarted";
|
|
74
|
-
const LINK_ATTRIBUTE = "data-markless-router-link";
|
|
75
|
-
const REPLACE_ATTRIBUTE = "data-markless-router-replace";
|
|
76
|
-
const SCROLL_ATTRIBUTE = "data-markless-router-scroll";
|
|
77
130
|
const LINK_INFO = "__marklessRouterLink";
|
|
78
131
|
function hashRoutePath(url) {
|
|
79
132
|
return url.hash.startsWith("#/") ? url.hash.slice(1) : void 0;
|
|
@@ -88,6 +141,7 @@ async function __marklessRouterStartSpaNavigation(options) {
|
|
|
88
141
|
state[STARTED] = true;
|
|
89
142
|
const context = {
|
|
90
143
|
documentModuleLoader: options.documentModuleLoader,
|
|
144
|
+
documentNavigation: options.documentNavigation,
|
|
91
145
|
manifest: buildRouteManifestFromFileIds(options.routeFileIds),
|
|
92
146
|
pageModuleLoaders: options.pageModuleLoaders,
|
|
93
147
|
preloadRouteModule: options.preloadRouteModule,
|
|
@@ -98,23 +152,30 @@ async function __marklessRouterStartSpaNavigation(options) {
|
|
|
98
152
|
navigation.addEventListener("navigate", (event) => {
|
|
99
153
|
handleNavigateEvent(event, context);
|
|
100
154
|
});
|
|
101
|
-
if (typeof __MARKLESS_DEBUG_ENABLED__ !== "undefined" && __MARKLESS_DEBUG_ENABLED__) await import("./debug-channel-
|
|
102
|
-
if (typeof __MARKLESS_DEBUG_ENABLED__ !== "undefined" && __MARKLESS_DEBUG_ENABLED__) await import("./debug-channel-
|
|
155
|
+
if (typeof __MARKLESS_DEBUG_ENABLED__ !== "undefined" && __MARKLESS_DEBUG_ENABLED__) await import("./debug-channel-CewnC9fH.js").then((debug) => debug.__marklessDebugRegisterRouter(void 0, "spa-click-listener")).catch(() => {});
|
|
156
|
+
if (typeof __MARKLESS_DEBUG_ENABLED__ !== "undefined" && __MARKLESS_DEBUG_ENABLED__) await import("./debug-channel-CewnC9fH.js").then((debug) => debug.__marklessDebugRegisterRouter(void 0, "navigation-event")).catch(() => {});
|
|
103
157
|
{
|
|
104
158
|
const bootUrl = parseSameOriginUrl(runtimeWindow.location.href, runtimeWindow.location.href);
|
|
105
159
|
const bootHashPath = bootUrl ? hashRoutePath(bootUrl) : void 0;
|
|
106
160
|
if (bootUrl && bootHashPath && matchRouteManifest(bootHashPath, context.manifest)) renderRoute(bootUrl, context);
|
|
107
161
|
}
|
|
108
162
|
}
|
|
163
|
+
const pendingPolyfills = /* @__PURE__ */ new WeakMap();
|
|
109
164
|
async function ensureNavigationRuntime(runtimeWindow = browserWindow(), loadPolyfill) {
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
165
|
+
if (runtimeWindow.navigation) return runtimeWindow.navigation;
|
|
166
|
+
let pending = pendingPolyfills.get(runtimeWindow);
|
|
167
|
+
if (!pending) {
|
|
168
|
+
pending = (async () => {
|
|
169
|
+
const { applyPolyfill } = await (loadPolyfill?.() ?? import("@virtualstate/navigation"));
|
|
170
|
+
return runtimeWindow.navigation ??= applyPolyfill({
|
|
171
|
+
interceptEvents: false,
|
|
172
|
+
window: runtimeWindow
|
|
173
|
+
});
|
|
174
|
+
})();
|
|
175
|
+
pendingPolyfills.set(runtimeWindow, pending);
|
|
176
|
+
pending.catch(() => pendingPolyfills.delete(runtimeWindow));
|
|
116
177
|
}
|
|
117
|
-
return
|
|
178
|
+
return pending;
|
|
118
179
|
}
|
|
119
180
|
function handleNavigateEvent(event, context) {
|
|
120
181
|
const url = routeUrl(event, context);
|
|
@@ -136,7 +197,10 @@ async function renderRoute(url, context, signal) {
|
|
|
136
197
|
return;
|
|
137
198
|
}
|
|
138
199
|
preloadRouteModule(context, match.route.file);
|
|
139
|
-
const [page, document] = await Promise.all([loadPageModule(), context.documentModuleLoader?.()])
|
|
200
|
+
const [page, document] = await Promise.all([loadPageModule(), context.documentModuleLoader?.()]).catch((error) => {
|
|
201
|
+
context.window.location.assign(url.href);
|
|
202
|
+
throw error;
|
|
203
|
+
});
|
|
140
204
|
if (signal?.aborted) return;
|
|
141
205
|
const update = {
|
|
142
206
|
document,
|
|
@@ -167,17 +231,17 @@ function warnUnknownHashRoute(url) {
|
|
|
167
231
|
function handleLinkClick(event, context, navigation) {
|
|
168
232
|
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) return;
|
|
169
233
|
const anchor = sourceAnchor(event);
|
|
170
|
-
if (!anchor || !anchor.hasAttribute(
|
|
234
|
+
if (!anchor || !anchor.hasAttribute("data-markless-router-link") || !isEligibleLink(anchor)) return;
|
|
171
235
|
const url = parseSameOriginUrl(anchor.href, context.window.location.href);
|
|
172
236
|
const match = url && matchRouteManifest(routePathname(url, context), context.manifest);
|
|
173
|
-
if (!match) return;
|
|
237
|
+
if (!url || !match || context.documentNavigation === "document" && !hashRoutePath(url)) return;
|
|
174
238
|
preloadRouteModule(context, match.route.file);
|
|
175
239
|
event.preventDefault();
|
|
176
240
|
navigation.navigate(url.href, {
|
|
177
|
-
history: anchor.hasAttribute(
|
|
241
|
+
history: anchor.hasAttribute("data-markless-router-replace") ? "replace" : "push",
|
|
178
242
|
info: {
|
|
179
243
|
[LINK_INFO]: true,
|
|
180
|
-
scroll: anchor.getAttribute(
|
|
244
|
+
scroll: anchor.getAttribute("data-markless-router-scroll") === "manual" ? "manual" : void 0
|
|
181
245
|
}
|
|
182
246
|
});
|
|
183
247
|
}
|
|
@@ -189,7 +253,7 @@ function preloadRouteModule(context, file) {
|
|
|
189
253
|
function routeUrl(event, context) {
|
|
190
254
|
const destination = parseSameOriginUrl(event.destination.url, context.window.location.href);
|
|
191
255
|
const hashRouteNavigation = event.hashChange === true && !!destination && hashRoutePath(destination) !== void 0;
|
|
192
|
-
if (!isMarklessRouterNavigation(event) && !hashRouteNavigation || event.canIntercept === false || event.navigationType === "reload" || event.hashChange && !hashRouteNavigation || event.downloadRequest != null || event.formData != null) return;
|
|
256
|
+
if (!isMarklessRouterNavigation(event) && !hashRouteNavigation || context.documentNavigation === "document" && !hashRouteNavigation || event.canIntercept === false || event.navigationType === "reload" || event.hashChange && !hashRouteNavigation || event.downloadRequest != null || event.formData != null) return;
|
|
193
257
|
const matched = destination && matchRouteManifest(routePathname(destination), context.manifest) ? destination : void 0;
|
|
194
258
|
if (!matched && hashRouteNavigation && destination) warnUnknownHashRoute(destination);
|
|
195
259
|
return matched;
|
|
@@ -226,6 +290,7 @@ function browserWindow() {
|
|
|
226
290
|
function __marklessCreateHttpContext(event) {
|
|
227
291
|
const context = event.context ?? {};
|
|
228
292
|
const url = event.url ?? new URL("http://localhost/");
|
|
293
|
+
if (event.req) rememberRequestLocals(event.req, context, event.res?.headers);
|
|
229
294
|
return {
|
|
230
295
|
locals: context,
|
|
231
296
|
params: context.params ?? {},
|
|
@@ -236,9 +301,11 @@ function __marklessCreateHttpContext(event) {
|
|
|
236
301
|
}
|
|
237
302
|
const Html = Object.assign(function Html(props) {
|
|
238
303
|
return props.children;
|
|
239
|
-
}, { renderSsr(props = {}) {
|
|
304
|
+
}, { renderSsr(props = {}, renderContext) {
|
|
305
|
+
const { children, ...attributes } = props;
|
|
306
|
+
if (renderContext?.["__marklessRouterHtmlAttributes"]) Object.assign(renderContext[HTML_ATTRIBUTES_SLOT], attributes);
|
|
240
307
|
return {
|
|
241
|
-
html:
|
|
308
|
+
html: children == null ? "" : String(children),
|
|
242
309
|
elementCount: 0
|
|
243
310
|
};
|
|
244
311
|
} });
|
|
@@ -252,7 +319,7 @@ const Link = Object.assign(function Link(props = {}) {
|
|
|
252
319
|
return {
|
|
253
320
|
root: anchor,
|
|
254
321
|
view: linkExternalDelegateView(),
|
|
255
|
-
liveHostNodes: new Map([["router:link", anchor]])
|
|
322
|
+
liveHostNodes: /* @__PURE__ */ new Map([["router:link", anchor]])
|
|
256
323
|
};
|
|
257
324
|
},
|
|
258
325
|
renderSsr(props = {}, renderContext) {
|
|
@@ -285,9 +352,10 @@ function linkAnchorAttributes(props) {
|
|
|
285
352
|
if (attributeValue !== void 0) attributes.set(name, attributeValue);
|
|
286
353
|
}
|
|
287
354
|
attributes.set("href", typeof props.href === "string" ? props.href : "#");
|
|
288
|
-
attributes.set(
|
|
289
|
-
if (props.replace) attributes.set(
|
|
290
|
-
if (props.
|
|
355
|
+
attributes.set(LINK_ATTRIBUTE, "");
|
|
356
|
+
if (props.replace) attributes.set(REPLACE_ATTRIBUTE, "");
|
|
357
|
+
if (props.prefetch === false) attributes.set(PREFETCH_ATTRIBUTE, "none");
|
|
358
|
+
if (props.scroll === false) attributes.set(SCROLL_ATTRIBUTE, "manual");
|
|
291
359
|
return [...attributes];
|
|
292
360
|
}
|
|
293
361
|
function isLinkInternalProp(name) {
|
|
@@ -306,4 +374,4 @@ function escapeHtml(value) {
|
|
|
306
374
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
307
375
|
}
|
|
308
376
|
//#endregion
|
|
309
|
-
export { Html, Link, MARKLESS_ROUTER_ROUTE_EVENT, __marklessCreateHttpContext, __marklessRouterStartSpaNavigation, buildRouteManifestFromFileIds, dispatchRouteUpdate, ensureNavigationRuntime, matchRouteManifest, normalizeRequestFileId, normalizeRequestPathname, normalizeRouteFileId, parseRequestFile, routePageProps, startRouteUpdateRenderer, transformRequestFileSource };
|
|
377
|
+
export { Html, Link, MARKLESS_ROUTER_RENDERED_EVENT, MARKLESS_ROUTER_ROUTE_EVENT, __marklessCreateHttpContext, __marklessRouterStartSpaNavigation, buildRouteManifestFromFileIds, dispatchRouteUpdate, ensureNavigationRuntime, matchRouteManifest, navigate, normalizeRequestFileId, normalizeRequestPathname, normalizeRouteFileId, parseRequestFile, routePageProps, startRouteUpdateRenderer, transformRequestFileSource };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function protocolStateVersion(storage) {
|
|
2
|
+
return (storage?.length ?? 0) > 0 ? 2 : 1;
|
|
3
|
+
}
|
|
4
|
+
const PROTOCOL_INSTANCE_PATH = /^(?:[cpm]\d+:|r:[^:]*:)+/;
|
|
5
|
+
/** One island's identity segment, outermost of any path it prefixes. */
|
|
6
|
+
function protocolIslandSegment(islandIndex) {
|
|
7
|
+
return `m${islandIndex}:`;
|
|
8
|
+
}
|
|
9
|
+
/** The leading instance path of a composed id, or '' when the id is page-local. */
|
|
10
|
+
function protocolInstancePath(id) {
|
|
11
|
+
return PROTOCOL_INSTANCE_PATH.exec(id)?.[0] ?? "";
|
|
12
|
+
}
|
|
13
|
+
const PROTOCOL_INSTANCE_QUALIFIABLE = [
|
|
14
|
+
"prop:",
|
|
15
|
+
"state:",
|
|
16
|
+
"computed:",
|
|
17
|
+
"element:"
|
|
18
|
+
];
|
|
19
|
+
const PROTOCOL_PAGE_SPACE_ID_PREFIXES = ["shared:", "storage:"];
|
|
20
|
+
function protocolInstanceQualifies(graphNodeId) {
|
|
21
|
+
const local = graphNodeId.slice(protocolInstancePath(graphNodeId).length);
|
|
22
|
+
if (PROTOCOL_PAGE_SPACE_ID_PREFIXES.some((prefix) => local.startsWith(prefix))) return false;
|
|
23
|
+
return PROTOCOL_INSTANCE_QUALIFIABLE.some((prefix) => local.startsWith(prefix)) ? true : void 0;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { protocolStateVersion as i, protocolInstanceQualifies as n, protocolIslandSegment as r, protocolInstancePath as t };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { CONTAINER_ATTRIBUTE, PROTOCOL_CONTAINER_END_COMMENT, PROTOCOL_CONTAINER_START_COMMENT, PROTOCOL_LOCATOR_PATHS_ATTRIBUTE } from "@markless/web/fns/container-region";
|
|
2
|
+
//#region src/link-attributes.ts
|
|
3
|
+
const LINK_ATTRIBUTE = "data-markless-router-link";
|
|
4
|
+
const REPLACE_ATTRIBUTE = "data-markless-router-replace";
|
|
5
|
+
const SCROLL_ATTRIBUTE = "data-markless-router-scroll";
|
|
6
|
+
const PREFETCH_ATTRIBUTE = "data-markless-router-prefetch";
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/route-dom.ts
|
|
9
|
+
const ROUTE_SCRIPT_TYPE = "@markless/core/route";
|
|
10
|
+
const HTML_ATTRIBUTES_SLOT = "__marklessRouterHtmlAttributes";
|
|
11
|
+
function routeMountTarget(document, currentRoot) {
|
|
12
|
+
const root = currentRoot ?? document.querySelector(`script[type="@markless/core/route"]`)?.parentElement;
|
|
13
|
+
if (!root) return document.body;
|
|
14
|
+
const host = [root, root.parentElement].find((element) => element && containerPageEnd(element));
|
|
15
|
+
if (host) return authorElementTarget(document, host);
|
|
16
|
+
return {
|
|
17
|
+
ownerDocument: document,
|
|
18
|
+
replaceChildren(...children) {
|
|
19
|
+
root.replaceWith(...children);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function containerPageEnd(host) {
|
|
24
|
+
for (let node = host.lastChild; node; node = node.previousSibling) if (node.nodeType === 8 && node.data === PROTOCOL_CONTAINER_END_COMMENT) return node;
|
|
25
|
+
}
|
|
26
|
+
function containerPageStart(host) {
|
|
27
|
+
for (let node = host.firstChild; node; node = node.nextSibling) if (node.nodeType === 8 && node.data === PROTOCOL_CONTAINER_START_COMMENT) return node;
|
|
28
|
+
}
|
|
29
|
+
function authorElementTarget(document, host) {
|
|
30
|
+
const copy = () => {
|
|
31
|
+
const next = host.cloneNode(false);
|
|
32
|
+
next.removeAttribute(CONTAINER_ATTRIBUTE);
|
|
33
|
+
next.removeAttribute(PROTOCOL_LOCATOR_PATHS_ATTRIBUTE);
|
|
34
|
+
return next;
|
|
35
|
+
};
|
|
36
|
+
let holder;
|
|
37
|
+
return {
|
|
38
|
+
ownerDocument: document,
|
|
39
|
+
createHolder: () => holder = copy(),
|
|
40
|
+
replaceChildren(...children) {
|
|
41
|
+
const next = children.length === 1 && children[0] === holder ? holder : copy();
|
|
42
|
+
if (next !== holder) next.append(...children);
|
|
43
|
+
const end = containerPageEnd(host);
|
|
44
|
+
const focused = document.activeElement;
|
|
45
|
+
const start = containerPageStart(host);
|
|
46
|
+
if (start) {
|
|
47
|
+
const before = [];
|
|
48
|
+
for (let node = host.firstChild; node !== start; node = node.nextSibling) before.push(node);
|
|
49
|
+
next.prepend(...before, document.createComment(PROTOCOL_CONTAINER_START_COMMENT));
|
|
50
|
+
}
|
|
51
|
+
next.append(document.createComment(PROTOCOL_CONTAINER_END_COMMENT));
|
|
52
|
+
while (end.nextSibling) next.append(end.nextSibling);
|
|
53
|
+
host.replaceWith(next);
|
|
54
|
+
if (focused && focused !== document.activeElement && next.contains(focused)) focused.focus({ preventScroll: true });
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/request-locals.ts
|
|
60
|
+
const REQUEST_LOCALS = Symbol.for("@markless/router/request-locals");
|
|
61
|
+
function table() {
|
|
62
|
+
const scope = globalThis;
|
|
63
|
+
return scope[REQUEST_LOCALS] ??= /* @__PURE__ */ new WeakMap();
|
|
64
|
+
}
|
|
65
|
+
function rememberRequestLocals(request, locals, headers) {
|
|
66
|
+
const known = table().get(request);
|
|
67
|
+
table().set(request, {
|
|
68
|
+
locals,
|
|
69
|
+
headers: headers ?? known?.headers,
|
|
70
|
+
taken: known?.taken
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function requestLocals(request) {
|
|
74
|
+
return table().get(request)?.locals;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The response headers middleware wrote for this request, moved off the server's
|
|
78
|
+
* response: it drops them from a non-2xx page and would repeat them on a 2xx one.
|
|
79
|
+
*/
|
|
80
|
+
function takeMiddlewareHeaders(request) {
|
|
81
|
+
const record = table().get(request);
|
|
82
|
+
if (!record?.headers) return void 0;
|
|
83
|
+
if (!record.taken) {
|
|
84
|
+
record.taken = new Headers(record.headers);
|
|
85
|
+
for (const name of Array.from(record.headers.keys())) record.headers.delete(name);
|
|
86
|
+
}
|
|
87
|
+
return record.taken;
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { ROUTE_SCRIPT_TYPE as a, PREFETCH_ATTRIBUTE as c, HTML_ATTRIBUTES_SLOT as i, REPLACE_ATTRIBUTE as l, requestLocals as n, routeMountTarget as o, takeMiddlewareHeaders as r, LINK_ATTRIBUTE as s, rememberRequestLocals as t, SCROLL_ATTRIBUTE as u };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/vite/entries/route-href.ts
|
|
2
|
+
const routeParamPattern = /\[\.\.\.([A-Za-z_$][\w$]*)\]|\[([A-Za-z_$][\w$]*)\]/g;
|
|
3
|
+
function __marklessRouteHref(pattern, params) {
|
|
4
|
+
return pattern.replace(routeParamPattern, (_match, catchAll, dynamic) => {
|
|
5
|
+
const name = catchAll || dynamic;
|
|
6
|
+
const value = params?.[name];
|
|
7
|
+
if (catchAll) return encodeCatchAllParam(pattern, value);
|
|
8
|
+
if (value === null || value === void 0) throw new Error(`Typed route error: ${pattern} requires params:\n- ${name}`);
|
|
9
|
+
return encodeURIComponent(String(value));
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function encodeCatchAllParam(pattern, value) {
|
|
13
|
+
const segments = Array.isArray(value) ? value : value === null || value === void 0 ? [] : String(value).split("/");
|
|
14
|
+
if (segments.length === 0 || segments.some((segment) => String(segment) === "")) throw new Error(`Typed route error: ${pattern} requires a non-empty catch-all param.`);
|
|
15
|
+
return segments.map((segment) => encodeURIComponent(String(segment))).join("/");
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { __marklessRouteHref as t };
|