bertui 1.2.8 → 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 (182) hide show
  1. package/README.md +45 -196
  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 -151
  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 -12
  25. package/src/build.js +0 -266
  26. package/src/cli.js +0 -131
  27. package/src/client/compiler.js +0 -522
  28. package/src/client/fast-refresh.js +0 -72
  29. package/src/client/hmr-runtime.js +0 -59
  30. package/src/compiler/index.js +0 -25
  31. package/src/compiler/router-generator-pure.js +0 -104
  32. package/src/compiler/transform.js +0 -149
  33. package/src/config/defaultConfig.js +0 -37
  34. package/src/config/index.js +0 -2
  35. package/src/config/loadConfig.js +0 -64
  36. package/src/config/og-image.png +0 -0
  37. package/src/css/index.js +0 -46
  38. package/src/css/processor.js +0 -172
  39. package/src/dev.js +0 -68
  40. package/src/hydration/index.js +0 -151
  41. package/src/image-optimizer/index.js +0 -103
  42. package/src/images/index.js +0 -102
  43. package/src/images/processor.js +0 -169
  44. package/src/layouts/index.js +0 -165
  45. package/src/loading/index.js +0 -210
  46. package/src/logger/logger.js +0 -320
  47. package/src/logger/notes.md +0 -20
  48. package/src/middleware/index.js +0 -182
  49. package/src/router/Router.js +0 -150
  50. package/src/router/SSRRouter.js +0 -156
  51. package/src/router/index.js +0 -3
  52. package/src/scaffolder/index.js +0 -310
  53. package/src/serve.js +0 -193
  54. package/src/server/dev-handler.js +0 -195
  55. package/src/server/dev-server-utils.js +0 -406
  56. package/src/server/dev-server.js +0 -15
  57. package/src/server/hmr-handler.js +0 -148
  58. package/src/server/index.js +0 -3
  59. package/src/server/notes.md +0 -1
  60. package/src/server/request-handler.js +0 -36
  61. package/src/server-islands/extractor.js +0 -198
  62. package/src/server-islands/index.js +0 -59
  63. package/src/styles/bertui.css +0 -210
  64. package/src/utils/cache.js +0 -297
  65. package/src/utils/env.js +0 -87
  66. package/src/utils/importhow.js +0 -52
  67. package/src/utils/index.js +0 -11
  68. package/src/utils/meta-extractor.js +0 -127
  69. package/types/bin/bertui.d.ts +0 -3
  70. package/types/bin/bertui.d.ts.map +0 -1
  71. package/types/error-overlay.d.ts +0 -2
  72. package/types/error-overlay.d.ts.map +0 -1
  73. package/types/index.d.ts +0 -26
  74. package/types/index.d.ts.map +0 -1
  75. package/types/scripts/fix-wasm-exports.d.ts +0 -2
  76. package/types/scripts/fix-wasm-exports.d.ts.map +0 -1
  77. package/types/src/analyzer/index.d.ts +0 -8
  78. package/types/src/analyzer/index.d.ts.map +0 -1
  79. package/types/src/build/compiler/file-transpiler.d.ts +0 -5
  80. package/types/src/build/compiler/file-transpiler.d.ts.map +0 -1
  81. package/types/src/build/compiler/index.d.ts +0 -12
  82. package/types/src/build/compiler/index.d.ts.map +0 -1
  83. package/types/src/build/compiler/route-discoverer.d.ts +0 -2
  84. package/types/src/build/compiler/route-discoverer.d.ts.map +0 -1
  85. package/types/src/build/compiler/router-generator.d.ts +0 -2
  86. package/types/src/build/compiler/router-generator.d.ts.map +0 -1
  87. package/types/src/build/css-builder.d.ts +0 -18
  88. package/types/src/build/css-builder.d.ts.map +0 -1
  89. package/types/src/build/generators/html-generator.d.ts +0 -2
  90. package/types/src/build/generators/html-generator.d.ts.map +0 -1
  91. package/types/src/build/generators/robots-generator.d.ts +0 -11
  92. package/types/src/build/generators/robots-generator.d.ts.map +0 -1
  93. package/types/src/build/generators/sitemap-generator.d.ts +0 -5
  94. package/types/src/build/generators/sitemap-generator.d.ts.map +0 -1
  95. package/types/src/build/image-optimizer.d.ts +0 -11
  96. package/types/src/build/image-optimizer.d.ts.map +0 -1
  97. package/types/src/build/processors/asset-processor.d.ts +0 -2
  98. package/types/src/build/processors/asset-processor.d.ts.map +0 -1
  99. package/types/src/build/processors/css-builder.d.ts +0 -2
  100. package/types/src/build/processors/css-builder.d.ts.map +0 -1
  101. package/types/src/build/server-island-validator.d.ts +0 -27
  102. package/types/src/build/server-island-validator.d.ts.map +0 -1
  103. package/types/src/build.d.ts +0 -5
  104. package/types/src/build.d.ts.map +0 -1
  105. package/types/src/cli.d.ts +0 -2
  106. package/types/src/cli.d.ts.map +0 -1
  107. package/types/src/client/compiler.d.ts +0 -16
  108. package/types/src/client/compiler.d.ts.map +0 -1
  109. package/types/src/client/fast-refresh.d.ts +0 -3
  110. package/types/src/client/fast-refresh.d.ts.map +0 -1
  111. package/types/src/client/hmr-runtime.d.ts +0 -4
  112. package/types/src/client/hmr-runtime.d.ts.map +0 -1
  113. package/types/src/compiler/index.d.ts +0 -8
  114. package/types/src/compiler/index.d.ts.map +0 -1
  115. package/types/src/compiler/router-generator-pure.d.ts +0 -2
  116. package/types/src/compiler/router-generator-pure.d.ts.map +0 -1
  117. package/types/src/compiler/transform.d.ts +0 -36
  118. package/types/src/compiler/transform.d.ts.map +0 -1
  119. package/types/src/config/defaultConfig.d.ts +0 -26
  120. package/types/src/config/defaultConfig.d.ts.map +0 -1
  121. package/types/src/config/index.d.ts +0 -3
  122. package/types/src/config/index.d.ts.map +0 -1
  123. package/types/src/config/loadConfig.d.ts +0 -2
  124. package/types/src/config/loadConfig.d.ts.map +0 -1
  125. package/types/src/css/index.d.ts +0 -6
  126. package/types/src/css/index.d.ts.map +0 -1
  127. package/types/src/css/processor.d.ts +0 -23
  128. package/types/src/css/processor.d.ts.map +0 -1
  129. package/types/src/dev.d.ts +0 -2
  130. package/types/src/dev.d.ts.map +0 -1
  131. package/types/src/hydration/index.d.ts +0 -33
  132. package/types/src/hydration/index.d.ts.map +0 -1
  133. package/types/src/image-optimizer/index.d.ts +0 -24
  134. package/types/src/image-optimizer/index.d.ts.map +0 -1
  135. package/types/src/images/index.d.ts +0 -12
  136. package/types/src/images/index.d.ts.map +0 -1
  137. package/types/src/images/processor.d.ts +0 -30
  138. package/types/src/images/processor.d.ts.map +0 -1
  139. package/types/src/layouts/index.d.ts +0 -28
  140. package/types/src/layouts/index.d.ts.map +0 -1
  141. package/types/src/loading/index.d.ts +0 -28
  142. package/types/src/loading/index.d.ts.map +0 -1
  143. package/types/src/logger/logger.d.ts +0 -30
  144. package/types/src/logger/logger.d.ts.map +0 -1
  145. package/types/src/middleware/index.d.ts +0 -61
  146. package/types/src/middleware/index.d.ts.map +0 -1
  147. package/types/src/router/Router.d.ts +0 -16
  148. package/types/src/router/Router.d.ts.map +0 -1
  149. package/types/src/router/SSRRouter.d.ts +0 -20
  150. package/types/src/router/SSRRouter.d.ts.map +0 -1
  151. package/types/src/router/index.d.ts +0 -3
  152. package/types/src/router/index.d.ts.map +0 -1
  153. package/types/src/scaffolder/index.d.ts +0 -14
  154. package/types/src/scaffolder/index.d.ts.map +0 -1
  155. package/types/src/serve.d.ts +0 -3
  156. package/types/src/serve.d.ts.map +0 -1
  157. package/types/src/server/dev-handler.d.ts +0 -13
  158. package/types/src/server/dev-handler.d.ts.map +0 -1
  159. package/types/src/server/dev-server-utils.d.ts +0 -6
  160. package/types/src/server/dev-server-utils.d.ts.map +0 -1
  161. package/types/src/server/dev-server.d.ts +0 -18
  162. package/types/src/server/dev-server.d.ts.map +0 -1
  163. package/types/src/server/hmr-handler.d.ts +0 -19
  164. package/types/src/server/hmr-handler.d.ts.map +0 -1
  165. package/types/src/server/index.d.ts +0 -4
  166. package/types/src/server/index.d.ts.map +0 -1
  167. package/types/src/server/request-handler.d.ts +0 -19
  168. package/types/src/server/request-handler.d.ts.map +0 -1
  169. package/types/src/server-islands/extractor.d.ts +0 -16
  170. package/types/src/server-islands/extractor.d.ts.map +0 -1
  171. package/types/src/server-islands/index.d.ts +0 -3
  172. package/types/src/server-islands/index.d.ts.map +0 -1
  173. package/types/src/utils/cache.d.ts +0 -52
  174. package/types/src/utils/cache.d.ts.map +0 -1
  175. package/types/src/utils/env.d.ts +0 -20
  176. package/types/src/utils/env.d.ts.map +0 -1
  177. package/types/src/utils/importhow.d.ts +0 -15
  178. package/types/src/utils/importhow.d.ts.map +0 -1
  179. package/types/src/utils/index.d.ts +0 -3
  180. package/types/src/utils/index.d.ts.map +0 -1
  181. package/types/src/utils/meta-extractor.d.ts +0 -13
  182. 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';