@fynixorg/ui 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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/dist/README.md +36 -0
  3. package/dist/context/context.d.ts +19 -0
  4. package/dist/context/context.d.ts.map +1 -0
  5. package/dist/context/context.js +3 -11
  6. package/dist/context/context.js.map +3 -3
  7. package/dist/custom/button.d.ts +2 -0
  8. package/dist/custom/button.d.ts.map +1 -0
  9. package/dist/custom/button.js +2 -9
  10. package/dist/custom/button.js.map +3 -3
  11. package/dist/custom/index.d.ts +3 -0
  12. package/dist/custom/index.d.ts.map +1 -0
  13. package/dist/custom/index.js +2 -7
  14. package/dist/custom/index.js.map +3 -3
  15. package/dist/custom/path.d.ts +14 -0
  16. package/dist/custom/path.d.ts.map +1 -0
  17. package/dist/custom/path.js +17 -34
  18. package/dist/custom/path.js.map +3 -3
  19. package/dist/error/errorOverlay.d.ts +3 -0
  20. package/dist/error/errorOverlay.d.ts.map +1 -0
  21. package/dist/error/errorOverlay.js +82 -91
  22. package/dist/error/errorOverlay.js.map +3 -3
  23. package/dist/fynix/index.d.ts +5 -0
  24. package/dist/fynix/index.d.ts.map +1 -0
  25. package/dist/fynix/index.js +2 -7
  26. package/dist/fynix/index.js.map +3 -3
  27. package/dist/hooks/nixAsync.d.ts +14 -0
  28. package/dist/hooks/nixAsync.d.ts.map +1 -0
  29. package/dist/hooks/nixAsync.js +38 -43
  30. package/dist/hooks/nixAsync.js.map +3 -3
  31. package/dist/hooks/nixAsyncCache.d.ts +14 -0
  32. package/dist/hooks/nixAsyncCache.d.ts.map +1 -0
  33. package/dist/hooks/nixAsyncCache.js +57 -59
  34. package/dist/hooks/nixAsyncCache.js.map +3 -3
  35. package/dist/hooks/nixAsyncDebounce.d.ts +22 -0
  36. package/dist/hooks/nixAsyncDebounce.d.ts.map +1 -0
  37. package/dist/hooks/nixAsyncDebounce.js +74 -85
  38. package/dist/hooks/nixAsyncDebounce.js.map +3 -3
  39. package/dist/hooks/nixAsyncQuery.d.ts +16 -0
  40. package/dist/hooks/nixAsyncQuery.d.ts.map +1 -0
  41. package/dist/hooks/nixAsyncQuery.js +85 -79
  42. package/dist/hooks/nixAsyncQuery.js.map +3 -3
  43. package/dist/hooks/nixCallback.d.ts +2 -0
  44. package/dist/hooks/nixCallback.d.ts.map +1 -0
  45. package/dist/hooks/nixCallback.js +30 -40
  46. package/dist/hooks/nixCallback.js.map +3 -3
  47. package/dist/hooks/nixComputed.d.ts +16 -0
  48. package/dist/hooks/nixComputed.d.ts.map +1 -0
  49. package/dist/hooks/nixComputed.js +166 -198
  50. package/dist/hooks/nixComputed.js.map +4 -4
  51. package/dist/hooks/nixDebounce.d.ts +11 -0
  52. package/dist/hooks/nixDebounce.d.ts.map +1 -0
  53. package/dist/hooks/nixDebounce.js +53 -58
  54. package/dist/hooks/nixDebounce.js.map +3 -3
  55. package/dist/hooks/nixEffect.d.ts +4 -0
  56. package/dist/hooks/nixEffect.d.ts.map +1 -0
  57. package/dist/hooks/nixEffect.js +65 -75
  58. package/dist/hooks/nixEffect.js.map +3 -3
  59. package/dist/hooks/nixForm.d.ts +33 -0
  60. package/dist/hooks/nixForm.d.ts.map +1 -0
  61. package/dist/hooks/nixForm.js +110 -120
  62. package/dist/hooks/nixForm.js.map +3 -3
  63. package/dist/hooks/nixFormAsync.d.ts +42 -0
  64. package/dist/hooks/nixFormAsync.d.ts.map +1 -0
  65. package/dist/hooks/nixFormAsync.js +158 -167
  66. package/dist/hooks/nixFormAsync.js.map +3 -3
  67. package/dist/hooks/nixInterval.d.ts +2 -0
  68. package/dist/hooks/nixInterval.d.ts.map +1 -0
  69. package/dist/hooks/nixInterval.js +21 -27
  70. package/dist/hooks/nixInterval.js.map +3 -3
  71. package/dist/hooks/nixLazy.d.ts +8 -0
  72. package/dist/hooks/nixLazy.d.ts.map +1 -0
  73. package/dist/hooks/nixLazy.js +53 -58
  74. package/dist/hooks/nixLazy.js.map +3 -3
  75. package/dist/hooks/nixLazyAsync.d.ts +10 -0
  76. package/dist/hooks/nixLazyAsync.d.ts.map +1 -0
  77. package/dist/hooks/nixLazyAsync.js +65 -71
  78. package/dist/hooks/nixLazyAsync.js.map +3 -3
  79. package/dist/hooks/nixLazyFormAsync.d.ts +50 -0
  80. package/dist/hooks/nixLazyFormAsync.d.ts.map +1 -0
  81. package/dist/hooks/nixLazyFormAsync.js +209 -213
  82. package/dist/hooks/nixLazyFormAsync.js.map +3 -3
  83. package/dist/hooks/nixLocalStorage.d.ts +5 -0
  84. package/dist/hooks/nixLocalStorage.d.ts.map +1 -0
  85. package/dist/hooks/nixLocalStorage.js +21 -25
  86. package/dist/hooks/nixLocalStorage.js.map +3 -3
  87. package/dist/hooks/nixMemo.d.ts +2 -0
  88. package/dist/hooks/nixMemo.d.ts.map +1 -0
  89. package/dist/hooks/nixMemo.js +27 -31
  90. package/dist/hooks/nixMemo.js.map +3 -3
  91. package/dist/hooks/nixPrevious.d.ts +2 -0
  92. package/dist/hooks/nixPrevious.d.ts.map +1 -0
  93. package/dist/hooks/nixPrevious.js +13 -19
  94. package/dist/hooks/nixPrevious.js.map +3 -3
  95. package/dist/hooks/nixRef.d.ts +4 -0
  96. package/dist/hooks/nixRef.d.ts.map +1 -0
  97. package/dist/hooks/nixRef.js +14 -20
  98. package/dist/hooks/nixRef.js.map +3 -3
  99. package/dist/hooks/nixState.d.ts +15 -0
  100. package/dist/hooks/nixState.d.ts.map +1 -0
  101. package/dist/hooks/nixState.js +120 -173
  102. package/dist/hooks/nixState.js.map +3 -3
  103. package/dist/hooks/nixStore.d.ts +7 -0
  104. package/dist/hooks/nixStore.d.ts.map +1 -0
  105. package/dist/hooks/nixStore.js +48 -54
  106. package/dist/hooks/nixStore.js.map +3 -3
  107. package/dist/package.json +213 -0
  108. package/dist/plugins/vite-plugin-res.d.ts +41 -0
  109. package/dist/plugins/vite-plugin-res.d.ts.map +1 -0
  110. package/dist/plugins/vite-plugin-res.js +620 -36
  111. package/dist/plugins/vite-plugin-res.js.map +4 -4
  112. package/dist/router/router.d.ts +35 -0
  113. package/dist/router/router.d.ts.map +1 -0
  114. package/dist/router/router.js +520 -486
  115. package/dist/router/router.js.map +3 -3
  116. package/dist/runtime.d.ts +62 -0
  117. package/dist/runtime.d.ts.map +1 -0
  118. package/dist/runtime.js +833 -820
  119. package/dist/runtime.js.map +4 -4
  120. package/package.json +227 -44
  121. package/types/fnx.d.ts +72 -0
  122. package/types/fynix-ui.d.ts +323 -0
  123. package/types/global.d.ts +46 -6
  124. package/types/index.d.ts +37 -0
  125. package/types/vite-env.d.ts +553 -0
  126. package/runtime.d.ts +0 -83
  127. package/types/jsx.d.ts +0 -692
