olova 2.0.55 → 2.0.56

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.
Files changed (84) hide show
  1. package/README.md +28 -288
  2. package/dist/chunk-23UAGQ6N.js +2208 -0
  3. package/dist/chunk-23UAGQ6N.js.map +1 -0
  4. package/dist/chunk-D7SIC5TC.js +367 -0
  5. package/dist/chunk-D7SIC5TC.js.map +1 -0
  6. package/dist/entry-server.cjs +2341 -0
  7. package/dist/entry-server.cjs.map +1 -0
  8. package/dist/entry-server.js +114 -0
  9. package/dist/entry-server.js.map +1 -0
  10. package/dist/entry-worker.cjs +2354 -0
  11. package/dist/entry-worker.cjs.map +1 -0
  12. package/dist/entry-worker.js +126 -0
  13. package/dist/entry-worker.js.map +1 -0
  14. package/dist/main.cjs +18 -0
  15. package/dist/main.cjs.map +1 -0
  16. package/dist/main.js +16 -0
  17. package/dist/main.js.map +1 -0
  18. package/dist/olova.cjs +1684 -0
  19. package/dist/olova.cjs.map +1 -0
  20. package/dist/olova.d.cts +72 -0
  21. package/dist/olova.d.ts +72 -0
  22. package/dist/olova.js +1325 -0
  23. package/dist/olova.js.map +1 -0
  24. package/dist/performance.cjs +386 -0
  25. package/dist/performance.cjs.map +1 -0
  26. package/dist/performance.js +3 -0
  27. package/dist/performance.js.map +1 -0
  28. package/dist/router.cjs +646 -0
  29. package/dist/router.cjs.map +1 -0
  30. package/dist/router.d.cts +113 -0
  31. package/dist/router.d.ts +113 -0
  32. package/dist/router.js +632 -0
  33. package/dist/router.js.map +1 -0
  34. package/main.tsx +76 -0
  35. package/olova.ts +619 -0
  36. package/package.json +42 -61
  37. package/src/entry-server.tsx +165 -0
  38. package/src/entry-worker.tsx +201 -0
  39. package/src/generator/index.ts +409 -0
  40. package/src/hydration/flight.ts +320 -0
  41. package/src/hydration/index.ts +12 -0
  42. package/src/hydration/types.ts +225 -0
  43. package/src/logger.ts +182 -0
  44. package/src/main.tsx +24 -0
  45. package/src/performance.ts +488 -0
  46. package/src/plugin/index.ts +204 -0
  47. package/src/router/ErrorBoundary.tsx +145 -0
  48. package/src/router/Link.tsx +117 -0
  49. package/src/router/OlovaRouter.tsx +354 -0
  50. package/src/router/Outlet.tsx +8 -0
  51. package/src/router/context.ts +117 -0
  52. package/src/router/index.ts +29 -0
  53. package/src/router/matching.ts +63 -0
  54. package/src/router/router.tsx +23 -0
  55. package/src/router/search-params.ts +29 -0
  56. package/src/scanner/index.ts +116 -0
  57. package/src/types/index.ts +191 -0
  58. package/src/utils/export.ts +85 -0
  59. package/src/utils/index.ts +4 -0
  60. package/src/utils/naming.ts +54 -0
  61. package/src/utils/path.ts +45 -0
  62. package/tsup.config.ts +35 -0
  63. package/CHANGELOG.md +0 -31
  64. package/LICENSE +0 -21
  65. package/dist/index.cjs +0 -883
  66. package/dist/index.cjs.map +0 -1
  67. package/dist/index.d.cts +0 -138
  68. package/dist/index.d.ts +0 -138
  69. package/dist/index.js +0 -832
  70. package/dist/index.js.map +0 -1
  71. package/dist/plugin.cjs +0 -927
  72. package/dist/plugin.cjs.map +0 -1
  73. package/dist/plugin.d.cts +0 -18
  74. package/dist/plugin.d.ts +0 -18
  75. package/dist/plugin.js +0 -894
  76. package/dist/plugin.js.map +0 -1
  77. package/dist/ssg.cjs +0 -637
  78. package/dist/ssg.cjs.map +0 -1
  79. package/dist/ssg.d.cts +0 -191
  80. package/dist/ssg.d.ts +0 -191
  81. package/dist/ssg.js +0 -585
  82. package/dist/ssg.js.map +0 -1
  83. package/dist/types-BT6YsBGO.d.cts +0 -143
  84. package/dist/types-BT6YsBGO.d.ts +0 -143
