bertui 1.2.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +44 -242
  2. package/TYPES_PATCH.md +17 -0
  3. package/bin/bertui.js +2 -7
  4. package/package.json +32 -98
  5. package/src/config.ts +4 -0
  6. package/src/index.ts +32 -0
  7. package/src/optional.ts +49 -0
  8. package/src/router.ts +3 -0
  9. package/tsconfig.json +29 -0
  10. package/LICENSE +0 -21
  11. package/index.js +0 -103
  12. package/src/analyzer/index.js +0 -370
  13. package/src/build/compiler/file-transpiler.js +0 -216
  14. package/src/build/compiler/index.js +0 -31
  15. package/src/build/compiler/route-discoverer.js +0 -49
  16. package/src/build/compiler/router-generator.js +0 -105
  17. package/src/build/css-builder.js +0 -81
  18. package/src/build/generators/html-generator.js +0 -263
  19. package/src/build/generators/robots-generator.js +0 -58
  20. package/src/build/generators/sitemap-generator.js +0 -63
  21. package/src/build/image-optimizer.js +0 -137
  22. package/src/build/processors/asset-processor.js +0 -19
  23. package/src/build/processors/css-builder.js +0 -142
  24. package/src/build/server-island-validator.js +0 -67
  25. package/src/build/ssr-renderer.js +0 -64
  26. package/src/build.js +0 -273
  27. package/src/cli.js +0 -131
  28. package/src/client/compiler.js +0 -522
  29. package/src/client/fast-refresh.js +0 -72
  30. package/src/client/hmr-runtime.js +0 -59
  31. package/src/compiler/index.js +0 -25
  32. package/src/compiler/router-generator-pure.js +0 -104
  33. package/src/compiler/transform.js +0 -149
  34. package/src/config/defaultConfig.js +0 -37
  35. package/src/config/index.js +0 -2
  36. package/src/config/loadConfig.js +0 -64
  37. package/src/config/og-image.png +0 -0
  38. package/src/css/index.js +0 -46
  39. package/src/css/processor.js +0 -172
  40. package/src/dev.js +0 -68
  41. package/src/hydration/index.js +0 -151
  42. package/src/image-optimizer/index.js +0 -103
  43. package/src/images/index.js +0 -102
  44. package/src/images/processor.js +0 -169
  45. package/src/layouts/index.js +0 -165
  46. package/src/loading/index.js +0 -210
  47. package/src/logger/logger.js +0 -320
  48. package/src/logger/notes.md +0 -20
  49. package/src/middleware/index.js +0 -182
  50. package/src/router/Router.js +0 -150
  51. package/src/router/SSRRouter.js +0 -156
  52. package/src/router/index.js +0 -3
  53. package/src/scaffolder/index.js +0 -310
  54. package/src/serve.js +0 -193
  55. package/src/server/dev-handler.js +0 -195
  56. package/src/server/dev-server-utils.js +0 -406
  57. package/src/server/dev-server.js +0 -15
  58. package/src/server/hmr-handler.js +0 -148
  59. package/src/server/index.js +0 -3
  60. package/src/server/notes.md +0 -1
  61. package/src/server/request-handler.js +0 -36
  62. package/src/server-islands/extractor.js +0 -198
  63. package/src/server-islands/index.js +0 -59
  64. package/src/styles/bertui.css +0 -210
  65. package/src/utils/cache.js +0 -297
  66. package/src/utils/env.js +0 -87
  67. package/src/utils/importhow.js +0 -52
  68. package/src/utils/index.js +0 -11
  69. package/src/utils/meta-extractor.js +0 -127
  70. package/types/bin/bertui.d.ts +0 -3
  71. package/types/bin/bertui.d.ts.map +0 -1
  72. package/types/error-overlay.d.ts +0 -2
  73. package/types/error-overlay.d.ts.map +0 -1
  74. package/types/index.d.ts +0 -26
  75. package/types/index.d.ts.map +0 -1
  76. package/types/scripts/fix-wasm-exports.d.ts +0 -2
  77. package/types/scripts/fix-wasm-exports.d.ts.map +0 -1
  78. package/types/src/analyzer/index.d.ts +0 -8
  79. package/types/src/analyzer/index.d.ts.map +0 -1
  80. package/types/src/build/compiler/file-transpiler.d.ts +0 -5
  81. package/types/src/build/compiler/file-transpiler.d.ts.map +0 -1
  82. package/types/src/build/compiler/index.d.ts +0 -12
  83. package/types/src/build/compiler/index.d.ts.map +0 -1
  84. package/types/src/build/compiler/route-discoverer.d.ts +0 -2
  85. package/types/src/build/compiler/route-discoverer.d.ts.map +0 -1
  86. package/types/src/build/compiler/router-generator.d.ts +0 -2
  87. package/types/src/build/compiler/router-generator.d.ts.map +0 -1
  88. package/types/src/build/css-builder.d.ts +0 -18
  89. package/types/src/build/css-builder.d.ts.map +0 -1
  90. package/types/src/build/generators/html-generator.d.ts +0 -2
  91. package/types/src/build/generators/html-generator.d.ts.map +0 -1
  92. package/types/src/build/generators/robots-generator.d.ts +0 -11
  93. package/types/src/build/generators/robots-generator.d.ts.map +0 -1
  94. package/types/src/build/generators/sitemap-generator.d.ts +0 -5
  95. package/types/src/build/generators/sitemap-generator.d.ts.map +0 -1
  96. package/types/src/build/image-optimizer.d.ts +0 -11
  97. package/types/src/build/image-optimizer.d.ts.map +0 -1
  98. package/types/src/build/processors/asset-processor.d.ts +0 -2
  99. package/types/src/build/processors/asset-processor.d.ts.map +0 -1
  100. package/types/src/build/processors/css-builder.d.ts +0 -2
  101. package/types/src/build/processors/css-builder.d.ts.map +0 -1
  102. package/types/src/build/server-island-validator.d.ts +0 -27
  103. package/types/src/build/server-island-validator.d.ts.map +0 -1
  104. package/types/src/build.d.ts +0 -5
  105. package/types/src/build.d.ts.map +0 -1
  106. package/types/src/cli.d.ts +0 -2
  107. package/types/src/cli.d.ts.map +0 -1
  108. package/types/src/client/compiler.d.ts +0 -16
  109. package/types/src/client/compiler.d.ts.map +0 -1
  110. package/types/src/client/fast-refresh.d.ts +0 -3
  111. package/types/src/client/fast-refresh.d.ts.map +0 -1
  112. package/types/src/client/hmr-runtime.d.ts +0 -4
  113. package/types/src/client/hmr-runtime.d.ts.map +0 -1
  114. package/types/src/compiler/index.d.ts +0 -8
  115. package/types/src/compiler/index.d.ts.map +0 -1
  116. package/types/src/compiler/router-generator-pure.d.ts +0 -2
  117. package/types/src/compiler/router-generator-pure.d.ts.map +0 -1
  118. package/types/src/compiler/transform.d.ts +0 -36
  119. package/types/src/compiler/transform.d.ts.map +0 -1
  120. package/types/src/config/defaultConfig.d.ts +0 -26
  121. package/types/src/config/defaultConfig.d.ts.map +0 -1
  122. package/types/src/config/index.d.ts +0 -3
  123. package/types/src/config/index.d.ts.map +0 -1
  124. package/types/src/config/loadConfig.d.ts +0 -2
  125. package/types/src/config/loadConfig.d.ts.map +0 -1
  126. package/types/src/css/index.d.ts +0 -6
  127. package/types/src/css/index.d.ts.map +0 -1
  128. package/types/src/css/processor.d.ts +0 -23
  129. package/types/src/css/processor.d.ts.map +0 -1
  130. package/types/src/dev.d.ts +0 -2
  131. package/types/src/dev.d.ts.map +0 -1
  132. package/types/src/hydration/index.d.ts +0 -33
  133. package/types/src/hydration/index.d.ts.map +0 -1
  134. package/types/src/image-optimizer/index.d.ts +0 -24
  135. package/types/src/image-optimizer/index.d.ts.map +0 -1
  136. package/types/src/images/index.d.ts +0 -12
  137. package/types/src/images/index.d.ts.map +0 -1
  138. package/types/src/images/processor.d.ts +0 -30
  139. package/types/src/images/processor.d.ts.map +0 -1
  140. package/types/src/layouts/index.d.ts +0 -28
  141. package/types/src/layouts/index.d.ts.map +0 -1
  142. package/types/src/loading/index.d.ts +0 -28
  143. package/types/src/loading/index.d.ts.map +0 -1
  144. package/types/src/logger/logger.d.ts +0 -30
  145. package/types/src/logger/logger.d.ts.map +0 -1
  146. package/types/src/middleware/index.d.ts +0 -61
  147. package/types/src/middleware/index.d.ts.map +0 -1
  148. package/types/src/router/Router.d.ts +0 -16
  149. package/types/src/router/Router.d.ts.map +0 -1
  150. package/types/src/router/SSRRouter.d.ts +0 -20
  151. package/types/src/router/SSRRouter.d.ts.map +0 -1
  152. package/types/src/router/index.d.ts +0 -3
  153. package/types/src/router/index.d.ts.map +0 -1
  154. package/types/src/scaffolder/index.d.ts +0 -14
  155. package/types/src/scaffolder/index.d.ts.map +0 -1
  156. package/types/src/serve.d.ts +0 -3
  157. package/types/src/serve.d.ts.map +0 -1
  158. package/types/src/server/dev-handler.d.ts +0 -13
  159. package/types/src/server/dev-handler.d.ts.map +0 -1
  160. package/types/src/server/dev-server-utils.d.ts +0 -6
  161. package/types/src/server/dev-server-utils.d.ts.map +0 -1
  162. package/types/src/server/dev-server.d.ts +0 -18
  163. package/types/src/server/dev-server.d.ts.map +0 -1
  164. package/types/src/server/hmr-handler.d.ts +0 -19
  165. package/types/src/server/hmr-handler.d.ts.map +0 -1
  166. package/types/src/server/index.d.ts +0 -4
  167. package/types/src/server/index.d.ts.map +0 -1
  168. package/types/src/server/request-handler.d.ts +0 -19
  169. package/types/src/server/request-handler.d.ts.map +0 -1
  170. package/types/src/server-islands/extractor.d.ts +0 -16
  171. package/types/src/server-islands/extractor.d.ts.map +0 -1
  172. package/types/src/server-islands/index.d.ts +0 -3
  173. package/types/src/server-islands/index.d.ts.map +0 -1
  174. package/types/src/utils/cache.d.ts +0 -52
  175. package/types/src/utils/cache.d.ts.map +0 -1
  176. package/types/src/utils/env.d.ts +0 -20
  177. package/types/src/utils/env.d.ts.map +0 -1
  178. package/types/src/utils/importhow.d.ts +0 -15
  179. package/types/src/utils/importhow.d.ts.map +0 -1
  180. package/types/src/utils/index.d.ts +0 -3
  181. package/types/src/utils/index.d.ts.map +0 -1
  182. package/types/src/utils/meta-extractor.d.ts +0 -13
  183. package/types/src/utils/meta-extractor.d.ts.map +0 -1
