fynixui 1.0.10

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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/dist/context/context.d.ts +19 -0
  3. package/dist/context/context.d.ts.map +1 -0
  4. package/dist/context/context.js +4 -0
  5. package/dist/context/context.js.map +7 -0
  6. package/dist/custom/button.d.ts +2 -0
  7. package/dist/custom/button.d.ts.map +1 -0
  8. package/dist/custom/button.js +4 -0
  9. package/dist/custom/button.js.map +7 -0
  10. package/dist/custom/index.d.ts +3 -0
  11. package/dist/custom/index.d.ts.map +1 -0
  12. package/dist/custom/index.js +2 -0
  13. package/dist/custom/index.js.map +7 -0
  14. package/dist/custom/path.d.ts +14 -0
  15. package/dist/custom/path.d.ts.map +1 -0
  16. package/dist/custom/path.js +20 -0
  17. package/dist/custom/path.js.map +7 -0
  18. package/dist/error/errorOverlay.d.ts +3 -0
  19. package/dist/error/errorOverlay.d.ts.map +1 -0
  20. package/dist/error/errorOverlay.js +84 -0
  21. package/dist/error/errorOverlay.js.map +7 -0
  22. package/dist/fynix/index.d.ts +6 -0
  23. package/dist/fynix/index.d.ts.map +1 -0
  24. package/dist/fynix/index.js +5 -0
  25. package/dist/fynix/index.js.map +7 -0
  26. package/dist/hooks/nixAsync.d.ts +20 -0
  27. package/dist/hooks/nixAsync.d.ts.map +1 -0
  28. package/dist/hooks/nixAsync.js +114 -0
  29. package/dist/hooks/nixAsync.js.map +7 -0
  30. package/dist/hooks/nixAsyncCache.d.ts +19 -0
  31. package/dist/hooks/nixAsyncCache.d.ts.map +1 -0
  32. package/dist/hooks/nixAsyncCache.js +137 -0
  33. package/dist/hooks/nixAsyncCache.js.map +7 -0
  34. package/dist/hooks/nixAsyncDebounce.d.ts +22 -0
  35. package/dist/hooks/nixAsyncDebounce.d.ts.map +1 -0
  36. package/dist/hooks/nixAsyncDebounce.js +77 -0
  37. package/dist/hooks/nixAsyncDebounce.js.map +7 -0
  38. package/dist/hooks/nixAsyncQuery.d.ts +16 -0
  39. package/dist/hooks/nixAsyncQuery.d.ts.map +1 -0
  40. package/dist/hooks/nixAsyncQuery.js +87 -0
  41. package/dist/hooks/nixAsyncQuery.js.map +7 -0
  42. package/dist/hooks/nixCallback.d.ts +2 -0
  43. package/dist/hooks/nixCallback.d.ts.map +1 -0
  44. package/dist/hooks/nixCallback.js +34 -0
  45. package/dist/hooks/nixCallback.js.map +7 -0
  46. package/dist/hooks/nixComputed.d.ts +16 -0
  47. package/dist/hooks/nixComputed.d.ts.map +1 -0
  48. package/dist/hooks/nixComputed.js +175 -0
  49. package/dist/hooks/nixComputed.js.map +7 -0
  50. package/dist/hooks/nixDebounce.d.ts +11 -0
  51. package/dist/hooks/nixDebounce.d.ts.map +1 -0
  52. package/dist/hooks/nixDebounce.js +55 -0
  53. package/dist/hooks/nixDebounce.js.map +7 -0
  54. package/dist/hooks/nixEffect.d.ts +4 -0
  55. package/dist/hooks/nixEffect.d.ts.map +1 -0
  56. package/dist/hooks/nixEffect.js +75 -0
  57. package/dist/hooks/nixEffect.js.map +7 -0
  58. package/dist/hooks/nixFor.d.ts +13 -0
  59. package/dist/hooks/nixFor.d.ts.map +1 -0
  60. package/dist/hooks/nixFor.js +43 -0
  61. package/dist/hooks/nixFor.js.map +7 -0
  62. package/dist/hooks/nixForm.d.ts +33 -0
  63. package/dist/hooks/nixForm.d.ts.map +1 -0
  64. package/dist/hooks/nixForm.js +123 -0
  65. package/dist/hooks/nixForm.js.map +7 -0
  66. package/dist/hooks/nixFormAsync.d.ts +42 -0
  67. package/dist/hooks/nixFormAsync.d.ts.map +1 -0
  68. package/dist/hooks/nixFormAsync.js +169 -0
  69. package/dist/hooks/nixFormAsync.js.map +7 -0
  70. package/dist/hooks/nixInterval.d.ts +2 -0
  71. package/dist/hooks/nixInterval.d.ts.map +1 -0
  72. package/dist/hooks/nixInterval.js +23 -0
  73. package/dist/hooks/nixInterval.js.map +7 -0
  74. package/dist/hooks/nixLazy.d.ts +8 -0
  75. package/dist/hooks/nixLazy.d.ts.map +1 -0
  76. package/dist/hooks/nixLazy.js +58 -0
  77. package/dist/hooks/nixLazy.js.map +7 -0
  78. package/dist/hooks/nixLazyAsync.d.ts +10 -0
  79. package/dist/hooks/nixLazyAsync.d.ts.map +1 -0
  80. package/dist/hooks/nixLazyAsync.js +71 -0
  81. package/dist/hooks/nixLazyAsync.js.map +7 -0
  82. package/dist/hooks/nixLazyFormAsync.d.ts +50 -0
  83. package/dist/hooks/nixLazyFormAsync.d.ts.map +1 -0
  84. package/dist/hooks/nixLazyFormAsync.js +221 -0
  85. package/dist/hooks/nixLazyFormAsync.js.map +7 -0
  86. package/dist/hooks/nixLocalStorage.d.ts +8 -0
  87. package/dist/hooks/nixLocalStorage.d.ts.map +1 -0
  88. package/dist/hooks/nixLocalStorage.js +136 -0
  89. package/dist/hooks/nixLocalStorage.js.map +7 -0
  90. package/dist/hooks/nixMemo.d.ts +2 -0
  91. package/dist/hooks/nixMemo.d.ts.map +1 -0
  92. package/dist/hooks/nixMemo.js +30 -0
  93. package/dist/hooks/nixMemo.js.map +7 -0
  94. package/dist/hooks/nixPrevious.d.ts +2 -0
  95. package/dist/hooks/nixPrevious.d.ts.map +1 -0
  96. package/dist/hooks/nixPrevious.js +15 -0
  97. package/dist/hooks/nixPrevious.js.map +7 -0
  98. package/dist/hooks/nixRef.d.ts +4 -0
  99. package/dist/hooks/nixRef.d.ts.map +1 -0
  100. package/dist/hooks/nixRef.js +17 -0
  101. package/dist/hooks/nixRef.js.map +7 -0
  102. package/dist/hooks/nixState.d.ts +15 -0
  103. package/dist/hooks/nixState.d.ts.map +1 -0
  104. package/dist/hooks/nixState.js +127 -0
  105. package/dist/hooks/nixState.js.map +7 -0
  106. package/dist/hooks/nixStore.d.ts +10 -0
  107. package/dist/hooks/nixStore.d.ts.map +1 -0
  108. package/dist/hooks/nixStore.js +103 -0
  109. package/dist/hooks/nixStore.js.map +7 -0
  110. package/dist/package.json +221 -0
  111. package/dist/plugins/vite-plugin-res.d.ts +38 -0
  112. package/dist/plugins/vite-plugin-res.d.ts.map +1 -0
  113. package/dist/plugins/vite-plugin-res.js +106 -0
  114. package/dist/plugins/vite-plugin-res.js.map +7 -0
  115. package/dist/router/router.d.ts +48 -0
  116. package/dist/router/router.d.ts.map +1 -0
  117. package/dist/router/router.js +872 -0
  118. package/dist/router/router.js.map +7 -0
  119. package/dist/runtime.d.ts +124 -0
  120. package/dist/runtime.d.ts.map +1 -0
  121. package/dist/runtime.js +1361 -0
  122. package/dist/runtime.js.map +7 -0
  123. package/package.json +254 -0
  124. package/types/fnx.d.ts +34 -0
  125. package/types/fynix-ui.d.ts +323 -0
  126. package/types/global.d.ts +279 -0
  127. package/types/index.d.ts +37 -0
  128. package/types/jsx.d.ts +993 -0
  129. package/types/vite-env.d.ts +545 -0
