olova 2.0.17 → 2.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/dist/Link.d.ts +8 -0
- package/dist/Link.js +8 -0
- package/dist/Router.d.ts +53 -0
- package/dist/Router.js +11 -0
- package/dist/chunk-CYX762OE.js +21 -0
- package/dist/chunk-K6EDUQDD.js +19 -0
- package/dist/chunk-LOK5UEME.js +7 -0
- package/dist/chunk-NEMX72XA.js +39 -0
- package/dist/chunk-XGX5YRJV.js +27 -0
- package/dist/chunk-Y3CEUWVD.js +153 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.js +72 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +32 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +87 -0
- package/dist/useParams.d.ts +4 -0
- package/dist/useParams.js +11 -0
- package/dist/usePathname.d.ts +7 -0
- package/dist/usePathname.js +8 -0
- package/dist/useSearchParams.d.ts +27 -0
- package/dist/useSearchParams.js +8 -0
- package/package.json +58 -15
- package/.github/workflows/publish.yml +0 -18
- package/README.md +0 -1
- package/dist/olova.d.ts +0 -1
- package/dist/olova.js +0 -1
- package/package-lock.json +0 -1433
package/dist/Link.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React__default, { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
declare function Link({ href, children, ...props }: {
|
|
4
|
+
href: string;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
} & React__default.AnchorHTMLAttributes<HTMLAnchorElement>): React__default.ReactElement;
|
|
7
|
+
|
|
8
|
+
export { Link, Link as default };
|
package/dist/Link.js
ADDED
package/dist/Router.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
|
|
3
|
+
interface Metadata {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
keywords?: string | string[];
|
|
7
|
+
openGraph?: {
|
|
8
|
+
title?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
siteName?: string;
|
|
12
|
+
images?: {
|
|
13
|
+
url: string;
|
|
14
|
+
width?: number;
|
|
15
|
+
height?: number;
|
|
16
|
+
alt?: string;
|
|
17
|
+
}[];
|
|
18
|
+
type?: string;
|
|
19
|
+
};
|
|
20
|
+
twitter?: {
|
|
21
|
+
card?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
22
|
+
site?: string;
|
|
23
|
+
creator?: string;
|
|
24
|
+
title?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
images?: string[];
|
|
27
|
+
};
|
|
28
|
+
robots?: string;
|
|
29
|
+
canonical?: string;
|
|
30
|
+
jsonLd?: object | object[];
|
|
31
|
+
}
|
|
32
|
+
declare function matchRoute(path: string): {
|
|
33
|
+
loader: any;
|
|
34
|
+
params: Record<string, string>;
|
|
35
|
+
pattern: string;
|
|
36
|
+
} | null;
|
|
37
|
+
declare function loadRoute(path: string): Promise<{
|
|
38
|
+
module: any;
|
|
39
|
+
params: Record<string, string>;
|
|
40
|
+
metadata: Metadata | undefined;
|
|
41
|
+
} | null>;
|
|
42
|
+
interface RouterProps {
|
|
43
|
+
url?: string;
|
|
44
|
+
initialComponent?: React__default.ComponentType;
|
|
45
|
+
initialParams?: Record<string, string>;
|
|
46
|
+
onRouteChange?: (metadata: Metadata | undefined) => void;
|
|
47
|
+
}
|
|
48
|
+
declare function Router({ url, initialComponent, initialParams, onRouteChange }: RouterProps): React__default.DetailedReactHTMLElement<React__default.HTMLAttributes<HTMLElement>, HTMLElement> | React__default.FunctionComponentElement<React__default.ProviderProps<{
|
|
49
|
+
params: Record<string, string>;
|
|
50
|
+
path: string;
|
|
51
|
+
}>>;
|
|
52
|
+
|
|
53
|
+
export { type Metadata, Router, loadRoute, matchRoute };
|
package/dist/Router.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Link.tsx
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
function Link({ href, children, ...props }) {
|
|
4
|
+
const handleClick = (e) => {
|
|
5
|
+
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
6
|
+
if (href.startsWith("http") || href.startsWith("//")) return;
|
|
7
|
+
e.preventDefault();
|
|
8
|
+
const currentUrl = window.location.pathname + window.location.search;
|
|
9
|
+
const targetUrl = href.startsWith("/") ? href : "/" + href;
|
|
10
|
+
if (currentUrl === targetUrl) return;
|
|
11
|
+
window.history.pushState({}, "", href);
|
|
12
|
+
window.dispatchEvent(new Event("pushstate"));
|
|
13
|
+
};
|
|
14
|
+
return /* @__PURE__ */ jsx("a", { href, onClick: handleClick, ...props, children });
|
|
15
|
+
}
|
|
16
|
+
var Link_default = Link;
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
Link,
|
|
20
|
+
Link_default
|
|
21
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RouterContext
|
|
3
|
+
} from "./chunk-LOK5UEME.js";
|
|
4
|
+
|
|
5
|
+
// useParams.ts
|
|
6
|
+
import { useContext } from "react";
|
|
7
|
+
function useParams() {
|
|
8
|
+
return useContext(RouterContext).params;
|
|
9
|
+
}
|
|
10
|
+
function usePath() {
|
|
11
|
+
return useContext(RouterContext).path;
|
|
12
|
+
}
|
|
13
|
+
var useParams_default = useParams;
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
useParams,
|
|
17
|
+
usePath,
|
|
18
|
+
useParams_default
|
|
19
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// useSearchParams.ts
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
function useSearchParams() {
|
|
4
|
+
const [searchParams, setSearchParams] = useState(() => {
|
|
5
|
+
if (typeof window === "undefined") return new URLSearchParams();
|
|
6
|
+
return new URLSearchParams(window.location.search);
|
|
7
|
+
});
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (typeof window === "undefined") return;
|
|
10
|
+
const handleNavigation = () => {
|
|
11
|
+
setSearchParams(new URLSearchParams(window.location.search));
|
|
12
|
+
};
|
|
13
|
+
window.addEventListener("popstate", handleNavigation);
|
|
14
|
+
window.addEventListener("pushstate", handleNavigation);
|
|
15
|
+
return () => {
|
|
16
|
+
window.removeEventListener("popstate", handleNavigation);
|
|
17
|
+
window.removeEventListener("pushstate", handleNavigation);
|
|
18
|
+
};
|
|
19
|
+
}, []);
|
|
20
|
+
return {
|
|
21
|
+
get: (name) => searchParams.get(name),
|
|
22
|
+
getAll: (name) => searchParams.getAll(name),
|
|
23
|
+
has: (name) => searchParams.has(name),
|
|
24
|
+
keys: () => searchParams.keys(),
|
|
25
|
+
values: () => searchParams.values(),
|
|
26
|
+
entries: () => searchParams.entries(),
|
|
27
|
+
forEach: (callback) => searchParams.forEach(callback),
|
|
28
|
+
toString: () => searchParams.toString(),
|
|
29
|
+
get size() {
|
|
30
|
+
return Array.from(searchParams.keys()).length;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
var useSearchParams_default = useSearchParams;
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
useSearchParams,
|
|
38
|
+
useSearchParams_default
|
|
39
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// usePathname.ts
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
function usePathname() {
|
|
4
|
+
const [pathname, setPathname] = useState(() => {
|
|
5
|
+
if (typeof window === "undefined") return "/";
|
|
6
|
+
return window.location.pathname;
|
|
7
|
+
});
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (typeof window === "undefined") return;
|
|
10
|
+
const handleNavigation = () => {
|
|
11
|
+
setPathname(window.location.pathname);
|
|
12
|
+
};
|
|
13
|
+
window.addEventListener("popstate", handleNavigation);
|
|
14
|
+
window.addEventListener("pushstate", handleNavigation);
|
|
15
|
+
return () => {
|
|
16
|
+
window.removeEventListener("popstate", handleNavigation);
|
|
17
|
+
window.removeEventListener("pushstate", handleNavigation);
|
|
18
|
+
};
|
|
19
|
+
}, []);
|
|
20
|
+
return pathname;
|
|
21
|
+
}
|
|
22
|
+
var usePathname_default = usePathname;
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
usePathname,
|
|
26
|
+
usePathname_default
|
|
27
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RouterContext
|
|
3
|
+
} from "./chunk-LOK5UEME.js";
|
|
4
|
+
|
|
5
|
+
// Router.tsx
|
|
6
|
+
import React, { useState, useEffect } from "react";
|
|
7
|
+
import { routes } from "virtual:olova-routes";
|
|
8
|
+
function parseMarkdown(md) {
|
|
9
|
+
return md.replace(/^### (.*$)/gim, "<h3>$1</h3>").replace(/^## (.*$)/gim, "<h2>$1</h2>").replace(/^# (.*$)/gim, "<h1>$1</h1>").replace(/\*\*\*(.*?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\*(.*?)\*/g, "<em>$1</em>").replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>").replace(/`(.*?)`/g, "<code>$1</code>").replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>').replace(/\n\n/g, "</p><p>").replace(/\n/g, "<br>").replace(/^(.*)$/, "<p>$1</p>");
|
|
10
|
+
}
|
|
11
|
+
function HtmlContent({ html }) {
|
|
12
|
+
return React.createElement("div", {
|
|
13
|
+
dangerouslySetInnerHTML: { __html: html },
|
|
14
|
+
className: "olova-html-content"
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function MarkdownContent({ markdown }) {
|
|
18
|
+
const html = parseMarkdown(markdown);
|
|
19
|
+
return React.createElement("article", {
|
|
20
|
+
dangerouslySetInnerHTML: { __html: html },
|
|
21
|
+
className: "olova-markdown-content"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
var normalizePath = (path) => {
|
|
25
|
+
let p = path.split("?")[0].split("#")[0];
|
|
26
|
+
if (p.length > 1 && p.endsWith("/")) p = p.slice(0, -1);
|
|
27
|
+
return p || "/";
|
|
28
|
+
};
|
|
29
|
+
function matchRoute(path) {
|
|
30
|
+
const normalizedPath = normalizePath(path);
|
|
31
|
+
const routeKeys = Object.keys(routes);
|
|
32
|
+
for (const route of routeKeys) {
|
|
33
|
+
if (route === normalizedPath) {
|
|
34
|
+
return { loader: routes[route], params: {}, pattern: route };
|
|
35
|
+
}
|
|
36
|
+
const regexPath = route.replace(/:[^\/]+/g, "([^/]+)").replace(/\$[^\/]+/g, "([^/]+)");
|
|
37
|
+
const regex = new RegExp(`^${regexPath}$`);
|
|
38
|
+
const match = normalizedPath.match(regex);
|
|
39
|
+
if (match) {
|
|
40
|
+
const params = {};
|
|
41
|
+
const paramNames = (route.match(/[:$][^\/]+/g) || []).map((s) => s.slice(1));
|
|
42
|
+
paramNames.forEach((name, i) => {
|
|
43
|
+
params[name] = match[i + 1];
|
|
44
|
+
});
|
|
45
|
+
return { loader: routes[route], params, pattern: route };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
async function loadRoute(path) {
|
|
51
|
+
const match = matchRoute(path);
|
|
52
|
+
if (match) {
|
|
53
|
+
console.log(`[Router] Loading route: ${path} (pattern: ${match.pattern})`);
|
|
54
|
+
const module = await match.loader();
|
|
55
|
+
if (module.__isHtml) {
|
|
56
|
+
return {
|
|
57
|
+
module: {
|
|
58
|
+
default: () => HtmlContent({ html: module.__rawHtml })
|
|
59
|
+
},
|
|
60
|
+
params: match.params,
|
|
61
|
+
metadata: void 0
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (module.__isMd) {
|
|
65
|
+
return {
|
|
66
|
+
module: {
|
|
67
|
+
default: () => MarkdownContent({ markdown: module.default })
|
|
68
|
+
},
|
|
69
|
+
params: match.params,
|
|
70
|
+
metadata: void 0
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
module,
|
|
75
|
+
params: match.params,
|
|
76
|
+
metadata: module.metadata
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
console.warn(`[Router] No match for: ${path}`);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function Router({ url, initialComponent, initialParams, onRouteChange }) {
|
|
83
|
+
const [path, setPath] = useState(() => normalizePath(url || (typeof window !== "undefined" ? window.location.pathname : "/")));
|
|
84
|
+
const [Component, setComponent] = useState(() => initialComponent || null);
|
|
85
|
+
const [params, setParams] = useState(() => initialParams || {});
|
|
86
|
+
const hasHydrated = React.useRef(false);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (typeof window === "undefined") return;
|
|
89
|
+
const handleNavigation = () => {
|
|
90
|
+
const newPath = normalizePath(window.location.pathname);
|
|
91
|
+
console.log(`[Router] Navigation event: ${newPath}`);
|
|
92
|
+
setPath(newPath);
|
|
93
|
+
};
|
|
94
|
+
window.addEventListener("popstate", handleNavigation);
|
|
95
|
+
window.addEventListener("pushstate", handleNavigation);
|
|
96
|
+
return () => {
|
|
97
|
+
window.removeEventListener("popstate", handleNavigation);
|
|
98
|
+
window.removeEventListener("pushstate", handleNavigation);
|
|
99
|
+
};
|
|
100
|
+
}, []);
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (!hasHydrated.current && initialComponent && path === normalizePath(url || "")) {
|
|
103
|
+
console.log(`[Router] Hydration skipped for: ${path}`);
|
|
104
|
+
hasHydrated.current = true;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
let isCancelled = false;
|
|
108
|
+
const load = async () => {
|
|
109
|
+
const result = await loadRoute(path);
|
|
110
|
+
if (!isCancelled) {
|
|
111
|
+
if (result) {
|
|
112
|
+
setComponent(() => result.module.default);
|
|
113
|
+
setParams(result.params);
|
|
114
|
+
if (onRouteChange) {
|
|
115
|
+
onRouteChange(result.metadata);
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
const fallbackResult = await loadRoute("/404");
|
|
119
|
+
if (fallbackResult) {
|
|
120
|
+
console.log("[Router] Serving custom 404 page");
|
|
121
|
+
setComponent(() => fallbackResult.module.default);
|
|
122
|
+
setParams(fallbackResult.params);
|
|
123
|
+
if (onRouteChange) {
|
|
124
|
+
onRouteChange(fallbackResult.metadata);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
setComponent(() => () => React.createElement("div", null, "404 Not Found"));
|
|
128
|
+
setParams({});
|
|
129
|
+
if (onRouteChange) {
|
|
130
|
+
onRouteChange(void 0);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
load();
|
|
137
|
+
return () => {
|
|
138
|
+
isCancelled = true;
|
|
139
|
+
};
|
|
140
|
+
}, [path, onRouteChange]);
|
|
141
|
+
if (!Component) return React.createElement("div", null, "Loading...");
|
|
142
|
+
return React.createElement(
|
|
143
|
+
RouterContext.Provider,
|
|
144
|
+
{ value: { params, path } },
|
|
145
|
+
React.createElement(Component, params)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
matchRoute,
|
|
151
|
+
loadRoute,
|
|
152
|
+
Router
|
|
153
|
+
};
|
package/dist/client.d.ts
ADDED
package/dist/client.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Router,
|
|
3
|
+
loadRoute
|
|
4
|
+
} from "./chunk-Y3CEUWVD.js";
|
|
5
|
+
import "./chunk-LOK5UEME.js";
|
|
6
|
+
|
|
7
|
+
// client.tsx
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { hydrateRoot, createRoot } from "react-dom/client";
|
|
10
|
+
async function hydrate(RootLayout) {
|
|
11
|
+
const hydrationData = window.__OLOVA_DATA__;
|
|
12
|
+
const url = window.location.pathname;
|
|
13
|
+
let Component;
|
|
14
|
+
let params = {};
|
|
15
|
+
if (hydrationData) {
|
|
16
|
+
const result = await loadRoute(url);
|
|
17
|
+
if (result) {
|
|
18
|
+
Component = result.module.default;
|
|
19
|
+
params = hydrationData.params;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (!Component) {
|
|
23
|
+
const result = await loadRoute(url);
|
|
24
|
+
if (result) {
|
|
25
|
+
Component = result.module.default;
|
|
26
|
+
params = result.params;
|
|
27
|
+
} else {
|
|
28
|
+
const fallback = await loadRoute("/404");
|
|
29
|
+
if (fallback) {
|
|
30
|
+
Component = fallback.module.default;
|
|
31
|
+
params = fallback.params;
|
|
32
|
+
} else {
|
|
33
|
+
Component = () => React.createElement("div", null, "404 Not Found");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (RootLayout) {
|
|
38
|
+
const App = React.createElement(
|
|
39
|
+
RootLayout,
|
|
40
|
+
null,
|
|
41
|
+
React.createElement(Router, {
|
|
42
|
+
url,
|
|
43
|
+
initialComponent: Component,
|
|
44
|
+
initialParams: params
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
if (hydrationData) {
|
|
48
|
+
hydrateRoot(document, App);
|
|
49
|
+
} else {
|
|
50
|
+
createRoot(document).render(App);
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
const root = document.getElementById("root");
|
|
54
|
+
if (root) {
|
|
55
|
+
const App = React.createElement(Router, {
|
|
56
|
+
url,
|
|
57
|
+
initialComponent: Component,
|
|
58
|
+
initialParams: params
|
|
59
|
+
});
|
|
60
|
+
if (hydrationData) {
|
|
61
|
+
hydrateRoot(root, App);
|
|
62
|
+
} else {
|
|
63
|
+
createRoot(root).render(App);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (typeof window !== "undefined" && !window.__OLOVA_HYDRATE_MANUAL__) {
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
hydrate
|
|
72
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export { default as Link } from './Link.js';
|
|
3
|
+
export { ReadonlyURLSearchParams, default as useSearchParams } from './useSearchParams.js';
|
|
4
|
+
export { default as usePathname } from './usePathname.js';
|
|
5
|
+
export { default as useParams, usePath } from './useParams.js';
|
|
6
|
+
export { Metadata, Router, loadRoute, matchRoute } from './Router.js';
|
|
7
|
+
|
|
8
|
+
declare const RouterContext: React.Context<{
|
|
9
|
+
params: Record<string, string>;
|
|
10
|
+
path: string;
|
|
11
|
+
}>;
|
|
12
|
+
|
|
13
|
+
export { RouterContext };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Link
|
|
3
|
+
} from "./chunk-CYX762OE.js";
|
|
4
|
+
import {
|
|
5
|
+
Router,
|
|
6
|
+
loadRoute,
|
|
7
|
+
matchRoute
|
|
8
|
+
} from "./chunk-Y3CEUWVD.js";
|
|
9
|
+
import {
|
|
10
|
+
useParams,
|
|
11
|
+
usePath
|
|
12
|
+
} from "./chunk-K6EDUQDD.js";
|
|
13
|
+
import {
|
|
14
|
+
RouterContext
|
|
15
|
+
} from "./chunk-LOK5UEME.js";
|
|
16
|
+
import {
|
|
17
|
+
usePathname
|
|
18
|
+
} from "./chunk-XGX5YRJV.js";
|
|
19
|
+
import {
|
|
20
|
+
useSearchParams
|
|
21
|
+
} from "./chunk-NEMX72XA.js";
|
|
22
|
+
export {
|
|
23
|
+
Link,
|
|
24
|
+
Router,
|
|
25
|
+
RouterContext,
|
|
26
|
+
loadRoute,
|
|
27
|
+
matchRoute,
|
|
28
|
+
useParams,
|
|
29
|
+
usePath,
|
|
30
|
+
usePathname,
|
|
31
|
+
useSearchParams
|
|
32
|
+
};
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { Metadata } from './Router.js';
|
|
3
|
+
|
|
4
|
+
declare function render(url: string, RootLayout?: React__default.ComponentType<any>): Promise<{
|
|
5
|
+
html: string;
|
|
6
|
+
hydrationData: {
|
|
7
|
+
params: {};
|
|
8
|
+
metadata: Metadata;
|
|
9
|
+
};
|
|
10
|
+
}>;
|
|
11
|
+
declare function renderShellWithMetadata(metadata: Metadata): string;
|
|
12
|
+
|
|
13
|
+
export { render, renderShellWithMetadata };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Router,
|
|
3
|
+
loadRoute
|
|
4
|
+
} from "./chunk-Y3CEUWVD.js";
|
|
5
|
+
import "./chunk-LOK5UEME.js";
|
|
6
|
+
|
|
7
|
+
// server.tsx
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { renderToString } from "react-dom/server";
|
|
10
|
+
function renderShell(content, metadata) {
|
|
11
|
+
const title = metadata.title || "My Framework";
|
|
12
|
+
const description = metadata.description || "";
|
|
13
|
+
const head = `
|
|
14
|
+
<meta charset="UTF-8" />
|
|
15
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
16
|
+
<title>${title}</title>
|
|
17
|
+
<meta name="description" content="${description}" />
|
|
18
|
+
${metadata.keywords ? `<meta name="keywords" content="${Array.isArray(metadata.keywords) ? metadata.keywords.join(",") : metadata.keywords}" />` : ""}
|
|
19
|
+
${metadata.robots ? `<meta name="robots" content="${metadata.robots}" />` : ""}
|
|
20
|
+
${metadata.canonical ? `<link rel="canonical" href="${metadata.canonical}" />` : ""}
|
|
21
|
+
`;
|
|
22
|
+
return `<!DOCTYPE html>
|
|
23
|
+
<html lang="en">
|
|
24
|
+
<head>
|
|
25
|
+
${head}
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<div id="root">${content}</div>
|
|
29
|
+
</body>
|
|
30
|
+
</html>`;
|
|
31
|
+
}
|
|
32
|
+
async function render(url, RootLayout) {
|
|
33
|
+
const result = await loadRoute(url);
|
|
34
|
+
let Component = void 0;
|
|
35
|
+
let params = {};
|
|
36
|
+
let metadata = {};
|
|
37
|
+
if (result) {
|
|
38
|
+
Component = result.module.default;
|
|
39
|
+
params = result.params;
|
|
40
|
+
metadata = result.metadata || {};
|
|
41
|
+
} else {
|
|
42
|
+
const fallback = await loadRoute("/404");
|
|
43
|
+
if (fallback) {
|
|
44
|
+
Component = fallback.module.default;
|
|
45
|
+
params = fallback.params;
|
|
46
|
+
metadata = fallback.metadata || {};
|
|
47
|
+
} else {
|
|
48
|
+
Component = () => React.createElement("div", null, "404 Not Found");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
let appHtml;
|
|
52
|
+
if (RootLayout) {
|
|
53
|
+
const App = React.createElement(
|
|
54
|
+
RootLayout,
|
|
55
|
+
null,
|
|
56
|
+
React.createElement(Router, {
|
|
57
|
+
url,
|
|
58
|
+
initialComponent: Component,
|
|
59
|
+
initialParams: params
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
appHtml = "<!DOCTYPE html>" + renderToString(App);
|
|
63
|
+
} else {
|
|
64
|
+
const content = renderToString(
|
|
65
|
+
React.createElement(Router, {
|
|
66
|
+
url,
|
|
67
|
+
initialComponent: Component,
|
|
68
|
+
initialParams: params
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
appHtml = renderShell(content, metadata);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
html: appHtml,
|
|
75
|
+
hydrationData: {
|
|
76
|
+
params,
|
|
77
|
+
metadata
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function renderShellWithMetadata(metadata) {
|
|
82
|
+
return renderShell("", metadata);
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
render,
|
|
86
|
+
renderShellWithMetadata
|
|
87
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A read-only interface for URLSearchParams
|
|
3
|
+
* Similar to Next.js useSearchParams hook
|
|
4
|
+
*/
|
|
5
|
+
interface ReadonlyURLSearchParams {
|
|
6
|
+
get(name: string): string | null;
|
|
7
|
+
getAll(name: string): string[];
|
|
8
|
+
has(name: string): boolean;
|
|
9
|
+
keys(): IterableIterator<string>;
|
|
10
|
+
values(): IterableIterator<string>;
|
|
11
|
+
entries(): IterableIterator<[string, string]>;
|
|
12
|
+
forEach(callback: (value: string, key: string, parent: URLSearchParams) => void): void;
|
|
13
|
+
toString(): string;
|
|
14
|
+
size: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Returns the current URL search parameters
|
|
18
|
+
* Similar to Next.js useSearchParams hook
|
|
19
|
+
*
|
|
20
|
+
* Example usage:
|
|
21
|
+
* const searchParams = useSearchParams();
|
|
22
|
+
* const query = searchParams.get('q'); // ?q=hello -> 'hello'
|
|
23
|
+
* const tags = searchParams.getAll('tag'); // ?tag=a&tag=b -> ['a', 'b']
|
|
24
|
+
*/
|
|
25
|
+
declare function useSearchParams(): ReadonlyURLSearchParams;
|
|
26
|
+
|
|
27
|
+
export { type ReadonlyURLSearchParams, useSearchParams as default, useSearchParams };
|