fynixui 1.0.11 → 1.0.13
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/LICENSE +21 -21
- package/README.md +396 -0
- package/dist/README.md +396 -0
- package/dist/custom/DataTable.js +359 -0
- package/dist/custom/button.js +241 -1
- package/dist/custom/index.js +2 -1
- package/dist/error/errorOverlay.js +1 -1
- package/dist/hooks/nixFor.js +15 -17
- package/dist/package.json +2 -3
- package/dist/plugins/vite-plugin-res.js +26 -4
- package/dist/router/router.js +108 -217
- package/dist/runtime.js +1261 -1026
- package/dist-types/context/context.d.ts +1 -1
- package/dist-types/custom/DataTable.d.ts +54 -0
- package/dist-types/custom/button.d.ts +35 -1
- package/dist-types/custom/index.d.ts +2 -1
- package/dist-types/hooks/nixFor.d.ts +1 -1
- package/dist-types/router/router.d.ts +14 -10
- package/dist-types/runtime.d.ts +118 -40
- package/package.json +256 -254
- package/types/fnx.d.ts +34 -34
- package/types/global.d.ts +277 -279
- package/types/jsx.d.ts +1046 -993
- package/types/vite-env.d.ts +545 -545
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fynixui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core package for Fynix UI framework - A lightweight, reactive UI framework with TypeScript support.",
|
|
6
6
|
"main": "./dist/fynix/index.js",
|
|
@@ -214,6 +214,5 @@
|
|
|
214
214
|
"./types/global.d.ts"
|
|
215
215
|
]
|
|
216
216
|
}
|
|
217
|
-
}
|
|
218
|
-
"dependencies": {}
|
|
217
|
+
}
|
|
219
218
|
}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { transform } from "esbuild";
|
|
2
2
|
import { normalizePath } from "vite";
|
|
3
|
+
import crypto from "crypto";
|
|
3
4
|
export default function fynixPlugin(options = {}) {
|
|
4
|
-
const { jsxFactory = "Fynix", jsxFragment = "Fynix.Fragment", include = [".ts", ".js", ".jsx", ".tsx", ".fnx"], exclude = ["node_modules"],
|
|
5
|
+
const { jsxFactory = "Fynix", jsxFragment = "Fynix.Fragment", include = [".ts", ".js", ".jsx", ".tsx", ".fnx"], exclude = ["node_modules"], esbuildOptions = {}, } = options;
|
|
5
6
|
let viteServer = null;
|
|
7
|
+
const transformCache = new Map();
|
|
8
|
+
function hasJsxLike(code) {
|
|
9
|
+
return (/<[A-Za-z]/.test(code) ||
|
|
10
|
+
/Fynix\s*\(/.test(code) ||
|
|
11
|
+
/Fragment|<>/.test(code));
|
|
12
|
+
}
|
|
13
|
+
function getContentHash(code) {
|
|
14
|
+
return crypto.createHash("md5").update(code).digest("hex");
|
|
15
|
+
}
|
|
6
16
|
return {
|
|
7
17
|
name: "vite-plugin-fynix",
|
|
8
18
|
enforce: "pre",
|
|
@@ -17,6 +27,14 @@ export default function fynixPlugin(options = {}) {
|
|
|
17
27
|
const shouldInclude = include.some((ext) => normalizedId.endsWith(ext));
|
|
18
28
|
if (!shouldInclude)
|
|
19
29
|
return null;
|
|
30
|
+
if (!hasJsxLike(code)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const contentHash = getContentHash(code);
|
|
34
|
+
const cached = transformCache.get(normalizedId);
|
|
35
|
+
if (cached && cached.contentHash === contentHash) {
|
|
36
|
+
return { code: cached.code, map: cached.map };
|
|
37
|
+
}
|
|
20
38
|
const ctx = this;
|
|
21
39
|
if (typeof ctx.addWatchFile === "function") {
|
|
22
40
|
ctx.addWatchFile(id);
|
|
@@ -39,16 +57,19 @@ export default function fynixPlugin(options = {}) {
|
|
|
39
57
|
loader,
|
|
40
58
|
jsxFactory,
|
|
41
59
|
jsxFragment,
|
|
42
|
-
sourcemap,
|
|
60
|
+
sourcemap: false,
|
|
43
61
|
sourcefile: id,
|
|
44
62
|
target: "esnext",
|
|
45
63
|
format: "esm",
|
|
46
64
|
...esbuildOptions,
|
|
47
65
|
});
|
|
48
|
-
|
|
66
|
+
const transformed = {
|
|
49
67
|
code: result.code,
|
|
50
|
-
map:
|
|
68
|
+
map: null,
|
|
69
|
+
contentHash,
|
|
51
70
|
};
|
|
71
|
+
transformCache.set(normalizedId, transformed);
|
|
72
|
+
return { code: transformed.code, map: transformed.map };
|
|
52
73
|
}
|
|
53
74
|
catch (error) {
|
|
54
75
|
const err = error;
|
|
@@ -71,6 +92,7 @@ export default function fynixPlugin(options = {}) {
|
|
|
71
92
|
handleHotUpdate(ctx) {
|
|
72
93
|
const { file, server } = ctx;
|
|
73
94
|
const normalizedFile = normalizePath(file);
|
|
95
|
+
transformCache.delete(normalizedFile);
|
|
74
96
|
const shouldReload = include.some((ext) => normalizedFile.endsWith(ext));
|
|
75
97
|
if (shouldReload) {
|
|
76
98
|
console.log(`\x1b[32m[vite-plugin-fynix]\x1b[0m HMR: full-reload triggered by ${normalizedFile}`);
|
package/dist/router/router.js
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
import { mount } from "../runtime";
|
|
2
|
+
import { nixLazy } from "../hooks/nixLazy";
|
|
3
|
+
class LocationManager {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.current = {
|
|
6
|
+
path: typeof window !== "undefined" ? window.location.pathname : "/",
|
|
7
|
+
params: {},
|
|
8
|
+
search: typeof window !== "undefined" ? window.location.search : "",
|
|
9
|
+
};
|
|
10
|
+
this.subscribers = new Set();
|
|
11
|
+
}
|
|
12
|
+
get value() {
|
|
13
|
+
return this.current;
|
|
14
|
+
}
|
|
15
|
+
set value(newLocation) {
|
|
16
|
+
this.current = newLocation;
|
|
17
|
+
this.subscribers.forEach((callback) => {
|
|
18
|
+
try {
|
|
19
|
+
callback(newLocation);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error("[Router] Location subscriber error:", error);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
subscribe(callback) {
|
|
27
|
+
this.subscribers.add(callback);
|
|
28
|
+
return () => {
|
|
29
|
+
this.subscribers.delete(callback);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export const location = new LocationManager();
|
|
2
34
|
const MAX_CACHE_SIZE = 50;
|
|
3
35
|
const PROPS_NAMESPACE = "__fynixLinkProps__";
|
|
4
36
|
const MAX_LISTENERS = 100;
|
|
@@ -42,6 +74,30 @@ function sanitizeContent(content) {
|
|
|
42
74
|
.replace(/expression\s*\(/gi, "");
|
|
43
75
|
}
|
|
44
76
|
function sanitizeProps(props) {
|
|
77
|
+
const sanitized = {};
|
|
78
|
+
for (const [key, value] of Object.entries(props)) {
|
|
79
|
+
if (typeof key !== "string" || key.startsWith("__")) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (typeof value === "string") {
|
|
83
|
+
const cleanContent = sanitizeContent(value);
|
|
84
|
+
sanitized[key] = escapeHTML(cleanContent);
|
|
85
|
+
}
|
|
86
|
+
else if (typeof value === "object" && value !== null) {
|
|
87
|
+
if (Object.keys(value).length < 50) {
|
|
88
|
+
sanitized[key] = sanitizeProps(value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (typeof value === "function") {
|
|
92
|
+
sanitized[key] = value;
|
|
93
|
+
}
|
|
94
|
+
else if (typeof value === "number" || typeof value === "boolean") {
|
|
95
|
+
sanitized[key] = value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return sanitized;
|
|
99
|
+
}
|
|
100
|
+
function sanitizeExternalProps(props) {
|
|
45
101
|
const sanitized = {};
|
|
46
102
|
for (const [key, value] of Object.entries(props)) {
|
|
47
103
|
if (typeof key !== "string" ||
|
|
@@ -51,12 +107,11 @@ function sanitizeProps(props) {
|
|
|
51
107
|
continue;
|
|
52
108
|
}
|
|
53
109
|
if (typeof value === "string") {
|
|
54
|
-
|
|
55
|
-
sanitized[key] = escapeHTML(cleanContent);
|
|
110
|
+
sanitized[key] = escapeHTML(sanitizeContent(value));
|
|
56
111
|
}
|
|
57
112
|
else if (typeof value === "object" && value !== null) {
|
|
58
113
|
if (Object.keys(value).length < 50) {
|
|
59
|
-
sanitized[key] =
|
|
114
|
+
sanitized[key] = sanitizeExternalProps(value);
|
|
60
115
|
}
|
|
61
116
|
}
|
|
62
117
|
else if (typeof value === "number" || typeof value === "boolean") {
|
|
@@ -134,18 +189,37 @@ function sanitizePath(path) {
|
|
|
134
189
|
}
|
|
135
190
|
return path || "/";
|
|
136
191
|
}
|
|
137
|
-
function tryGlobPaths() {
|
|
192
|
+
function tryGlobPaths(lazy = false) {
|
|
138
193
|
try {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
194
|
+
if (lazy) {
|
|
195
|
+
let modules = import.meta.glob("/src/**/*.{tsx,jsx,ts,js}");
|
|
196
|
+
if (Object.keys(modules).length === 0) {
|
|
197
|
+
modules = import.meta.glob([
|
|
198
|
+
"./**/*.tsx",
|
|
199
|
+
"./**/*.jsx",
|
|
200
|
+
"./**/*.ts",
|
|
201
|
+
"./**/*.js",
|
|
202
|
+
]);
|
|
203
|
+
}
|
|
204
|
+
if (Object.keys(modules).length === 0) {
|
|
205
|
+
modules = import.meta.glob(["../**/*.tsx", "../**/*.jsx"]);
|
|
206
|
+
}
|
|
207
|
+
return modules || {};
|
|
144
208
|
}
|
|
145
|
-
|
|
146
|
-
modules = import.meta.glob(
|
|
209
|
+
else {
|
|
210
|
+
let modules = import.meta.glob("/src/**/*.{tsx,jsx,ts,js}", {
|
|
211
|
+
eager: true,
|
|
212
|
+
});
|
|
213
|
+
if (Object.keys(modules).length === 0) {
|
|
214
|
+
modules = import.meta.glob(["./**/*.tsx", "./**/*.jsx", "./**/*.ts", "./**/*.js"], { eager: true });
|
|
215
|
+
}
|
|
216
|
+
if (Object.keys(modules).length === 0) {
|
|
217
|
+
modules = import.meta.glob(["../**/*.tsx", "../**/*.jsx"], {
|
|
218
|
+
eager: true,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return modules || {};
|
|
147
222
|
}
|
|
148
|
-
return modules || {};
|
|
149
223
|
}
|
|
150
224
|
catch (error) {
|
|
151
225
|
console.error("[Router] Failed to load modules:", error);
|
|
@@ -155,7 +229,7 @@ function tryGlobPaths() {
|
|
|
155
229
|
function filePathToRoute(filePath) {
|
|
156
230
|
let route = filePath
|
|
157
231
|
.replace(/^.*\/src/, "")
|
|
158
|
-
.replace(/\.(ts|tsx|js|jsx
|
|
232
|
+
.replace(/\.(ts|tsx|js|jsx)$/, "")
|
|
159
233
|
.replace(/\/view$/, "")
|
|
160
234
|
.replace(/\/$/, "");
|
|
161
235
|
if (!route)
|
|
@@ -266,175 +340,7 @@ function updateMetaTags(meta = {}) {
|
|
|
266
340
|
el.setAttribute("content", sanitizedValue);
|
|
267
341
|
});
|
|
268
342
|
}
|
|
269
|
-
|
|
270
|
-
constructor() {
|
|
271
|
-
this.routeCache = new Map();
|
|
272
|
-
this.preloadQueue = new Set();
|
|
273
|
-
this.routeMatchCache = new Map();
|
|
274
|
-
this.routes = {};
|
|
275
|
-
}
|
|
276
|
-
setRoutes(routes) {
|
|
277
|
-
if (!routes || typeof routes !== "object") {
|
|
278
|
-
console.warn("[EnterpriseRouter] Invalid routes configuration");
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
this.routes = routes;
|
|
282
|
-
}
|
|
283
|
-
async preloadRoute(path) {
|
|
284
|
-
if (this.routeCache.has(path))
|
|
285
|
-
return;
|
|
286
|
-
const route = this.routes[path];
|
|
287
|
-
if (route?.component) {
|
|
288
|
-
const loadRoute = async () => {
|
|
289
|
-
try {
|
|
290
|
-
const component = await route.component();
|
|
291
|
-
this.routeCache.set(path, component);
|
|
292
|
-
route.prefetch?.forEach((prefetchPath) => {
|
|
293
|
-
this.preloadQueue.add(prefetchPath);
|
|
294
|
-
});
|
|
295
|
-
console.log(`[EnterpriseRouter] Preloaded route: ${path}`);
|
|
296
|
-
}
|
|
297
|
-
catch (error) {
|
|
298
|
-
console.warn(`[EnterpriseRouter] Failed to preload route ${path}:`, error);
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
if ("requestIdleCallback" in window) {
|
|
302
|
-
requestIdleCallback(loadRoute);
|
|
303
|
-
}
|
|
304
|
-
else {
|
|
305
|
-
setTimeout(loadRoute, 0);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
matchRoute(path) {
|
|
310
|
-
const cached = this.routeMatchCache.get(path);
|
|
311
|
-
if (cached !== undefined)
|
|
312
|
-
return cached;
|
|
313
|
-
const match = this.computeRouteMatch(path);
|
|
314
|
-
if (this.routeMatchCache.size > 100) {
|
|
315
|
-
const firstKey = this.routeMatchCache.keys().next().value;
|
|
316
|
-
if (firstKey !== undefined) {
|
|
317
|
-
this.routeMatchCache.delete(firstKey);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
this.routeMatchCache.set(path, match);
|
|
321
|
-
return match;
|
|
322
|
-
}
|
|
323
|
-
computeRouteMatch(path) {
|
|
324
|
-
const segments = path.split("/").filter(Boolean);
|
|
325
|
-
for (const [routePath, routeConfig] of Object.entries(this.routes)) {
|
|
326
|
-
const routeSegments = routePath.split("/").filter(Boolean);
|
|
327
|
-
if (segments.length !== routeSegments.length)
|
|
328
|
-
continue;
|
|
329
|
-
const params = {};
|
|
330
|
-
let isMatch = true;
|
|
331
|
-
for (let i = 0; i < segments.length; i++) {
|
|
332
|
-
const segment = segments[i];
|
|
333
|
-
const routeSegment = routeSegments[i];
|
|
334
|
-
if (routeSegment && segment) {
|
|
335
|
-
if (routeSegment.startsWith(":")) {
|
|
336
|
-
params[routeSegment.slice(1)] = segment;
|
|
337
|
-
}
|
|
338
|
-
else if (segment !== routeSegment) {
|
|
339
|
-
isMatch = false;
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
isMatch = false;
|
|
345
|
-
break;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
if (isMatch) {
|
|
349
|
-
return {
|
|
350
|
-
component: routeConfig.component,
|
|
351
|
-
params,
|
|
352
|
-
meta: typeof routeConfig.meta === "function"
|
|
353
|
-
? routeConfig.meta(params)
|
|
354
|
-
: routeConfig.meta,
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
return null;
|
|
359
|
-
}
|
|
360
|
-
async checkRouteGuard(route, path, params) {
|
|
361
|
-
if (!route.guard)
|
|
362
|
-
return true;
|
|
363
|
-
if (route.guard.canActivate) {
|
|
364
|
-
const canActivate = await route.guard.canActivate(path, params);
|
|
365
|
-
return canActivate;
|
|
366
|
-
}
|
|
367
|
-
return true;
|
|
368
|
-
}
|
|
369
|
-
getPreloadedComponent(path) {
|
|
370
|
-
return this.routeCache.get(path);
|
|
371
|
-
}
|
|
372
|
-
clearCache() {
|
|
373
|
-
this.routeCache.clear();
|
|
374
|
-
this.routeMatchCache.clear();
|
|
375
|
-
this.preloadQueue.clear();
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
class LayoutRouter {
|
|
379
|
-
constructor() {
|
|
380
|
-
this.layoutCache = new Map();
|
|
381
|
-
this.keepAliveComponents = new Map();
|
|
382
|
-
}
|
|
383
|
-
renderNestedRoutes(routes, segments) {
|
|
384
|
-
if (segments.length === 0)
|
|
385
|
-
return null;
|
|
386
|
-
const [currentSegment, ...remainingSegments] = segments;
|
|
387
|
-
const currentRoute = routes.find((r) => r.path === currentSegment);
|
|
388
|
-
if (!currentRoute)
|
|
389
|
-
return null;
|
|
390
|
-
let content;
|
|
391
|
-
if (remainingSegments.length > 0 && currentRoute.children) {
|
|
392
|
-
content = this.renderNestedRoutes(currentRoute.children, remainingSegments);
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
if (currentRoute.keepAlive && currentSegment) {
|
|
396
|
-
content = this.renderKeepAlive(currentRoute.component, currentSegment);
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
content = this.renderComponent(currentRoute.component);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
if (currentRoute.layout) {
|
|
403
|
-
const layoutKey = `${currentSegment}_layout`;
|
|
404
|
-
let layoutComponent = this.layoutCache.get(layoutKey);
|
|
405
|
-
if (!layoutComponent) {
|
|
406
|
-
layoutComponent = this.renderComponent(currentRoute.layout);
|
|
407
|
-
this.layoutCache.set(layoutKey, layoutComponent);
|
|
408
|
-
}
|
|
409
|
-
return this.renderComponent(currentRoute.layout, { children: content });
|
|
410
|
-
}
|
|
411
|
-
return content;
|
|
412
|
-
}
|
|
413
|
-
renderKeepAlive(component, key) {
|
|
414
|
-
if (this.keepAliveComponents.has(key)) {
|
|
415
|
-
return this.keepAliveComponents.get(key);
|
|
416
|
-
}
|
|
417
|
-
const rendered = this.renderComponent(component);
|
|
418
|
-
this.keepAliveComponents.set(key, rendered);
|
|
419
|
-
return rendered;
|
|
420
|
-
}
|
|
421
|
-
renderComponent(component, props = {}) {
|
|
422
|
-
try {
|
|
423
|
-
return component(props);
|
|
424
|
-
}
|
|
425
|
-
catch (error) {
|
|
426
|
-
console.error("[LayoutRouter] Component render error:", error);
|
|
427
|
-
return null;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
cleanup() {
|
|
431
|
-
this.layoutCache.clear();
|
|
432
|
-
this.keepAliveComponents.clear();
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const enterpriseRouter = new EnterpriseRouter();
|
|
436
|
-
const layoutRouter = new LayoutRouter();
|
|
437
|
-
function createFynix() {
|
|
343
|
+
function createFynix(options = {}) {
|
|
438
344
|
const isDevMode = import.meta.hot !== undefined;
|
|
439
345
|
if (routerInstance && isRouterInitialized && !isDevMode) {
|
|
440
346
|
console.warn("[Router] Router already initialized, returning existing instance");
|
|
@@ -462,13 +368,17 @@ function createFynix() {
|
|
|
462
368
|
}
|
|
463
369
|
const propsCache = window.__fynixPropsCache || new Map();
|
|
464
370
|
window.__fynixPropsCache = propsCache;
|
|
465
|
-
const
|
|
371
|
+
const isLazy = !!options.lazy;
|
|
372
|
+
const modules = tryGlobPaths(isLazy);
|
|
466
373
|
const routes = {};
|
|
467
374
|
const dynamicRoutes = [];
|
|
468
375
|
for (const [filePath, mod] of Object.entries(modules)) {
|
|
469
376
|
const routePath = filePathToRoute(filePath);
|
|
470
377
|
let component = undefined;
|
|
471
|
-
if (
|
|
378
|
+
if (isLazy && typeof mod === "function") {
|
|
379
|
+
component = nixLazy(mod);
|
|
380
|
+
}
|
|
381
|
+
else if (mod && typeof mod === "object") {
|
|
472
382
|
if ("default" in mod && mod.default) {
|
|
473
383
|
component = mod.default;
|
|
474
384
|
}
|
|
@@ -512,17 +422,6 @@ function createFynix() {
|
|
|
512
422
|
let Page = routes[path];
|
|
513
423
|
let params = {};
|
|
514
424
|
let routeProps = {};
|
|
515
|
-
const enterpriseMatch = enterpriseRouter.matchRoute(path);
|
|
516
|
-
if (enterpriseMatch) {
|
|
517
|
-
const preloadedComponent = enterpriseRouter.getPreloadedComponent(path);
|
|
518
|
-
if (preloadedComponent) {
|
|
519
|
-
Page = preloadedComponent;
|
|
520
|
-
}
|
|
521
|
-
else {
|
|
522
|
-
Page = enterpriseMatch.component;
|
|
523
|
-
}
|
|
524
|
-
params = enterpriseMatch.params;
|
|
525
|
-
}
|
|
526
425
|
if (!Page) {
|
|
527
426
|
const match = matchDynamicRoute(path, dynamicRoutes);
|
|
528
427
|
if (match) {
|
|
@@ -557,9 +456,6 @@ function createFynix() {
|
|
|
557
456
|
container.appendChild(backButton);
|
|
558
457
|
root.appendChild(container);
|
|
559
458
|
updateMetaTags({ title: "404 - Page Not Found" });
|
|
560
|
-
["/", "/home", "/about"].forEach((commonPath) => {
|
|
561
|
-
enterpriseRouter.preloadRoute(commonPath).catch(console.warn);
|
|
562
|
-
});
|
|
563
459
|
return;
|
|
564
460
|
}
|
|
565
461
|
const state = (window.history.state || {});
|
|
@@ -577,13 +473,16 @@ function createFynix() {
|
|
|
577
473
|
const meta = typeof Page.meta === "function" ? Page.meta(params) : Page.meta;
|
|
578
474
|
updateMetaTags(meta);
|
|
579
475
|
}
|
|
580
|
-
const
|
|
581
|
-
...
|
|
582
|
-
...
|
|
583
|
-
params,
|
|
476
|
+
const safeProps = {
|
|
477
|
+
...sanitizeExternalProps(passedProps),
|
|
478
|
+
...sanitizeProps({ ...routeProps, params }),
|
|
584
479
|
};
|
|
585
|
-
const safeProps = sanitizeProps(unsafeProps);
|
|
586
480
|
window.__lastRouteProps = safeProps;
|
|
481
|
+
location.value = {
|
|
482
|
+
path,
|
|
483
|
+
params,
|
|
484
|
+
search: window.location.search,
|
|
485
|
+
};
|
|
587
486
|
try {
|
|
588
487
|
mount(Page, rootSelector, safeProps);
|
|
589
488
|
}
|
|
@@ -624,7 +523,6 @@ function createFynix() {
|
|
|
624
523
|
}
|
|
625
524
|
if (normalizedPath === currentPath)
|
|
626
525
|
return;
|
|
627
|
-
enterpriseRouter.preloadRoute(normalizedPath).catch(console.warn);
|
|
628
526
|
const sanitizedProps = sanitizeProps(props);
|
|
629
527
|
const cacheKey = generateCacheKey();
|
|
630
528
|
addToCache(propsCache, cacheKey, sanitizedProps);
|
|
@@ -729,11 +627,15 @@ function createFynix() {
|
|
|
729
627
|
handler: clickHandler,
|
|
730
628
|
});
|
|
731
629
|
listenerCount++;
|
|
732
|
-
|
|
630
|
+
const popstateHandler = (_e) => {
|
|
631
|
+
if (!isDestroyed)
|
|
632
|
+
renderRoute();
|
|
633
|
+
};
|
|
634
|
+
window.addEventListener("popstate", popstateHandler);
|
|
733
635
|
listeners.push({
|
|
734
636
|
element: window,
|
|
735
637
|
event: "popstate",
|
|
736
|
-
handler:
|
|
638
|
+
handler: popstateHandler,
|
|
737
639
|
});
|
|
738
640
|
listenerCount++;
|
|
739
641
|
}
|
|
@@ -756,8 +658,6 @@ function createFynix() {
|
|
|
756
658
|
renderTimeout = null;
|
|
757
659
|
}
|
|
758
660
|
isDestroyed = true;
|
|
759
|
-
enterpriseRouter.clearCache();
|
|
760
|
-
layoutRouter.cleanup();
|
|
761
661
|
listeners.forEach(({ element, event, handler }) => {
|
|
762
662
|
try {
|
|
763
663
|
element.removeEventListener(event, handler);
|
|
@@ -818,15 +718,6 @@ function createFynix() {
|
|
|
818
718
|
cleanup,
|
|
819
719
|
routes,
|
|
820
720
|
dynamicRoutes,
|
|
821
|
-
preloadRoute: enterpriseRouter.preloadRoute.bind(enterpriseRouter),
|
|
822
|
-
clearCache: () => {
|
|
823
|
-
enterpriseRouter.clearCache();
|
|
824
|
-
layoutRouter.cleanup();
|
|
825
|
-
},
|
|
826
|
-
enableNestedRouting: (nestedRoutes) => {
|
|
827
|
-
router.nestedRoutes = nestedRoutes;
|
|
828
|
-
console.log("[Router] Nested routing enabled with", nestedRoutes.length, "routes");
|
|
829
|
-
},
|
|
830
721
|
};
|
|
831
722
|
routerInstance = router;
|
|
832
723
|
return router;
|