@estjs/template 0.0.15-beta.9 → 0.0.16-beta.1

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