@estjs/template 0.0.15 → 0.0.16-beta.2

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.
@@ -3,24 +3,23 @@
3
3
  var shared = require('@estjs/shared');
4
4
  var signals = require('@estjs/signals');
5
5
 
6
- var __defProp = Object.defineProperty;
7
6
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
8
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
- var __spreadValues = (a, b) => {
12
- for (var prop in b || (b = {}))
13
- if (__hasOwnProp.call(b, prop))
14
- __defNormalProp(a, prop, b[prop]);
15
- if (__getOwnPropSymbols)
16
- for (var prop of __getOwnPropSymbols(b)) {
17
- if (__propIsEnum.call(b, prop))
18
- __defNormalProp(a, prop, b[prop]);
19
- }
20
- return a;
9
+ var __objRest = (source, exclude) => {
10
+ var target = {};
11
+ for (var prop in source)
12
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
13
+ target[prop] = source[prop];
14
+ if (source != null && __getOwnPropSymbols)
15
+ for (var prop of __getOwnPropSymbols(source)) {
16
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
17
+ target[prop] = source[prop];
18
+ }
19
+ return target;
21
20
  };
22
21
  var __async = (__this, __arguments, generator) => {
23
- return new Promise((resolve, reject) => {
22
+ return new Promise((resolve2, reject) => {
24
23
  var fulfilled = (value) => {
25
24
  try {
26
25
  step(generator.next(value));
@@ -35,138 +34,51 @@ var __async = (__this, __arguments, generator) => {
35
34
  reject(e);
36
35
  }
37
36
  };
38
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
37
+ var step = (x) => x.done ? resolve2(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
39
38
  step((generator = generator.apply(__this, __arguments)).next());
40
39
  });
41
40
  };
42
- var LIFECYCLE = {
43
- mount: "mount",
44
- destroy: "destroy",
45
- update: "update"
46
- };
47
- function registerScopedHook(scope, listKey, hook) {
48
- let hookList = scope[listKey];
49
- if (!hookList) {
50
- hookList = scope[listKey] = [];
51
- }
52
- if (!hookList.includes(hook)) {
53
- hookList.push(hook);
54
- }
55
- }
56
- function executeHooks(hooks, scopeId2, phase) {
57
- const len = hooks.length;
58
- if (len === 0) return;
59
- let pending;
60
- for (let i = 0; i < len; i++) {
61
- try {
62
- const result = hooks[i]();
63
- if (shared.isPromise(result)) {
64
- const safePromise = result.catch((error_) => {
65
- if (true) {
66
- shared.error(`Scope(${scopeId2}): Async ${phase} hook rejected:`, error_);
67
- }
68
- });
69
- (pending != null ? pending : pending = []).push(safePromise);
70
- }
71
- } catch (error_) {
72
- {
73
- shared.error(`Scope(${scopeId2}): Error in ${phase} hook:`, error_);
74
- }
75
- }
76
- }
77
- if (!pending) return;
78
- return Promise.all(pending).then(() => void 0);
79
- }
80
- function onMount(hook) {
81
- const scope = getActiveScope();
82
- if (!scope) {
83
- shared.error("onMount() must be called within a scope");
84
- return;
85
- }
86
- if (scope.isMounted) {
87
- try {
88
- const result = hook();
89
- if (shared.isPromise(result)) {
90
- result.catch((error_) => {
91
- if (true) shared.error(`Scope(${scope.id}): Async ${LIFECYCLE.mount} hook rejected:`, error_);
92
- });
93
- }
94
- } catch (error_) {
95
- shared.error(`Scope(${scope.id}): Error in ${LIFECYCLE.mount} hook:`, error_);
96
- }
97
- return;
98
- }
99
- registerScopedHook(scope, "onMount", hook);
100
- }
101
- function onUpdate(hook) {
102
- const scope = getActiveScope();
103
- if (!scope) {
104
- shared.error("onUpdate() must be called within a scope");
105
- return;
106
- }
107
- registerScopedHook(scope, "onUpdate", hook);
108
- }
109
- function onDestroy(hook) {
110
- const scope = getActiveScope();
111
- if (!scope) {
112
- shared.error("onDestroy() must be called within a scope");
113
- return;
114
- }
115
- registerScopedHook(scope, "onDestroy", hook);
116
- }
117
- function triggerMountHooks(scope) {
118
- var _a2;
119
- if (scope.isDestroyed || !((_a2 = scope.onMount) == null ? void 0 : _a2.length)) {
120
- scope.isMounted = true;
121
- return;
122
- }
123
- const mountHooks = scope.onMount;
124
- const result = runWithScope(scope, () => executeHooks(mountHooks, scope.id, LIFECYCLE.mount));
125
- mountHooks.length = 0;
126
- scope.isMounted = true;
127
- return result;
128
- }
129
- function triggerUpdateHooks(scope) {
130
- var _a2;
131
- if (scope.isDestroyed || !((_a2 = scope.onUpdate) == null ? void 0 : _a2.length)) return;
132
- const updateHooks = scope.onUpdate;
133
- const result = runWithScope(scope, () => executeHooks(updateHooks, scope.id, "update"));
134
- updateHooks.length = 0;
135
- return result;
136
- }
137
- function triggerDestroyHooks(scope) {
138
- var _a2;
139
- if (scope.isDestroyed || !((_a2 = scope.onDestroy) == null ? void 0 : _a2.length)) return;
140
- return runWithScope(scope, () => executeHooks(scope.onDestroy, scope.id, "destroy"));
141
- }
142
41
 
143
- // src/scope.ts
42
+ // src/constants.ts
43
+ var SPREAD_NAME = "_$spread$";
44
+ var REF_KEY = "ref";
45
+ var KEY_PROP = "key";
46
+ var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
47
+ var XLINK_NAMESPACE = "http://www.w3.org/2000/xlink";
48
+ var XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/";
49
+ var FRAGMENT_COMPONENT = /* @__PURE__ */ Symbol("Fragment Component" );
50
+ var PORTAL_COMPONENT = /* @__PURE__ */ Symbol("Portal Component" );
51
+ var SUSPENSE_COMPONENT = /* @__PURE__ */ Symbol("Suspense Component" );
52
+ var FOR_COMPONENT = /* @__PURE__ */ Symbol("For Component" );
144
53
  var activeScope = null;
145
54
  var scopeId = 0;
146
55
  function getActiveScope() {
147
56
  return activeScope;
148
57
  }
149
- function setActiveScope(scope) {
150
- activeScope = scope;
151
- }
152
58
  function createScope(parent = activeScope) {
153
59
  const scope = {
154
60
  id: ++scopeId,
155
61
  parent,
156
62
  children: null,
63
+ // Lazy initialized
157
64
  provides: null,
65
+ // Lazy initialized
158
66
  cleanup: null,
67
+ // Lazy initialized
159
68
  onMount: null,
69
+ // Lazy initialized
160
70
  onUpdate: null,
71
+ // Lazy initialized
161
72
  onDestroy: null,
73
+ // Lazy initialized
162
74
  isMounted: false,
163
75
  isDestroyed: false
164
76
  };
165
77
  if (parent) {
166
78
  if (!parent.children) {
167
- parent.children = [];
79
+ parent.children = /* @__PURE__ */ new Set();
168
80
  }
169
- parent.children.push(scope);
81
+ parent.children.add(scope);
170
82
  }
171
83
  return scope;
172
84
  }
@@ -180,47 +92,61 @@ function runWithScope(scope, fn) {
180
92
  }
181
93
  }
182
94
  function disposeScope(scope) {
183
- var _a2, _b, _c;
95
+ var _a2;
184
96
  if (!scope || scope.isDestroyed) {
185
97
  return;
186
98
  }
187
- const parentScope = scope.parent;
188
- if (scope.children) {
189
- for (const child of scope.children) {
190
- disposeScope(child);
99
+ scope.isDestroyed = true;
100
+ if (scope.children && scope.children.size > 0) {
101
+ for (const child2 of scope.children) {
102
+ if (child2) {
103
+ child2.parent = null;
104
+ disposeScope(child2);
105
+ }
191
106
  }
192
- scope.children.length = 0;
193
- }
194
- if ((_a2 = scope.onDestroy) == null ? void 0 : _a2.length) {
195
- triggerDestroyHooks(scope);
196
- scope.onDestroy.length = 0;
107
+ scope.children.clear();
197
108
  }
198
- if ((_b = scope.cleanup) == null ? void 0 : _b.length) {
199
- for (const fn of scope.cleanup) {
200
- try {
201
- fn();
202
- } catch (error_) {
203
- {
204
- shared.error(`Scope(${scope.id}): Error in cleanup:`, error_);
109
+ const prevScope = activeScope;
110
+ activeScope = scope;
111
+ try {
112
+ if (scope.onDestroy) {
113
+ for (let i = 0; i < scope.onDestroy.length; i++) {
114
+ try {
115
+ scope.onDestroy[i]();
116
+ } catch (error_) {
117
+ if (true) {
118
+ shared.error(`Scope(${scope.id}): Error in destroy hook:`, error_);
119
+ }
205
120
  }
206
121
  }
122
+ scope.onDestroy = null;
207
123
  }
208
- scope.cleanup.length = 0;
209
- }
210
- if (parentScope == null ? void 0 : parentScope.children) {
211
- const idx = parentScope.children.indexOf(scope);
212
- if (idx !== -1) {
213
- parentScope.children.splice(idx, 1);
124
+ if (scope.cleanup) {
125
+ for (let i = 0; i < scope.cleanup.length; i++) {
126
+ try {
127
+ scope.cleanup[i]();
128
+ } catch (error_) {
129
+ if (true) {
130
+ shared.error(`Scope(${scope.id}): Error in cleanup:`, error_);
131
+ }
132
+ }
133
+ }
134
+ scope.cleanup = null;
214
135
  }
136
+ } finally {
137
+ activeScope = prevScope;
215
138
  }
216
- (_c = scope.provides) == null ? void 0 : _c.clear();
217
- if (scope.onMount) scope.onMount.length = 0;
218
- if (scope.onUpdate) scope.onUpdate.length = 0;
219
- scope.parent = null;
220
- scope.isDestroyed = true;
221
- if (activeScope === scope) {
222
- activeScope = parentScope;
139
+ if ((_a2 = scope.parent) == null ? void 0 : _a2.children) {
140
+ scope.parent.children.delete(scope);
223
141
  }
142
+ if (scope.provides) {
143
+ scope.provides.clear();
144
+ scope.provides = null;
145
+ }
146
+ scope.onMount = null;
147
+ scope.onUpdate = null;
148
+ scope.children = null;
149
+ scope.parent = null;
224
150
  }
225
151
  function onCleanup(fn) {
226
152
  const scope = activeScope;
@@ -235,456 +161,449 @@ function onCleanup(fn) {
235
161
  }
236
162
  scope.cleanup.push(fn);
237
163
  }
238
-
239
- // src/constants.ts
240
- var EVENT_PREFIX = "on";
241
- var SPREAD_NAME = "_$spread$";
242
- var REF_KEY = "ref";
243
- var KEY_PROP = "key";
244
- var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
245
- var XLINK_NAMESPACE = "http://www.w3.org/2000/xlink";
246
- var XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/";
247
- var NORMAL_COMPONENT = /* @__PURE__ */ Symbol("Normal Component" );
248
- var FRAGMENT_COMPONENT = /* @__PURE__ */ Symbol("Fragment Component" );
249
- var PORTAL_COMPONENT = /* @__PURE__ */ Symbol("Portal Component" );
250
- var SUSPENSE_COMPONENT = /* @__PURE__ */ Symbol("Suspense Component" );
251
- var FOR_COMPONENT = /* @__PURE__ */ Symbol("For Component" );
252
- var MAX_KEY_LENGTH = 1e3;
253
- var componentKeyPrefixCache = /* @__PURE__ */ new WeakMap();
254
- function getComponentKey(type) {
255
- let prefix = componentKeyPrefixCache.get(type);
256
- if (!prefix) {
257
- const name = type.name || "anonymous";
258
- const hash = simpleHash(type.toString()).toString(36);
259
- prefix = `${name}_${hash}`;
260
- componentKeyPrefixCache.set(type, prefix);
261
- }
262
- return prefix;
263
- }
264
- function simpleHash(str) {
265
- let hash = 0;
266
- const len = str.length < 100 ? str.length : 100;
267
- for (let i = 0; i < len; i++) {
268
- hash = Math.trunc((hash << 5) - hash + str.charCodeAt(i));
269
- }
270
- return hash < 0 ? -hash : hash;
271
- }
272
- var symbolIdCounter = 0;
273
- function normalizeKey(key) {
274
- if (shared.isFalsy(key)) {
275
- return void 0;
276
- }
277
- if (shared.isString(key)) {
278
- if (key.length <= MAX_KEY_LENGTH) {
279
- return key;
280
- }
281
- {
282
- shared.warn(
283
- `[Key System] Key length exceeds ${MAX_KEY_LENGTH} characters. Consider using a shorter identifier.`
284
- );
164
+ function patchAttr(el, key, prev, next2) {
165
+ if (key === KEY_PROP) {
166
+ if (next2 == null) {
167
+ el.removeAttribute(key);
168
+ } else {
169
+ el.setAttribute(key, String(next2));
285
170
  }
286
- return `${key.slice(0, MAX_KEY_LENGTH - 10)}_${simpleHash(key).toString(36)}`;
171
+ return;
287
172
  }
288
- if (shared.isNumber(key)) {
173
+ if (key === SPREAD_NAME) {
174
+ const prevObj = shared.isObject(prev) ? prev : null;
175
+ const nextObj = shared.isObject(next2) ? next2 : null;
289
176
  {
290
- if (key !== key) {
291
- shared.warn("[Key System] NaN cannot be used as a key");
292
- return void 0;
177
+ if (next2 != null && !nextObj) {
178
+ shared.warn("spread attribute must be an object");
293
179
  }
294
- if (!Number.isFinite(key)) {
295
- shared.warn("[Key System] Infinity cannot be used as a key");
296
- return void 0;
180
+ }
181
+ if (prevObj) {
182
+ for (const attrKey in prevObj) {
183
+ if (attrKey === SPREAD_NAME) {
184
+ {
185
+ shared.warn("nested spread attributes are ignored");
186
+ }
187
+ continue;
188
+ }
189
+ if (!nextObj || !(attrKey in nextObj)) {
190
+ patchAttr(el, attrKey, prevObj[attrKey], null);
191
+ }
297
192
  }
298
193
  }
299
- return String(key);
300
- }
301
- if (shared.isSymbol(key)) {
302
- const globalKey = Symbol.keyFor(key);
303
- if (globalKey) {
304
- return `_s.${globalKey}`;
194
+ if (nextObj) {
195
+ for (const attrKey in nextObj) {
196
+ if (attrKey === SPREAD_NAME) {
197
+ {
198
+ shared.warn("nested spread attributes are ignored");
199
+ }
200
+ continue;
201
+ }
202
+ patchAttr(el, attrKey, prevObj == null ? void 0 : prevObj[attrKey], nextObj[attrKey]);
203
+ }
305
204
  }
306
- const desc = key.description;
307
- return desc ? `_s.${desc}` : `${symbolIdCounter++}`;
205
+ return;
308
206
  }
309
- return String(key);
310
- }
311
- var NODE_KEY_SYMBOL = /* @__PURE__ */ Symbol("essor.key");
312
- function setNodeKey(node, key) {
313
- if (isComponent(node)) {
207
+ const elementIsSVG = (el == null ? void 0 : el.namespaceURI) === SVG_NAMESPACE;
208
+ const isXlink = elementIsSVG && key.startsWith("xlink:");
209
+ const isXmlns = elementIsSVG && key.startsWith("xmlns:");
210
+ const isBoolean = shared.isSpecialBooleanAttr(key) || shared.isBooleanAttr(key);
211
+ if (prev === next2) {
314
212
  return;
315
213
  }
316
- if (!node || node.nodeType === Node.DOCUMENT_NODE) {
214
+ if (key.length > 2 && key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110) {
215
+ return;
216
+ }
217
+ const lowerKey = key.toLowerCase();
218
+ if (lowerKey === "innerhtml" || lowerKey === "srcdoc") {
317
219
  {
318
- shared.warn("[Key System] Cannot set key on invalid node");
220
+ shared.warn(`${key} updates are ignored by patchAttr`);
319
221
  }
320
222
  return;
321
223
  }
322
- const normalizedKey = normalizeKey(key);
323
- if (shared.isFalsy(normalizedKey)) {
324
- delete node[NODE_KEY_SYMBOL];
325
- } else {
326
- node[NODE_KEY_SYMBOL] = normalizedKey;
327
- }
328
- }
329
- function getNodeKey(node) {
330
- if (!node) return void 0;
331
- return isComponent(node) ? node.key : node[NODE_KEY_SYMBOL];
332
- }
333
-
334
- // src/utils/node.ts
335
- function normalizeNode(node) {
336
- if (shared.isHTMLElement(node)) {
337
- return node;
338
- }
339
- if (shared.isPrimitive(node)) {
340
- const textContent = shared.isFalsy(node) ? "" : String(node);
341
- return document.createTextNode(textContent);
342
- }
343
- return node;
344
- }
345
- function isSameNode(a, b) {
346
- const keyA = getNodeKey(a);
347
- const keyB = getNodeKey(b);
348
- if (keyA !== keyB) {
349
- return false;
350
- }
351
- const aIsComponent = isComponent(a);
352
- const bIsComponent = isComponent(b);
353
- if (aIsComponent && bIsComponent) {
354
- return a.component === b.component;
224
+ if (next2 == null) {
225
+ if (isXlink) {
226
+ el.removeAttributeNS(XLINK_NAMESPACE, key.slice(6));
227
+ } else if (isXmlns) {
228
+ const localName = key.slice(6);
229
+ el.removeAttributeNS(XMLNS_NAMESPACE, localName);
230
+ } else {
231
+ el.removeAttribute(key);
232
+ }
233
+ return;
355
234
  }
356
- if (aIsComponent !== bIsComponent) {
357
- return false;
235
+ if (isBoolean) {
236
+ if (shared.includeBooleanAttr(next2)) {
237
+ el.setAttribute(key, "");
238
+ } else {
239
+ el.removeAttribute(key);
240
+ }
241
+ return;
358
242
  }
359
- if (shared.isPrimitive(a) || shared.isPrimitive(b)) {
360
- return a === b;
243
+ const attrValue = shared.isSymbol(next2) ? String(next2) : next2;
244
+ const isUrlAttr = lowerKey === "href" || lowerKey === "src" || lowerKey === "xlink:href" || lowerKey === "action" || lowerKey === "formaction" || lowerKey === "poster";
245
+ if (isUrlAttr && shared.isString(attrValue)) {
246
+ const v = attrValue.trim().toLowerCase();
247
+ if (v.startsWith("javascript:") || v.startsWith("data:")) {
248
+ return;
249
+ }
361
250
  }
362
- const aNode = a;
363
- const bNode = b;
364
- if (aNode.nodeType !== bNode.nodeType) {
365
- return false;
251
+ if (isXlink) {
252
+ el.setAttributeNS(XLINK_NAMESPACE, key, String(attrValue));
253
+ return;
366
254
  }
367
- if (aNode.nodeType === Node.ELEMENT_NODE) {
368
- return aNode.tagName === bNode.tagName;
255
+ if (isXmlns) {
256
+ el.setAttributeNS(XMLNS_NAMESPACE, key, String(attrValue));
257
+ return;
369
258
  }
370
- return true;
371
- }
372
- function shallowCompare(a, b) {
373
- if (a === b) return true;
374
- if (shared.isNull(a) || shared.isNull(b)) return false;
375
- if (!shared.isObject(a) || !shared.isObject(b)) return false;
376
- if (shared.isArray(a) !== shared.isArray(b)) return false;
377
- const aRecord = a;
378
- const bRecord = b;
379
- const aKeys = Object.keys(aRecord);
380
- const bKeys = Object.keys(bRecord);
381
- if (aKeys.length !== bKeys.length) return false;
382
- for (const key of aKeys) {
383
- if (!(key in bRecord) || aRecord[key] !== bRecord[key]) {
384
- return false;
259
+ if (elementIsSVG) {
260
+ el.setAttribute(key, String(attrValue));
261
+ } else {
262
+ if (key in el) {
263
+ try {
264
+ el[key] = attrValue;
265
+ } catch (e) {
266
+ el.setAttribute(key, String(attrValue));
267
+ }
268
+ } else {
269
+ el.setAttribute(key, String(attrValue));
385
270
  }
386
271
  }
387
- return true;
388
272
  }
389
- function removeNode(node) {
390
- if (!node) return;
391
- if (isComponent(node)) {
392
- node.destroy();
273
+ function patchClass(el, prev, next2, isSVG = false) {
274
+ if (prev === next2) {
393
275
  return;
394
276
  }
395
- const element = node;
396
- if (element.parentElement) {
397
- element.remove();
277
+ const normalizedNext = normalizeClass(next2);
278
+ if (!normalizedNext) {
279
+ el.removeAttribute("class");
280
+ return;
398
281
  }
399
- }
400
- function insertNode(parent, child, before) {
401
- if (!parent || !child) return;
402
- if (isComponent(child)) {
403
- const beforeNode2 = isComponent(before) ? before.firstChild : before;
404
- child.mount(parent, beforeNode2);
282
+ const normalizedPrev = shared.isString(prev) ? prev : normalizeClass(prev);
283
+ if (normalizedPrev === normalizedNext) {
405
284
  return;
406
285
  }
407
- const beforeNode = isComponent(before) ? before.firstChild : before;
408
- if (beforeNode) {
409
- parent.insertBefore(child, beforeNode);
286
+ if (isSVG) {
287
+ el.setAttribute("class", normalizedNext);
410
288
  } else {
411
- parent.appendChild(child);
289
+ el.className = normalizedNext;
412
290
  }
413
291
  }
414
- function replaceNode(parent, newNode, oldNode) {
415
- if (!parent || !newNode || !oldNode || newNode === oldNode) return;
416
- const beforeNode = isComponent(oldNode) ? oldNode.beforeNode : oldNode.nextSibling;
417
- removeNode(oldNode);
418
- insertNode(parent, newNode, beforeNode);
419
- }
420
- function getFirstDOMNode(node) {
421
- if (!node) {
292
+ var normalizeClass = shared.normalizeClassName;
293
+ var importantRE = /\s*!important$/;
294
+ var prefixes = ["Webkit", "Moz", "ms"];
295
+ var prefixCache = {};
296
+ function patchStyle(el, prev, next2) {
297
+ const style = el.style;
298
+ if (next2 && shared.isString(next2)) {
299
+ if (prev !== next2) {
300
+ style.cssText = next2;
301
+ }
422
302
  return;
423
303
  }
424
- if (isComponent(node)) {
425
- return node.firstChild;
304
+ if (!next2) {
305
+ if (prev) {
306
+ el.removeAttribute("style");
307
+ }
308
+ return;
426
309
  }
427
- if (shared.isPrimitive(node)) {
428
- return void 0;
310
+ if (prev && !shared.isString(prev)) {
311
+ const prevObj = prev;
312
+ for (const key in prevObj) {
313
+ if (!next2 || next2[key] == null) {
314
+ setStyle(style, key, "");
315
+ }
316
+ }
317
+ } else if (prev && shared.isString(prev)) {
318
+ const declRE = /(?:^|;)\s*([a-z][a-z\d-]*)\s*:/gi;
319
+ let match;
320
+ while ((match = declRE.exec(prev)) !== null) {
321
+ const key = match[1].trim();
322
+ if (key && next2 && shared.isObject(next2) && next2[key] == null) {
323
+ setStyle(style, key, "");
324
+ }
325
+ }
326
+ }
327
+ if (next2 && !shared.isString(next2)) {
328
+ const nextObj = next2;
329
+ for (const key in nextObj) {
330
+ const value = nextObj[key];
331
+ if ((!prev || shared.isString(prev) || prev[key] !== value) && value != null) {
332
+ setStyle(style, key, value);
333
+ }
334
+ }
429
335
  }
430
- return node;
431
336
  }
432
- function transferKey(oldNode, newNode) {
433
- if (isComponent(oldNode) || isComponent(newNode)) {
337
+ function setStyle(style, name, val) {
338
+ if (shared.isArray(val)) {
339
+ for (const element of val) {
340
+ setStyle(style, name, element);
341
+ }
342
+ return;
343
+ }
344
+ if (val == null || val === "") {
345
+ val = "";
346
+ }
347
+ if (name.startsWith("--")) {
348
+ style.setProperty(name, val);
434
349
  return;
435
350
  }
436
- const oldKey = getNodeKey(oldNode);
437
- if (oldKey && !getNodeKey(newNode)) {
438
- setNodeKey(newNode, oldKey);
351
+ const prefixed = autoPrefix(style, name);
352
+ if (shared.isString(val) && importantRE.test(val)) {
353
+ style.setProperty(shared.camelCase(prefixed), val.replace(importantRE, ""), "important");
354
+ } else {
355
+ style[prefixed] = val;
439
356
  }
440
357
  }
441
- function patch(parent, oldNode, newNode) {
442
- if (newNode === oldNode) {
443
- return oldNode;
358
+ function autoPrefix(style, rawName) {
359
+ const cached = prefixCache[rawName];
360
+ if (cached) {
361
+ return cached;
362
+ }
363
+ let name = shared.camelCase(rawName);
364
+ if (name !== "filter" && name in style) {
365
+ return prefixCache[rawName] = name;
444
366
  }
445
- const oldIsElement = shared.isHTMLElement(oldNode);
446
- const newIsElement = shared.isHTMLElement(newNode);
447
- if (newIsElement && oldIsElement) {
448
- if (newNode.isEqualNode(oldNode)) {
449
- return oldNode;
367
+ name = shared.capitalize(name);
368
+ for (const prefix of prefixes) {
369
+ const prefixed = prefix + name;
370
+ if (prefixed in style) {
371
+ return prefixCache[rawName] = prefixed;
450
372
  }
451
- if (oldNode.tagName === newNode.tagName) {
452
- const oldAttrs = oldNode.attributes;
453
- const newAttrs = newNode.attributes;
454
- for (let i = oldAttrs.length - 1; i >= 0; i--) {
455
- const attrName = oldAttrs[i].name;
456
- if (!newNode.hasAttribute(attrName)) {
457
- oldNode.removeAttribute(attrName);
458
- }
459
- }
460
- for (let i = 0, len = newAttrs.length; i < len; i++) {
461
- const attr = newAttrs[i];
462
- if (oldNode.getAttribute(attr.name) !== attr.value) {
463
- oldNode.setAttribute(attr.name, attr.value);
464
- }
465
- }
466
- transferKey(oldNode, newNode);
467
- return oldNode;
373
+ }
374
+ return rawName;
375
+ }
376
+
377
+ // src/hydration.ts
378
+ var _hydrationKey = 0;
379
+ function getHydrationKey() {
380
+ return String(_hydrationKey++);
381
+ }
382
+ function resetHydrationKey() {
383
+ _hydrationKey = 0;
384
+ }
385
+ var _isHydrating = false;
386
+ function isHydrating() {
387
+ return _isHydrating;
388
+ }
389
+ var _registry = /* @__PURE__ */ new Map();
390
+ function gatherHydratable(root) {
391
+ const nodes = root.querySelectorAll("[data-hk]");
392
+ for (const node of nodes) {
393
+ const key = node.dataset.hk;
394
+ if (key != null && !_registry.has(key)) {
395
+ _registry.set(key, node);
468
396
  }
469
397
  }
470
- if (shared.isTextNode(oldNode) && shared.isTextNode(newNode)) {
471
- if (oldNode.textContent !== newNode.textContent) {
472
- oldNode.textContent = newNode.textContent;
398
+ }
399
+ var _teleportCallsiteAnchors = [];
400
+ var _teleportTargetStarts = /* @__PURE__ */ new Map();
401
+ function gatherTeleportAnchors() {
402
+ if (typeof document === "undefined") return;
403
+ const walker = document.createNodeIterator(document.body, NodeFilter.SHOW_COMMENT);
404
+ let node;
405
+ while (node = walker.nextNode()) {
406
+ const data = node.data;
407
+ if (data === "teleport-anchor") {
408
+ _teleportCallsiteAnchors.push(node);
409
+ } else if (data === "teleport-start") {
410
+ const parent = node.parentElement;
411
+ if (!parent) continue;
412
+ let bucket = _teleportTargetStarts.get(parent);
413
+ if (!bucket) {
414
+ bucket = [];
415
+ _teleportTargetStarts.set(parent, bucket);
416
+ }
417
+ bucket.push(node);
473
418
  }
474
- transferKey(oldNode, newNode);
475
- return oldNode;
476
419
  }
477
- const oldIsComponent = isComponent(oldNode);
478
- const newIsComponent = isComponent(newNode);
479
- if (oldIsComponent && newIsComponent) {
480
- if (oldNode.component === newNode.component) {
481
- return newNode.update(oldNode);
420
+ }
421
+ function consumeTeleportAnchor() {
422
+ var _a2;
423
+ return (_a2 = _teleportCallsiteAnchors.shift()) != null ? _a2 : null;
424
+ }
425
+ function consumeTeleportBlock(target) {
426
+ const bucket = _teleportTargetStarts.get(target);
427
+ const start = bucket == null ? void 0 : bucket.shift();
428
+ if (!start) return null;
429
+ const nodes = [];
430
+ let cursor = start.nextSibling;
431
+ while (cursor) {
432
+ if (cursor.nodeType === Node.COMMENT_NODE && cursor.data === "teleport-end") {
433
+ return { start, end: cursor, nodes };
482
434
  }
435
+ nodes.push(cursor);
436
+ cursor = cursor.nextSibling;
483
437
  }
484
- replaceNode(parent, newNode, oldNode);
485
- return newNode;
438
+ {
439
+ shared.warn("[Portal] hydration: orphaned <!--teleport-start--> without matching <!--teleport-end-->");
440
+ }
441
+ return null;
486
442
  }
487
- function patchChildren(parent, oldChildren, newChildren, anchor) {
488
- const oldLength = oldChildren.length;
489
- const newLength = newChildren.length;
490
- if (oldLength === 0 && newLength === 0) {
491
- return [];
443
+ function beginHydration(root) {
444
+ _isHydrating = true;
445
+ _hydrationKey = 0;
446
+ _registry.clear();
447
+ _teleportCallsiteAnchors.length = 0;
448
+ _teleportTargetStarts.clear();
449
+ gatherHydratable(root);
450
+ gatherTeleportAnchors();
451
+ }
452
+ function endHydration() {
453
+ _isHydrating = false;
454
+ _registry.clear();
455
+ _teleportCallsiteAnchors.length = 0;
456
+ _teleportTargetStarts.clear();
457
+ }
458
+ function getRenderedElement(html) {
459
+ if (!shared.isBrowser()) {
460
+ return () => {
461
+ throw new Error("[essor] getRenderedElement called in non-browser environment");
462
+ };
492
463
  }
464
+ let _csrFactory = null;
465
+ return () => {
466
+ if (!_isHydrating) {
467
+ if (!_csrFactory) _csrFactory = template(html);
468
+ return _csrFactory();
469
+ }
470
+ const key = getHydrationKey();
471
+ const node = _registry.get(key);
472
+ if (node) {
473
+ _registry.delete(key);
474
+ return node;
475
+ }
476
+ shared.warn(`[essor] hydration mismatch: no SSR element for key "${key}"`);
477
+ if (!_csrFactory) _csrFactory = template(html);
478
+ return _csrFactory();
479
+ };
480
+ }
481
+ function patchClassHydrate(el, prev, next2, isSVG) {
482
+ if (_isHydrating) return;
483
+ patchClass(el, prev, next2, isSVG);
484
+ }
485
+ function patchAttrHydrate(el, key, prev, next2) {
486
+ if (_isHydrating) return;
487
+ patchAttr(el, key, prev, next2);
488
+ }
489
+ function patchStyleHydrate(el, prev, next2) {
490
+ if (_isHydrating) return;
491
+ patchStyle(el, prev, next2);
492
+ }
493
+
494
+ // src/reconcile.ts
495
+ function resolveInsertAnchor(parent, candidate) {
496
+ return candidate && candidate.parentNode === parent ? candidate : null;
497
+ }
498
+ function reconcileArrays(parent, oldNodes, newNodes, anchor) {
499
+ const fallbackAnchor = resolveInsertAnchor(parent, anchor);
500
+ const oldLength = oldNodes.length;
501
+ const newLength = newNodes.length;
502
+ if (oldLength === 0 && newLength === 0) return newNodes;
493
503
  if (oldLength === 0) {
494
504
  for (let i = 0; i < newLength; i++) {
495
- insertNode(parent, newChildren[i], anchor);
505
+ insertNode(parent, newNodes[i], fallbackAnchor);
496
506
  }
497
- return newChildren;
507
+ return newNodes;
498
508
  }
499
509
  if (newLength === 0) {
500
510
  for (let i = 0; i < oldLength; i++) {
501
- removeNode(oldChildren[i]);
511
+ removeNode(oldNodes[i]);
502
512
  }
503
513
  return [];
504
514
  }
505
- if (oldLength === 1 && newLength === 1) {
506
- const oldNode = oldChildren[0];
507
- const newNode = newChildren[0];
508
- if (isSameNode(oldNode, newNode)) {
509
- patch(parent, oldNode, newNode);
510
- newChildren[0] = oldNode;
511
- } else {
512
- replaceNode(parent, newNode, oldNode);
513
- }
514
- return newChildren;
515
- }
516
- if (oldLength === 2 && newLength === 2) {
517
- const o0 = oldChildren[0];
518
- const o1 = oldChildren[1];
519
- const n0 = newChildren[0];
520
- const n1 = newChildren[1];
521
- if (isSameNode(o0, n0) && isSameNode(o1, n1)) {
522
- patch(parent, o0, n0);
523
- patch(parent, o1, n1);
524
- newChildren[0] = o0;
525
- newChildren[1] = o1;
526
- return newChildren;
527
- }
528
- if (isSameNode(o0, n1) && isSameNode(o1, n0)) {
529
- patch(parent, o0, n1);
530
- patch(parent, o1, n0);
531
- const dom1 = getFirstDOMNode(o1);
532
- const dom0 = getFirstDOMNode(o0);
533
- if (dom1 && dom0 && dom1.parentNode === parent) {
534
- parent.insertBefore(dom1, dom0);
535
- }
536
- newChildren[0] = o1;
537
- newChildren[1] = o0;
538
- return newChildren;
539
- }
540
- }
541
- return patchKeyedChildren(parent, oldChildren, newChildren, anchor);
542
- }
543
- function patchKeyedChildren(parent, oldChildren, newChildren, anchor) {
544
- let oldStartIdx = 0;
545
- let newStartIdx = 0;
546
- let oldEndIdx = oldChildren.length - 1;
547
- let newEndIdx = newChildren.length - 1;
548
- let oldStartNode = oldChildren[0];
549
- let oldEndNode = oldChildren[oldEndIdx];
550
- let newStartNode = newChildren[0];
551
- let newEndNode = newChildren[newEndIdx];
552
- while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
553
- if (!oldStartNode) {
554
- oldStartNode = oldChildren[++oldStartIdx];
555
- } else if (!oldEndNode) {
556
- oldEndNode = oldChildren[--oldEndIdx];
557
- } else if (isSameNode(oldStartNode, newStartNode)) {
558
- patch(parent, oldStartNode, newStartNode);
559
- newChildren[newStartIdx] = oldStartNode;
560
- oldStartNode = oldChildren[++oldStartIdx];
561
- newStartNode = newChildren[++newStartIdx];
515
+ let start = 0;
516
+ let oldEnd = oldLength - 1;
517
+ let newEnd = newLength - 1;
518
+ while (start <= oldEnd && start <= newEnd) {
519
+ if (oldNodes[start] === newNodes[start]) {
520
+ start++;
562
521
  } else {
563
522
  break;
564
523
  }
565
524
  }
566
- while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
567
- if (!oldStartNode) {
568
- oldStartNode = oldChildren[++oldStartIdx];
569
- } else if (!oldEndNode) {
570
- oldEndNode = oldChildren[--oldEndIdx];
571
- } else if (isSameNode(oldEndNode, newEndNode)) {
572
- patch(parent, oldEndNode, newEndNode);
573
- newChildren[newEndIdx] = oldEndNode;
574
- oldEndNode = oldChildren[--oldEndIdx];
575
- newEndNode = newChildren[--newEndIdx];
525
+ while (oldEnd >= start && newEnd >= start) {
526
+ if (oldNodes[oldEnd] === newNodes[newEnd]) {
527
+ oldEnd--;
528
+ newEnd--;
576
529
  } else {
577
530
  break;
578
531
  }
579
532
  }
580
- if (oldStartIdx > oldEndIdx) {
581
- if (newStartIdx <= newEndIdx) {
582
- const anchorNode = newEndIdx + 1 < newChildren.length ? getFirstDOMNode(newChildren[newEndIdx + 1]) : anchor;
583
- for (let i = newStartIdx; i <= newEndIdx; i++) {
584
- insertNode(parent, newChildren[i], anchorNode);
533
+ if (start > oldEnd) {
534
+ if (start <= newEnd) {
535
+ const nextPos = newEnd + 1;
536
+ const nextNode = resolveInsertAnchor(
537
+ parent,
538
+ nextPos < newLength ? newNodes[nextPos] : fallbackAnchor
539
+ );
540
+ for (let i = start; i <= newEnd; i++) {
541
+ insertNode(parent, newNodes[i], nextNode);
585
542
  }
586
543
  }
587
- } else if (newStartIdx > newEndIdx) {
588
- for (let i = oldStartIdx; i <= oldEndIdx; i++) {
589
- const node = oldChildren[i];
590
- if (node) {
591
- removeNode(node);
592
- }
544
+ } else if (start > newEnd) {
545
+ for (let i = start; i <= oldEnd; i++) {
546
+ removeNode(oldNodes[i]);
593
547
  }
594
548
  } else {
595
- patchUnknownSequence(
596
- parent,
597
- oldChildren,
598
- newChildren,
599
- oldStartIdx,
600
- oldEndIdx,
601
- newStartIdx,
602
- newEndIdx,
603
- anchor
604
- );
549
+ reconcileUnknownSequence(parent, oldNodes, newNodes, start, oldEnd, newEnd, fallbackAnchor);
605
550
  }
606
- return newChildren;
551
+ return newNodes;
607
552
  }
608
- function patchUnknownSequence(parent, oldChildren, newChildren, oldStartIdx, oldEndIdx, newStartIdx, newEndIdx, anchor) {
609
- const newLength = newEndIdx - newStartIdx + 1;
610
- let keyToNewIndexMap;
611
- for (let i = newStartIdx; i <= newEndIdx; i++) {
612
- const key = getNodeKey(newChildren[i]);
613
- if (key !== void 0) {
614
- if (!keyToNewIndexMap) {
615
- keyToNewIndexMap = /* @__PURE__ */ Object.create(null);
616
- }
617
- keyToNewIndexMap[key] = i;
618
- }
553
+ function reconcileUnknownSequence(parent, oldNodes, newNodes, start, oldEnd, newEnd, anchor) {
554
+ const newLength = newEnd - start + 1;
555
+ const newIndexMap = /* @__PURE__ */ new Map();
556
+ for (let i = start; i <= newEnd; i++) {
557
+ newIndexMap.set(newNodes[i], i);
619
558
  }
620
559
  const newIndexToOldIndexMap = new Int32Array(newLength);
560
+ newIndexToOldIndexMap.fill(0);
561
+ let patched = 0;
621
562
  let moved = false;
622
563
  let maxNewIndexSoFar = 0;
623
- let patched = 0;
624
- for (let i = oldStartIdx; i <= oldEndIdx; i++) {
625
- const oldNode = oldChildren[i];
626
- if (!oldNode) continue;
564
+ for (let i = start; i <= oldEnd; i++) {
565
+ const oldNode = oldNodes[i];
627
566
  if (patched >= newLength) {
628
567
  removeNode(oldNode);
629
568
  continue;
630
569
  }
631
- let newIndex;
632
- const oldKey = getNodeKey(oldNode);
633
- if (oldKey !== void 0 && keyToNewIndexMap && oldKey in keyToNewIndexMap) {
634
- newIndex = keyToNewIndexMap[oldKey];
635
- } else {
636
- for (let j2 = newStartIdx; j2 <= newEndIdx; j2++) {
637
- if (newIndexToOldIndexMap[j2 - newStartIdx] === 0 && oldKey === void 0 && getNodeKey(newChildren[j2]) === void 0 && isSameNode(oldNode, newChildren[j2])) {
638
- newIndex = j2;
639
- break;
640
- }
641
- }
642
- }
570
+ const newIndex = newIndexMap.get(oldNode);
643
571
  if (newIndex === void 0) {
644
572
  removeNode(oldNode);
645
573
  } else {
646
- newIndexToOldIndexMap[newIndex - newStartIdx] = i + 1;
574
+ newIndexToOldIndexMap[newIndex - start] = i + 1;
647
575
  if (newIndex >= maxNewIndexSoFar) {
648
576
  maxNewIndexSoFar = newIndex;
649
577
  } else {
650
578
  moved = true;
651
579
  }
652
- patch(parent, oldNode, newChildren[newIndex]);
653
- newChildren[newIndex] = oldNode;
654
580
  patched++;
655
581
  }
656
582
  }
657
583
  const increasingNewIndexSequence = moved ? getSequence(newIndexToOldIndexMap) : [];
658
584
  let j = increasingNewIndexSequence.length - 1;
659
- let cachedAnchor = anchor;
660
585
  for (let i = newLength - 1; i >= 0; i--) {
661
- const nextIndex = newStartIdx + i;
662
- const nextNode = newChildren[nextIndex];
586
+ const nextIndex = start + i;
587
+ const nextNode = newNodes[nextIndex];
588
+ const anchorNode = resolveInsertAnchor(
589
+ parent,
590
+ nextIndex + 1 < newNodes.length ? newNodes[nextIndex + 1] : anchor
591
+ );
663
592
  if (newIndexToOldIndexMap[i] === 0) {
664
- insertNode(parent, nextNode, cachedAnchor);
665
- cachedAnchor = getFirstDOMNode(nextNode) || cachedAnchor;
593
+ insertNode(parent, nextNode, anchorNode);
666
594
  } else if (moved) {
667
595
  if (j < 0 || i !== increasingNewIndexSequence[j]) {
668
- const domNode = getFirstDOMNode(nextNode);
669
- if (domNode && domNode.parentNode === parent) {
670
- insertNode(parent, domNode, cachedAnchor);
671
- }
672
- cachedAnchor = domNode || cachedAnchor;
596
+ insertNode(parent, nextNode, anchorNode);
673
597
  } else {
674
- cachedAnchor = getFirstDOMNode(nextNode) || cachedAnchor;
675
598
  j--;
676
599
  }
677
- } else {
678
- cachedAnchor = getFirstDOMNode(nextNode) || cachedAnchor;
679
600
  }
680
601
  }
681
602
  }
682
603
  function getSequence(arr) {
604
+ const p = new Int32Array(arr.length);
605
+ const result = [0];
683
606
  const len = arr.length;
684
- if (len === 0) return [];
685
- if (len === 1) return arr[0] !== 0 ? [0] : [];
686
- const result = [];
687
- const p = new Int32Array(len);
688
607
  let i;
689
608
  let j;
690
609
  let u;
@@ -694,7 +613,7 @@ function getSequence(arr) {
694
613
  const arrI = arr[i];
695
614
  if (arrI !== 0) {
696
615
  j = result[result.length - 1];
697
- if (result.length === 0 || arr[j] < arrI) {
616
+ if (arr[j] < arrI) {
698
617
  p[i] = j;
699
618
  result.push(i);
700
619
  continue;
@@ -726,167 +645,261 @@ function getSequence(arr) {
726
645
  return result;
727
646
  }
728
647
 
729
- // src/binding.ts
730
- function addEventListener(element, event, handler, options) {
731
- element.addEventListener(event, handler, options);
732
- onCleanup(() => {
733
- element.removeEventListener(event, handler, options);
734
- });
735
- }
736
- function bindElement(node, key, defaultValue, setter) {
737
- if (shared.isHtmlInputElement(node)) {
738
- bindInputElement(node, setter);
739
- } else if (shared.isHtmlSelectElement(node)) {
740
- bindSelectElement(node, setter);
741
- } else if (shared.isHtmlTextAreaElement(node)) {
742
- addEventListener(node, "input", () => {
743
- setter(node.value);
744
- });
648
+ // src/dom.ts
649
+ function removeNode(node) {
650
+ if (!node) return;
651
+ if (isComponent(node)) {
652
+ node.destroy();
653
+ } else {
654
+ const element = node;
655
+ if (element.parentNode) {
656
+ element.remove();
657
+ }
745
658
  }
746
659
  }
747
- function bindInputElement(node, setter) {
748
- switch (node.type) {
749
- case "checkbox":
750
- addEventListener(node, "change", () => {
751
- setter(Boolean(node.checked));
752
- });
753
- break;
754
- case "radio":
755
- addEventListener(node, "change", () => {
756
- setter(node.checked ? node.value : "");
757
- });
758
- break;
759
- case "file":
760
- addEventListener(node, "change", () => {
761
- setter(node.files);
762
- });
763
- break;
764
- case "number":
765
- case "range":
766
- addEventListener(node, "input", () => {
767
- setter(node.value || "");
768
- });
769
- break;
770
- case "date":
771
- case "datetime-local":
772
- case "month":
773
- case "time":
774
- case "week":
775
- addEventListener(node, "change", () => {
776
- setter(node.value || "");
777
- });
778
- break;
779
- default:
780
- addEventListener(node, "input", () => {
781
- setter(node.value);
782
- });
783
- break;
660
+ function insertNode(parent, child2, before) {
661
+ if (!parent || !child2) return;
662
+ const beforeNode = isComponent(before) ? before.firstChild : before;
663
+ if (isComponent(child2)) {
664
+ child2.mount(parent, beforeNode);
665
+ return;
784
666
  }
785
- }
786
- function bindSelectElement(node, setter) {
787
- addEventListener(node, "change", () => {
788
- if (node.multiple) {
789
- const values = Array.from(node.options).filter((option) => option.selected).map((option) => option.value);
790
- setter(values);
791
- } else {
792
- setter(node.value);
667
+ if (beforeNode) {
668
+ parent.insertBefore(child2, beforeNode);
669
+ } else {
670
+ {
671
+ if (!child2) {
672
+ shared.error("insertNode: child is not a Node", child2);
673
+ }
793
674
  }
794
- });
675
+ parent.appendChild(child2);
676
+ }
677
+ }
678
+ function normalizeNode(node) {
679
+ if (node instanceof Node) return node;
680
+ if (isComponent(node)) return node;
681
+ const t = typeof node;
682
+ if (node == null || t === "string" || t === "number" || t === "boolean" || t === "symbol") {
683
+ return document.createTextNode(node === false || node == null ? "" : String(node));
684
+ }
685
+ if (shared.isObject(node)) {
686
+ shared.warn(
687
+ "Rendering a plain object as a node is not recommended. The object will be converted to its string representation.",
688
+ node
689
+ );
690
+ }
691
+ return document.createTextNode(String(node));
795
692
  }
796
693
  function insert(parent, nodeFactory, before) {
797
694
  if (!parent) return;
695
+ const ownerScope = getActiveScope();
798
696
  let renderedNodes = [];
799
- const currentScope = getActiveScope();
800
- const cleanup = signals.effect(() => {
801
- const run = () => {
697
+ let isFirstRun = true;
698
+ const resolveNodes = (raw) => {
699
+ if (raw instanceof Node) return [raw];
700
+ if (isComponent(raw)) return [raw];
701
+ const t = typeof raw;
702
+ if (raw == null || t === "string" || t === "number" || t === "boolean") {
703
+ return [normalizeNode(raw)];
704
+ }
705
+ return shared.coerceArray(raw).map((item) => shared.isFunction(item) ? item() : item).flatMap((i) => i).map(normalizeNode);
706
+ };
707
+ const effectRunner = signals.effect(() => {
708
+ const executeUpdate = () => {
802
709
  const rawNodes = shared.isFunction(nodeFactory) ? nodeFactory() : nodeFactory;
803
- const nodes = shared.coerceArray(rawNodes).map((item) => shared.isFunction(item) ? item() : item).flatMap(normalizeNode);
804
- renderedNodes = patchChildren(parent, renderedNodes, nodes, before);
710
+ const nodes = resolveNodes(rawNodes);
711
+ if (isFirstRun && isHydrating() && nodes.every((node) => node instanceof Node && node.parentNode === parent)) {
712
+ renderedNodes = nodes;
713
+ isFirstRun = false;
714
+ return;
715
+ }
716
+ renderedNodes = reconcileArrays(parent, renderedNodes, nodes, before);
717
+ isFirstRun = false;
805
718
  };
806
- if (currentScope) {
807
- runWithScope(currentScope, run);
719
+ if (ownerScope && !ownerScope.isDestroyed) {
720
+ runWithScope(ownerScope, executeUpdate);
808
721
  } else {
809
- run();
722
+ executeUpdate();
810
723
  }
811
724
  });
812
725
  onCleanup(() => {
813
- cleanup();
814
- renderedNodes.forEach((node) => removeNode(node));
815
- renderedNodes.length = 0;
726
+ effectRunner.stop();
727
+ for (const node of renderedNodes) removeNode(node);
728
+ renderedNodes = [];
816
729
  });
817
730
  return renderedNodes;
818
731
  }
819
- function mapNodes(template2, indexes) {
820
- const len = indexes.length;
821
- const tree = new Array(len);
822
- const indexSet = new Set(indexes);
823
- let index = 1;
824
- let found = 0;
825
- const walk = (node) => {
826
- if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
827
- if (indexSet.has(index)) {
828
- tree[found++] = node;
829
- if (found === len) return true;
732
+ function child(node) {
733
+ return (node == null ? void 0 : node.firstChild) || null;
734
+ }
735
+ function next(node, step = 1) {
736
+ while (node && step > 0) {
737
+ node = node.nextSibling;
738
+ step--;
739
+ }
740
+ return node || null;
741
+ }
742
+ function nthChild(node, index) {
743
+ if (!node || index < 0) return null;
744
+ let current = node.firstChild;
745
+ while (current && index > 0) {
746
+ current = current.nextSibling;
747
+ index--;
748
+ }
749
+ return current || null;
750
+ }
751
+
752
+ // src/operations/event.ts
753
+ function addEvent(el, event, handler, options) {
754
+ if (!(options == null ? void 0 : options.delegate)) {
755
+ el.addEventListener(event, handler, options);
756
+ return () => el.removeEventListener(event, handler, options);
757
+ }
758
+ const selector = options.delegate;
759
+ const wrappedHandler = (e) => {
760
+ const target = e.target;
761
+ if (target.matches(selector) || target.closest(selector)) {
762
+ handler.call(el, e);
763
+ }
764
+ };
765
+ const _a2 = options, { delegate: _ } = _a2, nativeOptions = __objRest(_a2, ["delegate"]);
766
+ el.addEventListener(event, wrappedHandler, nativeOptions);
767
+ return () => {
768
+ el.removeEventListener(event, wrappedHandler, nativeOptions);
769
+ };
770
+ }
771
+ function registerScopedHook(scope, listKey, hook) {
772
+ let hookList = scope[listKey];
773
+ if (!hookList) {
774
+ hookList = [];
775
+ scope[listKey] = hookList;
776
+ }
777
+ hookList.push(hook);
778
+ }
779
+ function executeHooks(hooks, scopeId2, phase) {
780
+ const len = hooks.length;
781
+ if (len === 0) return;
782
+ let pending;
783
+ for (let i = 0; i < len; i++) {
784
+ try {
785
+ const result = hooks[i]();
786
+ if (shared.isPromise(result)) {
787
+ const safePromise = result.catch((error_) => {
788
+ if (true) {
789
+ shared.error(`Scope(${scopeId2}): Async ${phase} hook rejected:`, error_);
790
+ }
791
+ });
792
+ (pending || (pending = [])).push(safePromise);
793
+ }
794
+ } catch (error_) {
795
+ {
796
+ shared.error(`Scope(${scopeId2}): Error in ${phase} hook:`, error_);
830
797
  }
831
- index++;
832
798
  }
833
- let child = node.firstChild;
834
- while (child) {
835
- if (walk(child)) return true;
836
- child = child.nextSibling;
799
+ }
800
+ if (!pending) return;
801
+ return Promise.all(pending).then(() => {
802
+ });
803
+ }
804
+ function onMount(hook) {
805
+ const scope = getActiveScope();
806
+ if (!scope) {
807
+ shared.error("onMount() must be called within a scope");
808
+ return;
809
+ }
810
+ if (scope.isMounted) {
811
+ try {
812
+ const result = hook();
813
+ if (shared.isPromise(result)) {
814
+ result.catch((error_) => {
815
+ if (true) shared.error(`Scope(${scope.id}): Async mount hook rejected:`, error_);
816
+ });
817
+ }
818
+ } catch (error_) {
819
+ shared.error(`Scope(${scope.id}): Error in mount hook:`, error_);
837
820
  }
838
- return false;
839
- };
840
- walk(template2);
841
- return tree;
821
+ return;
822
+ }
823
+ registerScopedHook(scope, "onMount", hook);
824
+ }
825
+ function onUpdate(hook) {
826
+ const scope = getActiveScope();
827
+ if (!scope) {
828
+ shared.error("onUpdate() must be called within a scope");
829
+ return;
830
+ }
831
+ registerScopedHook(scope, "onUpdate", hook);
832
+ }
833
+ function onDestroy(hook) {
834
+ const scope = getActiveScope();
835
+ if (!scope) {
836
+ shared.error("onDestroy() must be called within a scope");
837
+ return;
838
+ }
839
+ registerScopedHook(scope, "onDestroy", hook);
840
+ }
841
+ function triggerMountHooks(scope) {
842
+ if (scope.isDestroyed) {
843
+ return;
844
+ }
845
+ if (!scope.onMount || scope.onMount.length === 0) {
846
+ scope.isMounted = true;
847
+ return;
848
+ }
849
+ const mountHooks = scope.onMount;
850
+ const result = runWithScope(scope, () => executeHooks(mountHooks, scope.id, "mount"));
851
+ mountHooks.length = 0;
852
+ scope.isMounted = true;
853
+ return result;
854
+ }
855
+ function triggerUpdateHooks(scope) {
856
+ if (scope.isDestroyed || !scope.onUpdate || scope.onUpdate.length === 0) return;
857
+ return runWithScope(scope, () => executeHooks(scope.onUpdate, scope.id, "update"));
842
858
  }
843
859
 
844
860
  // src/component.ts
861
+ function syncDescriptors(target, source, pruneMissing = false) {
862
+ const seen = pruneMissing ? /* @__PURE__ */ new Set() : null;
863
+ for (const key of Object.getOwnPropertyNames(source)) {
864
+ seen == null ? void 0 : seen.add(key);
865
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
866
+ }
867
+ if (seen) {
868
+ for (const key of Object.getOwnPropertyNames(target)) {
869
+ if (!seen.has(key)) delete target[key];
870
+ }
871
+ }
872
+ }
873
+ function readProp(source, key) {
874
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
875
+ return descriptor.get ? descriptor.get.call(source) : descriptor.value;
876
+ }
845
877
  var _a;
846
- _a = NORMAL_COMPONENT;
878
+ _a = "normal" /* NORMAL */;
847
879
  var Component = class {
848
880
  constructor(component, props = {}) {
849
881
  this.component = component;
850
882
  this.props = props;
851
- // Component rendered nodes (supports arrays and fragments)
852
- this.renderedNodes = [];
853
- // Component scope (unified context management)
883
+ this[_a] = true;
854
884
  this.scope = null;
855
- // Component parent node
856
- this.parentNode = void 0;
857
- // Component before node
858
- this.beforeNode = void 0;
859
- // Component props (reactive and snapshot)
860
- this.reactiveProps = {};
861
- this._propSnapshots = {};
862
- // Component lifecycle state
863
885
  this.state = 0 /* INITIAL */;
864
- // Parent scope captured at construction time for correct hierarchy
865
- this.parentScope = null;
866
- // @ts-ignore
867
- this[_a] = true;
868
- this.key = props.key ? normalizeKey(props.key) : getComponentKey(component);
869
- this.reactiveProps = signals.shallowReactive(__spreadValues({}, props));
886
+ this.beforeNode = void 0;
887
+ this.renderedNodes = [];
888
+ this.firstChild = void 0;
889
+ this.parentNode = void 0;
890
+ this.rootEventCleanups = [];
870
891
  this.parentScope = getActiveScope();
871
- for (const key in props) {
872
- const val = props[key];
873
- if (shared.isObject(val)) {
874
- this._propSnapshots[key] = shared.isArray(val) ? [...val] : __spreadValues({}, val);
875
- }
876
- }
877
- }
878
- get isConnected() {
879
- return this.state === 2 /* MOUNTED */;
880
- }
881
- get firstChild() {
882
- for (const node of this.renderedNodes) {
883
- const dom = getFirstDOMNode(node);
884
- if (dom) return dom;
885
- }
886
- return void 0;
892
+ const container = {};
893
+ syncDescriptors(container, props);
894
+ this.reactiveProps = signals.shallowReactive(container);
887
895
  }
896
+ /**
897
+ * Mount the component into `parentNode` (optionally before `beforeNode`).
898
+ * If already rendered, the existing DOM is re-inserted without re-running
899
+ * the component function.
900
+ */
888
901
  mount(parentNode, beforeNode) {
889
- var _a2, _b;
902
+ var _a2;
890
903
  this.parentNode = parentNode;
891
904
  this.beforeNode = beforeNode;
892
905
  this.state = 1 /* MOUNTING */;
@@ -897,177 +910,128 @@ var Component = class {
897
910
  this.state = 2 /* MOUNTED */;
898
911
  return this.renderedNodes;
899
912
  }
900
- const parentScope = (_a2 = this.parentScope) != null ? _a2 : getActiveScope();
901
- this.scope = createScope(parentScope);
902
- setActiveScope(this.scope);
903
- let result = this.component(this.reactiveProps);
904
- if (shared.isFunction(result)) {
905
- result = result(this.reactiveProps);
906
- }
907
- if (signals.isSignal(result) || signals.isComputed(result)) {
908
- result = result.value;
909
- }
910
- const renderedNodes = (_b = insert(parentNode, result, beforeNode)) != null ? _b : [];
913
+ const scope = createScope((_a2 = this.parentScope) != null ? _a2 : getActiveScope());
914
+ this.scope = scope;
915
+ const renderedNodes = runWithScope(scope, () => {
916
+ var _a3;
917
+ let result = this.component(this.reactiveProps);
918
+ if (shared.isFunction(result)) {
919
+ result = result(this.reactiveProps);
920
+ }
921
+ if (signals.isSignal(result) || signals.isComputed(result)) {
922
+ result = result.value;
923
+ }
924
+ return (_a3 = insert(parentNode, result, beforeNode)) != null ? _a3 : [];
925
+ });
911
926
  this.renderedNodes = renderedNodes;
912
- this.applyProps(this.props);
927
+ this.firstChild = renderedNodes[0];
928
+ this.syncSpecialProps(this.props);
913
929
  this.state = 2 /* MOUNTED */;
914
- triggerMountHooks(this.scope);
930
+ triggerMountHooks(scope);
915
931
  return this.renderedNodes;
916
932
  }
917
- update(prevNode) {
918
- if (this.key !== prevNode.key) {
919
- this.mount(prevNode.parentNode, prevNode.beforeNode);
920
- return this;
921
- }
922
- this.parentNode = prevNode.parentNode;
923
- this.beforeNode = prevNode.beforeNode;
924
- this.scope = prevNode.scope;
925
- this.parentScope = prevNode.parentScope;
926
- this.renderedNodes = prevNode.renderedNodes;
927
- this.state = prevNode.state;
928
- this.reactiveProps = prevNode.reactiveProps;
929
- this._propSnapshots = prevNode._propSnapshots;
930
- this._updateReactiveProps(this.props);
931
- if (!this.isConnected && this.parentNode) {
932
- this.mount(this.parentNode, this.beforeNode);
933
- return this;
934
- }
935
- if (this.scope) {
936
- setActiveScope(this.scope);
937
- this.applyProps(this.props);
938
- triggerUpdateHooks(this.scope);
939
- }
940
- return this;
941
- }
942
933
  /**
943
- * Update reactive props by comparing with current values
934
+ * Re-install props into the same `reactiveProps` container (preserving
935
+ * any closures already holding a reference to it) and re-apply
936
+ * refs/events against the current root element.
944
937
  */
945
- _updateReactiveProps(props) {
946
- for (const key in props) {
947
- if (key === "key") continue;
948
- const newValue = props[key];
949
- const oldValue = this.reactiveProps[key];
950
- if (newValue === oldValue && !this._propSnapshots[key]) continue;
951
- const isNewValueObject = shared.isObject(newValue);
952
- if (isNewValueObject) {
953
- const snapshot = this._propSnapshots[key];
954
- if (snapshot && shallowCompare(newValue, snapshot)) continue;
955
- const newSnapshot = shared.isArray(newValue) ? [...newValue] : __spreadValues({}, newValue);
956
- this.reactiveProps[key] = newSnapshot;
957
- this._propSnapshots[key] = newSnapshot;
958
- } else {
959
- if (shared.hasChanged(newValue, oldValue)) {
960
- this.reactiveProps[key] = newValue;
961
- if (this._propSnapshots[key]) {
962
- delete this._propSnapshots[key];
963
- }
964
- }
965
- }
966
- }
967
- }
968
- unwrapRenderResult(result) {
969
- if (shared.isFunction(result)) {
970
- result = result(this.reactiveProps);
971
- }
972
- if (signals.isSignal(result) || signals.isComputed(result)) {
973
- result = result.value;
974
- }
975
- if (isComponent(result)) {
976
- result = result.mount(this.parentNode, this.beforeNode);
977
- }
978
- if (shared.isPromise(result)) {
979
- result = result.then((r) => this.unwrapRenderResult(r));
980
- }
981
- return result;
982
- }
983
- forceUpdate() {
984
- if (this.state === 5 /* DESTROYED */ || !this.parentNode || !this.scope) {
985
- return;
986
- }
987
- const originalNodes = [...this.renderedNodes];
988
- try {
989
- runWithScope(this.scope, () => {
990
- let result = this.component(this.reactiveProps);
991
- if (shared.isFunction(result)) {
992
- result = result(this.reactiveProps);
993
- }
994
- if (signals.isSignal(result) || signals.isComputed(result)) {
995
- result = result.value;
996
- }
997
- const newNodes = shared.coerceArray(result);
998
- const anchor = this._getAnchorNode();
999
- if (!this.parentNode) return;
1000
- for (const node of this.renderedNodes) {
1001
- removeNode(node);
1002
- }
1003
- for (const node of newNodes) {
1004
- insertNode(this.parentNode, node, anchor);
1005
- }
1006
- this.renderedNodes = newNodes;
1007
- });
1008
- if (this.scope) {
1009
- triggerUpdateHooks(this.scope);
1010
- }
1011
- } catch (error8) {
1012
- this.renderedNodes = originalNodes;
1013
- throw error8;
1014
- }
938
+ update(props) {
939
+ this.props = props;
940
+ const scope = this.scope;
941
+ if (!scope || scope.isDestroyed) return;
942
+ syncDescriptors(
943
+ this.reactiveProps,
944
+ props != null ? props : {},
945
+ /* pruneMissing */
946
+ true
947
+ );
948
+ this.syncSpecialProps(props);
949
+ triggerUpdateHooks(scope);
1015
950
  }
1016
951
  /**
1017
- * Get anchor node for insertion
952
+ * Tear down and re-mount the component at its current insertion point.
953
+ * No-op if the component has never been mounted.
1018
954
  */
1019
- _getAnchorNode() {
1020
- if (this.beforeNode) return this.beforeNode;
1021
- if (this.renderedNodes.length > 0) {
1022
- const lastNode = this.renderedNodes[this.renderedNodes.length - 1];
1023
- const lastDom = getFirstDOMNode(lastNode);
1024
- if (lastDom) {
1025
- return lastDom.nextSibling;
1026
- }
1027
- }
1028
- return void 0;
955
+ forceUpdate() {
956
+ if (!this.parentNode) return;
957
+ const parent = this.parentNode;
958
+ const before = this.beforeNode;
959
+ this.destroy();
960
+ this.mount(parent, before);
1029
961
  }
1030
962
  /**
1031
- * Destroy component
963
+ * Dispose the scope, remove all rendered nodes, and clear bookkeeping.
964
+ * Idempotent: subsequent calls are no-ops.
1032
965
  */
1033
966
  destroy() {
1034
- if (this.state === 4 /* DESTROYING */ || this.state === 5 /* DESTROYED */) {
1035
- return;
1036
- }
1037
- this.state = 4 /* DESTROYING */;
1038
- for (const node of this.renderedNodes) {
1039
- removeNode(node);
1040
- }
1041
967
  const scope = this.scope;
1042
- if (scope) {
1043
- disposeScope(scope);
1044
- this.scope = null;
1045
- }
968
+ if (!scope || scope.isDestroyed) return;
969
+ this.scope = null;
970
+ this.releaseSpecialProps();
971
+ disposeScope(scope);
972
+ for (const node of this.renderedNodes) removeNode(node);
1046
973
  this.renderedNodes = [];
974
+ this.firstChild = void 0;
1047
975
  this.parentNode = void 0;
1048
- this.beforeNode = void 0;
1049
- this.parentScope = null;
1050
- this.reactiveProps = {};
1051
- this.props = {};
1052
- this.state = 5 /* DESTROYED */;
1053
976
  }
1054
- applyProps(props) {
977
+ /**
978
+ * Apply props that bind to the root DOM element rather than flowing into
979
+ * the component body: `ref` (signal/function) and `onXxx` event handlers.
980
+ * The render-facing `reactiveProps` already has those keys; here we just
981
+ * wire them to the actual DOM node.
982
+ */
983
+ syncSpecialProps(props) {
1055
984
  if (!props) return;
1056
- const firstElement = this.firstChild;
1057
- for (const [propName, propValue] of Object.entries(props)) {
1058
- if (shared.startsWith(propName, EVENT_PREFIX)) {
1059
- if (!firstElement || !shared.isHTMLElement(firstElement)) return;
1060
- const eventName = propName.slice(EVENT_PREFIX.length).toLowerCase();
1061
- addEventListener(firstElement, eventName, propValue);
1062
- } else if (propName === REF_KEY && signals.isSignal(propValue)) {
1063
- propValue.value = firstElement;
985
+ const root = this.firstChild;
986
+ if (!root) return;
987
+ this.releaseSpecialProps();
988
+ for (const key of Object.getOwnPropertyNames(props)) {
989
+ const value = readProp(props, key);
990
+ if (key === REF_KEY) {
991
+ this.rootRefCleanup = this.bindRootRef(value, root);
992
+ continue;
993
+ }
994
+ if (shared.isOn(key) && shared.isFunction(value)) {
995
+ const eventName = key.slice(2).toLowerCase();
996
+ this.rootEventCleanups.push(addEvent(root, eventName, value));
1064
997
  }
1065
998
  }
1066
- this.props = props;
999
+ }
1000
+ /**
1001
+ * Remove all listeners/ref bindings currently attached to the root element.
1002
+ */
1003
+ releaseSpecialProps() {
1004
+ for (const cleanup of this.rootEventCleanups) {
1005
+ cleanup();
1006
+ }
1007
+ this.rootEventCleanups.length = 0;
1008
+ if (this.rootRefCleanup) {
1009
+ this.rootRefCleanup();
1010
+ this.rootRefCleanup = void 0;
1011
+ }
1012
+ }
1013
+ /**
1014
+ * Bind the root ref prop and return a cleanup that restores the previous ref state.
1015
+ */
1016
+ bindRootRef(value, root) {
1017
+ if (shared.isFunction(value)) {
1018
+ value(root);
1019
+ return () => value(null);
1020
+ }
1021
+ if (signals.isSignal(value)) {
1022
+ const previousValue = value.value;
1023
+ value.value = root;
1024
+ return () => {
1025
+ if (value.value === root) {
1026
+ value.value = previousValue;
1027
+ }
1028
+ };
1029
+ }
1030
+ return void 0;
1067
1031
  }
1068
1032
  };
1069
1033
  function isComponent(node) {
1070
- return !!node && !!node[NORMAL_COMPONENT];
1034
+ return !!node && !!node["normal" /* NORMAL */];
1071
1035
  }
1072
1036
  function createComponent(componentFn, props) {
1073
1037
  if (isComponent(componentFn)) {
@@ -1093,17 +1057,72 @@ function template(html) {
1093
1057
  function createApp(component, target) {
1094
1058
  const container = shared.isString(target) ? document.querySelector(target) : target;
1095
1059
  if (!container) {
1096
- shared.error(`Target element not found: ${target}`);
1060
+ {
1061
+ shared.warn(`Target element not found: ${target}`);
1062
+ }
1097
1063
  return;
1098
1064
  }
1099
- const existingContext = container.innerHTML;
1100
- if (existingContext) {
1101
- shared.error(`Target element is not empty, it will be delete: ${target}`);
1065
+ const existingContent = container.innerHTML;
1066
+ if (existingContent) {
1067
+ {
1068
+ shared.warn(`Target element is not empty, it will be cleared: ${target}`);
1069
+ }
1102
1070
  container.innerHTML = "";
1103
1071
  }
1104
- const rootComponent = isComponent(component) ? component : createComponent(component);
1105
- rootComponent.mount(container);
1106
- return rootComponent;
1072
+ const scope = createScope();
1073
+ let rootNode;
1074
+ try {
1075
+ runWithScope(scope, () => {
1076
+ const mountedRoot = createComponent(component);
1077
+ if (isComponent(mountedRoot)) {
1078
+ rootNode = mountedRoot;
1079
+ insertNode(container, mountedRoot);
1080
+ }
1081
+ });
1082
+ } catch (error_) {
1083
+ disposeScope(scope);
1084
+ throw error_;
1085
+ }
1086
+ return {
1087
+ root: rootNode,
1088
+ unmount: () => {
1089
+ disposeScope(scope);
1090
+ rootNode == null ? void 0 : rootNode.destroy();
1091
+ }
1092
+ };
1093
+ }
1094
+ function hydrate(component, target) {
1095
+ const container = shared.isString(target) ? document.querySelector(target) : target;
1096
+ if (!container) {
1097
+ {
1098
+ shared.warn(`[essor] hydrate: target element not found: ${target}`);
1099
+ }
1100
+ return;
1101
+ }
1102
+ beginHydration(container);
1103
+ const scope = createScope();
1104
+ let rootNode;
1105
+ try {
1106
+ runWithScope(scope, () => {
1107
+ const mountedRoot = createComponent(component);
1108
+ if (isComponent(mountedRoot)) {
1109
+ rootNode = mountedRoot;
1110
+ insert(container, mountedRoot);
1111
+ }
1112
+ });
1113
+ } catch (error_) {
1114
+ disposeScope(scope);
1115
+ throw error_;
1116
+ } finally {
1117
+ endHydration();
1118
+ }
1119
+ return {
1120
+ root: rootNode,
1121
+ unmount: () => {
1122
+ disposeScope(scope);
1123
+ rootNode == null ? void 0 : rootNode.destroy();
1124
+ }
1125
+ };
1107
1126
  }
1108
1127
  function provide(key, value) {
1109
1128
  const scope = getActiveScope();
@@ -1129,68 +1148,66 @@ function inject(key, defaultValue) {
1129
1148
  let current = scope;
1130
1149
  while (current) {
1131
1150
  if (current.provides) {
1132
- const value = current.provides.get(key);
1133
- if (value) {
1134
- return value;
1151
+ if (current.provides.has(key)) {
1152
+ return current.provides.get(key);
1135
1153
  }
1136
1154
  }
1137
1155
  current = current.parent;
1138
1156
  }
1139
1157
  return defaultValue;
1140
1158
  }
1141
- function reTarget(event, value) {
1142
- Object.defineProperty(event, "target", {
1159
+ function reTargetEvent(e, value) {
1160
+ Object.defineProperty(e, "target", {
1143
1161
  configurable: true,
1144
1162
  value
1145
1163
  });
1146
1164
  }
1147
- function handleNodeEvent(node, event, key) {
1148
- const handler = node[`_$${key}`];
1149
- if (handler && shared.isFunction(handler) && !node.disabled) {
1150
- const data = node[`${key}Data`];
1151
- data ? handler.call(node, data, event) : handler.call(node, event);
1152
- if (event.cancelBubble) return false;
1153
- }
1154
- if (node.host && !shared.isString(node.host) && !node.host._$host && shared.isFunction(node.contains) && node.contains(event.target)) {
1155
- reTarget(event, node.host);
1156
- }
1157
- return true;
1158
- }
1159
- function walkUpTree(startNode, event, key) {
1160
- let node = startNode;
1161
- while (handleNodeEvent(node, event, key) && (node = node._$host || node.parentNode || node.host)) ;
1162
- return node;
1163
- }
1164
- function eventHandler(event) {
1165
- let node = event.target;
1166
- const key = `${event.type}`;
1167
- const oriTarget = event.target;
1168
- const oriCurrentTarget = event.currentTarget;
1169
- Object.defineProperty(event, "currentTarget", {
1165
+ function eventHandler(e) {
1166
+ let node = e.target;
1167
+ const key = e.type;
1168
+ const oriTarget = e.target;
1169
+ const oriCurrentTarget = e.currentTarget;
1170
+ const handleNode = () => {
1171
+ const handler = node[`_$${key}`];
1172
+ if (handler && shared.isFunction(handler) && !node.disabled) {
1173
+ const data = node[`${key}Data`];
1174
+ data ? handler.call(node, data, e) : handler.call(node, e);
1175
+ if (e.cancelBubble) return false;
1176
+ }
1177
+ if (node.host && !shared.isString(node.host) && !node.host._$host && shared.isFunction(node.contains) && node.contains(e.target)) {
1178
+ reTargetEvent(e, node.host);
1179
+ }
1180
+ return true;
1181
+ };
1182
+ const walkUpTree = () => {
1183
+ while (handleNode() && (node = node._$host || node.parentNode || node.host)) ;
1184
+ };
1185
+ Object.defineProperty(e, "currentTarget", {
1170
1186
  configurable: true,
1187
+ /**
1188
+ * Returns the current delegated target for the event.
1189
+ */
1171
1190
  get() {
1172
1191
  return node || document;
1173
1192
  }
1174
1193
  });
1175
- if (event.composedPath) {
1176
- const path = event.composedPath();
1177
- reTarget(event, path[0]);
1194
+ if (e.composedPath) {
1195
+ const path = e.composedPath();
1196
+ reTargetEvent(e, path[0]);
1178
1197
  for (let i = 0; i < path.length - 2; i++) {
1179
1198
  node = path[i];
1180
- if (!handleNodeEvent(node, event, key)) break;
1199
+ if (!handleNode()) break;
1181
1200
  if (node._$host) {
1182
1201
  node = node._$host;
1183
- node = walkUpTree(node, event, key);
1202
+ walkUpTree();
1184
1203
  break;
1185
1204
  }
1186
1205
  if (node.parentNode === oriCurrentTarget) {
1187
1206
  break;
1188
1207
  }
1189
1208
  }
1190
- } else {
1191
- node = walkUpTree(node, event, key);
1192
- }
1193
- reTarget(event, oriTarget);
1209
+ } else walkUpTree();
1210
+ reTargetEvent(e, oriTarget);
1194
1211
  }
1195
1212
  var $EVENTS = /* @__PURE__ */ Symbol("_$EVENTS");
1196
1213
  function delegateEvents(eventNames, document2 = window.document) {
@@ -1203,424 +1220,344 @@ function delegateEvents(eventNames, document2 = window.document) {
1203
1220
  }
1204
1221
  }
1205
1222
  }
1206
-
1207
- // src/utils/props.ts
1208
- function omitProps(target, keys) {
1209
- const excludeSet = new Set(keys);
1210
- return new Proxy(target, {
1211
- // Intercept property reads
1212
- get(obj, prop) {
1213
- if (excludeSet.has(prop)) {
1214
- return void 0;
1215
- }
1216
- return Reflect.get(obj, prop);
1217
- },
1218
- // Intercept property enumeration (for...in, Object.keys, etc.)
1219
- ownKeys(obj) {
1220
- return Reflect.ownKeys(obj).filter((key) => !excludeSet.has(key));
1221
- },
1222
- // Intercept property descriptor retrieval
1223
- getOwnPropertyDescriptor(obj, prop) {
1224
- if (excludeSet.has(prop)) {
1225
- return void 0;
1226
- }
1227
- return Reflect.getOwnPropertyDescriptor(obj, prop);
1228
- },
1229
- // Intercept the 'in' operator
1230
- has(obj, prop) {
1231
- if (excludeSet.has(prop)) {
1232
- return false;
1233
- }
1234
- return Reflect.has(obj, prop);
1235
- }
1236
- });
1237
- }
1238
-
1239
- // src/hydration/shared.ts
1240
- var isHydrationActive = false;
1241
- function startHydration() {
1242
- isHydrationActive = true;
1243
- }
1244
- function endHydration() {
1245
- isHydrationActive = false;
1246
- }
1247
- function isHydrating() {
1248
- return isHydrationActive;
1249
- }
1250
- var hydrationCounter = 0;
1251
- function getHydrationKey() {
1252
- return `${hydrationCounter++}`;
1253
- }
1254
- function resetHydrationKey() {
1255
- hydrationCounter = 0;
1256
- }
1257
-
1258
- // src/hydration/hydration.ts
1259
- var DATA_IDX_REGEX = /^\d+-\d+$/;
1260
- function getRenderedElement(temp) {
1261
- return () => {
1262
- if (!shared.isBrowser()) {
1263
- return null;
1264
- }
1265
- const key = getHydrationKey();
1266
- const node = document.querySelector(`[data-hk="${key}"]`);
1267
- if (node) {
1268
- return node;
1269
- }
1270
- return template(temp)();
1271
- };
1272
- }
1273
- function mapSSRNodes(templateEl, idx) {
1274
- const hk = templateEl.dataset.hk;
1275
- if (!hk) {
1276
- return mapNodes(templateEl, idx);
1277
- }
1278
- const nodesList = [];
1279
- const elements = templateEl.querySelectorAll(`[data-idx^="${hk}"]`);
1280
- if (elements.length > 0) {
1281
- nodesList.push(
1282
- ...Array.from(elements).filter((item) => {
1283
- const idxAttr = item.dataset.idx;
1284
- return idxAttr !== null && DATA_IDX_REGEX.test(idxAttr);
1285
- }).map((item) => {
1286
- const idxAttr = item.dataset.idx || "";
1287
- const [hkPart, idxPart] = idxAttr.split("-");
1288
- return {
1289
- hk: hkPart,
1290
- idx: idxPart,
1291
- node: item
1292
- };
1293
- })
1294
- );
1295
- }
1296
- const commentNodes = [];
1297
- const walkNodes = (node) => {
1298
- if (node.nodeType === Node.COMMENT_NODE && node.textContent && DATA_IDX_REGEX.test(node.textContent)) {
1299
- const [hkPart, idxPart] = node.textContent.split("-");
1300
- commentNodes.push({
1301
- hk: hkPart,
1302
- idx: idxPart,
1303
- node
1304
- });
1305
- }
1306
- let child = node.firstChild;
1307
- while (child) {
1308
- walkNodes(child);
1309
- child = child.nextSibling;
1310
- }
1311
- };
1312
- walkNodes(templateEl);
1313
- nodesList.push(...commentNodes);
1314
- const nodes = [templateEl];
1315
- idx.forEach((indexValue) => {
1316
- const node = nodesList.find((item) => item.idx === String(indexValue));
1317
- if (node) {
1318
- nodes.push(node.node);
1319
- }
1320
- });
1321
- return nodes;
1322
- }
1323
- function hydrate(component, container) {
1324
- startHydration();
1325
- resetHydrationKey();
1326
- try {
1327
- const rootElement = shared.isString(container) ? document.querySelector(container) : container;
1328
- if (!rootElement) {
1329
- shared.error("Hydration error: Root element not found");
1330
- return void 0;
1331
- }
1332
- const rootComponent = createComponent(component);
1333
- rootComponent.mount(rootElement);
1334
- endHydration();
1335
- return rootComponent;
1336
- } catch (error_) {
1337
- shared.error("Hydration error:", error_);
1338
- endHydration();
1339
- return void 0;
1340
- }
1341
- }
1342
- function patchClass(el, prev, next, isSVG = false) {
1343
- if (prev === next) {
1344
- return;
1345
- }
1346
- if (isHydrating()) {
1347
- return;
1348
- }
1349
- const normalizedNext = normalizeClass(next);
1350
- const normalizedPrev = normalizeClass(prev);
1351
- if (normalizedNext && normalizedPrev === normalizedNext) {
1352
- return;
1353
- }
1354
- if (!normalizedNext) {
1355
- el.removeAttribute("class");
1356
- } else if (isSVG) {
1357
- el.setAttribute("class", normalizedNext);
1358
- } else {
1359
- el.className = normalizedNext;
1360
- }
1361
- }
1362
- function normalizeClass(value) {
1363
- return shared.normalizeClassName(value);
1364
- }
1365
- var importantRE = /\s*!important$/;
1366
- var prefixes = ["Webkit", "Moz", "ms"];
1367
- var prefixCache = {};
1368
- function patchStyle(el, prev, next) {
1369
- const style = el.style;
1370
- const isCssString = shared.isString(next);
1371
- if (isHydrating()) {
1372
- return;
1373
- }
1374
- if (next && isCssString) {
1375
- if (prev !== next) {
1376
- style.cssText = next;
1377
- }
1378
- return;
1379
- }
1380
- if (!next) {
1381
- if (prev) {
1382
- el.removeAttribute("style");
1383
- }
1384
- return;
1385
- }
1386
- if (prev && !shared.isString(prev)) {
1387
- for (const key in prev) {
1388
- if (!next || next[key] == null) {
1389
- setStyle(style, key, "");
1390
- }
1391
- }
1392
- } else if (prev && shared.isString(prev)) {
1393
- const prevStyles = prev.split(";");
1394
- for (const stylePart of prevStyles) {
1395
- const colonIndex = stylePart.indexOf(":");
1396
- if (colonIndex > 0) {
1397
- const key = stylePart.slice(0, colonIndex).trim();
1398
- if (next && shared.isObject(next) && next[key] == null) {
1399
- setStyle(style, key, "");
1400
- }
1401
- }
1402
- }
1403
- }
1404
- if (next && !shared.isString(next)) {
1405
- for (const key in next) {
1406
- const value = next[key];
1407
- if ((!prev || shared.isString(prev) || prev[key] !== value) && value != null) {
1408
- setStyle(style, key, value);
1409
- }
1410
- }
1411
- }
1412
- }
1413
- function setStyle(style, name, val) {
1414
- if (shared.isArray(val)) {
1415
- for (const element of val) {
1416
- setStyle(style, name, element);
1223
+ function clearDelegatedEvents(document2 = window.document) {
1224
+ const docWithEvents = document2;
1225
+ const eventSet = docWithEvents[$EVENTS];
1226
+ if (eventSet) {
1227
+ for (const name of eventSet.keys()) {
1228
+ document2.removeEventListener(name, eventHandler);
1417
1229
  }
1418
- return;
1419
- }
1420
- if (val == null || val === "") {
1421
- val = "";
1422
- }
1423
- if (name.startsWith("--")) {
1424
- style.setProperty(name, val);
1425
- return;
1426
- }
1427
- const prefixed = autoPrefix(style, name);
1428
- if (shared.isString(val) && importantRE.test(val)) {
1429
- style.setProperty(shared.camelCase(prefixed), val.replace(importantRE, ""), "important");
1430
- } else {
1431
- style[prefixed] = val;
1230
+ delete docWithEvents[$EVENTS];
1432
1231
  }
1433
1232
  }
1434
- function autoPrefix(style, rawName) {
1435
- const cached = prefixCache[rawName];
1436
- if (cached) {
1437
- return cached;
1438
- }
1439
- let name = shared.camelCase(rawName);
1440
- if (name !== "filter" && name in style) {
1441
- return prefixCache[rawName] = name;
1442
- }
1443
- name = shared.capitalize(name);
1444
- for (const prefix of prefixes) {
1445
- const prefixed = prefix + name;
1446
- if (prefixed in style) {
1447
- return prefixCache[rawName] = prefixed;
1448
- }
1233
+ function addEventListener(element, event, handler, options) {
1234
+ const cleanup = addEvent(element, event, handler, options);
1235
+ if (getActiveScope()) {
1236
+ onCleanup(cleanup);
1449
1237
  }
1450
- return rawName;
1451
1238
  }
1452
- function patchAttr(el, key, prev, next) {
1453
- if (key === KEY_PROP) {
1454
- if (next == null) {
1455
- setNodeKey(el, void 0);
1456
- } else {
1457
- setNodeKey(el, String(next));
1458
- }
1459
- return;
1460
- }
1461
- if (key === SPREAD_NAME) {
1462
- {
1463
- if (!shared.isObject(next)) {
1464
- shared.warn("spread attribute must be an object");
1465
- }
1466
- }
1467
- Object.keys(next).forEach((k) => {
1468
- patchAttr(el, k, prev == null ? void 0 : prev[k], next == null ? void 0 : next[k]);
1469
- });
1470
- return;
1471
- }
1472
- if (isHydrating()) {
1473
- return;
1474
- }
1475
- const elementIsSVG = (el == null ? void 0 : el.namespaceURI) === SVG_NAMESPACE;
1476
- const isXlink = elementIsSVG && key.startsWith("xlink:");
1477
- const isXmlns = elementIsSVG && key.startsWith("xmlns:");
1478
- const isBoolean = shared.isSpecialBooleanAttr(key) || shared.isBooleanAttr(key);
1479
- if (prev === next) {
1480
- return;
1239
+
1240
+ // src/binding.ts
1241
+ function writeValue(el, v) {
1242
+ const target = el;
1243
+ const next2 = v == null ? "" : String(v);
1244
+ if (target.value !== next2) target.value = next2;
1245
+ }
1246
+ var CHECKBOX = {
1247
+ event: "change",
1248
+ forceChange: true,
1249
+ read: (el) => el.checked,
1250
+ write(el, v) {
1251
+ const e = el;
1252
+ const next2 = Boolean(v);
1253
+ if (e.checked !== next2) e.checked = next2;
1481
1254
  }
1482
- const lowerKey = key.toLowerCase();
1483
- if (lowerKey.length > 2 && lowerKey.charCodeAt(0) === 111 && lowerKey.charCodeAt(1) === 110) {
1484
- return;
1255
+ };
1256
+ var RADIO = {
1257
+ event: "change",
1258
+ forceChange: true,
1259
+ read(el) {
1260
+ const e = el;
1261
+ return e.checked ? e.value : "";
1262
+ },
1263
+ write(el, v) {
1264
+ const e = el;
1265
+ const next2 = String(v) === e.value;
1266
+ if (e.checked !== next2) e.checked = next2;
1485
1267
  }
1486
- if (lowerKey === "innerhtml") {
1487
- return;
1268
+ };
1269
+ var FILE = {
1270
+ event: "change",
1271
+ forceChange: true,
1272
+ read: (el) => el.files,
1273
+ write() {
1488
1274
  }
1489
- if (next == null) {
1490
- if (isXlink) {
1491
- el.removeAttributeNS(XLINK_NAMESPACE, key.slice(6));
1492
- } else if (isXmlns) {
1493
- const localName = key.slice(6);
1494
- el.removeAttributeNS(XMLNS_NAMESPACE, localName);
1275
+ // browsers forbid programmatic writes to file inputs
1276
+ };
1277
+ var TEXT = {
1278
+ event: "input",
1279
+ ime: true,
1280
+ read: (el) => el.value,
1281
+ write: writeValue
1282
+ };
1283
+ var TEXTAREA = {
1284
+ event: "input",
1285
+ ime: true,
1286
+ read: (el) => el.value,
1287
+ write: writeValue
1288
+ };
1289
+ var SELECT = {
1290
+ event: "change",
1291
+ forceChange: true,
1292
+ read(el) {
1293
+ const s = el;
1294
+ return s.multiple ? Array.from(s.selectedOptions, (o) => o.value) : s.value;
1295
+ },
1296
+ write(el, v) {
1297
+ const s = el;
1298
+ if (s.multiple) {
1299
+ const selected = new Set((Array.isArray(v) ? v : []).map(String));
1300
+ for (const opt of Array.from(s.options)) opt.selected = selected.has(opt.value);
1495
1301
  } else {
1496
- el.removeAttribute(key);
1302
+ writeValue(el, v);
1497
1303
  }
1498
- return;
1499
1304
  }
1500
- if (isXlink) {
1501
- el.setAttributeNS(XLINK_NAMESPACE, key, String(next));
1502
- return;
1305
+ };
1306
+ function resolve(node, prop) {
1307
+ switch (node.nodeName) {
1308
+ case "INPUT":
1309
+ if (prop === "checked") return node.type === "radio" ? RADIO : CHECKBOX;
1310
+ if (prop === "files") return FILE;
1311
+ return TEXT;
1312
+ case "SELECT":
1313
+ return SELECT;
1314
+ case "TEXTAREA":
1315
+ return TEXTAREA;
1316
+ default:
1317
+ return {
1318
+ event: "input",
1319
+ read: (el) => el[prop],
1320
+ write(el, v) {
1321
+ el[prop] = v;
1322
+ }
1323
+ };
1503
1324
  }
1504
- if (isXmlns) {
1505
- el.setAttributeNS(XMLNS_NAMESPACE, key, String(next));
1506
- return;
1325
+ }
1326
+ function applyModifiers(v, trim, toNum) {
1327
+ if (!shared.isString(v)) return v;
1328
+ let s = v;
1329
+ if (trim) s = s.trim();
1330
+ if (toNum && s !== "") {
1331
+ const n = Number(s);
1332
+ if (!Number.isNaN(n)) return n;
1507
1333
  }
1508
- if (isBoolean) {
1509
- if (shared.includeBooleanAttr(next)) {
1510
- el.setAttribute(key, "");
1511
- } else {
1512
- el.removeAttribute(key);
1513
- }
1514
- return;
1334
+ return s;
1335
+ }
1336
+ function isFocused(el) {
1337
+ const root = el.getRootNode();
1338
+ return (root instanceof Document || root instanceof ShadowRoot) && root.activeElement === el;
1339
+ }
1340
+ function bindElement(node, prop, getter, setter, modifiers = {}) {
1341
+ if (!node) return;
1342
+ const { event, read, write, forceChange, ime } = resolve(node, prop);
1343
+ const trim = modifiers.trim === true;
1344
+ const toNum = modifiers.number === true;
1345
+ const lazy = modifiers.lazy === true;
1346
+ const shouldCast = (trim || toNum) && prop !== "files";
1347
+ const getModel = shared.isFunction(getter) ? getter : () => getter;
1348
+ const cast = shouldCast ? (v) => applyModifiers(v, trim, toNum) : (v) => v;
1349
+ let composing = false;
1350
+ const eventName = lazy || forceChange ? "change" : event;
1351
+ const syncToModel = () => {
1352
+ if (composing) return;
1353
+ const raw = read(node);
1354
+ if (raw === void 0) return;
1355
+ const next2 = cast(raw);
1356
+ if (!Object.is(getModel(), next2)) setter(next2);
1357
+ };
1358
+ addEventListener(node, eventName, syncToModel);
1359
+ if (!lazy && shouldCast && eventName !== "change") {
1360
+ addEventListener(node, "change", () => write(node, cast(read(node))));
1515
1361
  }
1516
- const attrValue = shared.isSymbol(next) ? String(next) : next;
1517
- const isUrlAttr = lowerKey === "href" || lowerKey === "src" || lowerKey === "xlink:href";
1518
- if (isUrlAttr && shared.isString(attrValue)) {
1519
- const v = attrValue.trim().toLowerCase();
1520
- if (v.startsWith("javascript:") || v.startsWith("data:")) {
1521
- return;
1522
- }
1362
+ if (ime && !lazy) {
1363
+ addEventListener(node, "compositionstart", () => {
1364
+ composing = true;
1365
+ });
1366
+ addEventListener(node, "compositionend", () => {
1367
+ if (!composing) return;
1368
+ composing = false;
1369
+ syncToModel();
1370
+ });
1523
1371
  }
1524
- if (elementIsSVG) {
1525
- el.setAttribute(key, String(attrValue));
1526
- } else {
1527
- if (key in el) {
1528
- try {
1529
- el[key] = attrValue;
1530
- } catch (e) {
1531
- el.setAttribute(key, String(attrValue));
1532
- }
1533
- } else {
1534
- el.setAttribute(key, String(attrValue));
1372
+ const runner = signals.effect(() => {
1373
+ const value = getModel();
1374
+ if (ime && !lazy && isFocused(node)) {
1375
+ if (composing) return;
1376
+ if (Object.is(cast(read(node)), value)) return;
1535
1377
  }
1378
+ write(node, value);
1379
+ });
1380
+ if (getActiveScope()) {
1381
+ onCleanup(() => runner.stop());
1536
1382
  }
1537
1383
  }
1538
1384
 
1539
- // src/operations/event.ts
1540
- function addEvent(el, event, handler, options) {
1541
- if (!(options == null ? void 0 : options.delegate)) {
1542
- el.addEventListener(event, handler, options);
1543
- return () => el.removeEventListener(event, handler, options);
1544
- }
1545
- const selector = options.delegate;
1546
- const wrappedHandler = (e) => {
1547
- const target = e.target;
1548
- if (target.matches(selector) || target.closest(selector)) {
1549
- handler.call(el, e);
1385
+ // src/utils.ts
1386
+ function omitProps(target, keys) {
1387
+ const excludeSet = new Set(keys);
1388
+ return new Proxy(target, {
1389
+ /**
1390
+ * Returns a property unless it is excluded by the proxy.
1391
+ */
1392
+ get(obj, prop) {
1393
+ if (excludeSet.has(prop)) {
1394
+ return void 0;
1395
+ }
1396
+ return Reflect.get(obj, prop);
1397
+ },
1398
+ /**
1399
+ * Returns the enumerable keys that are not excluded from the proxy.
1400
+ */
1401
+ ownKeys(obj) {
1402
+ return Reflect.ownKeys(obj).filter((key) => !excludeSet.has(key));
1403
+ },
1404
+ /**
1405
+ * Returns the property descriptor unless the key is excluded.
1406
+ */
1407
+ getOwnPropertyDescriptor(obj, prop) {
1408
+ if (excludeSet.has(prop)) {
1409
+ return void 0;
1410
+ }
1411
+ return Reflect.getOwnPropertyDescriptor(obj, prop);
1412
+ },
1413
+ /**
1414
+ * Returns whether the requested value exists.
1415
+ */
1416
+ has(obj, prop) {
1417
+ if (excludeSet.has(prop)) {
1418
+ return false;
1419
+ }
1420
+ return Reflect.has(obj, prop);
1550
1421
  }
1551
- };
1552
- const cleanOptions = __spreadValues({}, options);
1553
- cleanOptions.delegate = void 0;
1554
- el.addEventListener(event, wrappedHandler, cleanOptions);
1555
- return () => {
1556
- el.removeEventListener(event, wrappedHandler, cleanOptions);
1557
- };
1422
+ });
1558
1423
  }
1424
+
1425
+ // src/components/Fragment.ts
1559
1426
  function Fragment(props) {
1560
- {
1561
- if (!props) {
1562
- shared.error("Fragment component requires props");
1563
- return null;
1564
- }
1565
- }
1566
- if (!(props == null ? void 0 : props.children)) {
1567
- shared.error("Fragment component requires children");
1568
- return null;
1569
- }
1570
- const { children } = props;
1571
- return children;
1427
+ if (!props || props.children == null) return null;
1428
+ return props.children;
1572
1429
  }
1573
1430
  Fragment[FRAGMENT_COMPONENT] = true;
1574
1431
  function isFragment(node) {
1575
1432
  return !!node && !!node[FRAGMENT_COMPONENT];
1576
1433
  }
1434
+ function resolveTarget(props) {
1435
+ const raw = shared.isFunction(props.target) ? props.target() : props.target;
1436
+ if (raw == null) return null;
1437
+ if (shared.isString(raw)) return document.querySelector(raw);
1438
+ return raw;
1439
+ }
1440
+ function evalDisabled(props) {
1441
+ return shared.isFunction(props.disabled) ? !!props.disabled() : !!props.disabled;
1442
+ }
1577
1443
  function Portal(props) {
1444
+ if (isHydrating()) {
1445
+ const adopted = tryHydratePortal(props);
1446
+ if (adopted) return adopted;
1447
+ }
1578
1448
  const placeholder = document.createComment("portal");
1579
1449
  placeholder[PORTAL_COMPONENT] = true;
1580
- const children = props.children;
1581
- if (children) {
1582
- const childArray = shared.isArray(children) ? children : [children];
1583
- const nodes = [];
1584
- onMount(() => {
1585
- const targetElement = shared.isString(props.target) ? document.querySelector(props.target) : props.target;
1586
- if (!targetElement) {
1587
- if (true) {
1588
- shared.warn(`[Portal] Target element not found: ${props.target}`);
1589
- }
1590
- return;
1450
+ const { children } = props;
1451
+ if (children == null) return placeholder;
1452
+ const ownerScope = getActiveScope();
1453
+ let innerScope = null;
1454
+ const mountAt = (parent, before) => {
1455
+ innerScope = createScope(ownerScope);
1456
+ runWithScope(innerScope, () => {
1457
+ insert(parent, () => children, before);
1458
+ });
1459
+ };
1460
+ const teardown = () => {
1461
+ if (innerScope) {
1462
+ disposeScope(innerScope);
1463
+ innerScope = null;
1464
+ }
1465
+ };
1466
+ const apply = (disabled, target) => {
1467
+ teardown();
1468
+ if (disabled) {
1469
+ const parent = placeholder.parentNode;
1470
+ if (!parent) return;
1471
+ mountAt(parent, placeholder);
1472
+ return;
1473
+ }
1474
+ if (!target) {
1475
+ {
1476
+ shared.warn(`[Portal] Target element not found: ${String(props.target)}`);
1591
1477
  }
1592
- childArray.forEach((child) => {
1593
- if (child != null) {
1594
- const normalized = normalizeNode(child);
1595
- if (normalized) {
1596
- insertNode(targetElement, normalized);
1597
- nodes.push(normalized);
1598
- }
1599
- }
1600
- });
1601
- onCleanup(() => {
1602
- nodes.forEach((node) => {
1603
- if (!shared.isString(node) && node.parentNode === targetElement) {
1604
- targetElement.removeChild(node);
1605
- }
1606
- });
1607
- });
1478
+ return;
1479
+ }
1480
+ mountAt(target);
1481
+ };
1482
+ let mounted = false;
1483
+ const effectRunner = signals.effect(() => {
1484
+ const disabled = evalDisabled(props);
1485
+ const target = disabled ? null : resolveTarget(props);
1486
+ if (mounted) {
1487
+ apply(disabled, target);
1488
+ }
1489
+ });
1490
+ onMount(() => {
1491
+ mounted = true;
1492
+ const disabled = evalDisabled(props);
1493
+ const target = disabled ? null : resolveTarget(props);
1494
+ if (disabled || target) {
1495
+ apply(disabled, target);
1496
+ return;
1497
+ }
1498
+ queueMicrotask(() => {
1499
+ if (!placeholder.parentNode) return;
1500
+ apply(evalDisabled(props), resolveTarget(props));
1608
1501
  });
1609
- }
1502
+ });
1503
+ onCleanup(() => {
1504
+ effectRunner.stop();
1505
+ teardown();
1506
+ });
1610
1507
  return placeholder;
1611
1508
  }
1612
1509
  Portal[PORTAL_COMPONENT] = true;
1510
+ function tryHydratePortal(props) {
1511
+ if (evalDisabled(props)) return null;
1512
+ const anchor = consumeTeleportAnchor();
1513
+ if (!anchor) {
1514
+ {
1515
+ shared.warn("[Portal] hydration mismatch: no <!--teleport-anchor--> at call site.");
1516
+ }
1517
+ return null;
1518
+ }
1519
+ const target = resolveTarget(props);
1520
+ if (!target) {
1521
+ {
1522
+ shared.warn(`[Portal] hydration mismatch: target not found: ${String(props.target)}`);
1523
+ }
1524
+ return null;
1525
+ }
1526
+ const block = consumeTeleportBlock(target);
1527
+ if (!block) {
1528
+ {
1529
+ shared.warn(
1530
+ `[Portal] hydration mismatch: no <!--teleport-start--> in target ${String(props.target)}`
1531
+ );
1532
+ }
1533
+ return null;
1534
+ }
1535
+ anchor[PORTAL_COMPONENT] = true;
1536
+ return anchor;
1537
+ }
1613
1538
  function isPortal(node) {
1614
1539
  return !!node && !!node[PORTAL_COMPONENT];
1615
1540
  }
1541
+ function clearContainer(el) {
1542
+ while (el.firstChild) {
1543
+ el.removeChild(el.firstChild);
1544
+ }
1545
+ }
1546
+ function resolveNodeValue(value) {
1547
+ let current = value;
1548
+ while (shared.isFunction(current)) {
1549
+ current = current();
1550
+ }
1551
+ if (signals.isSignal(current) || signals.isComputed(current)) {
1552
+ return resolveNodeValue(current.value);
1553
+ }
1554
+ return current;
1555
+ }
1616
1556
  var SuspenseContext = /* @__PURE__ */ Symbol("SuspenseContext");
1617
1557
  function Suspense(props) {
1618
- if (shared.isUndefined(document)) {
1619
- const fallback = props.fallback;
1620
- if (fallback) {
1621
- return String(fallback || "");
1622
- }
1623
- return "";
1558
+ var _a2;
1559
+ if (!shared.isBrowser()) {
1560
+ return (_a2 = props.fallback) != null ? _a2 : "";
1624
1561
  }
1625
1562
  const container = document.createElement("div");
1626
1563
  container.style.display = "contents";
@@ -1628,19 +1565,42 @@ function Suspense(props) {
1628
1565
  let pendingCount = 0;
1629
1566
  let isShowingFallback = false;
1630
1567
  let resolvedChildren = null;
1631
- const showFallback = () => {
1632
- if (isShowingFallback) return;
1633
- isShowingFallback = true;
1634
- while (container.firstChild) {
1635
- container.removeChild(container.firstChild);
1568
+ const materializeChild = (value) => {
1569
+ const current = resolveNodeValue(value);
1570
+ if (shared.isArray(current)) {
1571
+ const nodes = [];
1572
+ for (const item of current) {
1573
+ const materialized = materializeChild(item);
1574
+ if (shared.isArray(materialized)) {
1575
+ nodes.push(...materialized);
1576
+ } else {
1577
+ nodes.push(materialized);
1578
+ }
1579
+ }
1580
+ return nodes;
1636
1581
  }
1637
- if (props.fallback != null) {
1638
- const normalized = normalizeNode(props.fallback);
1639
- if (normalized) {
1640
- insertNode(container, normalized);
1582
+ return normalizeNode(current);
1583
+ };
1584
+ const insertMaterializedChild = (value) => {
1585
+ const normalized = materializeChild(value);
1586
+ const nodes = shared.isArray(normalized) ? normalized : [normalized];
1587
+ for (const node of nodes) {
1588
+ if (node != null) {
1589
+ insertNode(container, node);
1641
1590
  }
1642
1591
  }
1643
1592
  };
1593
+ const renderFallbackContent = () => {
1594
+ clearContainer(container);
1595
+ if (props.fallback != null) {
1596
+ insertMaterializedChild(props.fallback);
1597
+ }
1598
+ };
1599
+ const showFallback = () => {
1600
+ if (isShowingFallback) return;
1601
+ isShowingFallback = true;
1602
+ renderFallbackContent();
1603
+ };
1644
1604
  const showChildren = () => {
1645
1605
  if (!isShowingFallback) return;
1646
1606
  const hasContent = resolvedChildren || props.children != null && !shared.isPromise(props.children);
@@ -1648,9 +1608,7 @@ function Suspense(props) {
1648
1608
  return;
1649
1609
  }
1650
1610
  isShowingFallback = false;
1651
- while (container.firstChild) {
1652
- container.removeChild(container.firstChild);
1653
- }
1611
+ clearContainer(container);
1654
1612
  if (resolvedChildren) {
1655
1613
  renderChildren(resolvedChildren);
1656
1614
  } else if (props.children != null && !shared.isPromise(props.children)) {
@@ -1658,33 +1616,17 @@ function Suspense(props) {
1658
1616
  }
1659
1617
  };
1660
1618
  const renderChildren = (children2) => {
1661
- while (container.firstChild) {
1662
- container.removeChild(container.firstChild);
1663
- }
1619
+ if (isShowingFallback) return;
1620
+ clearContainer(container);
1664
1621
  if (children2 == null) return;
1665
- const currentScope = getActiveScope();
1666
1622
  const childArray = shared.isArray(children2) ? children2 : [children2];
1667
- childArray.forEach((child) => {
1668
- if (child != null) {
1669
- if (isComponent(child)) {
1670
- child.parentContext = currentScope;
1671
- }
1672
- const normalized = normalizeNode(child);
1673
- if (normalized) {
1674
- insertNode(container, normalized);
1675
- }
1623
+ for (const child2 of childArray) {
1624
+ if (child2 != null) {
1625
+ insertMaterializedChild(child2);
1676
1626
  }
1677
- });
1627
+ }
1678
1628
  if (isShowingFallback) {
1679
- while (container.firstChild) {
1680
- container.removeChild(container.firstChild);
1681
- }
1682
- if (props.fallback != null) {
1683
- const normalized = normalizeNode(props.fallback);
1684
- if (normalized) {
1685
- insertNode(container, normalized);
1686
- }
1687
- }
1629
+ renderFallbackContent();
1688
1630
  }
1689
1631
  };
1690
1632
  const suspenseContext = {
@@ -1697,9 +1639,9 @@ function Suspense(props) {
1697
1639
  if (pendingCount === 0) {
1698
1640
  showChildren();
1699
1641
  }
1700
- }).catch((error8) => {
1642
+ }).catch((error5) => {
1701
1643
  {
1702
- shared.warn("[Suspense] Resource failed:", error8);
1644
+ shared.warn("[Suspense] Resource failed:", error5);
1703
1645
  }
1704
1646
  if (!isMounted) return;
1705
1647
  pendingCount--;
@@ -1713,7 +1655,7 @@ function Suspense(props) {
1713
1655
  showFallback();
1714
1656
  },
1715
1657
  decrement: () => {
1716
- pendingCount--;
1658
+ pendingCount = Math.max(0, pendingCount - 1);
1717
1659
  if (pendingCount === 0) {
1718
1660
  showChildren();
1719
1661
  }
@@ -1734,9 +1676,10 @@ function Suspense(props) {
1734
1676
  }
1735
1677
  onDestroy(() => {
1736
1678
  isMounted = false;
1737
- while (container.firstChild) {
1738
- container.removeChild(container.firstChild);
1739
- }
1679
+ pendingCount = 0;
1680
+ resolvedChildren = null;
1681
+ clearContainer(container);
1682
+ container.remove();
1740
1683
  });
1741
1684
  return container;
1742
1685
  }
@@ -1747,19 +1690,25 @@ function isSuspense(node) {
1747
1690
  function createResource(fetcher, options) {
1748
1691
  const value = signals.signal(options == null ? void 0 : options.initialValue);
1749
1692
  const loading = signals.signal(true);
1750
- const error8 = signals.signal(null);
1693
+ const error5 = signals.signal(null);
1751
1694
  const state = signals.signal("pending");
1752
1695
  let fetchId = 0;
1753
1696
  let currentPromise = null;
1697
+ let suspenseRegistered = false;
1698
+ const suspenseContext = inject(SuspenseContext, null);
1754
1699
  const fetch = () => __async(null, null, function* () {
1755
1700
  const currentFetchId = ++fetchId;
1756
1701
  loading.value = true;
1757
1702
  state.value = "pending";
1758
- error8.value = null;
1703
+ error5.value = null;
1704
+ suspenseRegistered = false;
1705
+ if (suspenseContext) {
1706
+ suspenseContext.increment();
1707
+ }
1759
1708
  try {
1760
1709
  const promise = fetcher();
1761
- currentPromise = promise.then(() => {
1762
- }).catch(() => {
1710
+ currentPromise = promise;
1711
+ promise.catch(() => {
1763
1712
  });
1764
1713
  const result = yield promise;
1765
1714
  if (currentFetchId === fetchId) {
@@ -1769,31 +1718,33 @@ function createResource(fetcher, options) {
1769
1718
  }
1770
1719
  } catch (error_) {
1771
1720
  if (currentFetchId === fetchId) {
1772
- error8.value = error_ instanceof Error ? error_ : new Error(String(error_));
1721
+ error5.value = error_ instanceof Error ? error_ : new Error(String(error_));
1773
1722
  state.value = "errored";
1774
1723
  loading.value = false;
1775
1724
  }
1725
+ } finally {
1726
+ if (suspenseContext) {
1727
+ suspenseContext.decrement();
1728
+ }
1776
1729
  }
1777
1730
  });
1778
1731
  fetch();
1779
1732
  const resource = (() => {
1780
- if (loading.value && currentPromise) {
1781
- const suspenseContext = inject(SuspenseContext, null);
1782
- if (suspenseContext) {
1783
- suspenseContext.register(currentPromise);
1784
- }
1733
+ if (!suspenseRegistered && loading.value && currentPromise && suspenseContext) {
1734
+ suspenseRegistered = true;
1735
+ suspenseContext.register(currentPromise);
1785
1736
  }
1786
1737
  return value.value;
1787
1738
  });
1788
1739
  resource.loading = loading;
1789
- resource.error = error8;
1740
+ resource.error = error5;
1790
1741
  resource.state = state;
1791
1742
  const actions = {
1792
1743
  mutate: (newValue) => {
1793
1744
  value.value = newValue;
1794
1745
  state.value = "ready";
1795
1746
  loading.value = false;
1796
- error8.value = null;
1747
+ error5.value = null;
1797
1748
  },
1798
1749
  refetch: () => __async(null, null, function* () {
1799
1750
  yield fetch();
@@ -1801,89 +1752,274 @@ function createResource(fetcher, options) {
1801
1752
  };
1802
1753
  return [resource, actions];
1803
1754
  }
1755
+ function resolveModule(mod) {
1756
+ return shared.isFunction(mod) ? mod : mod.default;
1757
+ }
1758
+ function renderInto(el, fn, props) {
1759
+ const comp = new Component(fn, props);
1760
+ comp.mount(el);
1761
+ return comp;
1762
+ }
1763
+ function defineAsyncComponent(loader, options = {}) {
1764
+ const { delay = 200, timeout, ssr = "blocking", onError } = options;
1765
+ if (typeof window === "undefined") {
1766
+ if (ssr === "client-only") {
1767
+ const placeholder = () => "";
1768
+ placeholder.__asyncLoader = loader;
1769
+ placeholder.__asyncResolved = () => null;
1770
+ return placeholder;
1771
+ }
1772
+ let ssrResolved = null;
1773
+ let ssrPromise = null;
1774
+ const ssrLoad = () => {
1775
+ if (ssrPromise) return ssrPromise;
1776
+ ssrPromise = loader().then((mod) => {
1777
+ ssrResolved = resolveModule(mod);
1778
+ }).catch(() => {
1779
+ });
1780
+ return ssrPromise;
1781
+ };
1782
+ ssrLoad();
1783
+ const ssrWrapper = (props) => {
1784
+ if (ssrResolved) {
1785
+ return ssrResolved(props);
1786
+ }
1787
+ return "";
1788
+ };
1789
+ ssrWrapper.__asyncLoader = ssrLoad;
1790
+ ssrWrapper.__asyncResolved = () => ssrResolved;
1791
+ return ssrWrapper;
1792
+ }
1793
+ let cachedComponent = null;
1794
+ let cachedError = null;
1795
+ let cachedStatus = "pending";
1796
+ let loadPromise = null;
1797
+ function load() {
1798
+ if (loadPromise) return loadPromise;
1799
+ loadPromise = loader().then((mod) => {
1800
+ cachedComponent = resolveModule(mod);
1801
+ cachedStatus = "resolved";
1802
+ }).catch((error5) => {
1803
+ cachedError = error5 instanceof Error ? error5 : new Error(String(error5));
1804
+ cachedStatus = "errored";
1805
+ loadPromise = null;
1806
+ });
1807
+ return loadPromise;
1808
+ }
1809
+ load();
1810
+ function AsyncWrapper(props) {
1811
+ var _a2;
1812
+ if (cachedStatus === "resolved" && cachedComponent) {
1813
+ const el = document.createElement("div");
1814
+ el.style.display = "contents";
1815
+ const comp = renderInto(el, cachedComponent, props);
1816
+ onCleanup(() => comp.destroy());
1817
+ return el;
1818
+ }
1819
+ if (cachedStatus === "errored" && cachedError) {
1820
+ const el = document.createElement("div");
1821
+ el.style.display = "contents";
1822
+ if (options.error) {
1823
+ let alive2 = true;
1824
+ let currentComp2 = null;
1825
+ const swap2 = (fn, swapProps) => {
1826
+ if (!alive2) return;
1827
+ currentComp2 == null ? void 0 : currentComp2.destroy();
1828
+ currentComp2 = renderInto(el, fn, swapProps);
1829
+ };
1830
+ const retry = () => {
1831
+ loadPromise = null;
1832
+ cachedStatus = "pending";
1833
+ cachedError = null;
1834
+ if (options.loading) swap2(options.loading);
1835
+ load().then(() => {
1836
+ if (!alive2) return;
1837
+ if (cachedStatus === "resolved" && cachedComponent) {
1838
+ swap2(cachedComponent, props);
1839
+ } else if (cachedStatus === "errored" && cachedError) {
1840
+ if (options.error) swap2(options.error, { error: cachedError, retry });
1841
+ }
1842
+ });
1843
+ };
1844
+ swap2(options.error, { error: cachedError, retry });
1845
+ onDestroy(() => {
1846
+ alive2 = false;
1847
+ currentComp2 == null ? void 0 : currentComp2.destroy();
1848
+ currentComp2 = null;
1849
+ });
1850
+ }
1851
+ return el;
1852
+ }
1853
+ const container = document.createElement("div");
1854
+ container.style.display = "contents";
1855
+ let alive = true;
1856
+ let currentComp = null;
1857
+ let delayTimer = null;
1858
+ let timeoutTimer = null;
1859
+ const swap = (fn, swapProps) => {
1860
+ if (!alive) return;
1861
+ currentComp == null ? void 0 : currentComp.destroy();
1862
+ currentComp = renderInto(container, fn, swapProps);
1863
+ };
1864
+ const retryWith = (retryProps) => () => {
1865
+ loadPromise = null;
1866
+ cachedStatus = "pending";
1867
+ cachedError = null;
1868
+ if (options.loading) swap(options.loading);
1869
+ load().then(() => {
1870
+ if (cachedStatus === "resolved" && cachedComponent) {
1871
+ swap(cachedComponent, retryProps);
1872
+ } else if (cachedStatus === "errored" && cachedError) {
1873
+ if (options.error) {
1874
+ swap(options.error, {
1875
+ error: cachedError,
1876
+ retry: retryWith(retryProps)
1877
+ });
1878
+ }
1879
+ }
1880
+ });
1881
+ };
1882
+ onDestroy(() => {
1883
+ alive = false;
1884
+ currentComp == null ? void 0 : currentComp.destroy();
1885
+ currentComp = null;
1886
+ if (delayTimer != null) clearTimeout(delayTimer);
1887
+ if (timeoutTimer != null) clearTimeout(timeoutTimer);
1888
+ });
1889
+ const suspenseCtx = (_a2 = inject(SuspenseContext)) != null ? _a2 : null;
1890
+ const showResolved = (compFn) => swap(compFn, props);
1891
+ const showError = (err) => {
1892
+ if (options.error) swap(options.error, { error: err, retry: retryWith(props) });
1893
+ };
1894
+ const showLoading = () => {
1895
+ if (options.loading) swap(options.loading);
1896
+ };
1897
+ const instancePromise = load().then(() => {
1898
+ if (!alive) return;
1899
+ if (cachedStatus === "resolved" && cachedComponent) {
1900
+ showResolved(cachedComponent);
1901
+ } else if (cachedStatus === "errored" && cachedError) {
1902
+ showError(cachedError);
1903
+ if (onError) onError(cachedError, retryWith(props));
1904
+ }
1905
+ if (delayTimer != null) clearTimeout(delayTimer);
1906
+ if (timeoutTimer != null) clearTimeout(timeoutTimer);
1907
+ });
1908
+ if (suspenseCtx) {
1909
+ suspenseCtx.register(instancePromise);
1910
+ }
1911
+ if (delay > 0) {
1912
+ delayTimer = setTimeout(() => {
1913
+ if (alive && cachedStatus === "pending") {
1914
+ showLoading();
1915
+ }
1916
+ }, delay);
1917
+ } else if (options.loading) {
1918
+ showLoading();
1919
+ }
1920
+ if (timeout != null) {
1921
+ timeoutTimer = setTimeout(() => {
1922
+ if (alive && cachedStatus === "pending") {
1923
+ const err = new Error(`[defineAsyncComponent] Timeout after ${timeout}ms`);
1924
+ cachedError = err;
1925
+ cachedStatus = "errored";
1926
+ showError(err);
1927
+ if (onError) onError(err, retryWith(props));
1928
+ }
1929
+ }, timeout);
1930
+ }
1931
+ return container;
1932
+ }
1933
+ AsyncWrapper.__asyncLoader = load;
1934
+ AsyncWrapper.__asyncResolved = () => cachedComponent;
1935
+ return AsyncWrapper;
1936
+ }
1804
1937
  function For(props) {
1805
1938
  const fragment = document.createDocumentFragment();
1806
1939
  const marker = document.createComment("");
1807
1940
  fragment.appendChild(marker);
1808
1941
  let entries = [];
1809
- let fallbackNode = null;
1810
- const keyFn = props.keyFn;
1942
+ let fallbackNodes = [];
1943
+ const keyFn = props.key;
1811
1944
  const renderFn = props.children;
1812
1945
  const getList = () => {
1813
1946
  var _a2, _b;
1814
1947
  const input = props.each;
1815
1948
  if (signals.isSignal(input)) return (_a2 = input.value) != null ? _a2 : [];
1816
- if (typeof input === "function") return (_b = input()) != null ? _b : [];
1949
+ if (shared.isFunction(input)) return (_b = input()) != null ? _b : [];
1817
1950
  return input != null ? input : [];
1818
1951
  };
1819
1952
  const getKey = (item) => keyFn ? keyFn(item) : item;
1820
- const renderItem = (item, index, parent, before) => {
1821
- var _a2;
1822
- const prevScope = getActiveScope();
1823
- const scope = createScope(prevScope);
1824
- setActiveScope(scope);
1825
- let node;
1826
- try {
1827
- const result = renderFn(item, index);
1828
- if (isComponent(result)) {
1829
- result.mount(parent, before);
1830
- node = (_a2 = result.firstChild) != null ? _a2 : document.createComment("empty");
1953
+ const normalizeNodes = (value) => {
1954
+ if (Array.isArray(value)) {
1955
+ const nodes = [];
1956
+ for (const item of value) {
1957
+ nodes.push(...normalizeNodes(item));
1958
+ }
1959
+ return nodes;
1960
+ }
1961
+ return [normalizeNode(value)];
1962
+ };
1963
+ const mountValue = (value, parent, before) => {
1964
+ const nodes = normalizeNodes(value);
1965
+ for (const node of nodes) {
1966
+ if (before) {
1967
+ parent.insertBefore(node, before);
1831
1968
  } else {
1832
- node = result;
1833
- if (!node.parentNode) {
1834
- if (before) {
1835
- parent.insertBefore(node, before);
1836
- } else {
1837
- parent.appendChild(node);
1838
- }
1839
- }
1969
+ parent.appendChild(node);
1970
+ }
1971
+ }
1972
+ return nodes;
1973
+ };
1974
+ const mountFallback = (parent, before) => {
1975
+ if (!props.fallback) return;
1976
+ const nodes = mountValue(props.fallback(), parent, before);
1977
+ fallbackNodes = nodes;
1978
+ };
1979
+ const clearFallback = () => {
1980
+ for (const node of fallbackNodes) {
1981
+ if (node.parentNode) {
1982
+ node.parentNode.removeChild(node);
1840
1983
  }
1841
- } finally {
1842
- setActiveScope(prevScope);
1843
1984
  }
1844
- return { key: getKey(item), node, scope };
1985
+ fallbackNodes = [];
1986
+ };
1987
+ const renderItem = (item, index, parent, before) => {
1988
+ const parentScope = getActiveScope();
1989
+ const scope = createScope(parentScope);
1990
+ let mountedNodes = [];
1991
+ runWithScope(scope, () => {
1992
+ mountedNodes = mountValue(renderFn(item, index), parent, before);
1993
+ });
1994
+ return { key: getKey(item), item, nodes: mountedNodes, scope };
1845
1995
  };
1846
1996
  const disposeItem = (entry) => {
1847
1997
  disposeScope(entry.scope);
1848
- if (entry.node.parentNode) {
1849
- entry.node.parentNode.removeChild(entry.node);
1998
+ for (const node of entry.nodes) {
1999
+ if (node.parentNode) {
2000
+ node.parentNode.removeChild(node);
2001
+ }
1850
2002
  }
1851
2003
  };
1852
- signals.memoEffect(
1853
- ({ prev }) => {
1854
- var _a2;
1855
- const newItems = getList();
1856
- if (prev === newItems) return { prev: newItems };
1857
- const parent = marker.parentNode;
1858
- if (!parent) {
1859
- if (newItems.length === 0) {
1860
- if (props.fallback) {
1861
- const fb = props.fallback();
1862
- if (isComponent(fb)) {
1863
- fb.mount(fragment, marker);
1864
- fallbackNode = (_a2 = fb.firstChild) != null ? _a2 : document.createComment("empty");
1865
- } else {
1866
- fallbackNode = fb;
1867
- fragment.insertBefore(fallbackNode, marker);
1868
- }
1869
- }
1870
- return { prev: newItems };
1871
- }
2004
+ const effectRunner = signals.effect(() => {
2005
+ const newItems = getList();
2006
+ const parent = marker.parentNode;
2007
+ if (!parent) {
2008
+ if (newItems.length === 0) {
2009
+ mountFallback(fragment, marker);
2010
+ } else {
1872
2011
  entries = new Array(newItems.length);
1873
- for (const [i, newItem] of newItems.entries()) {
1874
- entries[i] = renderItem(newItem, i, fragment, marker);
2012
+ let idx = 0;
2013
+ for (const newItem of newItems) {
2014
+ entries[idx] = renderItem(newItem, idx, fragment, marker);
2015
+ idx++;
1875
2016
  }
1876
- return { prev: newItems };
1877
2017
  }
1878
- signals.untrack(() => reconcile(parent, newItems));
1879
- return { prev: newItems };
1880
- },
1881
- {
1882
- prev: []
2018
+ return;
1883
2019
  }
1884
- );
2020
+ reconcile(parent, newItems);
2021
+ });
1885
2022
  function reconcile(parent, newItems) {
1886
- var _a2;
1887
2023
  const oldLen = entries.length;
1888
2024
  const newLen = newItems.length;
1889
2025
  if (newLen === 0) {
@@ -1891,22 +2027,14 @@ function For(props) {
1891
2027
  disposeItem(entries[i]);
1892
2028
  }
1893
2029
  entries = [];
1894
- if (props.fallback && !fallbackNode) {
1895
- const fb = props.fallback();
1896
- if (isComponent(fb)) {
1897
- fb.mount(parent, marker);
1898
- fallbackNode = (_a2 = fb.firstChild) != null ? _a2 : document.createComment("empty");
1899
- } else {
1900
- fallbackNode = fb;
1901
- parent.insertBefore(fallbackNode, marker);
1902
- }
2030
+ if (props.fallback && fallbackNodes.length === 0) {
2031
+ mountFallback(parent, marker);
1903
2032
  }
1904
2033
  return;
1905
2034
  }
1906
- if (oldLen === 0 || fallbackNode) {
1907
- if (fallbackNode) {
1908
- if (fallbackNode.parentNode) fallbackNode.parentNode.removeChild(fallbackNode);
1909
- fallbackNode = null;
2035
+ if (oldLen === 0 || fallbackNodes.length > 0) {
2036
+ if (fallbackNodes.length > 0) {
2037
+ clearFallback();
1910
2038
  }
1911
2039
  entries = new Array(newLen);
1912
2040
  const batchFragment2 = document.createDocumentFragment();
@@ -1920,46 +2048,76 @@ function For(props) {
1920
2048
  for (let i = 0; i < oldLen; i++) {
1921
2049
  const entry = entries[i];
1922
2050
  const list = oldKeyMap.get(entry.key);
1923
- if (list) {
1924
- list.push(entry);
1925
- } else {
1926
- oldKeyMap.set(entry.key, [entry]);
1927
- }
2051
+ const pair = [entry, i];
2052
+ if (list) list.push(pair);
2053
+ else oldKeyMap.set(entry.key, [pair]);
1928
2054
  }
1929
2055
  const newEntries = new Array(newLen);
1930
2056
  const toRemove = [];
1931
- const batchFragment = document.createDocumentFragment();
2057
+ let batchFragment = null;
2058
+ const newIndexToOldIndex = new Int32Array(newLen);
2059
+ let moved = false;
2060
+ let maxOldSeen = 0;
2061
+ const newKeys = new Array(newLen);
2062
+ for (let i = 0; i < newLen; i++) {
2063
+ newKeys[i] = getKey(newItems[i]);
2064
+ }
1932
2065
  for (let i = 0; i < newLen; i++) {
1933
2066
  const item = newItems[i];
1934
- const key = getKey(item);
2067
+ const key = newKeys[i];
1935
2068
  const oldList = oldKeyMap.get(key);
1936
2069
  if (oldList && oldList.length > 0) {
1937
- newEntries[i] = oldList.shift();
2070
+ const [reused, oldIndex] = oldList.shift();
2071
+ if (Object.is(reused.item, item)) {
2072
+ reused.item = item;
2073
+ newEntries[i] = reused;
2074
+ newIndexToOldIndex[i] = oldIndex + 1;
2075
+ if (oldIndex < maxOldSeen) moved = true;
2076
+ else maxOldSeen = oldIndex;
2077
+ } else {
2078
+ if (!batchFragment) batchFragment = document.createDocumentFragment();
2079
+ disposeItem(reused);
2080
+ newEntries[i] = renderItem(item, i, batchFragment, null);
2081
+ }
1938
2082
  } else {
2083
+ if (!batchFragment) batchFragment = document.createDocumentFragment();
1939
2084
  newEntries[i] = renderItem(item, i, batchFragment, null);
1940
2085
  }
1941
2086
  }
1942
2087
  for (const list of oldKeyMap.values()) {
1943
- for (const entry of list) {
1944
- toRemove.push(entry);
2088
+ for (const [entry] of list) toRemove.push(entry);
2089
+ }
2090
+ for (const entry of toRemove) disposeItem(entry);
2091
+ const lis = moved ? getSequence(newIndexToOldIndex) : [];
2092
+ let lisCursor = lis.length - 1;
2093
+ let nextNode = marker;
2094
+ for (let i = newLen - 1; i >= 0; i--) {
2095
+ const entry = newEntries[i];
2096
+ const nodes = entry.nodes;
2097
+ const isFresh = newIndexToOldIndex[i] === 0;
2098
+ const inLis = !isFresh && moved && lisCursor >= 0 && i === lis[lisCursor];
2099
+ if (inLis) {
2100
+ lisCursor--;
2101
+ for (let j = nodes.length - 1; j >= 0; j--) nextNode = nodes[j];
2102
+ continue;
2103
+ }
2104
+ for (let j = nodes.length - 1; j >= 0; j--) {
2105
+ const node = nodes[j];
2106
+ if (node.nextSibling !== nextNode) {
2107
+ parent.insertBefore(node, nextNode);
2108
+ }
2109
+ nextNode = node;
1945
2110
  }
1946
- }
1947
- for (const entry of toRemove) {
1948
- disposeItem(entry);
1949
- }
1950
- for (let i = 0; i < newLen; i++) {
1951
- const node = newEntries[i].node;
1952
- parent.insertBefore(node, marker);
1953
2111
  }
1954
2112
  entries = newEntries;
1955
2113
  }
1956
2114
  onCleanup(() => {
2115
+ effectRunner.stop();
1957
2116
  for (const entry of entries) {
1958
2117
  disposeItem(entry);
1959
2118
  }
1960
- if (fallbackNode && fallbackNode.parentNode) {
1961
- fallbackNode.parentNode.removeChild(fallbackNode);
1962
- }
2119
+ entries = [];
2120
+ clearFallback();
1963
2121
  if (marker.parentNode) {
1964
2122
  marker.parentNode.removeChild(marker);
1965
2123
  }
@@ -1975,49 +2133,44 @@ exports.Portal = Portal;
1975
2133
  exports.Suspense = Suspense;
1976
2134
  exports.addEvent = addEvent;
1977
2135
  exports.addEventListener = addEventListener;
2136
+ exports.beginHydration = beginHydration;
1978
2137
  exports.bindElement = bindElement;
2138
+ exports.child = child;
2139
+ exports.clearDelegatedEvents = clearDelegatedEvents;
2140
+ exports.consumeTeleportAnchor = consumeTeleportAnchor;
2141
+ exports.consumeTeleportBlock = consumeTeleportBlock;
1979
2142
  exports.createApp = createApp;
1980
2143
  exports.createComponent = createComponent;
1981
2144
  exports.createResource = createResource;
1982
- exports.createScope = createScope;
2145
+ exports.defineAsyncComponent = defineAsyncComponent;
1983
2146
  exports.delegateEvents = delegateEvents;
1984
- exports.disposeScope = disposeScope;
1985
2147
  exports.endHydration = endHydration;
1986
- exports.getActiveScope = getActiveScope;
1987
- exports.getFirstDOMNode = getFirstDOMNode;
1988
2148
  exports.getHydrationKey = getHydrationKey;
1989
2149
  exports.getRenderedElement = getRenderedElement;
1990
2150
  exports.hydrate = hydrate;
1991
2151
  exports.inject = inject;
1992
2152
  exports.insert = insert;
1993
- exports.insertNode = insertNode;
1994
2153
  exports.isComponent = isComponent;
1995
2154
  exports.isFragment = isFragment;
1996
2155
  exports.isHydrating = isHydrating;
1997
2156
  exports.isPortal = isPortal;
1998
- exports.isSameNode = isSameNode;
1999
2157
  exports.isSuspense = isSuspense;
2000
- exports.mapNodes = mapNodes;
2001
- exports.mapSSRNodes = mapSSRNodes;
2158
+ exports.next = next;
2002
2159
  exports.normalizeClass = normalizeClass;
2003
- exports.normalizeNode = normalizeNode;
2160
+ exports.nthChild = nthChild;
2004
2161
  exports.omitProps = omitProps;
2005
- exports.onCleanup = onCleanup;
2006
2162
  exports.onDestroy = onDestroy;
2007
2163
  exports.onMount = onMount;
2008
2164
  exports.onUpdate = onUpdate;
2009
2165
  exports.patchAttr = patchAttr;
2166
+ exports.patchAttrHydrate = patchAttrHydrate;
2010
2167
  exports.patchClass = patchClass;
2168
+ exports.patchClassHydrate = patchClassHydrate;
2011
2169
  exports.patchStyle = patchStyle;
2170
+ exports.patchStyleHydrate = patchStyleHydrate;
2012
2171
  exports.provide = provide;
2013
- exports.removeNode = removeNode;
2014
- exports.replaceNode = replaceNode;
2015
2172
  exports.resetHydrationKey = resetHydrationKey;
2016
- exports.runWithScope = runWithScope;
2017
- exports.setActiveScope = setActiveScope;
2018
2173
  exports.setStyle = setStyle;
2019
- exports.shallowCompare = shallowCompare;
2020
- exports.startHydration = startHydration;
2021
2174
  exports.template = template;
2022
2175
  //# sourceMappingURL=template.dev.cjs.js.map
2023
2176
  //# sourceMappingURL=template.dev.cjs.js.map