olova 2.0.17 → 2.0.18
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 +9 -0
- package/dist/Router.d.ts +53 -0
- package/dist/Router.js +12 -0
- package/dist/chunk-4CH3KNWP.js +157 -0
- package/dist/chunk-7BXNTMPM.js +12 -0
- package/dist/chunk-K2URQPLW.js +44 -0
- package/dist/chunk-RCRG2FBU.js +32 -0
- package/dist/chunk-TFRUFD5A.js +1480 -0
- package/dist/chunk-WNRULQF5.js +350 -0
- package/dist/chunk-YVUSXRPM.js +23 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +33 -0
- package/dist/useParams.d.ts +4 -0
- package/dist/useParams.js +12 -0
- package/dist/usePathname.d.ts +7 -0
- package/dist/usePathname.js +9 -0
- package/dist/useSearchParams.d.ts +27 -0
- package/dist/useSearchParams.js +9 -0
- package/package.json +46 -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,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RouterContext
|
|
3
|
+
} from "./chunk-7BXNTMPM.js";
|
|
4
|
+
import {
|
|
5
|
+
__toESM,
|
|
6
|
+
require_react
|
|
7
|
+
} from "./chunk-TFRUFD5A.js";
|
|
8
|
+
|
|
9
|
+
// Router.tsx
|
|
10
|
+
var import_react = __toESM(require_react(), 1);
|
|
11
|
+
import { routes } from "olova/routes";
|
|
12
|
+
function parseMarkdown(md) {
|
|
13
|
+
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>");
|
|
14
|
+
}
|
|
15
|
+
function HtmlContent({ html }) {
|
|
16
|
+
return import_react.default.createElement("div", {
|
|
17
|
+
dangerouslySetInnerHTML: { __html: html },
|
|
18
|
+
className: "olova-html-content"
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function MarkdownContent({ markdown }) {
|
|
22
|
+
const html = parseMarkdown(markdown);
|
|
23
|
+
return import_react.default.createElement("article", {
|
|
24
|
+
dangerouslySetInnerHTML: { __html: html },
|
|
25
|
+
className: "olova-markdown-content"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
var normalizePath = (path) => {
|
|
29
|
+
let p = path.split("?")[0].split("#")[0];
|
|
30
|
+
if (p.length > 1 && p.endsWith("/")) p = p.slice(0, -1);
|
|
31
|
+
return p || "/";
|
|
32
|
+
};
|
|
33
|
+
function matchRoute(path) {
|
|
34
|
+
const normalizedPath = normalizePath(path);
|
|
35
|
+
const routeKeys = Object.keys(routes);
|
|
36
|
+
for (const route of routeKeys) {
|
|
37
|
+
if (route === normalizedPath) {
|
|
38
|
+
return { loader: routes[route], params: {}, pattern: route };
|
|
39
|
+
}
|
|
40
|
+
const regexPath = route.replace(/:[^\/]+/g, "([^/]+)").replace(/\$[^\/]+/g, "([^/]+)");
|
|
41
|
+
const regex = new RegExp(`^${regexPath}$`);
|
|
42
|
+
const match = normalizedPath.match(regex);
|
|
43
|
+
if (match) {
|
|
44
|
+
const params = {};
|
|
45
|
+
const paramNames = (route.match(/[:$][^\/]+/g) || []).map((s) => s.slice(1));
|
|
46
|
+
paramNames.forEach((name, i) => {
|
|
47
|
+
params[name] = match[i + 1];
|
|
48
|
+
});
|
|
49
|
+
return { loader: routes[route], params, pattern: route };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
async function loadRoute(path) {
|
|
55
|
+
const match = matchRoute(path);
|
|
56
|
+
if (match) {
|
|
57
|
+
console.log(`[Router] Loading route: ${path} (pattern: ${match.pattern})`);
|
|
58
|
+
const module = await match.loader();
|
|
59
|
+
if (module.__isHtml) {
|
|
60
|
+
return {
|
|
61
|
+
module: {
|
|
62
|
+
default: () => HtmlContent({ html: module.__rawHtml })
|
|
63
|
+
},
|
|
64
|
+
params: match.params,
|
|
65
|
+
metadata: void 0
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (module.__isMd) {
|
|
69
|
+
return {
|
|
70
|
+
module: {
|
|
71
|
+
default: () => MarkdownContent({ markdown: module.default })
|
|
72
|
+
},
|
|
73
|
+
params: match.params,
|
|
74
|
+
metadata: void 0
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
module,
|
|
79
|
+
params: match.params,
|
|
80
|
+
metadata: module.metadata
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
console.warn(`[Router] No match for: ${path}`);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function Router({ url, initialComponent, initialParams, onRouteChange }) {
|
|
87
|
+
const [path, setPath] = (0, import_react.useState)(() => normalizePath(url || (typeof window !== "undefined" ? window.location.pathname : "/")));
|
|
88
|
+
const [Component, setComponent] = (0, import_react.useState)(() => initialComponent || null);
|
|
89
|
+
const [params, setParams] = (0, import_react.useState)(() => initialParams || {});
|
|
90
|
+
const hasHydrated = import_react.default.useRef(false);
|
|
91
|
+
(0, import_react.useEffect)(() => {
|
|
92
|
+
if (typeof window === "undefined") return;
|
|
93
|
+
const handleNavigation = () => {
|
|
94
|
+
const newPath = normalizePath(window.location.pathname);
|
|
95
|
+
console.log(`[Router] Navigation event: ${newPath}`);
|
|
96
|
+
setPath(newPath);
|
|
97
|
+
};
|
|
98
|
+
window.addEventListener("popstate", handleNavigation);
|
|
99
|
+
window.addEventListener("pushstate", handleNavigation);
|
|
100
|
+
return () => {
|
|
101
|
+
window.removeEventListener("popstate", handleNavigation);
|
|
102
|
+
window.removeEventListener("pushstate", handleNavigation);
|
|
103
|
+
};
|
|
104
|
+
}, []);
|
|
105
|
+
(0, import_react.useEffect)(() => {
|
|
106
|
+
if (!hasHydrated.current && initialComponent && path === normalizePath(url || "")) {
|
|
107
|
+
console.log(`[Router] Hydration skipped for: ${path}`);
|
|
108
|
+
hasHydrated.current = true;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
let isCancelled = false;
|
|
112
|
+
const load = async () => {
|
|
113
|
+
const result = await loadRoute(path);
|
|
114
|
+
if (!isCancelled) {
|
|
115
|
+
if (result) {
|
|
116
|
+
setComponent(() => result.module.default);
|
|
117
|
+
setParams(result.params);
|
|
118
|
+
if (onRouteChange) {
|
|
119
|
+
onRouteChange(result.metadata);
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
const fallbackResult = await loadRoute("/404");
|
|
123
|
+
if (fallbackResult) {
|
|
124
|
+
console.log("[Router] Serving custom 404 page");
|
|
125
|
+
setComponent(() => fallbackResult.module.default);
|
|
126
|
+
setParams(fallbackResult.params);
|
|
127
|
+
if (onRouteChange) {
|
|
128
|
+
onRouteChange(fallbackResult.metadata);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
setComponent(() => () => import_react.default.createElement("div", null, "404 Not Found"));
|
|
132
|
+
setParams({});
|
|
133
|
+
if (onRouteChange) {
|
|
134
|
+
onRouteChange(void 0);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
load();
|
|
141
|
+
return () => {
|
|
142
|
+
isCancelled = true;
|
|
143
|
+
};
|
|
144
|
+
}, [path, onRouteChange]);
|
|
145
|
+
if (!Component) return import_react.default.createElement("div", null, "Loading...");
|
|
146
|
+
return import_react.default.createElement(
|
|
147
|
+
RouterContext.Provider,
|
|
148
|
+
{ value: { params, path } },
|
|
149
|
+
import_react.default.createElement(Component, params)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export {
|
|
154
|
+
matchRoute,
|
|
155
|
+
loadRoute,
|
|
156
|
+
Router
|
|
157
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__toESM,
|
|
3
|
+
require_react
|
|
4
|
+
} from "./chunk-TFRUFD5A.js";
|
|
5
|
+
|
|
6
|
+
// useSearchParams.ts
|
|
7
|
+
var import_react = __toESM(require_react(), 1);
|
|
8
|
+
function useSearchParams() {
|
|
9
|
+
const [searchParams, setSearchParams] = (0, import_react.useState)(() => {
|
|
10
|
+
if (typeof window === "undefined") return new URLSearchParams();
|
|
11
|
+
return new URLSearchParams(window.location.search);
|
|
12
|
+
});
|
|
13
|
+
(0, import_react.useEffect)(() => {
|
|
14
|
+
if (typeof window === "undefined") return;
|
|
15
|
+
const handleNavigation = () => {
|
|
16
|
+
setSearchParams(new URLSearchParams(window.location.search));
|
|
17
|
+
};
|
|
18
|
+
window.addEventListener("popstate", handleNavigation);
|
|
19
|
+
window.addEventListener("pushstate", handleNavigation);
|
|
20
|
+
return () => {
|
|
21
|
+
window.removeEventListener("popstate", handleNavigation);
|
|
22
|
+
window.removeEventListener("pushstate", handleNavigation);
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
return {
|
|
26
|
+
get: (name) => searchParams.get(name),
|
|
27
|
+
getAll: (name) => searchParams.getAll(name),
|
|
28
|
+
has: (name) => searchParams.has(name),
|
|
29
|
+
keys: () => searchParams.keys(),
|
|
30
|
+
values: () => searchParams.values(),
|
|
31
|
+
entries: () => searchParams.entries(),
|
|
32
|
+
forEach: (callback) => searchParams.forEach(callback),
|
|
33
|
+
toString: () => searchParams.toString(),
|
|
34
|
+
get size() {
|
|
35
|
+
return Array.from(searchParams.keys()).length;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
var useSearchParams_default = useSearchParams;
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
useSearchParams,
|
|
43
|
+
useSearchParams_default
|
|
44
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__toESM,
|
|
3
|
+
require_react
|
|
4
|
+
} from "./chunk-TFRUFD5A.js";
|
|
5
|
+
|
|
6
|
+
// usePathname.ts
|
|
7
|
+
var import_react = __toESM(require_react(), 1);
|
|
8
|
+
function usePathname() {
|
|
9
|
+
const [pathname, setPathname] = (0, import_react.useState)(() => {
|
|
10
|
+
if (typeof window === "undefined") return "/";
|
|
11
|
+
return window.location.pathname;
|
|
12
|
+
});
|
|
13
|
+
(0, import_react.useEffect)(() => {
|
|
14
|
+
if (typeof window === "undefined") return;
|
|
15
|
+
const handleNavigation = () => {
|
|
16
|
+
setPathname(window.location.pathname);
|
|
17
|
+
};
|
|
18
|
+
window.addEventListener("popstate", handleNavigation);
|
|
19
|
+
window.addEventListener("pushstate", handleNavigation);
|
|
20
|
+
return () => {
|
|
21
|
+
window.removeEventListener("popstate", handleNavigation);
|
|
22
|
+
window.removeEventListener("pushstate", handleNavigation);
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
return pathname;
|
|
26
|
+
}
|
|
27
|
+
var usePathname_default = usePathname;
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
usePathname,
|
|
31
|
+
usePathname_default
|
|
32
|
+
};
|