package/dist/index.cjs DELETED
@@ -1,883 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- DefaultErrorComponent: () => DefaultErrorComponent,
24
- DefaultLoadingComponent: () => DefaultLoadingComponent,
25
- DefaultNotFoundComponent: () => DefaultNotFoundComponent,
26
- Link: () => Link,
27
- MetadataHead: () => MetadataHead,
28
- MetadataProvider: () => MetadataProvider,
29
- NavLink: () => NavLink,
30
- NotFoundBoundary: () => NotFoundBoundary,
31
- NotFoundError: () => NotFoundError,
32
- OlovaRouter: () => OlovaRouter,
33
- RouteErrorBoundary: () => RouteErrorBoundary,
34
- RouteLoadingBoundary: () => RouteLoadingBoundary,
35
- Skeleton: () => Skeleton,
36
- SkeletonCard: () => SkeletonCard,
37
- SkeletonText: () => SkeletonText,
38
- generateMetadataHtml: () => generateMetadataHtml,
39
- notFound: () => notFound,
40
- setSSRContext: () => setSSRContext,
41
- useMetadata: () => useMetadata,
42
- useOlovaRouter: () => useOlovaRouter,
43
- usePageMetadata: () => usePageMetadata,
44
- useParams: () => useParams,
45
- usePathname: () => usePathname,
46
- useRouter: () => useRouter,
47
- useSearchParams: () => useSearchParams
48
- });
49
- module.exports = __toCommonJS(src_exports);
50
-
51
- // src/router.tsx
52
- var import_react5 = require("react");
53
-
54
- // src/context.tsx
55
- var import_react = require("react");
56
- var import_jsx_runtime = require("react/jsx-runtime");
57
- var OlovaRouterContext = (0, import_react.createContext)(null);
58
- var isBrowser = typeof window !== "undefined";
59
- var ssrContextValue = {
60
- pathname: "/",
61
- params: {},
62
- searchParams: new URLSearchParams(),
63
- navigate: () => {
64
- },
65
- replace: () => {
66
- },
67
- back: () => {
68
- },
69
- forward: () => {
70
- },
71
- refresh: () => {
72
- },
73
- prefetch: () => {
74
- },
75
- isNavigating: false
76
- };
77
- function setSSRContext(pathname, params = {}) {
78
- ssrContextValue = {
79
- pathname,
80
- params,
81
- searchParams: new URLSearchParams(),
82
- navigate: () => {
83
- },
84
- replace: () => {
85
- },
86
- back: () => {
87
- },
88
- forward: () => {
89
- },
90
- refresh: () => {
91
- },
92
- prefetch: () => {
93
- },
94
- isNavigating: false
95
- };
96
- }
97
- function useOlovaRouter() {
98
- const context = (0, import_react.useContext)(OlovaRouterContext);
99
- if (!context) {
100
- if (!isBrowser) {
101
- return ssrContextValue;
102
- }
103
- throw new Error("useOlovaRouter must be used within an OlovaRouter");
104
- }
105
- return context;
106
- }
107
- function usePathname() {
108
- return useOlovaRouter().pathname;
109
- }
110
- function useParams() {
111
- return useOlovaRouter().params;
112
- }
113
- function useSearchParams() {
114
- return useOlovaRouter().searchParams;
115
- }
116
- function useRouter() {
117
- const { navigate, replace, back, forward, refresh, prefetch, isNavigating } = useOlovaRouter();
118
- return {
119
- push: navigate,
120
- replace,
121
- back,
122
- forward,
123
- refresh,
124
- prefetch,
125
- isNavigating
126
- };
127
- }
128
- function OlovaRouterProvider({ children, basePath = "" }) {
129
- const [pathname, setPathname] = (0, import_react.useState)(() => {
130
- const path = window.location.pathname;
131
- return basePath ? path.replace(new RegExp(`^${basePath}`), "") || "/" : path;
132
- });
133
- const [searchParams, setSearchParams] = (0, import_react.useState)(() => new URLSearchParams(window.location.search));
134
- const [params, setParams] = (0, import_react.useState)({});
135
- const [isPending, startTransition] = (0, import_react.useTransition)();
136
- (0, import_react.useEffect)(() => {
137
- const handlePopState = () => {
138
- startTransition(() => {
139
- const path = window.location.pathname;
140
- setPathname(basePath ? path.replace(new RegExp(`^${basePath}`), "") || "/" : path);
141
- setSearchParams(new URLSearchParams(window.location.search));
142
- });
143
- };
144
- window.addEventListener("popstate", handlePopState);
145
- return () => window.removeEventListener("popstate", handlePopState);
146
- }, [basePath]);
147
- const navigate = (0, import_react.useCallback)((to, options = {}) => {
148
- const url = new URL(to, window.location.origin);
149
- const fullPath = basePath + url.pathname;
150
- startTransition(() => {
151
- if (options.replace) {
152
- window.history.replaceState(null, "", fullPath + url.search);
153
- } else {
154
- window.history.pushState(null, "", fullPath + url.search);
155
- }
156
- setPathname(url.pathname);
157
- setSearchParams(new URLSearchParams(url.search));
158
- if (options.scroll !== false) {
159
- window.scrollTo(0, 0);
160
- }
161
- });
162
- }, [basePath]);
163
- const replace = (0, import_react.useCallback)((to, options = {}) => {
164
- navigate(to, { ...options, replace: true });
165
- }, [navigate]);
166
- const back = (0, import_react.useCallback)(() => {
167
- window.history.back();
168
- }, []);
169
- const forward = (0, import_react.useCallback)(() => {
170
- window.history.forward();
171
- }, []);
172
- const refresh = (0, import_react.useCallback)(() => {
173
- startTransition(() => {
174
- setPathname((prev) => prev);
175
- });
176
- }, []);
177
- const prefetch = (0, import_react.useCallback)((href) => {
178
- console.log("[Olova] Prefetching:", href);
179
- }, []);
180
- const updateParams = (0, import_react.useCallback)((newParams) => {
181
- setParams(newParams);
182
- }, []);
183
- const contextValue = {
184
- pathname,
185
- params,
186
- searchParams,
187
- navigate,
188
- replace,
189
- back,
190
- forward,
191
- refresh,
192
- prefetch,
193
- isNavigating: isPending
194
- };
195
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OlovaRouterContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OlovaParamsUpdater, { updateParams, children }) });
196
- }
197
- var ParamsUpdaterContext = (0, import_react.createContext)(null);
198
- function OlovaParamsUpdater({
199
- children,
200
- updateParams
201
- }) {
202
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ParamsUpdaterContext.Provider, { value: updateParams, children });
203
- }
204
- function useParamsUpdater() {
205
- return (0, import_react.useContext)(ParamsUpdaterContext);
206
- }
207
-
208
- // src/components/ErrorBoundary.tsx
209
- var import_react2 = require("react");
210
- var import_jsx_runtime2 = require("react/jsx-runtime");
211
- var RouteErrorBoundary = class extends import_react2.Component {
212
- constructor(props) {
213
- super(props);
214
- this.reset = () => {
215
- this.setState({ hasError: false, error: null });
216
- };
217
- this.state = { hasError: false, error: null };
218
- }
219
- static getDerivedStateFromError(error) {
220
- return { hasError: true, error };
221
- }
222
- componentDidCatch(error, errorInfo) {
223
- console.error("[Olova] Route error:", error, errorInfo);
224
- this.props.onError?.(error, errorInfo);
225
- }
226
- render() {
227
- if (this.state.hasError && this.state.error) {
228
- const FallbackComponent = this.props.fallback;
229
- if (FallbackComponent) {
230
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FallbackComponent, { error: this.state.error, reset: this.reset });
231
- }
232
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex min-h-[400px] flex-col items-center justify-center p-8", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rounded-lg border border-destructive/20 bg-destructive/5 p-6 text-center", children: [
233
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "mb-2 text-xl font-semibold text-destructive", children: "Something went wrong!" }),
234
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mb-4 text-sm text-muted-foreground", children: this.state.error.message }),
235
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
236
- "button",
237
- {
238
- onClick: this.reset,
239
- className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90",
240
- children: "Try again"
241
- }
242
- )
243
- ] }) });
244
- }
245
- return this.props.children;
246
- }
247
- };
248
- function DefaultErrorComponent({ error, reset }) {
249
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex min-h-[400px] flex-col items-center justify-center p-8", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-md rounded-lg border border-destructive/20 bg-destructive/5 p-6 text-center", children: [
250
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
251
- "svg",
252
- {
253
- className: "h-6 w-6 text-destructive",
254
- fill: "none",
255
- viewBox: "0 0 24 24",
256
- stroke: "currentColor",
257
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
258
- "path",
259
- {
260
- strokeLinecap: "round",
261
- strokeLinejoin: "round",
262
- strokeWidth: 2,
263
- d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
264
- }
265
- )
266
- }
267
- ) }),
268
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "mb-2 text-xl font-semibold text-foreground", children: "Something went wrong!" }),
269
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mb-4 text-sm text-muted-foreground", children: error.message }),
270
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
271
- "button",
272
- {
273
- onClick: reset,
274
- className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90",
275
- children: "Try again"
276
- }
277
- )
278
- ] }) });
279
- }
280
-
281
- // src/components/Loading.tsx
282
- var import_react3 = require("react");
283
- var import_jsx_runtime3 = require("react/jsx-runtime");
284
- function RouteLoadingBoundary({ children, fallback }) {
285
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react3.Suspense, { fallback: fallback || /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultLoadingComponent, {}), children });
286
- }
287
- function DefaultLoadingComponent() {
288
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex min-h-[400px] flex-col items-center justify-center p-8", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
289
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative h-10 w-10", children: [
290
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute inset-0 animate-ping rounded-full bg-primary/20" }),
291
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute inset-0 animate-pulse rounded-full bg-primary/40" }),
292
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute inset-2 animate-spin rounded-full border-2 border-primary border-t-transparent" })
293
- ] }),
294
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm text-muted-foreground", children: "Loading..." })
295
- ] }) });
296
- }
297
- function Skeleton({ className = "" }) {
298
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
299
- "div",
300
- {
301
- className: `animate-pulse rounded-md bg-muted ${className}`,
302
- "aria-hidden": "true"
303
- }
304
- );
305
- }
306
- function SkeletonText({ lines = 3, className = "" }) {
307
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `space-y-2 ${className}`, children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
308
- Skeleton,
309
- {
310
- className: `h-4 ${i === lines - 1 ? "w-3/4" : "w-full"}`
311
- },
312
- i
313
- )) });
314
- }
315
- function SkeletonCard({ className = "" }) {
316
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `rounded-lg border bg-card p-6 ${className}`, children: [
317
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Skeleton, { className: "mb-4 h-6 w-1/2" }),
318
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SkeletonText, { lines: 3 })
319
- ] });
320
- }
321
-
322
- // src/components/NotFound.tsx
323
- var import_jsx_runtime4 = require("react/jsx-runtime");
324
- function NotFoundBoundary({ children, fallback: Fallback, show404 }) {
325
- if (show404) {
326
- if (Fallback) {
327
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Fallback, {});
328
- }
329
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DefaultNotFoundComponent, {});
330
- }
331
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
332
- }
333
- function DefaultNotFoundComponent() {
334
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex min-h-[60vh] flex-col items-center justify-center p-8", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "text-center", children: [
335
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { className: "mb-2 text-8xl font-bold text-primary", children: "404" }),
336
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "mb-4 text-2xl font-semibold text-foreground", children: "Page Not Found" }),
337
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mb-8 max-w-md text-muted-foreground", children: "The page you're looking for doesn't exist or has been moved." }),
338
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
339
- "a",
340
- {
341
- href: "/",
342
- className: "inline-flex items-center gap-2 rounded-md bg-primary px-6 py-3 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90",
343
- children: [
344
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
345
- "svg",
346
- {
347
- className: "h-4 w-4",
348
- fill: "none",
349
- viewBox: "0 0 24 24",
350
- stroke: "currentColor",
351
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
352
- "path",
353
- {
354
- strokeLinecap: "round",
355
- strokeLinejoin: "round",
356
- strokeWidth: 2,
357
- d: "M10 19l-7-7m0 0l7-7m-7 7h18"
358
- }
359
- )
360
- }
361
- ),
362
- "Go back home"
363
- ]
364
- }
365
- )
366
- ] }) });
367
- }
368
- function notFound() {
369
- throw new NotFoundError();
370
- }
371
- var NotFoundError = class extends Error {
372
- constructor() {
373
- super("NEXT_NOT_FOUND");
374
- this.name = "NotFoundError";
375
- }
376
- };
377
-
378
- // src/components/Metadata.tsx
379
- var import_react4 = require("react");
380
- var import_jsx_runtime5 = require("react/jsx-runtime");
381
- var MetadataContext = (0, import_react4.createContext)(null);
382
- function MetadataProvider({ children, rootMetadata }) {
383
- const [metadata, setMetadataState] = (0, import_react4.useState)(rootMetadata || null);
384
- const setMetadata = (0, import_react4.useCallback)((newMetadata) => {
385
- setMetadataState(newMetadata);
386
- }, []);
387
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(MetadataContext.Provider, { value: { metadata, rootMetadata: rootMetadata || null, setMetadata }, children: [
388
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MetadataHead, { metadata, fallback: rootMetadata }),
389
- children
390
- ] });
391
- }
392
- function useMetadata() {
393
- const context = (0, import_react4.useContext)(MetadataContext);
394
- if (!context) {
395
- throw new Error("useMetadata must be used within a MetadataProvider");
396
- }
397
- return context;
398
- }
399
- function usePageMetadata(metadata) {
400
- const context = (0, import_react4.useContext)(MetadataContext);
401
- (0, import_react4.useEffect)(() => {
402
- if (context && metadata) {
403
- context.setMetadata(metadata);
404
- }
405
- return () => {
406
- if (context) {
407
- context.setMetadata(context.rootMetadata);
408
- }
409
- };
410
- }, [metadata, context]);
411
- }
412
- function MetadataHead({ metadata, fallback }) {
413
- (0, import_react4.useEffect)(() => {
414
- const activeMetadata = metadata || fallback;
415
- if (!activeMetadata) return;
416
- if (activeMetadata.title) {
417
- document.title = activeMetadata.title;
418
- }
419
- const addedMetas = [];
420
- const setMeta = (name, content, property) => {
421
- const attr = property ? "property" : "name";
422
- let meta = document.querySelector(`meta[${attr}="${name}"]`);
423
- if (!meta) {
424
- meta = document.createElement("meta");
425
- meta.setAttribute(attr, name);
426
- document.head.appendChild(meta);
427
- addedMetas.push(meta);
428
- }
429
- meta.content = content;
430
- };
431
- if (activeMetadata.description) {
432
- setMeta("description", activeMetadata.description);
433
- }
434
- if (activeMetadata.keywords?.length) {
435
- setMeta("keywords", activeMetadata.keywords.join(", "));
436
- }
437
- if (activeMetadata.authors?.length) {
438
- setMeta("author", activeMetadata.authors.map((a) => a.name).join(", "));
439
- }
440
- if (activeMetadata.robots) {
441
- setMeta("robots", activeMetadata.robots);
442
- }
443
- if (activeMetadata.openGraph) {
444
- const og = activeMetadata.openGraph;
445
- if (og.title) {
446
- setMeta("og:title", og.title, true);
447
- }
448
- if (og.description) {
449
- setMeta("og:description", og.description, true);
450
- }
451
- if (og.url) {
452
- setMeta("og:url", og.url, true);
453
- }
454
- if (og.siteName) {
455
- setMeta("og:site_name", og.siteName, true);
456
- }
457
- if (og.type) {
458
- setMeta("og:type", og.type, true);
459
- }
460
- if (og.images?.length) {
461
- const img = og.images[0];
462
- setMeta("og:image", img.url, true);
463
- if (img.width) setMeta("og:image:width", String(img.width), true);
464
- if (img.height) setMeta("og:image:height", String(img.height), true);
465
- if (img.alt) setMeta("og:image:alt", img.alt, true);
466
- }
467
- }
468
- if (activeMetadata.twitter) {
469
- const tw = activeMetadata.twitter;
470
- if (tw.card) {
471
- setMeta("twitter:card", tw.card);
472
- }
473
- if (tw.title) {
474
- setMeta("twitter:title", tw.title);
475
- }
476
- if (tw.description) {
477
- setMeta("twitter:description", tw.description);
478
- }
479
- if (tw.site) {
480
- setMeta("twitter:site", tw.site);
481
- }
482
- if (tw.creator) {
483
- setMeta("twitter:creator", tw.creator);
484
- }
485
- if (tw.images?.length) {
486
- setMeta("twitter:image", tw.images[0]);
487
- }
488
- }
489
- if (activeMetadata.canonical) {
490
- let link = document.querySelector('link[rel="canonical"]');
491
- if (!link) {
492
- link = document.createElement("link");
493
- link.rel = "canonical";
494
- document.head.appendChild(link);
495
- }
496
- link.href = activeMetadata.canonical;
497
- }
498
- return () => {
499
- addedMetas.forEach((meta) => {
500
- if (meta.parentNode) {
501
- meta.parentNode.removeChild(meta);
502
- }
503
- });
504
- };
505
- }, [metadata, fallback]);
506
- return null;
507
- }
508
- function generateMetadataHtml(metadata) {
509
- const tags = [];
510
- if (metadata.title) {
511
- tags.push(` <title>${escapeHtml(metadata.title)}</title>`);
512
- }
513
- if (metadata.description) {
514
- tags.push(` <meta name="description" content="${escapeHtml(metadata.description)}" />`);
515
- }
516
- if (metadata.keywords?.length) {
517
- tags.push(` <meta name="keywords" content="${escapeHtml(metadata.keywords.join(", "))}" />`);
518
- }
519
- if (metadata.authors?.length) {
520
- tags.push(` <meta name="author" content="${escapeHtml(metadata.authors.map((a) => a.name).join(", "))}" />`);
521
- }
522
- if (metadata.robots) {
523
- tags.push(` <meta name="robots" content="${escapeHtml(metadata.robots)}" />`);
524
- }
525
- if (metadata.openGraph) {
526
- const og = metadata.openGraph;
527
- if (og.title) tags.push(` <meta property="og:title" content="${escapeHtml(og.title)}" />`);
528
- if (og.description) tags.push(` <meta property="og:description" content="${escapeHtml(og.description)}" />`);
529
- if (og.url) tags.push(` <meta property="og:url" content="${escapeHtml(og.url)}" />`);
530
- if (og.siteName) tags.push(` <meta property="og:site_name" content="${escapeHtml(og.siteName)}" />`);
531
- if (og.type) tags.push(` <meta property="og:type" content="${escapeHtml(og.type)}" />`);
532
- if (og.images?.length) {
533
- const img = og.images[0];
534
- tags.push(` <meta property="og:image" content="${escapeHtml(img.url)}" />`);
535
- if (img.width) tags.push(` <meta property="og:image:width" content="${img.width}" />`);
536
- if (img.height) tags.push(` <meta property="og:image:height" content="${img.height}" />`);
537
- if (img.alt) tags.push(` <meta property="og:image:alt" content="${escapeHtml(img.alt)}" />`);
538
- }
539
- }
540
- if (metadata.twitter) {
541
- const tw = metadata.twitter;
542
- if (tw.card) tags.push(` <meta name="twitter:card" content="${escapeHtml(tw.card)}" />`);
543
- if (tw.title) tags.push(` <meta name="twitter:title" content="${escapeHtml(tw.title)}" />`);
544
- if (tw.description) tags.push(` <meta name="twitter:description" content="${escapeHtml(tw.description)}" />`);
545
- if (tw.site) tags.push(` <meta name="twitter:site" content="${escapeHtml(tw.site)}" />`);
546
- if (tw.creator) tags.push(` <meta name="twitter:creator" content="${escapeHtml(tw.creator)}" />`);
547
- if (tw.images?.length) tags.push(` <meta name="twitter:image" content="${escapeHtml(tw.images[0])}" />`);
548
- }
549
- if (metadata.canonical) {
550
- tags.push(` <link rel="canonical" href="${escapeHtml(metadata.canonical)}" />`);
551
- }
552
- return tags.join("\n");
553
- }
554
- function escapeHtml(text) {
555
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
556
- }
557
-
558
- // src/router.tsx
559
- var import_jsx_runtime6 = require("react/jsx-runtime");
560
- function OlovaRouter({
561
- routes,
562
- basePath = "",
563
- defaultLoading,
564
- defaultNotFound,
565
- defaultError,
566
- rootMetadata,
567
- routeMetadata
568
- }) {
569
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(OlovaRouterProvider, { basePath, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
570
- RouteRenderer,
571
- {
572
- routes,
573
- defaultLoading,
574
- defaultNotFound,
575
- defaultError,
576
- rootMetadata,
577
- routeMetadata
578
- }
579
- ) });
580
- }
581
- function RouteRenderer({
582
- routes,
583
- defaultLoading,
584
- defaultNotFound,
585
- defaultError,
586
- rootMetadata,
587
- routeMetadata
588
- }) {
589
- const pathname = usePathname();
590
- const updateParams = useParamsUpdater();
591
- const match = (0, import_react5.useMemo)(() => {
592
- return matchRoute(routes, pathname);
593
- }, [routes, pathname]);
594
- (0, import_react5.useEffect)(() => {
595
- if (updateParams && match) {
596
- updateParams(match.params);
597
- }
598
- }, [match, updateParams]);
599
- const currentMetadata = (0, import_react5.useMemo)(() => {
600
- if (!routeMetadata) return null;
601
- if (routeMetadata[pathname]) {
602
- return routeMetadata[pathname];
603
- }
604
- return null;
605
- }, [pathname, routeMetadata]);
606
- if (!match) {
607
- const NotFoundComponent = defaultNotFound || DefaultNotFoundComponent;
608
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
609
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MetadataHead, { metadata: currentMetadata, fallback: rootMetadata }),
610
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NotFoundComponent, {})
611
- ] });
612
- }
613
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
614
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MetadataHead, { metadata: currentMetadata, fallback: rootMetadata }),
615
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
616
- LayoutRenderer,
617
- {
618
- match,
619
- routes,
620
- defaultLoading,
621
- defaultError
622
- }
623
- )
624
- ] });
625
- }
626
- function LayoutRenderer({ match, routes, defaultLoading, defaultError }) {
627
- const { route, params } = match;
628
- const layoutChain = (0, import_react5.useMemo)(() => {
629
- return findLayoutChain(routes, route);
630
- }, [routes, route]);
631
- const renderSlots = (currentRoute) => {
632
- const slots = {};
633
- if (currentRoute.slots) {
634
- for (const [slotName, slotRoute] of Object.entries(currentRoute.slots)) {
635
- if (slotRoute.component) {
636
- const SlotComponent = slotRoute.component;
637
- const SlotLoading = slotRoute.loading;
638
- const SlotError = slotRoute.error || defaultError;
639
- slots[slotName] = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RouteErrorBoundary, { fallback: SlotError, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RouteLoadingBoundary, { fallback: SlotLoading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SlotLoading, {}) : defaultLoading, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SlotComponent, { params, searchParams: {} }) }) }, slotName);
640
- }
641
- }
642
- }
643
- return slots;
644
- };
645
- const renderLayouts = (index) => {
646
- if (index >= layoutChain.length) {
647
- if (!route.component) {
648
- return null;
649
- }
650
- const PageComponent = route.component;
651
- const LoadingComponent2 = route.loading;
652
- const ErrorComponent2 = route.error || defaultError;
653
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RouteErrorBoundary, { fallback: ErrorComponent2, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RouteLoadingBoundary, { fallback: LoadingComponent2 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LoadingComponent2, {}) : defaultLoading, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PageComponent, { params, searchParams: {} }) }) });
654
- }
655
- const currentLayout = layoutChain[index];
656
- if (!currentLayout.layout) {
657
- return renderLayouts(index + 1);
658
- }
659
- const LayoutComponent = currentLayout.layout;
660
- const LoadingComponent = currentLayout.loading;
661
- const ErrorComponent = currentLayout.error || defaultError;
662
- const slots = renderSlots(currentLayout);
663
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RouteErrorBoundary, { fallback: ErrorComponent, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RouteLoadingBoundary, { fallback: LoadingComponent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LoadingComponent, {}) : defaultLoading, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayoutComponent, { params, ...slots, children: renderLayouts(index + 1) }) }) });
664
- };
665
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: renderLayouts(0) });
666
- }
667
- function matchRoute(routes, pathname) {
668
- const segments = pathname.split("/").filter(Boolean);
669
- function matchRecursive(routeList, segmentIndex, params) {
670
- if (segmentIndex >= segments.length) {
671
- for (const route of routeList) {
672
- if (route.path === "" || route.path === "/") {
673
- if (route.component) {
674
- return {
675
- route,
676
- params,
677
- pathname,
678
- searchParams: new URLSearchParams(window.location.search)
679
- };
680
- }
681
- }
682
- }
683
- return null;
684
- }
685
- const currentSegment = segments[segmentIndex];
686
- for (const route of routeList) {
687
- if (route.path.startsWith("(") && route.path.endsWith(")")) {
688
- if (route.children.length > 0) {
689
- const childMatch = matchRecursive(route.children, segmentIndex, params);
690
- if (childMatch) return childMatch;
691
- }
692
- continue;
693
- }
694
- if (route.isCatchAll && route.paramName) {
695
- const remainingSegments = segments.slice(segmentIndex);
696
- const newParams = { ...params, [route.paramName]: remainingSegments.join("/") };
697
- if (route.component) {
698
- return {
699
- route,
700
- params: newParams,
701
- pathname,
702
- searchParams: new URLSearchParams(window.location.search)
703
- };
704
- }
705
- }
706
- if (route.isDynamic && route.paramName) {
707
- const newParams = { ...params, [route.paramName]: currentSegment };
708
- if (segmentIndex === segments.length - 1) {
709
- if (route.component) {
710
- return {
711
- route,
712
- params: newParams,
713
- pathname,
714
- searchParams: new URLSearchParams(window.location.search)
715
- };
716
- }
717
- }
718
- if (route.children.length > 0) {
719
- const childMatch = matchRecursive(route.children, segmentIndex + 1, newParams);
720
- if (childMatch) return childMatch;
721
- }
722
- }
723
- if (route.path === currentSegment) {
724
- if (segmentIndex === segments.length - 1) {
725
- if (route.component) {
726
- return {
727
- route,
728
- params,
729
- pathname,
730
- searchParams: new URLSearchParams(window.location.search)
731
- };
732
- }
733
- for (const child of route.children) {
734
- if ((child.path === "" || child.path === "/") && child.component) {
735
- return {
736
- route: child,
737
- params,
738
- pathname,
739
- searchParams: new URLSearchParams(window.location.search)
740
- };
741
- }
742
- }
743
- }
744
- if (route.children.length > 0) {
745
- const childMatch = matchRecursive(route.children, segmentIndex + 1, params);
746
- if (childMatch) return childMatch;
747
- }
748
- }
749
- }
750
- return null;
751
- }
752
- if (pathname === "/" || pathname === "") {
753
- for (const route of routes) {
754
- if ((route.path === "" || route.path === "/") && route.component) {
755
- return {
756
- route,
757
- params: {},
758
- pathname: "/",
759
- searchParams: new URLSearchParams(window.location.search)
760
- };
761
- }
762
- }
763
- }
764
- return matchRecursive(routes, 0, {});
765
- }
766
- function findLayoutChain(routes, targetRoute) {
767
- const chain = [];
768
- function findRecursive(routeList, path) {
769
- for (const route of routeList) {
770
- const currentPath = [...path, route];
771
- if (route.id === targetRoute.id) {
772
- for (const r of currentPath) {
773
- if (r.layout) {
774
- chain.push(r);
775
- }
776
- }
777
- return true;
778
- }
779
- if (route.children.length > 0) {
780
- if (findRecursive(route.children, currentPath)) {
781
- return true;
782
- }
783
- }
784
- }
785
- return false;
786
- }
787
- findRecursive(routes, []);
788
- return chain;
789
- }
790
-
791
- // src/components/Link.tsx
792
- var import_react6 = require("react");
793
- var import_jsx_runtime7 = require("react/jsx-runtime");
794
- var Link = (0, import_react6.forwardRef)(
795
- ({ href, replace = false, scroll = true, prefetch = true, children, onClick, ...props }, ref) => {
796
- const router = useOlovaRouter();
797
- const handleClick = (0, import_react6.useCallback)(
798
- (e) => {
799
- onClick?.(e);
800
- if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) {
801
- return;
802
- }
803
- if (href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) {
804
- return;
805
- }
806
- if (href.startsWith("#")) {
807
- return;
808
- }
809
- e.preventDefault();
810
- if (replace) {
811
- router.replace(href, { scroll });
812
- } else {
813
- router.navigate(href, { scroll });
814
- }
815
- },
816
- [href, replace, scroll, router, onClick]
817
- );
818
- const handleMouseEnter = (0, import_react6.useCallback)(() => {
819
- if (prefetch && !href.startsWith("http")) {
820
- router.prefetch(href);
821
- }
822
- }, [href, prefetch, router]);
823
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
824
- "a",
825
- {
826
- ref,
827
- href,
828
- onClick: handleClick,
829
- onMouseEnter: handleMouseEnter,
830
- ...props,
831
- children
832
- }
833
- );
834
- }
835
- );
836
- Link.displayName = "Link";
837
- var NavLink = (0, import_react6.forwardRef)(
838
- ({ href, activeClassName = "", inactiveClassName = "", exact = false, className = "", ...props }, ref) => {
839
- const { pathname } = useOlovaRouter();
840
- const isActive = exact ? pathname === href : pathname.startsWith(href) && (href === "/" ? pathname === "/" : true);
841
- const combinedClassName = `${className} ${isActive ? activeClassName : inactiveClassName}`.trim();
842
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
843
- Link,
844
- {
845
- ref,
846
- href,
847
- className: combinedClassName,
848
- "aria-current": isActive ? "page" : void 0,
849
- ...props
850
- }
851
- );
852
- }
853
- );
854
- NavLink.displayName = "NavLink";
855
- // Annotate the CommonJS export names for ESM import in node:
856
- 0 && (module.exports = {
857
- DefaultErrorComponent,
858
- DefaultLoadingComponent,
859
- DefaultNotFoundComponent,
860
- Link,
861
- MetadataHead,
862
- MetadataProvider,
863
- NavLink,
864
- NotFoundBoundary,
865
- NotFoundError,
866
- OlovaRouter,
867
- RouteErrorBoundary,
868
- RouteLoadingBoundary,
869
- Skeleton,
870
- SkeletonCard,
871
- SkeletonText,
872
- generateMetadataHtml,
873
- notFound,
874
- setSSRContext,
875
- useMetadata,
876
- useOlovaRouter,
877
- usePageMetadata,
878
- useParams,
879
- usePathname,
880
- useRouter,
881
- useSearchParams
882
- });
883
- //# sourceMappingURL=index.cjs.map