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 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
@@ -0,0 +1,8 @@
1
+ import {
2
+ Link,
3
+ Link_default
4
+ } from "./chunk-CYX762OE.js";
5
+ export {
6
+ Link,
7
+ Link_default as default
8
+ };
@@ -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,11 @@
1
+ import {
2
+ Router,
3
+ loadRoute,
4
+ matchRoute
5
+ } from "./chunk-Y3CEUWVD.js";
6
+ import "./chunk-LOK5UEME.js";
7
+ export {
8
+ Router,
9
+ loadRoute,
10
+ matchRoute
11
+ };
@@ -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,7 @@
1
+ // context.ts
2
+ import { createContext } from "react";
3
+ var RouterContext = createContext({ params: {}, path: "/" });
4
+
5
+ export {
6
+ RouterContext
7
+ };
@@ -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
+ };
@@ -0,0 +1,5 @@
1
+ import React__default from 'react';
2
+
3
+ declare function hydrate(RootLayout?: React__default.ComponentType<any>): Promise<void>;
4
+
5
+ export { hydrate };
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
+ };
@@ -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
+ };
@@ -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,4 @@
1
+ declare function useParams(): Record<string, string>;
2
+ declare function usePath(): string;
3
+
4
+ export { useParams as default, useParams, usePath };
@@ -0,0 +1,11 @@
1
+ import {
2
+ useParams,
3
+ useParams_default,
4
+ usePath
5
+ } from "./chunk-K6EDUQDD.js";
6
+ import "./chunk-LOK5UEME.js";
7
+ export {
8
+ useParams_default as default,
9
+ useParams,
10
+ usePath
11
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Returns the current pathname (without query string or hash)
3
+ * Similar to Next.js usePathname hook
4
+ */
5
+ declare function usePathname(): string;
6
+
7
+ export { usePathname as default, usePathname };
@@ -0,0 +1,8 @@
1
+ import {
2
+ usePathname,
3
+ usePathname_default
4
+ } from "./chunk-XGX5YRJV.js";
5
+ export {
6
+ usePathname_default as default,
7
+ usePathname
8
+ };
@@ -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 };
@@ -0,0 +1,8 @@
1
+ import {
2
+ useSearchParams,
3
+ useSearchParams_default
4
+ } from "./chunk-NEMX72XA.js";
5
+ export {
6
+ useSearchParams_default as default,
7
+ useSearchParams
8
+ };