@@ -0,0 +1,1361 @@
1
+ import { activeContext, setActiveContext } from "./context/context";
2
+ import { Button, Path } from "./custom/index";
3
+ import { removeErrorOverlay, showErrorOverlay } from "./error/errorOverlay";
4
+ import { nixAsync } from "./hooks/nixAsync";
5
+ import { nixAsyncCached } from "./hooks/nixAsyncCache";
6
+ import { nixAsyncDebounce } from "./hooks/nixAsyncDebounce";
7
+ import { nixAsyncQuery } from "./hooks/nixAsyncQuery";
8
+ import { nixCallback } from "./hooks/nixCallback";
9
+ import { nixComputed } from "./hooks/nixComputed";
10
+ import { nixDebounce } from "./hooks/nixDebounce";
11
+ import { nixEffect, nixEffectAlways, nixEffectOnce } from "./hooks/nixEffect";
12
+ import { nixForm } from "./hooks/nixForm";
13
+ import { nixFormAsync } from "./hooks/nixFormAsync";
14
+ import { nixInterval } from "./hooks/nixInterval";
15
+ import { nixLazy, Suspense } from "./hooks/nixLazy";
16
+ import { nixLazyAsync } from "./hooks/nixLazyAsync";
17
+ import { nixLazyFormAsync } from "./hooks/nixLazyFormAsync";
18
+ import { nixLocalStorage } from "./hooks/nixLocalStorage";
19
+ import { nixMemo } from "./hooks/nixMemo";
20
+ import { nixPrevious } from "./hooks/nixPrevious";
21
+ import { nixRef } from "./hooks/nixRef";
22
+ import { nixState } from "./hooks/nixState";
23
+ import { nixStore } from "./hooks/nixStore";
24
+ import createFynix from "./router/router";
25
+ class SimplePriorityQueue {
26
+ constructor() {
27
+ this.items = [];
28
+ this.priorityOrder = {
29
+ immediate: 0,
30
+ high: 1,
31
+ normal: 2,
32
+ low: 3,
33
+ idle: 4,
34
+ };
35
+ }
36
+ push(item, priority) {
37
+ this.items.push({ item, priority });
38
+ this.items.sort((a, b) => this.priorityOrder[a.priority] - this.priorityOrder[b.priority]);
39
+ }
40
+ pop() {
41
+ return this.items.shift()?.item;
42
+ }
43
+ peek() {
44
+ return this.items[0]?.item;
45
+ }
46
+ size() {
47
+ return this.items.length;
48
+ }
49
+ isEmpty() {
50
+ return this.items.length === 0;
51
+ }
52
+ }
53
+ class FynixScheduler {
54
+ constructor() {
55
+ this.updateQueue = new SimplePriorityQueue();
56
+ this.batchedUpdates = new Set();
57
+ this.isScheduled = false;
58
+ this.isWorking = false;
59
+ this.currentPriority = "normal";
60
+ this.updateIdCounter = 0;
61
+ }
62
+ schedule(update, priority = "normal") {
63
+ update.id = `update_${this.updateIdCounter++}`;
64
+ update.priority = priority;
65
+ update.timestamp = performance.now();
66
+ if (priority === "immediate") {
67
+ this.flushUpdate(update);
68
+ }
69
+ else {
70
+ this.updateQueue.push(update, priority);
71
+ this.scheduleWork();
72
+ }
73
+ }
74
+ batchUpdates(updates) {
75
+ updates.forEach((update) => this.batchedUpdates.add(update));
76
+ this.scheduleWork();
77
+ }
78
+ timeSlice(deadline) {
79
+ const startTime = performance.now();
80
+ const previousPriority = this.currentPriority;
81
+ while (!this.updateQueue.isEmpty() &&
82
+ performance.now() - startTime < deadline) {
83
+ const update = this.updateQueue.pop();
84
+ if (update) {
85
+ if (this.shouldYield() && update.priority !== "immediate") {
86
+ this.updateQueue.push(update, update.priority);
87
+ break;
88
+ }
89
+ this.flushUpdate(update);
90
+ }
91
+ }
92
+ this.currentPriority = previousPriority;
93
+ return this.updateQueue.isEmpty();
94
+ }
95
+ flush() {
96
+ if (this.isWorking)
97
+ return;
98
+ this.isWorking = true;
99
+ try {
100
+ while (!this.updateQueue.isEmpty()) {
101
+ const update = this.updateQueue.peek();
102
+ if (update && update.priority === "immediate") {
103
+ this.flushUpdate(this.updateQueue.pop());
104
+ }
105
+ else {
106
+ break;
107
+ }
108
+ }
109
+ this.batchedUpdates.forEach((update) => this.flushUpdate(update));
110
+ this.batchedUpdates.clear();
111
+ }
112
+ finally {
113
+ this.isWorking = false;
114
+ this.isScheduled = false;
115
+ }
116
+ }
117
+ flushUpdate(update) {
118
+ const previousPriority = this.currentPriority;
119
+ this.currentPriority = update.priority;
120
+ try {
121
+ update.callback();
122
+ }
123
+ catch (error) {
124
+ console.error("[FynixScheduler] Update error:", error);
125
+ showErrorOverlay(error);
126
+ }
127
+ finally {
128
+ this.currentPriority = previousPriority;
129
+ }
130
+ }
131
+ scheduleWork() {
132
+ if (this.isScheduled)
133
+ return;
134
+ this.isScheduled = true;
135
+ const nextUpdate = this.updateQueue.peek();
136
+ if (nextUpdate) {
137
+ if (nextUpdate.priority === "high") {
138
+ requestAnimationFrame(() => this.workLoop(16.67));
139
+ }
140
+ else {
141
+ if ("requestIdleCallback" in window) {
142
+ requestIdleCallback((deadline) => {
143
+ this.workLoop(deadline.timeRemaining());
144
+ });
145
+ }
146
+ else {
147
+ setTimeout(() => this.workLoop(5), 0);
148
+ }
149
+ }
150
+ }
151
+ }
152
+ workLoop(deadline) {
153
+ const hasMoreWork = !this.timeSlice(deadline);
154
+ if (hasMoreWork) {
155
+ this.isScheduled = false;
156
+ this.scheduleWork();
157
+ }
158
+ else {
159
+ this.flush();
160
+ }
161
+ }
162
+ getCurrentPriority() {
163
+ return this.currentPriority;
164
+ }
165
+ shouldYield() {
166
+ const nextUpdate = this.updateQueue.peek();
167
+ if (!nextUpdate)
168
+ return false;
169
+ const currentPriorityLevel = this.getPriorityLevel(this.currentPriority);
170
+ const nextPriorityLevel = this.getPriorityLevel(nextUpdate.priority);
171
+ return nextPriorityLevel < currentPriorityLevel;
172
+ }
173
+ getPriorityLevel(priority) {
174
+ const levels = { immediate: 0, high: 1, normal: 2, low: 3, idle: 4 };
175
+ return levels[priority];
176
+ }
177
+ }
178
+ const scheduler = new FynixScheduler();
179
+ class FiberRenderer {
180
+ constructor() {
181
+ this.workInProgressRoot = null;
182
+ this.nextUnitOfWork = null;
183
+ this.currentRoot = null;
184
+ this.deletions = [];
185
+ }
186
+ scheduleWork(fiber) {
187
+ this.workInProgressRoot = {
188
+ ...fiber,
189
+ alternate: this.currentRoot,
190
+ };
191
+ this.nextUnitOfWork = this.workInProgressRoot;
192
+ this.deletions = [];
193
+ scheduler.schedule({
194
+ id: "",
195
+ type: "layout",
196
+ priority: "high",
197
+ callback: () => this.workLoop(5),
198
+ timestamp: performance.now(),
199
+ }, "high");
200
+ }
201
+ workLoop(deadline) {
202
+ const startTime = performance.now();
203
+ while (this.nextUnitOfWork && performance.now() - startTime < deadline) {
204
+ this.nextUnitOfWork = this.performUnitOfWork(this.nextUnitOfWork);
205
+ }
206
+ if (!this.nextUnitOfWork && this.workInProgressRoot) {
207
+ this.commitRoot();
208
+ }
209
+ else if (this.nextUnitOfWork) {
210
+ scheduler.schedule({
211
+ id: "",
212
+ type: "layout",
213
+ priority: "normal",
214
+ callback: () => this.workLoop(5),
215
+ timestamp: performance.now(),
216
+ }, "normal");
217
+ }
218
+ }
219
+ performUnitOfWork(fiber) {
220
+ this.reconcileChildren(fiber, fiber.props?.children || []);
221
+ if (fiber.child) {
222
+ return fiber.child;
223
+ }
224
+ let nextFiber = fiber;
225
+ while (nextFiber) {
226
+ if (nextFiber.sibling) {
227
+ return nextFiber.sibling;
228
+ }
229
+ nextFiber = nextFiber.parent;
230
+ }
231
+ return null;
232
+ }
233
+ reconcileChildren(wipFiber, elements) {
234
+ let index = 0;
235
+ let oldFiber = wipFiber.alternate?.child;
236
+ let prevSibling = null;
237
+ while (index < elements.length || oldFiber != null) {
238
+ const element = elements[index];
239
+ let newFiber = null;
240
+ const sameType = oldFiber && element && element.type === oldFiber.type;
241
+ if (sameType && oldFiber) {
242
+ newFiber = {
243
+ type: oldFiber.type,
244
+ props: element.props,
245
+ key: element.key,
246
+ _domNode: oldFiber._domNode,
247
+ parent: wipFiber,
248
+ alternate: oldFiber,
249
+ effectTag: "UPDATE",
250
+ updatePriority: "normal",
251
+ child: null,
252
+ sibling: null,
253
+ _rendered: null,
254
+ };
255
+ }
256
+ if (element && !sameType) {
257
+ newFiber = {
258
+ type: element.type,
259
+ props: element.props,
260
+ key: element.key,
261
+ _domNode: null,
262
+ parent: wipFiber,
263
+ alternate: null,
264
+ effectTag: "PLACEMENT",
265
+ updatePriority: "normal",
266
+ child: null,
267
+ sibling: null,
268
+ _rendered: null,
269
+ };
270
+ }
271
+ if (oldFiber && !sameType) {
272
+ oldFiber.effectTag = "DELETION";
273
+ this.deletions.push(oldFiber);
274
+ }
275
+ if (oldFiber) {
276
+ oldFiber = oldFiber.sibling;
277
+ }
278
+ if (index === 0) {
279
+ wipFiber.child = newFiber;
280
+ }
281
+ else if (newFiber && prevSibling) {
282
+ prevSibling.sibling = newFiber;
283
+ }
284
+ prevSibling = newFiber;
285
+ index++;
286
+ }
287
+ }
288
+ commitRoot() {
289
+ this.deletions.forEach((fiber) => this.commitWork(fiber));
290
+ if (this.workInProgressRoot?.child) {
291
+ this.commitWork(this.workInProgressRoot.child);
292
+ }
293
+ this.currentRoot = this.workInProgressRoot;
294
+ this.workInProgressRoot = null;
295
+ }
296
+ commitWork(fiber) {
297
+ if (!fiber)
298
+ return;
299
+ let domParentFiber = fiber.parent;
300
+ while (!domParentFiber?._domNode) {
301
+ domParentFiber = domParentFiber?.parent || null;
302
+ }
303
+ const domParent = domParentFiber?._domNode;
304
+ if (fiber.effectTag === "PLACEMENT" && fiber._domNode && domParent) {
305
+ domParent.appendChild(fiber._domNode);
306
+ }
307
+ else if (fiber.effectTag === "UPDATE" && fiber._domNode) {
308
+ this.updateDom(fiber._domNode, fiber.alternate?.props || {}, fiber.props);
309
+ }
310
+ else if (fiber.effectTag === "DELETION" && domParent) {
311
+ this.commitDeletion(fiber, domParent);
312
+ }
313
+ this.commitWork(fiber.child);
314
+ this.commitWork(fiber.sibling);
315
+ }
316
+ commitDeletion(fiber, domParent) {
317
+ if (fiber._domNode) {
318
+ domParent.removeChild(fiber._domNode);
319
+ }
320
+ else if (fiber.child) {
321
+ this.commitDeletion(fiber.child, domParent);
322
+ }
323
+ }
324
+ updateDom(dom, prevProps, nextProps) {
325
+ Object.keys(prevProps)
326
+ .filter((key) => key !== "children" && !(key in nextProps))
327
+ .forEach((name) => {
328
+ if (name.startsWith("on")) {
329
+ const eventType = name.toLowerCase().substring(2);
330
+ dom.removeEventListener(eventType, prevProps[name]);
331
+ }
332
+ else {
333
+ dom[name] = "";
334
+ }
335
+ });
336
+ Object.keys(nextProps)
337
+ .filter((key) => key !== "children")
338
+ .forEach((name) => {
339
+ if (prevProps[name] !== nextProps[name]) {
340
+ if (name.startsWith("on")) {
341
+ const eventType = name.toLowerCase().substring(2);
342
+ dom.addEventListener(eventType, nextProps[name]);
343
+ }
344
+ else {
345
+ dom[name] = nextProps[name];
346
+ }
347
+ }
348
+ });
349
+ }
350
+ }
351
+ const fiberRenderer = new FiberRenderer();
352
+ export function useFiberRenderer() {
353
+ return fiberRenderer;
354
+ }
355
+ class HierarchicalStore {
356
+ constructor() {
357
+ this.root = new Map();
358
+ this.selectorCache = new Map();
359
+ this.stateSnapshot = {};
360
+ }
361
+ select(selector) {
362
+ const selectorKey = selector.toString();
363
+ if (this.selectorCache.has(selectorKey)) {
364
+ return this.selectorCache.get(selectorKey);
365
+ }
366
+ const result = selector(this.getState());
367
+ this.selectorCache.set(selectorKey, result);
368
+ return result;
369
+ }
370
+ optimisticUpdate(path, update, rollback) {
371
+ const original = this.get(path);
372
+ this.set(path, update);
373
+ return {
374
+ commit: () => this.clearRollback(path),
375
+ rollback: () => {
376
+ this.set(path, original);
377
+ rollback?.();
378
+ },
379
+ };
380
+ }
381
+ getState() {
382
+ return this.stateSnapshot;
383
+ }
384
+ get(path) {
385
+ return this.root.get(path)?.value;
386
+ }
387
+ set(path, value) {
388
+ const node = this.root.get(path);
389
+ if (node) {
390
+ node.value = value;
391
+ this.stateSnapshot = { ...this.stateSnapshot, [path]: value };
392
+ this.invalidateSelectors();
393
+ }
394
+ }
395
+ clearRollback(path) {
396
+ console.log(`[HierarchicalStore] Optimistic update committed for path: ${path}`);
397
+ }
398
+ invalidateSelectors() {
399
+ this.selectorCache.clear();
400
+ }
401
+ }
402
+ const hierarchicalStore = new HierarchicalStore();
403
+ export function useHierarchicalStore() {
404
+ return hierarchicalStore;
405
+ }
406
+ export const TEXT = Symbol("text");
407
+ export const Fragment = Symbol("Fragment");
408
+ const BOOLEAN_ATTRS = new Set([
409
+ "checked",
410
+ "selected",
411
+ "disabled",
412
+ "readonly",
413
+ "multiple",
414
+ "autoplay",
415
+ "controls",
416
+ "loop",
417
+ "muted",
418
+ "open",
419
+ "required",
420
+ "reversed",
421
+ "scoped",
422
+ "seamless",
423
+ "autofocus",
424
+ "novalidate",
425
+ "formnovalidate",
426
+ ]);
427
+ const DOM_PROPERTIES = new Set([
428
+ "value",
429
+ "checked",
430
+ "selected",
431
+ "selectedIndex",
432
+ "innerHTML",
433
+ "textContent",
434
+ "innerText",
435
+ ]);
436
+ const DANGEROUS_HTML_PROPS = new Set([
437
+ "innerHTML",
438
+ "outerHTML",
439
+ "insertAdjacentHTML",
440
+ "srcdoc",
441
+ ]);
442
+ const DANGEROUS_PROTOCOLS = new Set([
443
+ "javascript:",
444
+ "data:",
445
+ "vbscript:",
446
+ "file:",
447
+ "about:",
448
+ ]);
449
+ const SAFE_PROTOCOLS = new Set([
450
+ "http:",
451
+ "https:",
452
+ "ftp:",
453
+ "ftps:",
454
+ "mailto:",
455
+ "tel:",
456
+ "#",
457
+ "/",
458
+ "./",
459
+ "../",
460
+ ]);
461
+ export function createTextVNode(text) {
462
+ if (text == null || text === false) {
463
+ return { type: TEXT, props: { nodeValue: "" }, key: null };
464
+ }
465
+ if (text && typeof text === "object" && text._isNixState) {
466
+ const vnode = {
467
+ type: TEXT,
468
+ props: { nodeValue: String(text.value) },
469
+ key: null,
470
+ _state: text,
471
+ _cleanup: null,
472
+ };
473
+ vnode._cleanup = text.subscribe(() => {
474
+ if (vnode._domNode) {
475
+ vnode._domNode.nodeValue = String(text.value);
476
+ }
477
+ });
478
+ return vnode;
479
+ }
480
+ return { type: TEXT, props: { nodeValue: String(text) }, key: null };
481
+ }
482
+ export function h(type, props = null, ...children) {
483
+ const normalizedProps = props === null || typeof props !== "object" || Array.isArray(props)
484
+ ? {}
485
+ : props;
486
+ const flatChildren = [];
487
+ for (const c of children.flat(Infinity)) {
488
+ if (c == null || c === false)
489
+ continue;
490
+ if (c && typeof c === "object" && "_isNixState" in c) {
491
+ flatChildren.push(createTextVNode(c));
492
+ }
493
+ else if (typeof c === "string" || typeof c === "number") {
494
+ flatChildren.push(createTextVNode(c));
495
+ }
496
+ else if (c && typeof c === "object" && "type" in c) {
497
+ if (c.type === Fragment) {
498
+ const fragmentChildren = (c.props.children || []).filter((x) => x != null && x !== false);
499
+ flatChildren.push(...fragmentChildren);
500
+ }
501
+ else {
502
+ flatChildren.push(c);
503
+ }
504
+ }
505
+ else if (typeof c === "function") {
506
+ flatChildren.push(c);
507
+ }
508
+ else {
509
+ flatChildren.push(createTextVNode(String(c)));
510
+ }
511
+ }
512
+ const key = normalizedProps.key ?? null;
513
+ if (key !== undefined)
514
+ delete normalizedProps.key;
515
+ if (type === Fragment) {
516
+ return { type: Fragment, props: { children: flatChildren }, key };
517
+ }
518
+ return {
519
+ type,
520
+ props: { ...normalizedProps, children: flatChildren },
521
+ key,
522
+ };
523
+ }
524
+ h.Fragment = ({ children }) => children || [];
525
+ export const Fynix = h;
526
+ Fynix.Fragment = h.Fragment;
527
+ const componentInstances = new WeakMap();
528
+ let rootRenderFn = null;
529
+ const pendingRerenders = new WeakSet();
530
+ function beginComponent(vnode) {
531
+ let ctx = componentInstances.get(vnode);
532
+ if (!ctx) {
533
+ ctx = {
534
+ hooks: [],
535
+ hookIndex: 0,
536
+ effects: [],
537
+ cleanups: [],
538
+ _vnode: vnode,
539
+ _accessedStates: new Set(),
540
+ _subscriptions: new Set(),
541
+ _subscriptionCleanups: [],
542
+ version: 0,
543
+ rerender: null,
544
+ Component: vnode.type,
545
+ _isMounted: false,
546
+ _isRerendering: false,
547
+ };
548
+ componentInstances.set(vnode, ctx);
549
+ }
550
+ ctx.hookIndex = 0;
551
+ ctx._accessedStates.clear();
552
+ setActiveContext(ctx);
553
+ ctx.version++;
554
+ return ctx;
555
+ }
556
+ function endComponent() {
557
+ const ctx = activeContext;
558
+ if (!ctx)
559
+ return;
560
+ ctx._accessedStates.forEach((state) => {
561
+ if (!ctx._subscriptions.has(state)) {
562
+ if (!ctx.rerender) {
563
+ let rerenderTimeout = null;
564
+ ctx.rerender = function rerender() {
565
+ if (ctx._isRerendering || pendingRerenders.has(ctx)) {
566
+ return;
567
+ }
568
+ if (rerenderTimeout) {
569
+ clearTimeout(rerenderTimeout);
570
+ }
571
+ rerenderTimeout = setTimeout(async () => {
572
+ if (ctx._isRerendering || !ctx._isMounted)
573
+ return;
574
+ ctx._isRerendering = true;
575
+ pendingRerenders.add(ctx);
576
+ try {
577
+ removeErrorOverlay();
578
+ const vnode = ctx._vnode;
579
+ const oldRendered = vnode._rendered;
580
+ beginComponent(vnode);
581
+ const result = ctx.Component(vnode.props);
582
+ const newRendered = result instanceof Promise ? await result : result;
583
+ endComponent();
584
+ vnode._rendered = newRendered;
585
+ const domNode = vnode._domNode;
586
+ if (domNode && domNode.parentNode) {
587
+ await patch(domNode.parentNode, newRendered, oldRendered);
588
+ if (newRendered && typeof newRendered === "object") {
589
+ vnode._domNode = newRendered._domNode;
590
+ }
591
+ ctx._isRerendering = false;
592
+ pendingRerenders.delete(ctx);
593
+ }
594
+ else if (rootRenderFn) {
595
+ await rootRenderFn();
596
+ ctx._isRerendering = false;
597
+ pendingRerenders.delete(ctx);
598
+ }
599
+ else {
600
+ ctx._isRerendering = false;
601
+ pendingRerenders.delete(ctx);
602
+ }
603
+ }
604
+ catch (err) {
605
+ console.error("[Fynix] Component rerender error:", err);
606
+ showErrorOverlay(err);
607
+ ctx._isRerendering = false;
608
+ pendingRerenders.delete(ctx);
609
+ }
610
+ rerenderTimeout = null;
611
+ }, 0);
612
+ };
613
+ }
614
+ const unsub = state.subscribe(() => {
615
+ if (ctx.rerender && ctx._isMounted) {
616
+ if (typeof queueMicrotask === "function") {
617
+ queueMicrotask(() => ctx.rerender());
618
+ }
619
+ else {
620
+ setTimeout(ctx.rerender, 0);
621
+ }
622
+ }
623
+ });
624
+ ctx._subscriptions.add(state);
625
+ ctx._subscriptionCleanups.push(unsub);
626
+ }
627
+ });
628
+ setActiveContext(null);
629
+ }
630
+ export function renderComponent(Component, props = {}) {
631
+ const vnode = { type: Component, props, key: null };
632
+ const ctx = beginComponent(vnode);
633
+ ctx.Component = Component;
634
+ if (!ctx.rerender) {
635
+ let rerenderTimeout = null;
636
+ ctx.rerender = () => {
637
+ if (ctx._isRerendering || pendingRerenders.has(ctx))
638
+ return;
639
+ if (rerenderTimeout) {
640
+ clearTimeout(rerenderTimeout);
641
+ }
642
+ rerenderTimeout = setTimeout(async () => {
643
+ if (ctx._isRerendering || !ctx._isMounted)
644
+ return;
645
+ ctx._isRerendering = true;
646
+ pendingRerenders.add(ctx);
647
+ try {
648
+ removeErrorOverlay();
649
+ const vnode = ctx._vnode;
650
+ const oldRendered = vnode._rendered;
651
+ beginComponent(vnode);
652
+ const result = ctx.Component(vnode.props);
653
+ const newRendered = result instanceof Promise ? await result : result;
654
+ endComponent();
655
+ vnode._rendered = newRendered;
656
+ const domNode = vnode._domNode;
657
+ if (domNode && domNode.parentNode) {
658
+ await patch(domNode.parentNode, newRendered, oldRendered);
659
+ if (newRendered && typeof newRendered === "object") {
660
+ vnode._domNode = newRendered._domNode;
661
+ }
662
+ ctx._isRerendering = false;
663
+ pendingRerenders.delete(ctx);
664
+ }
665
+ else if (rootRenderFn) {
666
+ await rootRenderFn();
667
+ ctx._isRerendering = false;
668
+ pendingRerenders.delete(ctx);
669
+ }
670
+ else {
671
+ ctx._isRerendering = false;
672
+ pendingRerenders.delete(ctx);
673
+ }
674
+ }
675
+ catch (err) {
676
+ console.error("[Fynix] Component rerender error:", err);
677
+ showErrorOverlay(err);
678
+ ctx._isRerendering = false;
679
+ pendingRerenders.delete(ctx);
680
+ }
681
+ rerenderTimeout = null;
682
+ }, 0);
683
+ };
684
+ }
685
+ try {
686
+ removeErrorOverlay();
687
+ const result = Component(props);
688
+ if (result instanceof Promise) {
689
+ const placeholderVNode = h("div", null, "Loading...");
690
+ ctx._vnode = vnode;
691
+ vnode._rendered = placeholderVNode;
692
+ ctx._isMounted = true;
693
+ result
694
+ .then((resolvedVNode) => {
695
+ vnode._rendered = resolvedVNode;
696
+ if (ctx.rerender) {
697
+ ctx.rerender();
698
+ }
699
+ })
700
+ .catch((err) => {
701
+ console.error("[Fynix] Async component error:", err);
702
+ showErrorOverlay(err);
703
+ });
704
+ return placeholderVNode;
705
+ }
706
+ ctx._vnode = vnode;
707
+ vnode._rendered = result;
708
+ ctx._isMounted = true;
709
+ return result;
710
+ }
711
+ catch (err) {
712
+ console.error("[Fynix] Component render error:", err);
713
+ showErrorOverlay(err);
714
+ return h("div", { style: "color:red" }, `Error: ${sanitizeErrorMessage(err)}`);
715
+ }
716
+ finally {
717
+ endComponent();
718
+ }
719
+ }
720
+ const delegatedEvents = new Map();
721
+ let eventIdCounter = 1;
722
+ function ensureDelegated(eventType) {
723
+ if (delegatedEvents.has(eventType))
724
+ return;
725
+ delegatedEvents.set(eventType, new Map());
726
+ document.addEventListener(eventType, (e) => {
727
+ let cur = e.target;
728
+ while (cur && cur !== document) {
729
+ if (cur.nodeType !== 1)
730
+ break;
731
+ const el = cur;
732
+ const eid = el._rest_eid;
733
+ const map = delegatedEvents.get(eventType);
734
+ if (eid != null && map?.has(eid)) {
735
+ map.get(eid)(e);
736
+ return;
737
+ }
738
+ cur = cur.parentElement;
739
+ }
740
+ });
741
+ }
742
+ function registerDelegatedHandler(el, eventName, fn) {
743
+ if (!fn || el.nodeType !== 1)
744
+ return;
745
+ const anyEl = el;
746
+ const eid = anyEl._rest_eid ?? (anyEl._rest_eid = ++eventIdCounter);
747
+ ensureDelegated(eventName);
748
+ delegatedEvents.get(eventName).set(eid, (e) => {
749
+ try {
750
+ fn.call(el, e);
751
+ }
752
+ catch (err) {
753
+ console.error("[Fynix] Event handler error:", err);
754
+ showErrorOverlay(err);
755
+ }
756
+ });
757
+ }
758
+ function sanitizeText(text) {
759
+ if (typeof text !== "string")
760
+ return String(text);
761
+ return text
762
+ .replace(/[<>"'&]/g, (match) => {
763
+ const entityMap = {
764
+ "<": "&lt;",
765
+ ">": "&gt;",
766
+ '"': "&quot;",
767
+ "'": "&#x27;",
768
+ "&": "&amp;",
769
+ };
770
+ return entityMap[match] || match;
771
+ })
772
+ .replace(/javascript:/gi, "blocked:")
773
+ .replace(/data:.*?base64/gi, "blocked:");
774
+ }
775
+ function sanitizeAttributeValue(value) {
776
+ if (typeof value !== "string")
777
+ return String(value);
778
+ return value
779
+ .replace(/["'<>]/g, (match) => {
780
+ const entityMap = {
781
+ '"': "&quot;",
782
+ "'": "&#x27;",
783
+ "<": "&lt;",
784
+ ">": "&gt;",
785
+ };
786
+ return entityMap[match] || match;
787
+ })
788
+ .replace(/javascript:/gi, "blocked:")
789
+ .replace(/on\w+=/gi, "blocked=");
790
+ }
791
+ function sanitizeErrorMessage(error) {
792
+ if (!error)
793
+ return "Unknown error";
794
+ const message = error.message || error.toString() || "Unknown error";
795
+ return sanitizeText(String(message)).slice(0, 200);
796
+ }
797
+ function setProperty(el, key, value) {
798
+ const k = key.toLowerCase();
799
+ if (key === "r-class" || key === "rc") {
800
+ if (typeof value === "string") {
801
+ el.setAttribute("class", value);
802
+ }
803
+ else if (value && (value._isNixState || value._isRestState)) {
804
+ el.setAttribute("class", value.value);
805
+ const anyEl = el;
806
+ if (!anyEl._fynixCleanups)
807
+ anyEl._fynixCleanups = [];
808
+ const unsub = value.subscribe(() => el.setAttribute("class", value.value));
809
+ anyEl._fynixCleanups.push(unsub);
810
+ }
811
+ return;
812
+ }
813
+ if (key.startsWith("r-")) {
814
+ registerDelegatedHandler(el, key.slice(2).toLowerCase(), value);
815
+ return;
816
+ }
817
+ if (key === "style" && typeof value === "object") {
818
+ Object.assign(el.style, value);
819
+ return;
820
+ }
821
+ if (DANGEROUS_HTML_PROPS.has(key)) {
822
+ console.error(`[Fynix] Security: ${key} is blocked for security reasons. Use textContent or children instead.`);
823
+ return;
824
+ }
825
+ if ((key === "href" ||
826
+ key === "src" ||
827
+ key === "action" ||
828
+ key === "formaction") &&
829
+ typeof value === "string") {
830
+ const normalizedValue = value.trim().toLowerCase();
831
+ for (const protocol of DANGEROUS_PROTOCOLS) {
832
+ if (normalizedValue.startsWith(protocol)) {
833
+ console.error(`[Fynix] Security: ${protocol} protocol blocked in ${key}`);
834
+ return;
835
+ }
836
+ }
837
+ if (normalizedValue.includes(":")) {
838
+ const protocol = normalizedValue.split(":")[0] + ":";
839
+ if (!SAFE_PROTOCOLS.has(protocol) &&
840
+ !SAFE_PROTOCOLS.has(normalizedValue.charAt(0))) {
841
+ console.error(`[Fynix] Security: Protocol '${protocol}' not in safe list for ${key}`);
842
+ return;
843
+ }
844
+ }
845
+ if (normalizedValue.startsWith("data:")) {
846
+ if (normalizedValue.includes("javascript") ||
847
+ normalizedValue.includes("<script")) {
848
+ console.error(`[Fynix] Security: Suspicious data: URL blocked in ${key}`);
849
+ return;
850
+ }
851
+ }
852
+ }
853
+ if (key.toLowerCase().startsWith("on") && key !== "open") {
854
+ console.error(`[Fynix] Security: Inline event handler '${key}' blocked. Use r-${key.slice(2)} instead.`);
855
+ return;
856
+ }
857
+ if (BOOLEAN_ATTRS.has(k)) {
858
+ if (value) {
859
+ el.setAttribute(k, "");
860
+ el[k] = true;
861
+ }
862
+ else {
863
+ el.removeAttribute(k);
864
+ el[k] = false;
865
+ }
866
+ return;
867
+ }
868
+ if (DOM_PROPERTIES.has(key) && !DANGEROUS_HTML_PROPS.has(key)) {
869
+ if (key === "textContent" || key === "innerText") {
870
+ el[key] = sanitizeText(value ?? "");
871
+ }
872
+ else {
873
+ el[key] = value ?? "";
874
+ }
875
+ return;
876
+ }
877
+ if (key.startsWith("data-") || key.startsWith("aria-")) {
878
+ if (value != null && value !== false) {
879
+ el.setAttribute(key, sanitizeAttributeValue(String(value)));
880
+ }
881
+ else {
882
+ el.removeAttribute(key);
883
+ }
884
+ return;
885
+ }
886
+ if (value != null && value !== false) {
887
+ el.setAttribute(key, value);
888
+ }
889
+ }
890
+ async function createDom(vnode, existing = null) {
891
+ if (vnode == null) {
892
+ return document.createTextNode("");
893
+ }
894
+ if (typeof vnode === "string" || typeof vnode === "number") {
895
+ return document.createTextNode(String(vnode));
896
+ }
897
+ if (vnode instanceof Promise) {
898
+ const placeholder = document.createTextNode("Loading...");
899
+ vnode
900
+ .then(async (resolved) => {
901
+ try {
902
+ const dom = await createDom(resolved);
903
+ if (placeholder.parentNode) {
904
+ placeholder.replaceWith(dom);
905
+ }
906
+ }
907
+ catch (err) {
908
+ console.error("[Fynix] Async component error:", err);
909
+ if (placeholder.parentNode) {
910
+ placeholder.textContent = "Error loading component";
911
+ }
912
+ }
913
+ })
914
+ .catch((err) => {
915
+ console.error("[Fynix] Async component promise error:", err);
916
+ if (placeholder.parentNode) {
917
+ placeholder.textContent = "Error loading async component";
918
+ }
919
+ });
920
+ return placeholder;
921
+ }
922
+ const vnodeObj = vnode;
923
+ if (vnodeObj.type === TEXT) {
924
+ const textNode = existing || document.createTextNode(vnodeObj.props.nodeValue ?? "");
925
+ vnodeObj._domNode = textNode;
926
+ return textNode;
927
+ }
928
+ if (vnodeObj.type === Fragment) {
929
+ const frag = document.createDocumentFragment();
930
+ for (const child of vnodeObj.props?.children || []) {
931
+ frag.appendChild(await createDom(child));
932
+ }
933
+ vnodeObj._domNode = frag;
934
+ return frag;
935
+ }
936
+ if (typeof vnodeObj.type === "function") {
937
+ const rendered = await renderMaybeAsyncComponent(vnodeObj.type, vnodeObj.props, vnodeObj);
938
+ vnodeObj._rendered = rendered;
939
+ const dom = await createDom(rendered);
940
+ vnodeObj._domNode = dom;
941
+ return dom;
942
+ }
943
+ const el = existing || document.createElement(vnodeObj.type);
944
+ for (const [k, v] of Object.entries(vnodeObj.props || {})) {
945
+ if (k !== "children") {
946
+ setProperty(el, k, v);
947
+ }
948
+ }
949
+ for (const child of vnodeObj.props?.children || []) {
950
+ el.appendChild(await createDom(child));
951
+ }
952
+ vnodeObj._domNode = el;
953
+ return el;
954
+ }
955
+ async function renderMaybeAsyncComponent(Component, props, vnode) {
956
+ const ctx = beginComponent(vnode);
957
+ removeErrorOverlay();
958
+ try {
959
+ const result = await Component(props);
960
+ ctx._vnode = vnode;
961
+ vnode._rendered = result;
962
+ ctx._isMounted = true;
963
+ endComponent();
964
+ return result ?? null;
965
+ }
966
+ catch (err) {
967
+ console.error("[Fynix] async render error:", err);
968
+ showErrorOverlay(err);
969
+ ctx._isMounted = false;
970
+ endComponent();
971
+ return h("div", { style: "color:red" }, `Error: ${sanitizeErrorMessage(err)}`);
972
+ }
973
+ }
974
+ export async function patch(parent, newVNode, oldVNode) {
975
+ if (!(parent instanceof Node)) {
976
+ console.error("[Fynix] patch() expects a DOM Node, got:", typeof parent, parent);
977
+ return;
978
+ }
979
+ if (!newVNode && !oldVNode)
980
+ return;
981
+ if (!newVNode && oldVNode) {
982
+ const domNode = oldVNode._domNode;
983
+ if (domNode?.parentNode) {
984
+ domNode.parentNode.removeChild(domNode);
985
+ }
986
+ unmountVNode(oldVNode);
987
+ return;
988
+ }
989
+ if (newVNode && !oldVNode) {
990
+ const newDom = await createDom(newVNode);
991
+ if (newDom instanceof Node) {
992
+ parent.appendChild(newDom);
993
+ }
994
+ return;
995
+ }
996
+ const newIsPrimitive = typeof newVNode === "string" || typeof newVNode === "number";
997
+ const oldIsPrimitive = typeof oldVNode === "string" || typeof oldVNode === "number";
998
+ if (newIsPrimitive || oldIsPrimitive) {
999
+ if (newIsPrimitive &&
1000
+ oldIsPrimitive &&
1001
+ String(newVNode) === String(oldVNode))
1002
+ return;
1003
+ const newDom = await createDom(newVNode);
1004
+ const oldDom = oldVNode?._domNode || parent.firstChild;
1005
+ if (oldDom?.parentNode && newDom instanceof Node) {
1006
+ oldDom.parentNode.replaceChild(newDom, oldDom);
1007
+ }
1008
+ if (oldVNode && typeof oldVNode === "object") {
1009
+ unmountVNode(oldVNode);
1010
+ }
1011
+ return;
1012
+ }
1013
+ const newVN = newVNode;
1014
+ const oldVN = oldVNode;
1015
+ const newType = newVN.type;
1016
+ const oldType = oldVN.type;
1017
+ if (newType !== oldType) {
1018
+ const newDom = await createDom(newVN);
1019
+ const oldDom = oldVN._domNode;
1020
+ if (oldDom?.parentNode && newDom instanceof Node) {
1021
+ oldDom.parentNode.replaceChild(newDom, oldDom);
1022
+ }
1023
+ unmountVNode(oldVN);
1024
+ return;
1025
+ }
1026
+ if (newType === TEXT) {
1027
+ const oldDom = oldVN._domNode;
1028
+ const newText = newVN.props.nodeValue ?? "";
1029
+ const oldText = oldVN.props.nodeValue ?? "";
1030
+ if (newText !== oldText && oldDom) {
1031
+ oldDom.nodeValue = newText;
1032
+ }
1033
+ newVN._domNode = oldDom;
1034
+ return;
1035
+ }
1036
+ if (newType === Fragment) {
1037
+ const newChildren = newVN.props?.children || [];
1038
+ const oldChildren = oldVN.props?.children || [];
1039
+ await patchChildren(parent, newChildren, oldChildren);
1040
+ newVN._domNode = oldVN._domNode;
1041
+ return;
1042
+ }
1043
+ if (typeof newType === "function") {
1044
+ const oldCtx = componentInstances.get(oldVN);
1045
+ if (oldCtx && newType === oldType) {
1046
+ componentInstances.delete(oldVN);
1047
+ componentInstances.set(newVN, oldCtx);
1048
+ oldCtx._vnode = newVN;
1049
+ beginComponent(newVN);
1050
+ const rendered = await oldCtx.Component(newVN.props);
1051
+ endComponent();
1052
+ newVN._rendered = rendered;
1053
+ const oldRendered = oldVN._rendered;
1054
+ const oldDom = oldVN._domNode;
1055
+ if (oldDom?.parentNode instanceof Node) {
1056
+ await patch(oldDom.parentNode, rendered, oldRendered);
1057
+ newVN._domNode = rendered?._domNode || oldDom;
1058
+ }
1059
+ }
1060
+ else {
1061
+ const rendered = await renderMaybeAsyncComponent(newType, newVN.props, newVN);
1062
+ newVN._rendered = rendered;
1063
+ const oldRendered = oldVN._rendered;
1064
+ const oldDom = oldVN._domNode;
1065
+ if (oldDom?.parentNode instanceof Node) {
1066
+ await patch(oldDom.parentNode, rendered, oldRendered);
1067
+ newVN._domNode = rendered?._domNode || oldDom;
1068
+ }
1069
+ else {
1070
+ const newDom = await createDom(rendered);
1071
+ if (parent && newDom instanceof Node) {
1072
+ parent.appendChild(newDom);
1073
+ }
1074
+ newVN._domNode = newDom;
1075
+ }
1076
+ if (oldCtx && newType !== oldType) {
1077
+ unmountVNode(oldVN);
1078
+ }
1079
+ }
1080
+ return;
1081
+ }
1082
+ const el = oldVN._domNode;
1083
+ if (!el || el.nodeType !== 1) {
1084
+ const newDom = await createDom(newVN);
1085
+ if (parent && newDom instanceof Node) {
1086
+ parent.appendChild(newDom);
1087
+ }
1088
+ unmountVNode(oldVN);
1089
+ return;
1090
+ }
1091
+ updateProps(el, newVN.props, oldVN.props);
1092
+ newVN._domNode = el;
1093
+ const newChildren = newVN.props?.children || [];
1094
+ const oldChildren = oldVN.props?.children || [];
1095
+ await patchChildren(el, newChildren, oldChildren);
1096
+ }
1097
+ async function patchChildren(parent, newChildren, oldChildren) {
1098
+ if (!(parent instanceof Node))
1099
+ return;
1100
+ const hasKeys = newChildren.some((c) => c?.key != null) ||
1101
+ oldChildren.some((c) => c?.key != null);
1102
+ if (!hasKeys) {
1103
+ const maxLen = Math.max(newChildren.length, oldChildren.length);
1104
+ for (let i = 0; i < maxLen; i++) {
1105
+ const newChild = newChildren[i];
1106
+ const oldChild = oldChildren[i];
1107
+ if (i >= newChildren.length) {
1108
+ const dom = oldChild?._domNode;
1109
+ if (dom?.parentNode) {
1110
+ dom.parentNode.removeChild(dom);
1111
+ }
1112
+ unmountVNode(oldChild);
1113
+ }
1114
+ else if (i >= oldChildren.length) {
1115
+ const newDom = await createDom(newChild);
1116
+ if (newDom instanceof Node) {
1117
+ parent.appendChild(newDom);
1118
+ }
1119
+ }
1120
+ else {
1121
+ await patch(parent, newChild, oldChild);
1122
+ }
1123
+ }
1124
+ return;
1125
+ }
1126
+ const oldKeyMap = new Map();
1127
+ oldChildren.forEach((child) => {
1128
+ if (child?.key != null) {
1129
+ oldKeyMap.set(child.key, child);
1130
+ }
1131
+ });
1132
+ const newKeySet = new Set(newChildren.filter((c) => c?.key != null).map((c) => c.key));
1133
+ oldChildren.forEach((oldChild) => {
1134
+ if (oldChild?.key != null && !newKeySet.has(oldChild.key)) {
1135
+ const dom = oldChild._domNode;
1136
+ if (dom?.parentNode) {
1137
+ dom.parentNode.removeChild(dom);
1138
+ }
1139
+ unmountVNode(oldChild);
1140
+ }
1141
+ });
1142
+ for (let i = 0; i < newChildren.length; i++) {
1143
+ const newChild = newChildren[i];
1144
+ const key = newChild?.key;
1145
+ if (key != null && oldKeyMap.has(key)) {
1146
+ const oldChild = oldKeyMap.get(key);
1147
+ const oldDom = oldChild._domNode;
1148
+ const childNodes = Array.from(parent.childNodes);
1149
+ const currentPos = childNodes.indexOf(oldDom);
1150
+ const desiredPos = i;
1151
+ if (currentPos !== desiredPos) {
1152
+ const refNode = childNodes[desiredPos] || null;
1153
+ if (oldDom && oldDom.parentNode === parent) {
1154
+ parent.insertBefore(oldDom, refNode);
1155
+ }
1156
+ }
1157
+ await patch(parent, newChild, oldChild);
1158
+ }
1159
+ else {
1160
+ const newDom = await createDom(newChild);
1161
+ if (newDom instanceof Node) {
1162
+ const childNodes = Array.from(parent.childNodes);
1163
+ const refNode = childNodes[i] || null;
1164
+ parent.insertBefore(newDom, refNode);
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1169
+ function unmountVNode(vnode) {
1170
+ if (!vnode)
1171
+ return;
1172
+ if (vnode._cleanup && typeof vnode._cleanup === "function") {
1173
+ try {
1174
+ vnode._cleanup();
1175
+ }
1176
+ catch (e) {
1177
+ console.error("[Fynix] Text vnode cleanup error:", e);
1178
+ }
1179
+ vnode._cleanup = null;
1180
+ }
1181
+ if (typeof vnode.type === "function") {
1182
+ const ctx = componentInstances.get(vnode);
1183
+ if (ctx) {
1184
+ ctx._isMounted = false;
1185
+ ctx._subscriptionCleanups.forEach((u) => {
1186
+ try {
1187
+ u();
1188
+ }
1189
+ catch (e) {
1190
+ console.error("[Fynix] Cleanup error:", e);
1191
+ }
1192
+ });
1193
+ ctx.cleanups.forEach((c) => {
1194
+ try {
1195
+ c?.();
1196
+ }
1197
+ catch (e) {
1198
+ console.error("[Fynix] Effect cleanup error:", e);
1199
+ }
1200
+ });
1201
+ ctx._subscriptions.clear();
1202
+ ctx._accessedStates.clear();
1203
+ ctx._subscriptionCleanups = [];
1204
+ ctx.cleanups = [];
1205
+ ctx.hooks = [];
1206
+ ctx.effects = [];
1207
+ ctx.rerender = null;
1208
+ ctx._vnode = null;
1209
+ componentInstances.delete(vnode);
1210
+ pendingRerenders.delete(ctx);
1211
+ }
1212
+ unmountVNode(vnode._rendered);
1213
+ return;
1214
+ }
1215
+ if (vnode._domNode && vnode._domNode.nodeType === 1) {
1216
+ const anyNode = vnode._domNode;
1217
+ const eid = anyNode._rest_eid;
1218
+ if (eid) {
1219
+ delegatedEvents.forEach((map) => map.delete(eid));
1220
+ }
1221
+ if (anyNode._fynixCleanups) {
1222
+ anyNode._fynixCleanups.forEach((cleanup) => {
1223
+ try {
1224
+ cleanup();
1225
+ }
1226
+ catch (e) {
1227
+ console.error("[Fynix] Element cleanup error:", e);
1228
+ }
1229
+ });
1230
+ anyNode._fynixCleanups = null;
1231
+ }
1232
+ }
1233
+ if (vnode.props?.children) {
1234
+ vnode.props.children.forEach((c) => unmountVNode(c));
1235
+ }
1236
+ vnode._domNode = null;
1237
+ vnode._rendered = null;
1238
+ }
1239
+ function updateProps(el, newProps = {}, oldProps = {}) {
1240
+ if (!el || el.nodeType !== 1)
1241
+ return;
1242
+ for (const k of Object.keys(oldProps)) {
1243
+ if (k === "children")
1244
+ continue;
1245
+ if (!(k in newProps)) {
1246
+ if (k.startsWith("r-")) {
1247
+ const anyEl = el;
1248
+ const eid = anyEl._rest_eid;
1249
+ if (eid && delegatedEvents.has(k.slice(2).toLowerCase())) {
1250
+ delegatedEvents.get(k.slice(2).toLowerCase()).delete(eid);
1251
+ }
1252
+ }
1253
+ else if (BOOLEAN_ATTRS.has(k.toLowerCase())) {
1254
+ el.removeAttribute(k);
1255
+ el[k] = false;
1256
+ }
1257
+ else if (DOM_PROPERTIES.has(k)) {
1258
+ el[k] = "";
1259
+ }
1260
+ else {
1261
+ el.removeAttribute(k);
1262
+ }
1263
+ }
1264
+ }
1265
+ for (const [k, v] of Object.entries(newProps)) {
1266
+ if (k === "children")
1267
+ continue;
1268
+ if (oldProps[k] !== v) {
1269
+ setProperty(el, k, v);
1270
+ }
1271
+ }
1272
+ }
1273
+ export function mount(AppComponent, root, props = {}) {
1274
+ if (typeof root === "string") {
1275
+ const element = document.querySelector(root);
1276
+ if (!element) {
1277
+ console.error("[Fynix] Mount error: Element not found for selector:", root);
1278
+ return;
1279
+ }
1280
+ root = element;
1281
+ }
1282
+ if (!(root instanceof Element)) {
1283
+ console.error("[Fynix] Mount error: Invalid root element", root);
1284
+ return;
1285
+ }
1286
+ let Component = AppComponent;
1287
+ let oldVNode = null;
1288
+ let currentProps = props;
1289
+ let appVNode = null;
1290
+ let isRendering = false;
1291
+ async function renderApp() {
1292
+ if (isRendering)
1293
+ return;
1294
+ isRendering = true;
1295
+ try {
1296
+ removeErrorOverlay();
1297
+ const win = window;
1298
+ const propsToUse = win.__lastRouteProps || win.__fynix__?.lastRouteProps || currentProps;
1299
+ if (!appVNode) {
1300
+ appVNode = { type: Component, props: propsToUse, key: null };
1301
+ if (root instanceof Element) {
1302
+ root.innerHTML = "";
1303
+ const dom = await createDom(appVNode);
1304
+ if (dom instanceof Node) {
1305
+ root.appendChild(dom);
1306
+ }
1307
+ }
1308
+ else {
1309
+ console.error("[Fynix] Mount error: root is not a DOM Element", root);
1310
+ return;
1311
+ }
1312
+ oldVNode = appVNode;
1313
+ }
1314
+ else {
1315
+ appVNode.props = propsToUse;
1316
+ if (root instanceof Node) {
1317
+ await patch(root, appVNode, oldVNode);
1318
+ oldVNode = appVNode;
1319
+ }
1320
+ else {
1321
+ console.error("[Fynix] Patch error: root is not a DOM Node", root);
1322
+ return;
1323
+ }
1324
+ }
1325
+ }
1326
+ catch (err) {
1327
+ console.error("[Fynix] Mount error:", err);
1328
+ showErrorOverlay(err);
1329
+ }
1330
+ finally {
1331
+ isRendering = false;
1332
+ }
1333
+ }
1334
+ rootRenderFn = renderApp;
1335
+ const win = window;
1336
+ win.__fynix__ = win.__fynix__ || {};
1337
+ win.__fynix__.rerender = renderApp;
1338
+ renderApp();
1339
+ if (import.meta.hot) {
1340
+ if (!win.__fynix__.hmr) {
1341
+ win.__fynix__.hmr = async ({ mod }) => {
1342
+ try {
1343
+ const UpdatedComponent = mod.App || mod.default;
1344
+ if (UpdatedComponent) {
1345
+ Component = UpdatedComponent;
1346
+ if (appVNode) {
1347
+ appVNode.type = UpdatedComponent;
1348
+ }
1349
+ win.__fynix__.rerender?.();
1350
+ }
1351
+ }
1352
+ catch (err) {
1353
+ console.error("[Fynix HMR] update error:", err);
1354
+ showErrorOverlay(err);
1355
+ }
1356
+ };
1357
+ import.meta.hot.accept();
1358
+ }
1359
+ }
1360
+ }
1361
+ export { Button, createFynix, nixAsync, nixAsyncCached, nixAsyncDebounce, nixAsyncQuery, nixCallback, nixComputed, nixDebounce, nixEffect, nixEffectAlways, nixEffectOnce, nixForm, nixFormAsync, nixInterval, nixLazy, nixLazyAsync, nixLazyFormAsync, nixLocalStorage, nixMemo, nixPrevious, nixRef, nixState, nixStore, Path, Suspense, };