@@ -1,182 +0,0 @@
1
- // bertui/src/middleware/index.js
2
- // Middleware system - src/middleware.ts runs before every request
3
-
4
- import { join, extname } from 'path';
5
- import { existsSync } from 'fs';
6
- import logger from '../logger/logger.js';
7
-
8
- /**
9
- * Middleware context passed to every middleware function
10
- */
11
- export class MiddlewareContext {
12
- constructor(request, options = {}) {
13
- this.request = request;
14
- this.url = new URL(request.url);
15
- this.pathname = this.url.pathname;
16
- this.method = request.method;
17
- this.headers = Object.fromEntries(request.headers.entries());
18
- this.params = options.params || {};
19
- this.route = options.route || null;
20
- this._response = null;
21
- this._redirectTo = null;
22
- this._stopped = false;
23
- this.locals = {}; // Share data between middlewares and pages
24
- }
25
-
26
- /** Respond early - stops further processing */
27
- respond(body, init = {}) {
28
- this._response = new Response(body, {
29
- status: init.status || 200,
30
- headers: {
31
- 'Content-Type': 'text/html',
32
- ...init.headers
33
- }
34
- });
35
- this._stopped = true;
36
- }
37
-
38
- /** Redirect to another URL */
39
- redirect(url, status = 302) {
40
- this._redirectTo = url;
41
- this._response = Response.redirect(url, status);
42
- this._stopped = true;
43
- }
44
-
45
- /** Set a response header (added to final response) */
46
- setHeader(key, value) {
47
- if (!this._extraHeaders) this._extraHeaders = {};
48
- this._extraHeaders[key] = value;
49
- }
50
-
51
- /** Check if middleware stopped the chain */
52
- get stopped() {
53
- return this._stopped;
54
- }
55
- }
56
-
57
- /**
58
- * Load and run user middleware from src/middleware.ts or src/middleware.js
59
- */
60
- export async function loadMiddleware(root) {
61
- const candidates = [
62
- join(root, 'src', 'middleware.ts'),
63
- join(root, 'src', 'middleware.tsx'),
64
- join(root, 'src', 'middleware.js'),
65
- ];
66
-
67
- for (const path of candidates) {
68
- if (existsSync(path)) {
69
- try {
70
- // Transpile if TypeScript
71
- const ext = extname(path);
72
- let code = await Bun.file(path).text();
73
-
74
- if (ext === '.ts' || ext === '.tsx') {
75
- const transpiler = new Bun.Transpiler({
76
- loader: ext === '.tsx' ? 'tsx' : 'ts',
77
- target: 'bun',
78
- });
79
- code = await transpiler.transform(code);
80
- }
81
-
82
- // Write to temp file and import
83
- const tmpPath = join(root, '.bertui', 'middleware.js');
84
- await Bun.write(tmpPath, code);
85
-
86
- const mod = await import(`${tmpPath}?t=${Date.now()}`);
87
- logger.success('✅ Middleware loaded: ' + path.replace(root, ''));
88
-
89
- return {
90
- default: mod.default || null,
91
- onRequest: mod.onRequest || mod.default || null,
92
- onResponse: mod.onResponse || null,
93
- onError: mod.onError || null,
94
- };
95
- } catch (err) {
96
- logger.error(`Failed to load middleware: ${err.message}`);
97
- return null;
98
- }
99
- }
100
- }
101
-
102
- return null;
103
- }
104
-
105
- /**
106
- * Run middleware chain for a request
107
- * Returns a Response if middleware intercepted, null to continue
108
- */
109
- export async function runMiddleware(middlewareMod, request, routeInfo = {}) {
110
- if (!middlewareMod) return null;
111
-
112
- const ctx = new MiddlewareContext(request, routeInfo);
113
-
114
- try {
115
- // Run onRequest middleware
116
- if (middlewareMod.onRequest) {
117
- await middlewareMod.onRequest(ctx);
118
- if (ctx.stopped) {
119
- logger.debug(`🛡️ Middleware intercepted: ${ctx.pathname}`);
120
- return ctx._response;
121
- }
122
- }
123
-
124
- return null; // Continue to route handler
125
- } catch (err) {
126
- logger.error(`Middleware error: ${err.message}`);
127
-
128
- // Run error handler if defined
129
- if (middlewareMod.onError) {
130
- try {
131
- await middlewareMod.onError(ctx, err);
132
- if (ctx._response) return ctx._response;
133
- } catch (e) {
134
- logger.error(`Middleware error handler failed: ${e.message}`);
135
- }
136
- }
137
-
138
- return null;
139
- }
140
- }
141
-
142
- /**
143
- * MiddlewareManager - watches and reloads middleware on change
144
- */
145
- export class MiddlewareManager {
146
- constructor(root) {
147
- this.root = root;
148
- this.middleware = null;
149
- this.watcher = null;
150
- }
151
-
152
- async load() {
153
- this.middleware = await loadMiddleware(this.root);
154
- return this;
155
- }
156
-
157
- async run(request, routeInfo = {}) {
158
- return runMiddleware(this.middleware, request, routeInfo);
159
- }
160
-
161
- watch() {
162
- const candidates = [
163
- join(this.root, 'src', 'middleware.ts'),
164
- join(this.root, 'src', 'middleware.tsx'),
165
- join(this.root, 'src', 'middleware.js'),
166
- ];
167
-
168
- const existing = candidates.find(existsSync);
169
- if (!existing) return;
170
-
171
- const { watch } = require('fs');
172
- this.watcher = watch(existing, async () => {
173
- logger.info('🔄 Reloading middleware...');
174
- this.middleware = await loadMiddleware(this.root);
175
- logger.success('✅ Middleware reloaded');
176
- });
177
- }
178
-
179
- dispose() {
180
- if (this.watcher) this.watcher.close();
181
- }
182
- }
@@ -1,150 +0,0 @@
1
- // src/router/Router.js - SSR COMPATIBLE VERSION
2
- import { useState, useEffect, createContext, useContext } from 'react';
3
-
4
- const RouterContext = createContext(null);
5
-
6
- // ✅ FIX: SSR-safe useRouter
7
- export function useRouter() {
8
- const context = useContext(RouterContext);
9
-
10
- // During SSR (when window doesn't exist), return a mock router
11
- if (typeof window === 'undefined') {
12
- return {
13
- pathname: '/',
14
- params: {},
15
- navigate: () => {},
16
- currentRoute: null,
17
- isSSR: true
18
- };
19
- }
20
-
21
- if (!context) {
22
- throw new Error('useRouter must be used within a Router component');
23
- }
24
-
25
- return context;
26
- }
27
-
28
- export function Router({ routes }) {
29
- const [currentRoute, setCurrentRoute] = useState(null);
30
- const [params, setParams] = useState({});
31
-
32
- useEffect(() => {
33
- matchAndSetRoute(window.location.pathname);
34
-
35
- const handlePopState = () => {
36
- matchAndSetRoute(window.location.pathname);
37
- };
38
-
39
- window.addEventListener('popstate', handlePopState);
40
- return () => window.removeEventListener('popstate', handlePopState);
41
- }, [routes]);
42
-
43
- function matchAndSetRoute(pathname) {
44
- // Try static routes first
45
- for (const route of routes) {
46
- if (route.type === 'static' && route.path === pathname) {
47
- setCurrentRoute(route);
48
- setParams({});
49
- return;
50
- }
51
- }
52
-
53
- // Try dynamic routes
54
- for (const route of routes) {
55
- if (route.type === 'dynamic') {
56
- const pattern = route.path.replace(/\[([^\]]+)\]/g, '([^/]+)');
57
- const regex = new RegExp('^' + pattern + '$');
58
- const match = pathname.match(regex);
59
-
60
- if (match) {
61
- const paramNames = [...route.path.matchAll(/\[([^\]]+)\]/g)].map(m => m[1]);
62
- const extractedParams = {};
63
- paramNames.forEach((name, i) => {
64
- extractedParams[name] = match[i + 1];
65
- });
66
-
67
- setCurrentRoute(route);
68
- setParams(extractedParams);
69
- return;
70
- }
71
- }
72
- }
73
-
74
- // No match found
75
- setCurrentRoute(null);
76
- setParams({});
77
- }
78
-
79
- function navigate(path) {
80
- if (typeof window !== 'undefined') {
81
- window.history.pushState({}, '', path);
82
- matchAndSetRoute(path);
83
- }
84
- }
85
-
86
- const routerValue = {
87
- currentRoute,
88
- params,
89
- navigate,
90
- pathname: typeof window !== 'undefined' ? window.location.pathname : '/',
91
- isSSR: typeof window === 'undefined'
92
- };
93
-
94
- const Component = currentRoute?.component;
95
-
96
- return (
97
- <RouterContext.Provider value={routerValue}>
98
- {Component ? <Component params={params} /> : <NotFound />}
99
- </RouterContext.Provider>
100
- );
101
- }
102
-
103
- // ✅ FIX: SSR-safe Link component
104
- export function Link({ to, children, ...props }) {
105
- // Try to get router, but don't fail if it doesn't exist
106
- let router;
107
- try {
108
- router = useRouter();
109
- } catch (e) {
110
- // During SSR, router might not be available
111
- router = null;
112
- }
113
-
114
- function handleClick(e) {
115
- // During SSR, just use normal link behavior
116
- if (typeof window === 'undefined') return;
117
-
118
- // If no router or navigate function, use normal link
119
- if (!router || !router.navigate) return;
120
-
121
- // Only prevent default if we have client-side routing
122
- e.preventDefault();
123
- router.navigate(to);
124
- }
125
-
126
- return (
127
- <a href={to} onClick={handleClick} {...props}>
128
- {children}
129
- </a>
130
- );
131
- }
132
-
133
- function NotFound() {
134
- return (
135
- <div style={{
136
- display: 'flex',
137
- flexDirection: 'column',
138
- alignItems: 'center',
139
- justifyContent: 'center',
140
- minHeight: '100vh',
141
- fontFamily: 'system-ui'
142
- }}>
143
- <h1 style={{ fontSize: '6rem', margin: 0 }}>404</h1>
144
- <p style={{ fontSize: '1.5rem', color: '#666' }}>Page not found</p>
145
- <a href="/" style={{ color: '#10b981', textDecoration: 'none', fontSize: '1.2rem' }}>
146
- Go home
147
- </a>
148
- </div>
149
- );
150
- }
@@ -1,156 +0,0 @@
1
- // src/router/SSRRouter.jsx
2
- // SSR-Compatible Router for BertUI - Works during build AND runtime
3
- import React, { useState, useEffect, createContext, useContext } from 'react';
4
-
5
- const RouterContext = createContext(null);
6
-
7
- // ✅ SSR-safe useRouter hook
8
- export function useRouter() {
9
- const context = useContext(RouterContext);
10
-
11
- // During SSR, provide a mock router
12
- if (!context) {
13
- return {
14
- pathname: '/',
15
- params: {},
16
- navigate: () => {},
17
- isSSR: true
18
- };
19
- }
20
-
21
- return context;
22
- }
23
-
24
- // ✅ SSR-safe Router component
25
- export function SSRRouter({ routes, initialPath = '/' }) {
26
- const [currentRoute, setCurrentRoute] = useState(null);
27
- const [params, setParams] = useState({});
28
- const [isClient, setIsClient] = useState(false);
29
-
30
- // Detect if we're in the browser
31
- useEffect(() => {
32
- setIsClient(true);
33
- matchAndSetRoute(window.location.pathname);
34
-
35
- const handlePopState = () => {
36
- matchAndSetRoute(window.location.pathname);
37
- };
38
-
39
- window.addEventListener('popstate', handlePopState);
40
- return () => window.removeEventListener('popstate', handlePopState);
41
- }, [routes]);
42
-
43
- // Match route on server-side (SSR)
44
- if (!isClient && !currentRoute) {
45
- const matched = matchRoute(initialPath, routes);
46
- if (matched) {
47
- return React.createElement(
48
- RouterContext.Provider,
49
- { value: { pathname: initialPath, params: matched.params, navigate: () => {}, isSSR: true } },
50
- React.createElement(matched.route.component, { params: matched.params })
51
- );
52
- }
53
- }
54
-
55
- function matchRoute(pathname, routesList) {
56
- // Try static routes first
57
- for (const route of routesList) {
58
- if (route.type === 'static' && route.path === pathname) {
59
- return { route, params: {} };
60
- }
61
- }
62
-
63
- // Try dynamic routes
64
- for (const route of routesList) {
65
- if (route.type === 'dynamic') {
66
- const pattern = route.path.replace(/\[([^\]]+)\]/g, '([^/]+)');
67
- const regex = new RegExp('^' + pattern + '$');
68
- const match = pathname.match(regex);
69
-
70
- if (match) {
71
- const paramNames = [...route.path.matchAll(/\[([^\]]+)\]/g)].map(m => m[1]);
72
- const extractedParams = {};
73
- paramNames.forEach((name, i) => {
74
- extractedParams[name] = match[i + 1];
75
- });
76
-
77
- return { route, params: extractedParams };
78
- }
79
- }
80
- }
81
-
82
- return null;
83
- }
84
-
85
- function matchAndSetRoute(pathname) {
86
- const matched = matchRoute(pathname, routes);
87
-
88
- if (matched) {
89
- setCurrentRoute(matched.route);
90
- setParams(matched.params);
91
- } else {
92
- setCurrentRoute(null);
93
- setParams({});
94
- }
95
- }
96
-
97
- function navigate(path) {
98
- if (typeof window !== 'undefined') {
99
- window.history.pushState({}, '', path);
100
- matchAndSetRoute(path);
101
- }
102
- }
103
-
104
- const routerValue = {
105
- currentRoute,
106
- params,
107
- navigate,
108
- pathname: typeof window !== 'undefined' ? window.location.pathname : initialPath,
109
- isSSR: !isClient
110
- };
111
-
112
- const Component = currentRoute?.component;
113
-
114
- return React.createElement(
115
- RouterContext.Provider,
116
- { value: routerValue },
117
- Component ? React.createElement(Component, { params }) : React.createElement(NotFound, null)
118
- );
119
- }
120
-
121
- // ✅ SSR-safe Link component
122
- export function Link({ to, children, ...props }) {
123
- const { navigate, isSSR } = useRouter();
124
-
125
- function handleClick(e) {
126
- // Don't prevent default during SSR
127
- if (isSSR) return;
128
-
129
- e.preventDefault();
130
- navigate(to);
131
- }
132
-
133
- return React.createElement('a', { href: to, onClick: handleClick, ...props }, children);
134
- }
135
-
136
- function NotFound() {
137
- return React.createElement(
138
- 'div',
139
- {
140
- style: {
141
- display: 'flex',
142
- flexDirection: 'column',
143
- alignItems: 'center',
144
- justifyContent: 'center',
145
- minHeight: '100vh',
146
- fontFamily: 'system-ui'
147
- }
148
- },
149
- React.createElement('h1', { style: { fontSize: '6rem', margin: 0 } }, '404'),
150
- React.createElement('p', { style: { fontSize: '1.5rem', color: '#666' } }, 'Page not found'),
151
- React.createElement('a', {
152
- href: '/',
153
- style: { color: '#10b981', textDecoration: 'none', fontSize: '1.2rem' }
154
- }, 'Go home')
155
- );
156
- }
@@ -1,3 +0,0 @@
1
- // bertui/src/router/index.js
2
- export { Router, Link, useRouter } from './Router.js';
3
- export { SSRRouter } from './SSRRouter.js';