@@ -1,530 +1,564 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
- function isExternal(url) {
4
- return /^https?:\/\//.test(url);
5
- }
6
- __name(isExternal, "isExternal");
7
- import { mount } from "../runtime.js";
1
+ import { mount } from "../runtime";
8
2
  const MAX_CACHE_SIZE = 50;
9
3
  const PROPS_NAMESPACE = "__fynixLinkProps__";
10
4
  const MAX_LISTENERS = 100;
11
5
  const ALLOWED_PROTOCOLS = ["http:", "https:", ""];
6
+ const RENDER_DEBOUNCE = 10;
12
7
  let routerInstance = null;
13
8
  let isRouterInitialized = false;
9
+ function isExternal(url) {
10
+ return /^https?:\/\//.test(url);
11
+ }
14
12
  function escapeHTML(str) {
15
- if (typeof str !== "string")
16
- return "";
17
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;").replace(/`/g, "&#96;").replace(/\//g, "&#x2F;");
13
+ if (typeof str !== "string")
14
+ return "";
15
+ return str
16
+ .replace(/&/g, "&amp;")
17
+ .replace(/</g, "&lt;")
18
+ .replace(/>/g, "&gt;")
19
+ .replace(/"/g, "&quot;")
20
+ .replace(/'/g, "&#039;")
21
+ .replace(/`/g, "&#96;")
22
+ .replace(/\//g, "&#x2F;");
18
23
  }
19
- __name(escapeHTML, "escapeHTML");
20
24
  function isValidURL(url) {
21
- try {
22
- const parsed = new URL(url, window.location.origin);
23
- if (parsed.origin !== window.location.origin) {
24
- console.warn("[Router] Security: Cross-origin navigation blocked");
25
- return false;
26
- }
27
- if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {
28
- console.warn(
29
- "[Router] Security: Dangerous protocol blocked:",
30
- parsed.protocol
31
- );
32
- return false;
33
- }
34
- return true;
35
- } catch (e) {
36
- console.warn("[Router] Security: Invalid URL blocked");
37
- return false;
38
- }
25
+ try {
26
+ const parsed = new URL(url, window.location.origin);
27
+ if (parsed.origin !== window.location.origin) {
28
+ console.warn("[Router] Security: Cross-origin navigation blocked");
29
+ return false;
30
+ }
31
+ if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {
32
+ console.warn("[Router] Security: Dangerous protocol blocked:", parsed.protocol);
33
+ return false;
34
+ }
35
+ return true;
36
+ }
37
+ catch (e) {
38
+ console.warn("[Router] Security: Invalid URL blocked");
39
+ return false;
40
+ }
39
41
  }
40
- __name(isValidURL, "isValidURL");
41
42
  function sanitizePath(path) {
42
- if (typeof path !== "string")
43
- return "/";
44
- try {
45
- path = decodeURIComponent(path);
46
- } catch (e) {
47
- console.warn("[Router] Invalid URL encoding in path");
48
- return "/";
49
- }
50
- path = path.replace(/\0/g, "");
51
- path = path.replace(/\\/g, "/");
52
- path = path.replace(/\/+/g, "/");
53
- path = path.split("/").filter((part) => part !== ".." && part !== ".").join("/");
54
- if (!path.startsWith("/")) {
55
- path = "/" + path;
56
- }
57
- if (path.length > 1 && path.endsWith("/")) {
58
- path = path.slice(0, -1);
59
- }
60
- return path || "/";
43
+ if (typeof path !== "string")
44
+ return "/";
45
+ try {
46
+ path = decodeURIComponent(path);
47
+ }
48
+ catch (e) {
49
+ console.warn("[Router] Invalid URL encoding in path");
50
+ return "/";
51
+ }
52
+ path = path.replace(/\0/g, "");
53
+ path = path.replace(/\\/g, "/");
54
+ path = path.replace(/\/+/g, "/");
55
+ path = path
56
+ .split("/")
57
+ .filter((part) => part !== ".." && part !== ".")
58
+ .join("/");
59
+ if (!path.startsWith("/")) {
60
+ path = "/" + path;
61
+ }
62
+ if (path.length > 1 && path.endsWith("/")) {
63
+ path = path.slice(0, -1);
64
+ }
65
+ return path || "/";
61
66
  }
62
- __name(sanitizePath, "sanitizePath");
63
67
  function tryGlobPaths() {
64
- try {
65
- const modules = import.meta.glob("/src/**/*.{ts,js,jsx,fnx}", {
66
- eager: true
67
- });
68
- return modules || {};
69
- } catch (error) {
70
- console.error("[Router] Failed to load modules:", error);
71
- return {};
72
- }
68
+ try {
69
+ let modules = import.meta.glob("/src/**/*.{fnx,tsx,jsx,ts,js}", {
70
+ eager: true,
71
+ });
72
+ console.log("[Router] Glob attempt 1 (/src/**):", Object.keys(modules));
73
+ if (Object.keys(modules).length === 0) {
74
+ modules = import.meta.glob(["./**/*.fnx", "./**/*.tsx", "./**/*.jsx", "./**/*.ts", "./**/*.js"], { eager: true });
75
+ console.log("[Router] Glob attempt 2 (./**):", Object.keys(modules));
76
+ }
77
+ if (Object.keys(modules).length === 0) {
78
+ modules = import.meta.glob(["../**/*.fnx", "../**/*.tsx", "../**/*.jsx"], { eager: true });
79
+ console.log("[Router] Glob attempt 3 (../**):", Object.keys(modules));
80
+ }
81
+ console.log("[Router] Final modules loaded:", Object.keys(modules).length);
82
+ return modules || {};
83
+ }
84
+ catch (error) {
85
+ console.error("[Router] Failed to load modules:", error);
86
+ return {};
87
+ }
73
88
  }
74
- __name(tryGlobPaths, "tryGlobPaths");
75
89
  function filePathToRoute(filePath) {
76
- let route = filePath.replace(/^.*\/src/, "").replace(/\.(js|jsx|fnx)$/, "").replace(/\/view$/, "").replace(/\/$/, "");
77
- if (!route)
78
- route = "/";
79
- route = route.replace(/\[([^\]]+)\]/g, ":$1");
80
- return route;
90
+ let route = filePath
91
+ .replace(/^.*\/src/, "")
92
+ .replace(/\.(ts|tsx|js|jsx|fnx)$/, "")
93
+ .replace(/\/view$/, "")
94
+ .replace(/\/$/, "");
95
+ if (!route)
96
+ route = "/";
97
+ route = route.replace(/\[([^\]]+)\]/g, ":$1");
98
+ return route;
81
99
  }
82
- __name(filePathToRoute, "filePathToRoute");
83
100
  function matchDynamicRoute(path, dynamicRoutes) {
84
- for (const route of dynamicRoutes) {
85
- const match = path.match(route.regex);
86
- if (match) {
87
- const params = {};
88
- route.params.forEach((param, i) => {
89
- params[param] = escapeHTML(match[i + 1]);
90
- });
91
- return { component: route.component, params };
92
- }
93
- }
94
- return null;
101
+ for (const route of dynamicRoutes) {
102
+ const match = path.match(route.regex);
103
+ if (match) {
104
+ const params = {};
105
+ route.params.forEach((param, i) => {
106
+ const matchValue = match[i + 1];
107
+ params[param] = escapeHTML(matchValue || "");
108
+ });
109
+ return { component: route.component, params };
110
+ }
111
+ }
112
+ return null;
95
113
  }
96
- __name(matchDynamicRoute, "matchDynamicRoute");
97
114
  function deserializeProps(props) {
98
- if (!props || typeof props !== "object")
99
- return {};
100
- const deserialized = {};
101
- for (const [key, value] of Object.entries(props)) {
102
- if (typeof key !== "string" || key.startsWith("__")) {
103
- continue;
115
+ if (!props || typeof props !== "object")
116
+ return {};
117
+ const deserialized = {};
118
+ for (const [key, value] of Object.entries(props)) {
119
+ if (typeof key !== "string" || key.startsWith("__")) {
120
+ continue;
121
+ }
122
+ deserialized[key] = value;
104
123
  }
105
- deserialized[key] = value;
106
- }
107
- return deserialized;
124
+ return deserialized;
108
125
  }
109
- __name(deserializeProps, "deserializeProps");
110
126
  function normalizePath(path) {
111
- return sanitizePath(path);
127
+ return sanitizePath(path);
112
128
  }
113
- __name(normalizePath, "normalizePath");
114
129
  function generateCacheKey() {
115
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
116
- return crypto.randomUUID();
117
- }
118
- return `${Date.now()}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`;
130
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
131
+ return crypto.randomUUID();
132
+ }
133
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}-${Math.random()
134
+ .toString(36)
135
+ .slice(2)}`;
119
136
  }
120
- __name(generateCacheKey, "generateCacheKey");
121
- function createFynix() {
122
- const isDevMode = import.meta.hot !== void 0;
123
- if (routerInstance && isRouterInitialized && !isDevMode) {
124
- console.warn(
125
- "[Router] Router already initialized, returning existing instance"
126
- );
127
- return routerInstance;
128
- }
129
- if (isDevMode && routerInstance) {
130
- console.log("[Router] HMR: Cleaning up old router instance");
131
- routerInstance.cleanup();
132
- routerInstance = null;
133
- isRouterInitialized = false;
134
- }
135
- let rootSelector = "#app-root";
136
- let currentPath = null;
137
- let isDestroyed = false;
138
- let listenerCount = 0;
139
- const listeners = [];
140
- if (!window[PROPS_NAMESPACE]) {
141
- window[PROPS_NAMESPACE] = {};
142
- }
143
- if (isDevMode && window.__fynixPropsCache) {
144
- window.__fynixPropsCache.clear();
145
- }
146
- const __fynixPropsCache = window.__fynixPropsCache || /* @__PURE__ */ new Map();
147
- window.__fynixPropsCache = __fynixPropsCache;
148
- const modules = tryGlobPaths();
149
- const routes = {};
150
- const dynamicRoutes = [];
151
- for (const [filePath, mod] of Object.entries(modules)) {
152
- const routePath = filePathToRoute(filePath);
153
- const component = mod.default || mod[Object.keys(mod)[0]] || Object.values(mod)[0];
154
- if (!component)
155
- continue;
156
- const hasDynamic = /:[^/]+/.test(routePath);
157
- if (hasDynamic) {
158
- dynamicRoutes.push({
159
- pattern: routePath,
160
- regex: new RegExp("^" + routePath.replace(/:[^/]+/g, "([^/]+)") + "$"),
161
- component,
162
- params: [...routePath.matchAll(/:([^/]+)/g)].map((m) => m[1])
163
- });
164
- } else {
165
- routes[routePath] = component;
166
- }
167
- }
168
- function addToCache(key, value) {
169
- if (__fynixPropsCache.size >= MAX_CACHE_SIZE) {
170
- const firstKey = __fynixPropsCache.keys().next().value;
171
- const evicted = __fynixPropsCache.get(firstKey);
172
- if (evicted && typeof evicted === "object") {
173
- Object.values(evicted).forEach((val) => {
174
- if (val && typeof val === "object" && val.cleanup) {
175
- try {
176
- val.cleanup();
177
- } catch (e) {
137
+ function addToCache(cache, key, value) {
138
+ if (cache.size >= MAX_CACHE_SIZE) {
139
+ const firstKey = cache.keys().next().value;
140
+ if (typeof firstKey === "string") {
141
+ const evicted = cache.get(firstKey);
142
+ if (evicted && typeof evicted === "object") {
143
+ Object.values(evicted).forEach((val) => {
144
+ if (val && typeof val === "object" && "cleanup" in val) {
145
+ try {
146
+ val.cleanup();
147
+ }
148
+ catch (e) {
149
+ }
150
+ }
151
+ });
178
152
  }
179
- }
180
- });
181
- }
182
- __fynixPropsCache.delete(firstKey);
153
+ cache.delete(firstKey);
154
+ }
183
155
  }
184
- __fynixPropsCache.set(key, value);
185
- }
186
- __name(addToCache, "addToCache");
187
- const MANAGED_META = [
156
+ cache.set(key, value);
157
+ }
158
+ const MANAGED_META = [
188
159
  { key: "description", name: "description" },
189
160
  { key: "keywords", name: "keywords" },
190
161
  { key: "twitterCard", name: "twitter:card" },
191
162
  { key: "ogTitle", property: "og:title" },
192
163
  { key: "ogDescription", property: "og:description" },
193
- { key: "ogImage", property: "og:image" }
194
- ];
195
- function updateMetaTags(meta = {}) {
164
+ { key: "ogImage", property: "og:image" },
165
+ ];
166
+ function updateMetaTags(meta = {}) {
196
167
  if (!meta || typeof meta !== "object")
197
- return;
168
+ return;
198
169
  if (meta.title && typeof meta.title === "string") {
199
- document.title = escapeHTML(meta.title);
170
+ document.title = escapeHTML(meta.title);
200
171
  }
201
172
  MANAGED_META.forEach((def) => {
202
- const value = meta[def.key];
203
- const selector = def.name ? `meta[name="${def.name}"]` : `meta[property="${def.property}"]`;
204
- let el = document.querySelector(selector);
205
- if (value == null) {
206
- if (el)
207
- el.remove();
208
- return;
209
- }
210
- if (typeof value !== "string")
211
- return;
212
- if (!el) {
213
- el = document.createElement("meta");
214
- if (def.name)
215
- el.setAttribute("name", def.name);
216
- if (def.property)
217
- el.setAttribute("property", def.property);
218
- document.head.appendChild(el);
219
- }
220
- el.setAttribute("content", escapeHTML(value));
173
+ const value = meta[def.key];
174
+ const selector = def.name
175
+ ? `meta[name="${def.name}"]`
176
+ : `meta[property="${def.property}"]`;
177
+ let el = document.querySelector(selector);
178
+ if (value == null) {
179
+ if (el)
180
+ el.remove();
181
+ return;
182
+ }
183
+ if (typeof value !== "string")
184
+ return;
185
+ if (!el) {
186
+ el = document.createElement("meta");
187
+ if (def.name)
188
+ el.setAttribute("name", def.name);
189
+ if (def.property)
190
+ el.setAttribute("property", def.property);
191
+ document.head.appendChild(el);
192
+ }
193
+ el.setAttribute("content", escapeHTML(value));
221
194
  });
222
- }
223
- __name(updateMetaTags, "updateMetaTags");
224
- let renderTimeout = null;
225
- const RENDER_DEBOUNCE = 10;
226
- function renderRoute() {
227
- if (isDestroyed)
228
- return;
229
- if (renderTimeout) {
230
- clearTimeout(renderTimeout);
231
- }
232
- renderTimeout = setTimeout(() => {
233
- _renderRouteImmediate();
234
- renderTimeout = null;
235
- }, RENDER_DEBOUNCE);
236
- }
237
- __name(renderRoute, "renderRoute");
238
- function _renderRouteImmediate() {
239
- if (isDestroyed)
240
- return;
241
- const path = normalizePath(window.location.pathname);
242
- let Page = routes[path];
243
- let params = {};
244
- let routeProps = {};
245
- if (!Page) {
246
- const match = matchDynamicRoute(path, dynamicRoutes);
247
- if (match) {
248
- Page = match.component;
249
- params = match.params;
250
- }
251
- }
252
- const root = document.querySelector(rootSelector);
253
- if (!root) {
254
- console.error("[Router] Root element not found:", rootSelector);
255
- return;
256
- }
257
- if (!Page) {
258
- root.innerHTML = `<h2>404 Not Found</h2><p>Path: ${escapeHTML(path)}</p>`;
259
- updateMetaTags({ title: "404 - Page Not Found" });
260
- return;
261
- }
262
- const state = window.history.state || {};
263
- let passedProps = {};
264
- if (state.__fynixCacheKey && __fynixPropsCache.has(state.__fynixCacheKey)) {
265
- passedProps = __fynixPropsCache.get(state.__fynixCacheKey);
266
- } else if (state.serializedProps) {
267
- passedProps = deserializeProps(state.serializedProps);
268
- }
269
- if (Page.props) {
270
- routeProps = typeof Page.props === "function" ? Page.props() : Page.props;
271
- }
272
- if (Page.meta) {
273
- const meta = typeof Page.meta === "function" ? Page.meta(params) : Page.meta;
274
- updateMetaTags(meta);
275
- }
276
- window.__lastRouteProps = {
277
- ...routeProps,
278
- ...passedProps,
279
- params
195
+ }
196
+ function createFynix() {
197
+ const isDevMode = import.meta.hot !== undefined;
198
+ if (routerInstance && isRouterInitialized && !isDevMode) {
199
+ console.warn("[Router] Router already initialized, returning existing instance");
200
+ return routerInstance;
201
+ }
202
+ if (isDevMode && routerInstance) {
203
+ console.log("[Router] HMR: Cleaning up old router instance");
204
+ routerInstance.cleanup();
205
+ routerInstance = null;
206
+ isRouterInitialized = false;
207
+ }
208
+ let rootSelector = "#app-root";
209
+ let currentPath = null;
210
+ let isDestroyed = false;
211
+ let listenerCount = 0;
212
+ let renderTimeout = null;
213
+ const listeners = [];
214
+ if (!window[PROPS_NAMESPACE]) {
215
+ window[PROPS_NAMESPACE] = {};
216
+ }
217
+ if (isDevMode && window.__fynixPropsCache) {
218
+ window.__fynixPropsCache.clear();
219
+ }
220
+ const propsCache = window.__fynixPropsCache || new Map();
221
+ window.__fynixPropsCache = propsCache;
222
+ const modules = tryGlobPaths();
223
+ const routes = {};
224
+ const dynamicRoutes = [];
225
+ for (const [filePath, mod] of Object.entries(modules)) {
226
+ const routePath = filePathToRoute(filePath);
227
+ let component = undefined;
228
+ if (mod && typeof mod === "object") {
229
+ if ("default" in mod && mod.default) {
230
+ component = mod.default;
231
+ }
232
+ else {
233
+ const keys = Object.keys(mod);
234
+ const firstKey = keys.length > 0 ? keys[0] : undefined;
235
+ if (firstKey !== undefined &&
236
+ typeof firstKey === "string" &&
237
+ typeof mod[firstKey] !== "undefined") {
238
+ component = mod[firstKey];
239
+ }
240
+ else {
241
+ const values = Object.values(mod).filter(Boolean);
242
+ if (values.length > 0) {
243
+ component = values[0];
244
+ }
245
+ }
246
+ }
247
+ }
248
+ if (!component || typeof routePath !== "string")
249
+ continue;
250
+ const hasDynamic = /:[^/]+/.test(routePath);
251
+ if (hasDynamic) {
252
+ dynamicRoutes.push({
253
+ pattern: routePath,
254
+ regex: new RegExp("^" + routePath.replace(/:[^/]+/g, "([^/]+)") + "$"),
255
+ component,
256
+ params: [...routePath.matchAll(/:([^/]+)/g)]
257
+ .map((m) => m[1])
258
+ .filter((p) => typeof p === "string"),
259
+ });
260
+ }
261
+ else {
262
+ routes[routePath] = component;
263
+ }
264
+ }
265
+ function renderRouteImmediate() {
266
+ if (isDestroyed)
267
+ return;
268
+ const path = normalizePath(window.location.pathname);
269
+ let Page = routes[path];
270
+ let params = {};
271
+ let routeProps = {};
272
+ if (!Page) {
273
+ const match = matchDynamicRoute(path, dynamicRoutes);
274
+ if (match) {
275
+ Page = match.component;
276
+ params = match.params;
277
+ }
278
+ }
279
+ const root = document.querySelector(rootSelector);
280
+ if (!root) {
281
+ console.error("[Router] Root element not found:", rootSelector);
282
+ return;
283
+ }
284
+ if (!Page) {
285
+ root.innerHTML = `<h2>404 Not Found</h2><p>Path: ${escapeHTML(path)}</p>`;
286
+ updateMetaTags({ title: "404 - Page Not Found" });
287
+ return;
288
+ }
289
+ const state = (window.history.state || {});
290
+ let passedProps = {};
291
+ if (state.__fynixCacheKey && propsCache.has(state.__fynixCacheKey)) {
292
+ passedProps = propsCache.get(state.__fynixCacheKey);
293
+ }
294
+ else if (state.serializedProps) {
295
+ passedProps = deserializeProps(state.serializedProps);
296
+ }
297
+ if (Page.props) {
298
+ routeProps = typeof Page.props === "function" ? Page.props() : Page.props;
299
+ }
300
+ if (Page.meta) {
301
+ const meta = typeof Page.meta === "function" ? Page.meta(params) : Page.meta;
302
+ updateMetaTags(meta);
303
+ }
304
+ window.__lastRouteProps = {
305
+ ...routeProps,
306
+ ...passedProps,
307
+ params,
308
+ };
309
+ try {
310
+ mount(Page, rootSelector, window.__lastRouteProps);
311
+ }
312
+ catch (err) {
313
+ console.error("[Router] Mount failed:", err);
314
+ root.innerHTML = `<pre style="color:red;">Mount Error occurred</pre>`;
315
+ }
316
+ currentPath = path;
317
+ }
318
+ function renderRoute() {
319
+ if (isDestroyed)
320
+ return;
321
+ if (renderTimeout) {
322
+ clearTimeout(renderTimeout);
323
+ }
324
+ renderTimeout = setTimeout(async () => {
325
+ await renderRouteImmediate();
326
+ renderTimeout = null;
327
+ }, RENDER_DEBOUNCE);
328
+ }
329
+ function navigate(path, props = {}) {
330
+ if (isDestroyed)
331
+ return;
332
+ const normalizedPath = normalizePath(path);
333
+ if (!isValidURL(window.location.origin + normalizedPath)) {
334
+ console.error("[Router] Invalid navigation URL");
335
+ return;
336
+ }
337
+ if (normalizedPath === currentPath)
338
+ return;
339
+ const cacheKey = generateCacheKey();
340
+ addToCache(propsCache, cacheKey, props);
341
+ try {
342
+ window.history.pushState({ __fynixCacheKey: cacheKey }, "", normalizedPath);
343
+ renderRoute();
344
+ }
345
+ catch (err) {
346
+ console.error("[Router] Navigation failed:", err);
347
+ }
348
+ }
349
+ function replace(path, props = {}) {
350
+ if (isDestroyed)
351
+ return;
352
+ const normalizedPath = normalizePath(path);
353
+ if (!isValidURL(window.location.origin + normalizedPath)) {
354
+ console.error("[Router] Invalid replace URL");
355
+ return;
356
+ }
357
+ const cacheKey = generateCacheKey();
358
+ addToCache(propsCache, cacheKey, props);
359
+ try {
360
+ window.history.replaceState({ __fynixCacheKey: cacheKey }, "", normalizedPath);
361
+ renderRoute();
362
+ }
363
+ catch (err) {
364
+ console.error("[Router] Replace failed:", err);
365
+ }
366
+ }
367
+ function back() {
368
+ if (isDestroyed)
369
+ return;
370
+ try {
371
+ window.history.back();
372
+ }
373
+ catch (err) {
374
+ console.error("[Router] Back navigation failed:", err);
375
+ }
376
+ }
377
+ const clickHandler = (e) => {
378
+ if (isDestroyed)
379
+ return;
380
+ const target = e.target;
381
+ const link = target.closest("a[data-fynix-link]");
382
+ if (!link)
383
+ return;
384
+ const href = link.getAttribute("href");
385
+ if (!href) {
386
+ console.warn("[Router] Missing href attribute");
387
+ return;
388
+ }
389
+ if (isExternal(href)) {
390
+ return;
391
+ }
392
+ const fullUrl = new URL(link.href, window.location.origin).href;
393
+ if (!isValidURL(fullUrl)) {
394
+ console.warn("[Router] Invalid link href");
395
+ return;
396
+ }
397
+ e.preventDefault();
398
+ const path = normalizePath(new URL(link.href, window.location.origin).pathname);
399
+ if (path === currentPath)
400
+ return;
401
+ let props = {};
402
+ const propsKey = link.getAttribute("data-props-key");
403
+ if (propsKey &&
404
+ typeof propsKey === "string" &&
405
+ !propsKey.startsWith("__")) {
406
+ if (window[PROPS_NAMESPACE]?.[propsKey]) {
407
+ props = window[PROPS_NAMESPACE][propsKey];
408
+ }
409
+ }
410
+ const serializableProps = {};
411
+ for (const [k, v] of Object.entries(props)) {
412
+ if (typeof k !== "string" || k.startsWith("__"))
413
+ continue;
414
+ serializableProps[k] =
415
+ v && (v._isNixState || v._isRestState) ? v.value : v;
416
+ }
417
+ const cacheKey = generateCacheKey();
418
+ addToCache(propsCache, cacheKey, serializableProps);
419
+ try {
420
+ window.history.pushState({ __fynixCacheKey: cacheKey, serializedProps: serializableProps }, "", path);
421
+ renderRoute();
422
+ }
423
+ catch (err) {
424
+ console.error("[Router] Link navigation failed:", err);
425
+ }
280
426
  };
281
- try {
282
- mount(Page, rootSelector, false, window.__lastRouteProps);
283
- } catch (err) {
284
- console.error("[Router] Mount failed:", err);
285
- root.innerHTML = `<pre style="color:red;">Mount Error occurred</pre>`;
286
- }
287
- currentPath = path;
288
- }
289
- __name(_renderRouteImmediate, "_renderRouteImmediate");
290
- function navigate(path, props = {}) {
291
- if (isDestroyed)
292
- return;
293
- path = normalizePath(path);
294
- if (!isValidURL(window.location.origin + path)) {
295
- console.error("[Router] Invalid navigation URL");
296
- return;
297
- }
298
- if (path === currentPath)
299
- return;
300
- const cacheKey = generateCacheKey();
301
- addToCache(cacheKey, props);
302
- try {
303
- window.history.pushState({ __fynixCacheKey: cacheKey }, "", path);
304
- renderRoute();
305
- } catch (err) {
306
- console.error("[Router] Navigation failed:", err);
307
- }
308
- }
309
- __name(navigate, "navigate");
310
- function replace(path, props = {}) {
311
- if (isDestroyed)
312
- return;
313
- path = normalizePath(path);
314
- if (!isValidURL(window.location.origin + path)) {
315
- console.error("[Router] Invalid replace URL");
316
- return;
317
- }
318
- const cacheKey = generateCacheKey();
319
- addToCache(cacheKey, props);
320
- try {
321
- window.history.replaceState({ __fynixCacheKey: cacheKey }, "", path);
322
- renderRoute();
323
- } catch (err) {
324
- console.error("[Router] Replace failed:", err);
325
- }
326
- }
327
- __name(replace, "replace");
328
- function back() {
329
- if (isDestroyed)
330
- return;
331
- try {
332
- window.history.back();
333
- } catch (err) {
334
- console.error("[Router] Back navigation failed:", err);
335
- }
336
- }
337
- __name(back, "back");
338
- function mountRouter(selector = "#app-root") {
339
- if (isDestroyed) {
340
- console.error("[Router] Cannot mount destroyed router");
341
- return;
342
- }
343
- if (typeof selector !== "string" || selector.length === 0) {
344
- console.error("[Router] Invalid selector");
345
- return;
346
- }
347
- rootSelector = selector;
348
- renderRoute();
349
- isRouterInitialized = true;
350
- }
351
- __name(mountRouter, "mountRouter");
352
- const clickHandler = /* @__PURE__ */ __name((e) => {
353
- if (isDestroyed)
354
- return;
355
- const link = e.target.closest("a[data-fynix-link]");
356
- if (!link)
357
- return;
358
- const href = link.getAttribute("href");
359
- if (!href) {
360
- console.warn("[Router] Missing href attribute");
361
- return;
362
- }
363
- if (isExternal(href)) {
364
- return;
365
- }
366
- const fullUrl = new URL(link.href, window.location.origin).href;
367
- if (!isValidURL(fullUrl)) {
368
- console.warn("[Router] Invalid link href");
369
- return;
370
- }
371
- e.preventDefault();
372
- const path = normalizePath(
373
- new URL(link.href, window.location.origin).pathname
374
- );
375
- if (path === currentPath)
376
- return;
377
- let props = {};
378
- const propsKey = link.getAttribute("data-props-key");
379
- if (propsKey && typeof propsKey === "string" && !propsKey.startsWith("__")) {
380
- if (window[PROPS_NAMESPACE]?.[propsKey]) {
381
- props = window[PROPS_NAMESPACE][propsKey];
382
- }
383
- }
384
- const serializableProps = {};
385
- for (const [k, v] of Object.entries(props)) {
386
- if (typeof k !== "string" || k.startsWith("__"))
387
- continue;
388
- serializableProps[k] = v && (v._isNixState || v._isRestState) ? v.value : v;
389
- }
390
- const cacheKey = generateCacheKey();
391
- addToCache(cacheKey, serializableProps);
392
- try {
393
- window.history.pushState(
394
- { __fynixCacheKey: cacheKey, serializedProps: serializableProps },
395
- "",
396
- path
397
- );
398
- renderRoute();
399
- } catch (err) {
400
- console.error("[Router] Link navigation failed:", err);
401
- }
402
- }, "clickHandler");
403
- if (listenerCount < MAX_LISTENERS && !isRouterInitialized) {
404
- document.addEventListener("click", clickHandler);
405
- listeners.push({
406
- element: document,
407
- event: "click",
408
- handler: clickHandler
409
- });
410
- listenerCount++;
411
- window.addEventListener("popstate", renderRoute);
412
- listeners.push({
413
- element: window,
414
- event: "popstate",
415
- handler: renderRoute
416
- });
417
- listenerCount++;
418
- }
419
- function cleanup() {
420
- if (renderTimeout) {
421
- clearTimeout(renderTimeout);
422
- renderTimeout = null;
423
- }
424
- isDestroyed = true;
425
- listeners.forEach(({ element, event, handler }) => {
426
- try {
427
- element.removeEventListener(event, handler);
428
- } catch (e) {
429
- console.error("[Router] Cleanup error:", e);
430
- }
431
- });
432
- listeners.length = 0;
433
- listenerCount = 0;
434
- __fynixPropsCache.forEach((props) => {
435
- if (props && typeof props === "object") {
436
- Object.values(props).forEach((val) => {
437
- if (val && typeof val === "object" && val.cleanup) {
427
+ if (listenerCount < MAX_LISTENERS && !isRouterInitialized) {
428
+ document.addEventListener("click", clickHandler);
429
+ listeners.push({
430
+ element: document,
431
+ event: "click",
432
+ handler: clickHandler,
433
+ });
434
+ listenerCount++;
435
+ window.addEventListener("popstate", renderRoute);
436
+ listeners.push({
437
+ element: window,
438
+ event: "popstate",
439
+ handler: renderRoute,
440
+ });
441
+ listenerCount++;
442
+ }
443
+ function mountRouter(selector = "#app-root") {
444
+ if (isDestroyed) {
445
+ console.error("[Router] Cannot mount destroyed router");
446
+ return;
447
+ }
448
+ if (typeof selector !== "string" || selector.length === 0) {
449
+ console.error("[Router] Invalid selector");
450
+ return;
451
+ }
452
+ rootSelector = selector;
453
+ renderRoute();
454
+ isRouterInitialized = true;
455
+ }
456
+ function cleanup() {
457
+ if (renderTimeout) {
458
+ clearTimeout(renderTimeout);
459
+ renderTimeout = null;
460
+ }
461
+ isDestroyed = true;
462
+ listeners.forEach(({ element, event, handler }) => {
438
463
  try {
439
- val.cleanup();
440
- } catch (e) {
464
+ element.removeEventListener(event, handler);
465
+ }
466
+ catch (e) {
467
+ console.error("[Router] Cleanup error:", e);
441
468
  }
442
- }
443
469
  });
444
- }
445
- });
446
- __fynixPropsCache.clear();
447
- if (window[PROPS_NAMESPACE]) {
448
- Object.keys(window[PROPS_NAMESPACE]).forEach((key) => {
449
- delete window[PROPS_NAMESPACE][key];
450
- });
451
- delete window[PROPS_NAMESPACE];
452
- }
453
- if (window.__lastRouteProps) {
454
- delete window.__lastRouteProps;
455
- }
456
- isRouterInitialized = false;
457
- routerInstance = null;
458
- console.log("[Router] Cleanup complete");
459
- }
460
- __name(cleanup, "cleanup");
461
- if (import.meta.hot) {
462
- import.meta.hot.accept(() => {
463
- console.log("[Router] HMR detected, re-rendering route...");
464
- renderRoute();
465
- });
466
- import.meta.hot.dispose(() => {
467
- console.log("[Router] HMR dispose, cleaning up...");
468
- cleanup();
469
- routerInstance = null;
470
- isRouterInitialized = false;
471
- });
472
- }
473
- const router = {
474
- mountRouter,
475
- navigate,
476
- replace,
477
- back,
478
- cleanup,
479
- routes,
480
- dynamicRoutes
481
- };
482
- routerInstance = router;
483
- return router;
470
+ listeners.length = 0;
471
+ listenerCount = 0;
472
+ propsCache.forEach((props) => {
473
+ if (props && typeof props === "object") {
474
+ Object.values(props).forEach((val) => {
475
+ if (val && typeof val === "object" && "cleanup" in val) {
476
+ try {
477
+ val.cleanup();
478
+ }
479
+ catch (e) {
480
+ }
481
+ }
482
+ });
483
+ }
484
+ });
485
+ propsCache.clear();
486
+ if (window[PROPS_NAMESPACE]) {
487
+ const ns = window[PROPS_NAMESPACE];
488
+ if (ns && typeof ns === "object") {
489
+ Object.keys(ns).forEach((key) => {
490
+ delete ns[key];
491
+ });
492
+ }
493
+ delete window[PROPS_NAMESPACE];
494
+ }
495
+ if (window.__lastRouteProps) {
496
+ delete window.__lastRouteProps;
497
+ }
498
+ isRouterInitialized = false;
499
+ routerInstance = null;
500
+ console.log("[Router] Cleanup complete");
501
+ }
502
+ if (import.meta.hot) {
503
+ import.meta.hot.accept(() => {
504
+ console.log("[Router] HMR detected, re-rendering route...");
505
+ renderRoute();
506
+ });
507
+ import.meta.hot.dispose(() => {
508
+ console.log("[Router] HMR dispose, cleaning up...");
509
+ cleanup();
510
+ routerInstance = null;
511
+ isRouterInitialized = false;
512
+ });
513
+ }
514
+ const router = {
515
+ mountRouter,
516
+ navigate,
517
+ replace,
518
+ back,
519
+ cleanup,
520
+ routes,
521
+ dynamicRoutes,
522
+ };
523
+ routerInstance = router;
524
+ return router;
484
525
  }
485
- __name(createFynix, "createFynix");
486
- function setLinkProps(key, props) {
487
- if (typeof key !== "string" || key.startsWith("__")) {
488
- console.error("[Router] Invalid props key");
489
- return;
490
- }
491
- if (!props || typeof props !== "object") {
492
- console.error("[Router] Invalid props object");
493
- return;
494
- }
495
- if (!window[PROPS_NAMESPACE]) {
496
- window[PROPS_NAMESPACE] = {};
497
- }
498
- if (Object.keys(window[PROPS_NAMESPACE]).length >= MAX_CACHE_SIZE) {
499
- console.warn("[Router] Props storage limit reached");
500
- return;
501
- }
502
- window[PROPS_NAMESPACE][key] = props;
526
+ export { createFynix };
527
+ export default createFynix;
528
+ export function setLinkProps(key, props) {
529
+ if (typeof key !== "string" || key.startsWith("__")) {
530
+ console.error("[Router] Invalid props key");
531
+ return;
532
+ }
533
+ if (!props || typeof props !== "object") {
534
+ console.error("[Router] Invalid props object");
535
+ return;
536
+ }
537
+ if (!window[PROPS_NAMESPACE]) {
538
+ window[PROPS_NAMESPACE] = {};
539
+ }
540
+ if (Object.keys(window[PROPS_NAMESPACE]).length >= MAX_CACHE_SIZE) {
541
+ console.warn("[Router] Props storage limit reached");
542
+ return;
543
+ }
544
+ window[PROPS_NAMESPACE][key] = props;
503
545
  }
504
- __name(setLinkProps, "setLinkProps");
505
- function clearLinkProps(key) {
506
- if (typeof key !== "string")
507
- return;
508
- if (window[PROPS_NAMESPACE]?.[key]) {
509
- const props = window[PROPS_NAMESPACE][key];
510
- if (props && typeof props === "object") {
511
- Object.values(props).forEach((val) => {
512
- if (val && typeof val === "object" && val.cleanup) {
513
- try {
514
- val.cleanup();
515
- } catch (e) {
516
- }
517
- }
518
- });
519
- }
520
- delete window[PROPS_NAMESPACE][key];
521
- }
546
+ export function clearLinkProps(key) {
547
+ if (typeof key !== "string")
548
+ return;
549
+ if (window[PROPS_NAMESPACE]?.[key]) {
550
+ const props = window[PROPS_NAMESPACE][key];
551
+ if (props && typeof props === "object") {
552
+ Object.values(props).forEach((val) => {
553
+ if (val && typeof val === "object" && "cleanup" in val) {
554
+ try {
555
+ val.cleanup();
556
+ }
557
+ catch (e) {
558
+ }
559
+ }
560
+ });
561
+ }
562
+ delete window[PROPS_NAMESPACE][key];
563
+ }
522
564
  }
523
- __name(clearLinkProps, "clearLinkProps");
524
- export {
525
- clearLinkProps,
526
- createFynix,
527
- createFynix as default,
528
- setLinkProps
529
- };
530
- //# sourceMappingURL=router.js.map