@vobs/runtime 1.7.8 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +1 -1
  2. package/dist/async-boundary.cjs +14 -4
  3. package/dist/async-boundary.cjs.map +1 -1
  4. package/dist/async-boundary.js +17 -7
  5. package/dist/async-boundary.js.map +1 -1
  6. package/dist/bind.cjs +43 -3
  7. package/dist/bind.cjs.map +1 -1
  8. package/dist/bind.js +48 -8
  9. package/dist/bind.js.map +1 -1
  10. package/dist/boundary.cjs +159 -84
  11. package/dist/boundary.cjs.map +1 -1
  12. package/dist/boundary.js +162 -87
  13. package/dist/boundary.js.map +1 -1
  14. package/dist/client-only.cjs +323 -0
  15. package/dist/client-only.cjs.map +1 -0
  16. package/dist/client-only.d.cts +42 -0
  17. package/dist/client-only.d.ts +42 -0
  18. package/dist/client-only.js +299 -0
  19. package/dist/client-only.js.map +1 -0
  20. package/dist/debug.cjs.map +1 -1
  21. package/dist/debug.d.cts +12 -2
  22. package/dist/debug.d.ts +12 -2
  23. package/dist/debug.js.map +1 -1
  24. package/dist/dom-events.cjs +46 -0
  25. package/dist/dom-events.cjs.map +1 -0
  26. package/dist/dom-events.d.cts +23 -0
  27. package/dist/dom-events.d.ts +23 -0
  28. package/dist/dom-events.js +21 -0
  29. package/dist/dom-events.js.map +1 -0
  30. package/dist/dom-props.cjs +154 -0
  31. package/dist/dom-props.cjs.map +1 -0
  32. package/dist/dom-props.d.cts +21 -0
  33. package/dist/dom-props.d.ts +21 -0
  34. package/dist/dom-props.js +128 -0
  35. package/dist/dom-props.js.map +1 -0
  36. package/dist/dynamic.cjs +68 -14
  37. package/dist/dynamic.cjs.map +1 -1
  38. package/dist/dynamic.js +73 -19
  39. package/dist/dynamic.js.map +1 -1
  40. package/dist/error-boundary.cjs +159 -84
  41. package/dist/error-boundary.cjs.map +1 -1
  42. package/dist/error-boundary.js +162 -87
  43. package/dist/error-boundary.js.map +1 -1
  44. package/dist/error.cjs +52 -20
  45. package/dist/error.cjs.map +1 -1
  46. package/dist/error.d.cts +8 -0
  47. package/dist/error.d.ts +8 -0
  48. package/dist/error.js +52 -20
  49. package/dist/error.js.map +1 -1
  50. package/dist/fragment.cjs.map +1 -1
  51. package/dist/fragment.js +1 -1
  52. package/dist/fragment.js.map +1 -1
  53. package/dist/hmr.cjs +137 -1
  54. package/dist/hmr.cjs.map +1 -1
  55. package/dist/hmr.js +135 -1
  56. package/dist/hmr.js.map +1 -1
  57. package/dist/index.cjs +713 -236
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.d.cts +5 -2
  60. package/dist/index.d.ts +5 -2
  61. package/dist/index.js +715 -245
  62. package/dist/index.js.map +1 -1
  63. package/dist/ops.cjs +561 -107
  64. package/dist/ops.cjs.map +1 -1
  65. package/dist/ops.d.cts +49 -4
  66. package/dist/ops.d.ts +49 -4
  67. package/dist/ops.js +557 -108
  68. package/dist/ops.js.map +1 -1
  69. package/dist/profiler.cjs +14 -4
  70. package/dist/profiler.cjs.map +1 -1
  71. package/dist/profiler.js +17 -7
  72. package/dist/profiler.js.map +1 -1
  73. package/dist/ref.cjs +160 -5
  74. package/dist/ref.cjs.map +1 -1
  75. package/dist/ref.js +160 -5
  76. package/dist/ref.js.map +1 -1
  77. package/dist/renderer.cjs.map +1 -1
  78. package/dist/renderer.d.cts +2 -0
  79. package/dist/renderer.d.ts +2 -0
  80. package/dist/show.cjs +196 -0
  81. package/dist/show.cjs.map +1 -0
  82. package/dist/show.d.cts +54 -0
  83. package/dist/show.d.ts +54 -0
  84. package/dist/show.js +171 -0
  85. package/dist/show.js.map +1 -0
  86. package/dist/svg.cjs +102 -0
  87. package/dist/svg.cjs.map +1 -0
  88. package/dist/svg.d.cts +21 -0
  89. package/dist/svg.d.ts +21 -0
  90. package/dist/svg.js +76 -0
  91. package/dist/svg.js.map +1 -0
  92. package/package.json +20 -2
  93. package/src/bind.ts +30 -2
  94. package/src/boundaries.test.ts +54 -1
  95. package/src/boundary.ts +24 -8
  96. package/src/clear-remove.test.ts +85 -0
  97. package/src/client-only.test.ts +140 -0
  98. package/src/client-only.ts +65 -0
  99. package/src/component-empty-return.test.ts +123 -0
  100. package/src/debug.ts +12 -1
  101. package/src/dom-events.ts +32 -0
  102. package/src/dom-props-consistency.test.ts +149 -0
  103. package/src/dom-props.test.ts +70 -0
  104. package/src/dom-props.ts +107 -0
  105. package/src/dynamic.ts +91 -14
  106. package/src/error.test.ts +76 -1
  107. package/src/error.ts +87 -22
  108. package/src/event-cleanup-growth.test.ts +128 -0
  109. package/src/events.test.ts +16 -3
  110. package/src/hmr.ts +8 -2
  111. package/src/index.ts +13 -1
  112. package/src/invariants.test.ts +252 -0
  113. package/src/list-fast-path.test.ts +83 -0
  114. package/src/list-reactive-item.test.ts +77 -0
  115. package/src/ops.ts +419 -60
  116. package/src/props.test.ts +61 -1
  117. package/src/ref-cleanup.test.ts +144 -0
  118. package/src/ref.ts +57 -8
  119. package/src/remove-listener-identity.test.ts +97 -0
  120. package/src/renderer.ts +3 -1
  121. package/src/select-hidden-subscription.test.ts +104 -0
  122. package/src/show-classlist.test.ts +205 -0
  123. package/src/show.ts +107 -0
  124. package/src/spread-stable-shape.test.ts +109 -0
  125. package/src/spread.test.ts +86 -0
  126. package/src/svg.test.ts +28 -1
  127. package/src/svg.ts +34 -0
package/dist/index.js CHANGED
@@ -84,7 +84,341 @@ __name(describeDebugNode, "describeDebugNode");
84
84
  import { getCurrentOwner as getCurrentOwner3 } from "@vobs/reactivity";
85
85
 
86
86
  // packages/runtime/src/ops.ts
87
- import { createOwner, getCurrentOwner as getCurrentOwner2, setOwnerDebugName, untrack } from "@vobs/reactivity";
87
+ import { createOwner, effect, getCurrentOwner as getCurrentOwner2, setOwnerDebugName, untrack } from "@vobs/reactivity";
88
+
89
+ // packages/runtime/src/dom-props.ts
90
+ var PROPERTY_NAMES = /* @__PURE__ */ new Set([
91
+ // 表单状态
92
+ "value",
93
+ "checked",
94
+ "selected",
95
+ "disabled",
96
+ "multiple",
97
+ "readOnly",
98
+ "required",
99
+ "defaultValue",
100
+ "defaultChecked",
101
+ "indeterminate",
102
+ /*
103
+ * `autoFocus` 用**驼峰**(与同表 readOnly/tabIndex/defaultChecked 一致),且必须走
104
+ * **property 通道**:`autofocus` 是**布尔属性**(只看存在与否、与值无关),
105
+ * 所以 `autoFocus={false}` 必须"移除属性"而不是写 `autofocus="false"`
106
+ * (attribute 通道只能把 false 序列化成字符串,属性照样存在 = 仍然聚焦)。
107
+ *
108
+ * ⚠️ 但 `setProperty` 必须把它映射成 **IDL 名 `autofocus`(全小写)** ——
109
+ * `Reflect.set(el, 'autoFocus', …)` 只会挂一个不反射的 expando,**静默无效**。
110
+ * 映射表见 ops.ts 的 `PROPERTY_IDL_NAMES`。实测(jsdom,与真实 DOM 同语义):
111
+ * IDL `autofocus` → 写 true 得 has=true/idl=true;写 false 得 has=false/idl=false ✓
112
+ * JSX `autoFocus` → 属性与 IDL 都不变(只是 expando) ✗
113
+ */
114
+ "autoFocus",
115
+ "hidden",
116
+ "tabIndex",
117
+ "colSpan",
118
+ "rowSpan",
119
+ "open",
120
+ // 只能走 property 的(attribute 路径会静默无效)
121
+ "innerHTML",
122
+ "innerText",
123
+ "textContent",
124
+ // 媒体
125
+ "muted",
126
+ "volume",
127
+ "currentTime",
128
+ "playbackRate"
129
+ ]);
130
+ var ATTRIBUTE_ALIASES = {
131
+ className: "class",
132
+ htmlFor: "for",
133
+ autoComplete: "autocomplete",
134
+ spellCheck: "spellcheck"
135
+ };
136
+ var SVG_KEBAB_ATTRIBUTES = /* @__PURE__ */ new Set([
137
+ // stroke
138
+ "strokeWidth",
139
+ "strokeLinecap",
140
+ "strokeLinejoin",
141
+ "strokeDasharray",
142
+ "strokeDashoffset",
143
+ "strokeMiterlimit",
144
+ "strokeOpacity",
145
+ // fill
146
+ "fillOpacity",
147
+ "fillRule",
148
+ // clip(注意 clipPathUnits 是结构属性,不在这里)
149
+ "clipPath",
150
+ "clipRule",
151
+ // 文本对齐
152
+ "textAnchor",
153
+ "dominantBaseline",
154
+ "alignmentBaseline",
155
+ "baselineShift",
156
+ // 字体
157
+ "fontFamily",
158
+ "fontSize",
159
+ "fontSizeAdjust",
160
+ "fontStretch",
161
+ "fontStyle",
162
+ "fontVariant",
163
+ "fontWeight",
164
+ "letterSpacing",
165
+ "wordSpacing",
166
+ // marker 的表现属性(markerWidth / markerHeight / markerUnits 是结构属性,不在这里)
167
+ "markerStart",
168
+ "markerMid",
169
+ "markerEnd",
170
+ // 颜色
171
+ "colorInterpolation",
172
+ "colorInterpolationFilters",
173
+ "colorProfile",
174
+ "colorRendering",
175
+ "floodColor",
176
+ "floodOpacity",
177
+ "lightingColor",
178
+ "stopColor",
179
+ "stopOpacity",
180
+ "glyphOrientationHorizontal",
181
+ "glyphOrientationVertical",
182
+ // 渲染与合成
183
+ "imageRendering",
184
+ "paintOrder",
185
+ "pointerEvents",
186
+ "shapeRendering",
187
+ "textDecoration",
188
+ "textRendering",
189
+ "transformOrigin",
190
+ "vectorEffect",
191
+ "writingMode"
192
+ ]);
193
+ function isPropertyName(name) {
194
+ return PROPERTY_NAMES.has(name);
195
+ }
196
+ __name(isPropertyName, "isPropertyName");
197
+ function domAttributeName(name) {
198
+ const alias = ATTRIBUTE_ALIASES[name];
199
+ if (alias !== void 0) return alias;
200
+ if (SVG_KEBAB_ATTRIBUTES.has(name)) return name.replace(/[A-Z]/gu, (letter) => `-${letter.toLowerCase()}`);
201
+ return name;
202
+ }
203
+ __name(domAttributeName, "domAttributeName");
204
+
205
+ // packages/runtime/src/dom-events.ts
206
+ var EVENT_NAME_ALIASES = {
207
+ // React 风格的 onDoubleClick 对应的 DOM 事件是 dblclick
208
+ doubleclick: "dblclick",
209
+ // 少数人按 addEventListener 的写法写成 onDblClick
210
+ dblclick: "dblclick"
211
+ };
212
+ function resolveEventName(attributeName) {
213
+ if (!attributeName.startsWith("on") || attributeName.length <= 2) return void 0;
214
+ const lowered = attributeName.slice(2).toLowerCase();
215
+ return EVENT_NAME_ALIASES[lowered] ?? lowered;
216
+ }
217
+ __name(resolveEventName, "resolveEventName");
218
+
219
+ // packages/runtime/src/svg.ts
220
+ var SVG_TAGS = /* @__PURE__ */ new Set([
221
+ "animate",
222
+ "animateMotion",
223
+ "animateTransform",
224
+ "circle",
225
+ "clipPath",
226
+ "defs",
227
+ "desc",
228
+ "ellipse",
229
+ "feBlend",
230
+ "feColorMatrix",
231
+ "feComponentTransfer",
232
+ "feComposite",
233
+ "feConvolveMatrix",
234
+ "feDiffuseLighting",
235
+ "feDisplacementMap",
236
+ "feDistantLight",
237
+ "feDropShadow",
238
+ "feFlood",
239
+ "feFuncA",
240
+ "feFuncB",
241
+ "feFuncG",
242
+ "feFuncR",
243
+ "feGaussianBlur",
244
+ "feImage",
245
+ "feMerge",
246
+ "feMergeNode",
247
+ "feMorphology",
248
+ "feOffset",
249
+ "fePointLight",
250
+ "feSpecularLighting",
251
+ "feSpotLight",
252
+ "feTile",
253
+ "feTurbulence",
254
+ "filter",
255
+ "foreignObject",
256
+ "g",
257
+ "image",
258
+ "line",
259
+ "linearGradient",
260
+ "marker",
261
+ "mask",
262
+ "metadata",
263
+ "mpath",
264
+ "path",
265
+ "pattern",
266
+ "polygon",
267
+ "polyline",
268
+ "radialGradient",
269
+ "rect",
270
+ "set",
271
+ "stop",
272
+ "svg",
273
+ "switch",
274
+ "symbol",
275
+ "text",
276
+ "textPath",
277
+ "tspan",
278
+ "use",
279
+ "view"
280
+ ]);
281
+ function isSvgTag(tag) {
282
+ return SVG_TAGS.has(tag);
283
+ }
284
+ __name(isSvgTag, "isSvgTag");
285
+
286
+ // packages/runtime/src/error.ts
287
+ var _VobsError = class _VobsError extends Error {
288
+ constructor(options) {
289
+ super(options.message);
290
+ this.name = "VobsError";
291
+ this.code = options.code;
292
+ this.severity = options.severity ?? "error";
293
+ this.layer = options.layer ?? "runtime";
294
+ this.cause = options.cause;
295
+ this.fix = options.fix;
296
+ this.location = options.location;
297
+ this.trace = options.trace;
298
+ this.example = options.example;
299
+ this.docs = options.docs;
300
+ this.codeFrame = options.codeFrame;
301
+ }
302
+ };
303
+ __name(_VobsError, "VobsError");
304
+ var VobsError = _VobsError;
305
+ function createVobsError(options) {
306
+ return new VobsError(options);
307
+ }
308
+ __name(createVobsError, "createVobsError");
309
+ function isVobsError(value) {
310
+ return value instanceof VobsError || Boolean(value && typeof value === "object" && typeof value.code === "string" && typeof value.message === "string");
311
+ }
312
+ __name(isVobsError, "isVobsError");
313
+ function isForeignVobsError(value) {
314
+ return value instanceof Error && value.name === "VobsError" && typeof value.code === "string";
315
+ }
316
+ __name(isForeignVobsError, "isForeignVobsError");
317
+ function describeUnknown(value) {
318
+ if (value === null || value === void 0) return String(value);
319
+ if (typeof value === "string") return value;
320
+ if (typeof value === "object") {
321
+ const message = value.message;
322
+ if (typeof message === "string" && message !== "") return message;
323
+ try {
324
+ return JSON.stringify(value) ?? String(value);
325
+ } catch {
326
+ return String(value);
327
+ }
328
+ }
329
+ return String(value);
330
+ }
331
+ __name(describeUnknown, "describeUnknown");
332
+ function adoptVobsError(value, defaults) {
333
+ return new VobsError({
334
+ code: value.code,
335
+ message: value.message,
336
+ severity: value.severity ?? defaults.severity,
337
+ layer: value.layer ?? defaults.layer,
338
+ cause: value.cause ?? (value instanceof Error ? value : void 0),
339
+ fix: value.fix ?? defaults.fix,
340
+ location: value.location,
341
+ trace: value.trace,
342
+ example: value.example,
343
+ docs: value.docs,
344
+ codeFrame: value.codeFrame
345
+ });
346
+ }
347
+ __name(adoptVobsError, "adoptVobsError");
348
+ function normalizeVobsError(value, defaults = {}) {
349
+ if (value instanceof VobsError) return value;
350
+ if (isForeignVobsError(value)) return adoptVobsError(value, defaults);
351
+ if (value instanceof Error) {
352
+ const metadata = value;
353
+ const code = defaults.code ?? (typeof metadata.vobsCode === "string" ? metadata.vobsCode : void 0);
354
+ if (code) {
355
+ defineErrorMetadata(value, "code", code);
356
+ if (value.code !== code) {
357
+ return new VobsError({
358
+ code,
359
+ message: value.message,
360
+ severity: defaults.severity ?? "error",
361
+ layer: defaults.layer ?? "runtime",
362
+ cause: value,
363
+ fix: defaults.fix ?? (typeof metadata.vobsHint === "string" ? metadata.vobsHint : void 0)
364
+ });
365
+ }
366
+ }
367
+ defineErrorMetadata(value, "severity", defaults.severity ?? "error");
368
+ defineErrorMetadata(value, "layer", defaults.layer ?? "runtime");
369
+ const fix = defaults.fix ?? (typeof metadata.vobsHint === "string" ? metadata.vobsHint : void 0);
370
+ if (fix) defineErrorMetadata(value, "fix", fix);
371
+ const source = metadata.vobsSource;
372
+ if (source && typeof source === "object" && typeof source.file === "string" && typeof source.line === "number" && typeof source.column === "number") {
373
+ defineErrorMetadata(value, "location", source);
374
+ }
375
+ return value;
376
+ }
377
+ if (isVobsError(value)) return adoptVobsError(value, defaults);
378
+ return new VobsError({
379
+ code: defaults.code ?? "VOBS_UNKNOWN",
380
+ message: describeUnknown(value),
381
+ severity: defaults.severity ?? "error",
382
+ layer: defaults.layer ?? "runtime",
383
+ cause: void 0,
384
+ fix: defaults.fix
385
+ });
386
+ }
387
+ __name(normalizeVobsError, "normalizeVobsError");
388
+ function defineErrorMetadata(target, key, value) {
389
+ if (key in target) return;
390
+ try {
391
+ Object.defineProperty(target, key, { configurable: true, enumerable: false, value, writable: true });
392
+ } catch {
393
+ }
394
+ }
395
+ __name(defineErrorMetadata, "defineErrorMetadata");
396
+ function formatVobsError(value, options = {}) {
397
+ const error = normalizeVobsError(value);
398
+ const code = error.code || "VOBS_UNKNOWN";
399
+ const severity = error.severity || "error";
400
+ if (options.environment === "production") return `[Vobs ${code}] ${error.message}`;
401
+ const lines = [`[Vobs ${capitalize(severity)}] ${error.message}`, `Code: ${code}`];
402
+ if (error.location) lines.push(`Location: ${error.location.file}:${error.location.line}:${error.location.column}`);
403
+ if (error.codeFrame) lines.push("", error.codeFrame);
404
+ if (error.cause !== void 0) lines.push(`Cause: ${formatCause(error.cause)}`);
405
+ if (error.trace?.length) lines.push("", `Trace: ${error.trace.join(" \u2192 ")}`);
406
+ if (error.fix) lines.push("", `Fix: ${error.fix}`);
407
+ if (error.example) lines.push("", `Example:
408
+ ${error.example}`);
409
+ if (error.docs) lines.push(`Docs: ${error.docs}`);
410
+ if (options.includeStack && error.stack) lines.push("", error.stack);
411
+ return lines.join("\n");
412
+ }
413
+ __name(formatVobsError, "formatVobsError");
414
+ function formatCause(value) {
415
+ return value instanceof Error ? `${value.name}: ${value.message}` : String(value);
416
+ }
417
+ __name(formatCause, "formatCause");
418
+ function capitalize(value) {
419
+ return value.slice(0, 1).toUpperCase() + value.slice(1);
420
+ }
421
+ __name(capitalize, "capitalize");
88
422
 
89
423
  // packages/runtime/src/hmr.ts
90
424
  var globalTarget = globalThis;
@@ -124,7 +458,8 @@ function updateHmrModule(moduleId, nextModule) {
124
458
  for (const instance of instances) {
125
459
  try {
126
460
  instance.refresh();
127
- } catch {
461
+ } catch (error) {
462
+ console.error(formatVobsError(error, { includeStack: true }));
128
463
  }
129
464
  }
130
465
  }
@@ -133,21 +468,21 @@ function disposeHmrModule(_moduleId) {
133
468
  }
134
469
  __name(disposeHmrModule, "disposeHmrModule");
135
470
  function createHmrStateStore(moduleId) {
136
- const state4 = getModule(moduleId).state;
471
+ const state5 = getModule(moduleId).state;
137
472
  return {
138
473
  get(key, initial) {
139
- if (!state4.has(key)) state4.set(key, typeof initial === "function" ? initial() : initial);
140
- return state4.get(key);
474
+ if (!state5.has(key)) state5.set(key, typeof initial === "function" ? initial() : initial);
475
+ return state5.get(key);
141
476
  },
142
477
  set(key, value) {
143
- state4.set(key, value);
478
+ state5.set(key, value);
144
479
  },
145
- has: /* @__PURE__ */ __name((key) => state4.has(key), "has"),
480
+ has: /* @__PURE__ */ __name((key) => state5.has(key), "has"),
146
481
  delete: /* @__PURE__ */ __name((key) => {
147
- state4.delete(key);
482
+ state5.delete(key);
148
483
  }, "delete"),
149
484
  clear: /* @__PURE__ */ __name(() => {
150
- state4.clear();
485
+ state5.clear();
151
486
  }, "clear")
152
487
  };
153
488
  }
@@ -192,15 +527,34 @@ function ref(initialValue = null) {
192
527
  return { current: initialValue };
193
528
  }
194
529
  __name(ref, "ref");
530
+ var refCleanups = /* @__PURE__ */ new WeakMap();
531
+ function rememberRefCleanup(owner, target, cleanup) {
532
+ let byTarget = refCleanups.get(owner);
533
+ if (!byTarget) {
534
+ byTarget = /* @__PURE__ */ new WeakMap();
535
+ refCleanups.set(owner, byTarget);
536
+ }
537
+ const previous = byTarget.get(target);
538
+ if (previous) owner.removeCleanup(previous);
539
+ byTarget.set(target, cleanup);
540
+ }
541
+ __name(rememberRefCleanup, "rememberRefCleanup");
195
542
  function setRef(node, target) {
196
543
  if (!isRefTarget(target)) return;
197
544
  if (isSSRNode(node)) return;
198
545
  const owner = getCurrentOwner();
199
546
  assignRef(target, node);
200
- owner?.onDispose(() => {
201
- if (isObjectRef(target) && target.current !== node) return;
202
- assignRef(target, null);
203
- });
547
+ if (!owner) return;
548
+ const cleanup = /* @__PURE__ */ __name(() => {
549
+ try {
550
+ if (isObjectRef(target) && target.current !== node) return;
551
+ assignRef(target, null);
552
+ } catch (error) {
553
+ console.error(formatVobsError(error, { includeStack: true }));
554
+ }
555
+ }, "cleanup");
556
+ rememberRefCleanup(owner, target, cleanup);
557
+ owner.onDispose(cleanup);
204
558
  }
205
559
  __name(setRef, "setRef");
206
560
  function isSSRNode(value) {
@@ -220,7 +574,8 @@ function assignRef(target, value) {
220
574
  try {
221
575
  if (typeof target === "function") target(value);
222
576
  else target.current = value;
223
- } catch {
577
+ } catch (error) {
578
+ console.error(formatVobsError(error, { includeStack: true }));
224
579
  }
225
580
  }
226
581
  __name(assignRef, "assignRef");
@@ -229,8 +584,22 @@ __name(assignRef, "assignRef");
229
584
  var currentRenderer = null;
230
585
  var nodeOwners = /* @__PURE__ */ new WeakMap();
231
586
  var eventBindings = /* @__PURE__ */ new WeakMap();
587
+ var eventCleanupSlots = /* @__PURE__ */ new WeakMap();
588
+ var eventCleanupNodeIds = /* @__PURE__ */ new WeakMap();
589
+ var nextEventCleanupNodeId = 0;
590
+ function eventCleanupKey(node, event) {
591
+ let id = eventCleanupNodeIds.get(node);
592
+ if (id === void 0) {
593
+ id = ++nextEventCleanupNodeId;
594
+ eventCleanupNodeIds.set(node, id);
595
+ }
596
+ return `${id}:${event}`;
597
+ }
598
+ __name(eventCleanupKey, "eventCleanupKey");
232
599
  function setRenderer(renderer) {
233
- currentRenderer = renderer;
600
+ const previous = currentRenderer;
601
+ currentRenderer = renderer ?? null;
602
+ return previous;
234
603
  }
235
604
  __name(setRenderer, "setRenderer");
236
605
  function getRenderer() {
@@ -244,75 +613,20 @@ function createText(content) {
244
613
  return getRenderer().createText(content);
245
614
  }
246
615
  __name(createText, "createText");
247
- var SVG_TAGS = /* @__PURE__ */ new Set([
248
- "animate",
249
- "animateMotion",
250
- "animateTransform",
251
- "circle",
252
- "clipPath",
253
- "defs",
254
- "desc",
255
- "ellipse",
256
- "feBlend",
257
- "feColorMatrix",
258
- "feComponentTransfer",
259
- "feComposite",
260
- "feConvolveMatrix",
261
- "feDiffuseLighting",
262
- "feDisplacementMap",
263
- "feDistantLight",
264
- "feDropShadow",
265
- "feFlood",
266
- "feFuncA",
267
- "feFuncB",
268
- "feFuncG",
269
- "feFuncR",
270
- "feGaussianBlur",
271
- "feImage",
272
- "feMerge",
273
- "feMergeNode",
274
- "feMorphology",
275
- "feOffset",
276
- "fePointLight",
277
- "feSpecularLighting",
278
- "feSpotLight",
279
- "feTile",
280
- "feTurbulence",
281
- "filter",
282
- "foreignObject",
283
- "g",
284
- "image",
285
- "line",
286
- "linearGradient",
287
- "marker",
288
- "mask",
289
- "metadata",
290
- "mpath",
291
- "path",
292
- "pattern",
293
- "polygon",
294
- "polyline",
295
- "radialGradient",
296
- "rect",
297
- "set",
298
- "stop",
299
- "svg",
300
- "switch",
301
- "symbol",
302
- "text",
303
- "textPath",
304
- "tspan",
305
- "use",
306
- "view"
307
- ]);
308
616
  function createElement(tag) {
309
- if (SVG_TAGS.has(tag)) {
617
+ if (isSvgTag(tag)) {
310
618
  const renderer = getRenderer();
311
619
  if (renderer.createSvgElement) return renderer.createSvgElement(tag);
312
620
  }
313
621
  return getRenderer().createElement(tag);
314
622
  }
315
623
  __name(createElement, "createElement");
624
+ function createSvgElement(tag) {
625
+ const renderer = getRenderer();
626
+ if (renderer.createSvgElement) return renderer.createSvgElement(tag);
627
+ return renderer.createElement(tag);
628
+ }
629
+ __name(createSvgElement, "createSvgElement");
316
630
  function createComment(content) {
317
631
  return getRenderer().createComment(content);
318
632
  }
@@ -346,7 +660,7 @@ function syncSelectValue(parent) {
346
660
  while (current !== null) {
347
661
  if (current.nodeName === "SELECT") {
348
662
  const read = selectValueReaders.get(current);
349
- if (read !== void 0) setProperty(current, "value", read());
663
+ if (read !== void 0) setProperty(current, "value", untrack(read));
350
664
  return;
351
665
  }
352
666
  current = current.parentNode;
@@ -354,9 +668,9 @@ function syncSelectValue(parent) {
354
668
  }
355
669
  __name(syncSelectValue, "syncSelectValue");
356
670
  function removeChild(parent, child) {
357
- disposeNodeOwner(child);
358
671
  if (isVobsFragment(child)) {
359
672
  child.unmount(parent);
673
+ disposeNodeOwner(child);
360
674
  return;
361
675
  }
362
676
  getRenderer().removeChild(parent, child);
@@ -367,6 +681,7 @@ function removeChild(parent, child) {
367
681
  parent: describeDebugNode(parent)
368
682
  });
369
683
  }
684
+ disposeNodeOwner(child);
370
685
  }
371
686
  __name(removeChild, "removeChild");
372
687
  function setTextContent(node, content) {
@@ -384,7 +699,7 @@ function setTextContent(node, content) {
384
699
  __name(setTextContent, "setTextContent");
385
700
  function setProperty(node, key, value) {
386
701
  const previousValue = getRuntimeDebugHooks() ? readDebugValue(() => Reflect.get(node, key)) : void 0;
387
- getRenderer().setProperty(node, key, value);
702
+ getRenderer().setProperty(node, PROPERTY_IDL_NAMES[key] ?? key, value);
388
703
  if (key === "value" && node.tagName === "SELECT") {
389
704
  scheduleSelectValueSync(node, value);
390
705
  }
@@ -405,12 +720,13 @@ function scheduleSelectValueSync(node, value) {
405
720
  pendingSelectValues.set(node, value);
406
721
  if (selectSyncScheduled.has(node)) return;
407
722
  selectSyncScheduled.add(node);
723
+ const renderer = getRenderer();
408
724
  queueMicrotask(() => {
409
725
  selectSyncScheduled.delete(node);
410
726
  if (!pendingSelectValues.has(node)) return;
411
727
  const pending = pendingSelectValues.get(node);
412
728
  pendingSelectValues.delete(node);
413
- getRenderer().setProperty(node, "value", pending);
729
+ renderer.setProperty(node, "value", pending);
414
730
  });
415
731
  }
416
732
  __name(scheduleSelectValueSync, "scheduleSelectValueSync");
@@ -429,48 +745,131 @@ function setAttribute(node, key, value) {
429
745
  }
430
746
  __name(setAttribute, "setAttribute");
431
747
  function spreadProps(node, props) {
432
- for (const [key, value] of Object.entries(props)) {
433
- if (key === "key" || value === null || value === void 0) continue;
748
+ applySpreadProps(node, null, props);
749
+ }
750
+ __name(spreadProps, "spreadProps");
751
+ function removeAttribute(node, key) {
752
+ const renderer = getRenderer();
753
+ if (renderer.removeAttribute) {
754
+ renderer.removeAttribute(node, key);
755
+ return;
756
+ }
757
+ renderer.setAttribute(node, key, "");
758
+ }
759
+ __name(removeAttribute, "removeAttribute");
760
+ var BOOLEAN_PROPERTIES = /* @__PURE__ */ new Set([
761
+ "checked",
762
+ "selected",
763
+ "disabled",
764
+ "multiple",
765
+ "readOnly",
766
+ "required",
767
+ "hidden",
768
+ "open",
769
+ "indeterminate",
770
+ "defaultChecked",
771
+ "muted",
772
+ "autoFocus"
773
+ ]);
774
+ var PROPERTY_IDL_NAMES = {
775
+ autoFocus: "autofocus"
776
+ };
777
+ function applySpreadProps(node, previous, next) {
778
+ for (const [key, value] of Object.entries(next)) {
779
+ if (key === "key") continue;
780
+ if (previous !== null && Object.is(previous[key], value)) continue;
781
+ if (key.startsWith("on")) {
782
+ const eventName = resolveEventName(key) ?? key.slice(2).toLowerCase();
783
+ const previousHandler = previous?.[key];
784
+ if (typeof previousHandler === "function") {
785
+ removeEventListener(node, eventName, previousHandler);
786
+ }
787
+ if (typeof value === "function") {
788
+ addEventListener(node, eventName, value);
789
+ }
790
+ continue;
791
+ }
434
792
  if (key === "ref") {
435
793
  setRef(node, value);
436
794
  continue;
437
795
  }
438
- if (key.startsWith("on") && typeof value === "function") addEventListener(node, key.slice(2).toLowerCase(), value);
439
- else if (isPropertyKey(key)) setProperty(node, key, value);
796
+ if (value === null || value === void 0) continue;
797
+ else if (isClassListKey(key)) applyClassList(node, value);
798
+ else if (isPropertyName(key)) setProperty(node, key, value);
440
799
  else if (value === false) continue;
441
800
  else setAttribute(node, domAttributeName(key), key === "style" && isStyleObject(value) ? formatStyle(value) : String(value));
442
801
  }
802
+ if (previous === null) return;
803
+ for (const key of Object.keys(previous)) {
804
+ if (key in next || key === "key") continue;
805
+ if (key.startsWith("on")) {
806
+ const eventName = resolveEventName(key) ?? key.slice(2).toLowerCase();
807
+ const previousHandler = previous[key];
808
+ if (typeof previousHandler === "function") {
809
+ removeEventListener(node, eventName, previousHandler);
810
+ }
811
+ continue;
812
+ }
813
+ if (key === "ref") continue;
814
+ if (isPropertyName(key)) setProperty(node, key, BOOLEAN_PROPERTIES.has(key) ? false : "");
815
+ else removeAttribute(node, domAttributeName(key));
816
+ }
443
817
  }
444
- __name(spreadProps, "spreadProps");
818
+ __name(applySpreadProps, "applySpreadProps");
819
+ var classListContributions = /* @__PURE__ */ new WeakMap();
820
+ function parseClassList(value) {
821
+ const names = [];
822
+ const push = /* @__PURE__ */ __name((candidate) => {
823
+ if (typeof candidate === "string") {
824
+ for (const name of candidate.split(/\s+/u)) if (name !== "") names.push(name);
825
+ }
826
+ }, "push");
827
+ if (Array.isArray(value)) {
828
+ for (const entry of value) {
829
+ if (entry !== null && typeof entry === "object") {
830
+ for (const [name, on] of Object.entries(entry)) if (on) push(name);
831
+ } else push(entry);
832
+ }
833
+ } else if (value !== null && typeof value === "object") {
834
+ for (const [name, on] of Object.entries(value)) if (on) push(name);
835
+ } else push(value);
836
+ return names;
837
+ }
838
+ __name(parseClassList, "parseClassList");
839
+ function applyClassList(node, value) {
840
+ const next = parseClassList(value);
841
+ const previous = classListContributions.get(node) ?? [];
842
+ classListContributions.set(node, next);
843
+ const base = (node.getAttribute("class") ?? "").split(/\s+/u).filter((name) => name !== "" && !previous.includes(name));
844
+ const merged = [.../* @__PURE__ */ new Set([...base, ...next])];
845
+ setAttribute(node, "class", merged.join(" "));
846
+ }
847
+ __name(applyClassList, "applyClassList");
848
+ function isClassListKey(key) {
849
+ return key === "classList";
850
+ }
851
+ __name(isClassListKey, "isClassListKey");
852
+ function bindSpreadProps(node, source) {
853
+ let previous = null;
854
+ effect(() => {
855
+ const next = source() ?? {};
856
+ const snapshot = { ...next };
857
+ applySpreadProps(node, previous, next);
858
+ previous = snapshot;
859
+ });
860
+ }
861
+ __name(bindSpreadProps, "bindSpreadProps");
445
862
  function setStaticProps(node, props) {
446
863
  for (const [key, value] of Object.entries(props)) {
447
864
  if (key === "key" || key === "ref" || key.startsWith("on")) continue;
448
865
  if (value === null || value === void 0) continue;
449
- if (isPropertyKey(key)) setProperty(node, key, value);
866
+ if (isClassListKey(key)) applyClassList(node, value);
867
+ else if (isPropertyName(key)) setProperty(node, key, value);
450
868
  else if (value === false) continue;
451
869
  else setAttribute(node, domAttributeName(key), key === "style" && isStyleObject(value) ? formatStyle(value) : String(value));
452
870
  }
453
871
  }
454
872
  __name(setStaticProps, "setStaticProps");
455
- function isPropertyKey(key) {
456
- return key === "value" || key === "checked" || key === "selected" || key === "disabled" || key === "multiple" || key === "readOnly" || key === "required" || key === "autofocus" || key === "hidden" || key === "tabIndex" || key === "colSpan" || key === "rowSpan";
457
- }
458
- __name(isPropertyKey, "isPropertyKey");
459
- function domAttributeName(key) {
460
- switch (key) {
461
- case "className":
462
- return "class";
463
- case "htmlFor":
464
- return "for";
465
- case "autoComplete":
466
- return "autocomplete";
467
- case "spellCheck":
468
- return "spellcheck";
469
- default:
470
- return key;
471
- }
472
- }
473
- __name(domAttributeName, "domAttributeName");
474
873
  function isStyleObject(value) {
475
874
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
476
875
  }
@@ -489,7 +888,9 @@ function addEventListener(node, event, handler) {
489
888
  }
490
889
  const previous = bindings.get(event);
491
890
  if (previous && previous.original === handler && previous.owner === owner) return;
492
- if (previous) renderer.removeEventListener(node, event, previous.handler);
891
+ if (previous) {
892
+ renderer.removeEventListener(node, event, previous.handler);
893
+ }
493
894
  const listener = owner ? (reason) => {
494
895
  if (owner.disposed) return;
495
896
  try {
@@ -503,28 +904,66 @@ function addEventListener(node, event, handler) {
503
904
  handled,
504
905
  recovery: handled ? "handled" : "propagated"
505
906
  });
907
+ if (handled && getRuntimeDebugHooks()?.error === void 0) {
908
+ console.error(formatVobsError(error, { includeStack: true }));
909
+ }
506
910
  if (!handled) throw error;
507
911
  }
508
912
  } : handler;
509
913
  const binding = { handler: listener, owner, original: handler };
510
914
  bindings.set(event, binding);
511
915
  renderer.addEventListener(node, event, listener);
512
- owner?.onDispose(() => {
513
- if (bindings?.get(event) !== binding) return;
514
- bindings.delete(event);
515
- renderer.removeEventListener(node, event, listener);
916
+ if (!owner) return;
917
+ const key = eventCleanupKey(node, event);
918
+ let slots = eventCleanupSlots.get(owner);
919
+ if (!slots) {
920
+ slots = /* @__PURE__ */ new Map();
921
+ eventCleanupSlots.set(owner, slots);
922
+ }
923
+ const hasSlot = slots.has(key);
924
+ slots.set(key, binding);
925
+ if (hasSlot) return;
926
+ owner.onDispose(() => {
927
+ const current = eventCleanupSlots.get(owner)?.get(key);
928
+ if (!current) return;
929
+ eventCleanupSlots.get(owner)?.delete(key);
930
+ const map = eventBindings.get(node);
931
+ if (map?.get(event) === current) map.delete(event);
932
+ renderer.removeEventListener(node, event, current.handler);
516
933
  });
517
934
  }
518
935
  __name(addEventListener, "addEventListener");
519
936
  function removeEventListener(node, event, handler) {
520
937
  const renderer = getRenderer();
521
- const binding = eventBindings.get(node)?.get(event);
938
+ const map = eventBindings.get(node);
939
+ const binding = map?.get(event);
940
+ if (binding) {
941
+ if (binding.handler !== handler) return;
942
+ map?.delete(event);
943
+ }
522
944
  renderer.removeEventListener(node, event, binding?.handler ?? handler);
523
- eventBindings.get(node)?.delete(event);
524
945
  }
525
946
  __name(removeEventListener, "removeEventListener");
526
947
  function clear(container) {
948
+ let firstError;
949
+ const walk = /* @__PURE__ */ __name((node) => {
950
+ try {
951
+ disposeNodeOwner(node);
952
+ } catch (error) {
953
+ firstError ?? (firstError = error);
954
+ }
955
+ for (const child of Array.from(node.childNodes)) walk(child);
956
+ }, "walk");
957
+ for (const child of Array.from(container.childNodes)) walk(child);
527
958
  getRenderer().clear(container);
959
+ if (getRuntimeDebugHooks()) {
960
+ invokeRuntimeDebug("domMutation", {
961
+ operation: "clear",
962
+ target: describeDebugNode(container),
963
+ parent: describeDebugNode(container)
964
+ });
965
+ }
966
+ if (firstError) throw firstError;
528
967
  }
529
968
  __name(clear, "clear");
530
969
  function createComponent(component, props, source) {
@@ -546,15 +985,16 @@ function createComponent(component, props, source) {
546
985
  owner.onDispose(cleanup);
547
986
  }
548
987
  const renderScope = owner.mark();
549
- let node;
988
+ let rendered;
550
989
  try {
551
- node = owner.run(() => untrack(() => component(props)));
990
+ rendered = owner.run(() => untrack(() => component(props)));
552
991
  } catch (error) {
553
992
  owner.dispose();
554
993
  attachSourceLocation(error, source);
555
994
  attachComponentContext(error, componentName, owner.id);
556
995
  throw error;
557
996
  }
997
+ const node = isRenderableNode(rendered) ? rendered : createComment("vobs:empty");
558
998
  associateNodeOwner(node, owner);
559
999
  if (instance) {
560
1000
  instance.node = node;
@@ -625,7 +1065,16 @@ function createBlock(factory) {
625
1065
  return node;
626
1066
  }
627
1067
  __name(createBlock, "createBlock");
1068
+ function isRenderableNode(value) {
1069
+ return typeof value === "object" && value !== null || typeof value === "function";
1070
+ }
1071
+ __name(isRenderableNode, "isRenderableNode");
628
1072
  function associateNodeOwner(node, owner) {
1073
+ if (node === null || node === void 0 || typeof node !== "object" && typeof node !== "function") {
1074
+ throw new Error(
1075
+ `Vobs: associateNodeOwner \u6536\u5230\u975E\u8282\u70B9\u503C\uFF08${String(node)}\uFF09\u3002\u7EC4\u4EF6\u5FC5\u987B\u8FD4\u56DE VobsNode\uFF1B\u8FD4\u56DE null/undefined \u7531 createComponent \u8F6C\u6210\u7A7A\u6CE8\u91CA\u8282\u70B9\u3002`
1076
+ );
1077
+ }
629
1078
  nodeOwners.set(node, owner);
630
1079
  }
631
1080
  __name(associateNodeOwner, "associateNodeOwner");
@@ -705,21 +1154,26 @@ function moveRange(parent, start, end, anchor) {
705
1154
  __name(moveRange, "moveRange");
706
1155
 
707
1156
  // packages/runtime/src/bind.ts
708
- import { effect } from "@vobs/reactivity";
1157
+ import { effect as effect2 } from "@vobs/reactivity";
709
1158
  function readSource(source) {
710
1159
  return typeof source === "function" ? source() : source.value;
711
1160
  }
712
1161
  __name(readSource, "readSource");
713
1162
  function bindText(node, source) {
714
- effect(() => {
1163
+ effect2(() => {
715
1164
  const value = readSource(source);
716
1165
  setTextContent(node, value === null || value === void 0 || typeof value === "boolean" ? "" : String(value));
717
1166
  });
718
1167
  }
719
1168
  __name(bindText, "bindText");
720
1169
  function bindAttribute(node, key, source) {
721
- effect(() => {
1170
+ effect2(() => {
722
1171
  const value = readSource(source);
1172
+ if (value === null || value === void 0) return;
1173
+ if (key === "classList") {
1174
+ applyClassList(node, value);
1175
+ return;
1176
+ }
723
1177
  setAttribute(node, key, key === "style" && value && typeof value === "object" && !Array.isArray(value) ? Object.entries(value).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== false).map(([name, entry]) => `${name.replace(/[A-Z]/gu, (match) => `-${match.toLowerCase()}`)}:${String(entry)}`).join(";") : String(value));
724
1178
  });
725
1179
  }
@@ -728,19 +1182,21 @@ function bindProperty(node, key, source) {
728
1182
  if (key === "value" && node.nodeName === "SELECT") {
729
1183
  registerSelectValueBinding(node, () => readSource(source));
730
1184
  }
731
- effect(() => {
732
- setProperty(node, key, readSource(source));
1185
+ effect2(() => {
1186
+ const value = readSource(source);
1187
+ if (value === null || value === void 0) return;
1188
+ setProperty(node, key, value);
733
1189
  });
734
1190
  }
735
1191
  __name(bindProperty, "bindProperty");
736
1192
 
737
1193
  // packages/runtime/src/dynamic.ts
738
- import { createOwner as createOwner2, effect as effect2, state } from "@vobs/reactivity";
1194
+ import { createOwner as createOwner2, effect as effect3, state } from "@vobs/reactivity";
739
1195
  function insertDynamic(parent, anchor, factory) {
740
1196
  const marker = createComment("vobs:dynamic");
741
1197
  insertBefore(parent, marker, anchor);
742
1198
  let current = null;
743
- effect2(() => {
1199
+ effect3(() => {
744
1200
  const next = createBlock(factory);
745
1201
  if (next === current) return;
746
1202
  if (current) removeChild(parent, current);
@@ -755,7 +1211,7 @@ function insertDynamicValue(parent, anchor, factory) {
755
1211
  let current = null;
756
1212
  let currentIsText = false;
757
1213
  let scope = null;
758
- effect2(() => {
1214
+ effect3(() => {
759
1215
  const nextScope = createOwner2();
760
1216
  const value = nextScope.run(factory);
761
1217
  if (typeof value === "string" || typeof value === "number") {
@@ -823,7 +1279,7 @@ function insertList(parent, anchor, source, renderItem, keyOf) {
823
1279
  insertBefore(parent, marker, anchor);
824
1280
  let entries = [];
825
1281
  const tracksIndex = renderItem.length >= 2;
826
- effect2(() => {
1282
+ effect3(() => {
827
1283
  const items = source();
828
1284
  let keys = null;
829
1285
  if (keyOf) {
@@ -839,6 +1295,32 @@ function insertList(parent, anchor, source, renderItem, keyOf) {
839
1295
  }
840
1296
  if (!allKeyed) keys = null;
841
1297
  }
1298
+ if (keys !== null && entries.length === items.length) {
1299
+ let fast = true;
1300
+ for (let index = 0; index < keys.length; index++) {
1301
+ if (!Object.is(entries[index].key, keys[index])) {
1302
+ fast = false;
1303
+ break;
1304
+ }
1305
+ const item = items[index];
1306
+ if (isPrimitiveItem(item) && !Object.is(entries[index].current, item)) {
1307
+ fast = false;
1308
+ break;
1309
+ }
1310
+ }
1311
+ if (fast) {
1312
+ for (let index = 0; index < items.length; index++) {
1313
+ const entry = entries[index];
1314
+ entry.index = index;
1315
+ const item = items[index];
1316
+ if (!Object.is(entry.current, item)) {
1317
+ entry.item.value = item;
1318
+ entry.current = item;
1319
+ }
1320
+ }
1321
+ return;
1322
+ }
1323
+ }
842
1324
  const nextEntries = keys ? reconcileKeyed(items, keys, entries, renderItem) : reconcileIndexed(items, entries, renderItem);
843
1325
  const refreshed = tracksIndex ? /* @__PURE__ */ new Set() : null;
844
1326
  for (let index = 0; index < nextEntries.length; index++) {
@@ -927,7 +1409,8 @@ function computeKeptByLis(seq) {
927
1409
  }
928
1410
  __name(computeKeptByLis, "computeKeptByLis");
929
1411
  function reconcileKeyed(items, keys, entries, renderItem) {
930
- const previous = new Map(entries.map((entry) => [entry.key, entry]));
1412
+ const previous = /* @__PURE__ */ new Map();
1413
+ for (const entry of entries) previous.set(entry.key, entry);
931
1414
  const seen = /* @__PURE__ */ new Set();
932
1415
  const nextEntries = [];
933
1416
  for (let index = 0; index < items.length; index++) {
@@ -940,12 +1423,12 @@ function reconcileKeyed(items, keys, entries, renderItem) {
940
1423
  const entry = previous.get(key);
941
1424
  if (entry) {
942
1425
  previous.delete(key);
943
- if (isPrimitiveItem(item) && !Object.is(entry.value, item)) {
1426
+ if (isPrimitiveItem(item) && !Object.is(entry.current, item)) {
944
1427
  nextEntries.push(createListEntry(item, index, key, renderItem));
945
1428
  continue;
946
1429
  }
947
1430
  entry.item.value = item;
948
- entry.value = item;
1431
+ entry.current = item;
949
1432
  nextEntries.push(entry);
950
1433
  continue;
951
1434
  }
@@ -959,13 +1442,13 @@ function reconcileIndexed(items, entries, renderItem) {
959
1442
  for (let index = 0; index < items.length; index++) {
960
1443
  const item = items[index];
961
1444
  const entry = entries[index];
962
- if (entry && isPrimitiveItem(item) && !Object.is(entry.value, item)) {
1445
+ if (entry && isPrimitiveItem(item) && !Object.is(entry.current, item)) {
963
1446
  nextEntries.push(createListEntry(item, index, index, renderItem));
964
1447
  continue;
965
1448
  }
966
1449
  if (entry) {
967
1450
  entry.item.value = item;
968
- entry.value = item;
1451
+ entry.current = item;
969
1452
  nextEntries.push(entry);
970
1453
  continue;
971
1454
  }
@@ -989,7 +1472,7 @@ function createListEntry(item, index, key, renderItem) {
989
1472
  node = viewOwner.run(() => renderItem(toReactiveItem(itemSignal, item), index));
990
1473
  });
991
1474
  associateNodeOwner(node, viewOwner);
992
- return { key, node, owner, viewOwner, item: itemSignal, value: item, index };
1475
+ return { key, node, owner, viewOwner, item: itemSignal, current: item, index };
993
1476
  }
994
1477
  __name(createListEntry, "createListEntry");
995
1478
  function refreshListEntry(parent, entry, index, renderItem) {
@@ -999,7 +1482,7 @@ function refreshListEntry(parent, entry, index, renderItem) {
999
1482
  entry.owner.run(() => {
1000
1483
  entry.viewOwner = createOwner2();
1001
1484
  entry.node = entry.viewOwner.run(() => renderItem(
1002
- toReactiveItem(entry.item, entry.value),
1485
+ toReactiveItem(entry.item, entry.current),
1003
1486
  index
1004
1487
  ));
1005
1488
  });
@@ -1011,7 +1494,7 @@ function toReactiveItem(item, initialValue) {
1011
1494
  if (typeof initialValue !== "object" || initialValue === null) {
1012
1495
  return initialValue;
1013
1496
  }
1014
- return new Proxy(initialValue, {
1497
+ return new Proxy(reactiveProxyTarget(initialValue), {
1015
1498
  get(_target, property, receiver) {
1016
1499
  return Reflect.get(item.value, property, receiver);
1017
1500
  },
@@ -1021,12 +1504,29 @@ function toReactiveItem(item, initialValue) {
1021
1504
  ownKeys() {
1022
1505
  return Reflect.ownKeys(item.value);
1023
1506
  },
1024
- getOwnPropertyDescriptor(_target, property) {
1025
- return Object.getOwnPropertyDescriptor(item.value, property);
1507
+ getOwnPropertyDescriptor(target, property) {
1508
+ const descriptor = Object.getOwnPropertyDescriptor(item.value, property);
1509
+ if (!descriptor) return void 0;
1510
+ const own = Object.getOwnPropertyDescriptor(target, property);
1511
+ return { ...descriptor, configurable: own ? own.configurable : true };
1026
1512
  }
1027
1513
  });
1028
1514
  }
1029
1515
  __name(toReactiveItem, "toReactiveItem");
1516
+ function reactiveProxyTarget(value) {
1517
+ if (Object.isExtensible(value)) {
1518
+ let allConfigurable = true;
1519
+ for (const key of Reflect.ownKeys(value)) {
1520
+ if (Object.getOwnPropertyDescriptor(value, key)?.configurable === false) {
1521
+ allConfigurable = false;
1522
+ break;
1523
+ }
1524
+ }
1525
+ if (allConfigurable) return value;
1526
+ }
1527
+ return Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
1528
+ }
1529
+ __name(reactiveProxyTarget, "reactiveProxyTarget");
1030
1530
  function disposeEntry(parent, entry) {
1031
1531
  removeChild(parent, entry.node);
1032
1532
  entry.owner.dispose();
@@ -1052,113 +1552,15 @@ function cloneTemplate(template) {
1052
1552
  }
1053
1553
  __name(cloneTemplate, "cloneTemplate");
1054
1554
 
1055
- // packages/runtime/src/error.ts
1056
- var _VobsError = class _VobsError extends Error {
1057
- constructor(options) {
1058
- super(options.message);
1059
- this.name = "VobsError";
1060
- this.code = options.code;
1061
- this.severity = options.severity ?? "error";
1062
- this.layer = options.layer ?? "runtime";
1063
- this.cause = options.cause;
1064
- this.fix = options.fix;
1065
- this.location = options.location;
1066
- this.trace = options.trace;
1067
- this.example = options.example;
1068
- this.docs = options.docs;
1069
- this.codeFrame = options.codeFrame;
1070
- }
1071
- };
1072
- __name(_VobsError, "VobsError");
1073
- var VobsError = _VobsError;
1074
- function createVobsError(options) {
1075
- return new VobsError(options);
1076
- }
1077
- __name(createVobsError, "createVobsError");
1078
- function isVobsError(value) {
1079
- return value instanceof VobsError || Boolean(value && typeof value === "object" && typeof value.code === "string" && typeof value.message === "string" && typeof value.layer === "string");
1080
- }
1081
- __name(isVobsError, "isVobsError");
1082
- function normalizeVobsError(value, defaults = {}) {
1083
- if (value instanceof VobsError) return value;
1084
- if (value instanceof Error) {
1085
- const metadata = value;
1086
- const code = defaults.code ?? (typeof metadata.vobsCode === "string" ? metadata.vobsCode : void 0);
1087
- if (code) defineErrorMetadata(value, "code", code);
1088
- defineErrorMetadata(value, "severity", defaults.severity ?? "error");
1089
- defineErrorMetadata(value, "layer", defaults.layer ?? "runtime");
1090
- const fix = defaults.fix ?? (typeof metadata.vobsHint === "string" ? metadata.vobsHint : void 0);
1091
- if (fix) defineErrorMetadata(value, "fix", fix);
1092
- const source = metadata.vobsSource;
1093
- if (source && typeof source === "object" && typeof source.file === "string" && typeof source.line === "number" && typeof source.column === "number") {
1094
- defineErrorMetadata(value, "location", source);
1095
- }
1096
- return value;
1097
- }
1098
- if (isVobsError(value)) {
1099
- const candidate = value;
1100
- return new VobsError({
1101
- code: candidate.code,
1102
- message: candidate.message,
1103
- severity: candidate.severity ?? defaults.severity,
1104
- layer: candidate.layer ?? defaults.layer,
1105
- cause: candidate.cause,
1106
- fix: candidate.fix ?? defaults.fix,
1107
- location: candidate.location,
1108
- trace: candidate.trace,
1109
- example: candidate.example,
1110
- docs: candidate.docs,
1111
- codeFrame: candidate.codeFrame
1112
- });
1113
- }
1114
- const message = String(value);
1115
- return new VobsError({
1116
- code: defaults.code ?? "VOBS_UNKNOWN",
1117
- message,
1118
- severity: defaults.severity ?? "error",
1119
- layer: defaults.layer ?? "runtime",
1120
- cause: void 0,
1121
- fix: defaults.fix
1122
- });
1123
- }
1124
- __name(normalizeVobsError, "normalizeVobsError");
1125
- function defineErrorMetadata(target, key, value) {
1126
- if (key in target) return;
1127
- try {
1128
- Object.defineProperty(target, key, { configurable: true, enumerable: false, value, writable: true });
1129
- } catch {
1130
- }
1131
- }
1132
- __name(defineErrorMetadata, "defineErrorMetadata");
1133
- function formatVobsError(value, options = {}) {
1134
- const error = normalizeVobsError(value);
1135
- const code = error.code || "VOBS_UNKNOWN";
1136
- const severity = error.severity || "error";
1137
- if (options.environment === "production") return `[Vobs ${code}] ${error.message}`;
1138
- const lines = [`[Vobs ${capitalize(severity)}] ${error.message}`, `Code: ${code}`];
1139
- if (error.location) lines.push(`Location: ${error.location.file}:${error.location.line}:${error.location.column}`);
1140
- if (error.codeFrame) lines.push("", error.codeFrame);
1141
- if (error.cause !== void 0) lines.push(`Cause: ${formatCause(error.cause)}`);
1142
- if (error.trace?.length) lines.push("", `Trace: ${error.trace.join(" \u2192 ")}`);
1143
- if (error.fix) lines.push("", `Fix: ${error.fix}`);
1144
- if (error.example) lines.push("", `Example:
1145
- ${error.example}`);
1146
- if (error.docs) lines.push(`Docs: ${error.docs}`);
1147
- if (options.includeStack && error.stack) lines.push("", error.stack);
1148
- return lines.join("\n");
1149
- }
1150
- __name(formatVobsError, "formatVobsError");
1151
- function formatCause(value) {
1152
- return value instanceof Error ? `${value.name}: ${value.message}` : String(value);
1153
- }
1154
- __name(formatCause, "formatCause");
1155
- function capitalize(value) {
1156
- return value.slice(0, 1).toUpperCase() + value.slice(1);
1157
- }
1158
- __name(capitalize, "capitalize");
1159
-
1160
1555
  // packages/runtime/src/boundary.ts
1161
1556
  import { createOwner as createOwner3, state as state2 } from "@vobs/reactivity";
1557
+ function reportBoundaryError(event, loud) {
1558
+ invokeRuntimeDebug("error", event);
1559
+ if (loud && getRuntimeDebugHooks()?.error === void 0) {
1560
+ console.error(formatVobsError(event.error, { includeStack: true }));
1561
+ }
1562
+ }
1563
+ __name(reportBoundaryError, "reportBoundaryError");
1162
1564
  function insertBoundary(parent, anchor, options) {
1163
1565
  const boundary = createOwner3();
1164
1566
  boundary.run(() => {
@@ -1175,24 +1577,24 @@ function insertBoundary(parent, anchor, options) {
1175
1577
  fix: "\u68C0\u67E5\u7EC4\u4EF6\u6E32\u67D3\u903B\u8F91\uFF0C\u6216\u5728\u8FB9\u754C fallback \u4E2D\u63D0\u4F9B\u6062\u590D\u64CD\u4F5C\u3002"
1176
1578
  });
1177
1579
  lastError = normalized;
1178
- invokeRuntimeDebug("error", {
1580
+ reportBoundaryError({
1179
1581
  error: normalized,
1180
1582
  owner: boundary,
1181
1583
  phase: "boundary",
1182
1584
  handled: true,
1183
1585
  recovery: "fallback"
1184
- });
1586
+ }, true);
1185
1587
  error.value = normalized;
1186
1588
  });
1187
1589
  const retry = /* @__PURE__ */ __name(() => {
1188
1590
  if (error.value) {
1189
- invokeRuntimeDebug("error", {
1591
+ reportBoundaryError({
1190
1592
  error: error.value,
1191
1593
  owner: boundary,
1192
1594
  phase: "boundary",
1193
1595
  handled: true,
1194
1596
  recovery: "retrying"
1195
- });
1597
+ }, false);
1196
1598
  }
1197
1599
  error.value = null;
1198
1600
  return options.onRetry?.();
@@ -1207,13 +1609,13 @@ function insertBoundary(parent, anchor, options) {
1207
1609
  const currentError = error.value;
1208
1610
  if (!currentError) {
1209
1611
  if (fallbackActive && lastError) {
1210
- invokeRuntimeDebug("error", {
1612
+ reportBoundaryError({
1211
1613
  error: lastError,
1212
1614
  owner: boundary,
1213
1615
  phase: "boundary",
1214
1616
  handled: true,
1215
1617
  recovery: "recovered"
1216
- });
1618
+ }, false);
1217
1619
  lastError = null;
1218
1620
  }
1219
1621
  fallbackActive = false;
@@ -1357,14 +1759,79 @@ function now() {
1357
1759
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
1358
1760
  }
1359
1761
  __name(now, "now");
1762
+
1763
+ // packages/runtime/src/show.ts
1764
+ import { effect as effect4 } from "@vobs/reactivity";
1765
+ function Show(props) {
1766
+ const resolved = typeof props.children === "function" ? props.children() : props.children;
1767
+ if (resolved === null || resolved === void 0 || resolved === false) {
1768
+ throw new Error("Vobs Show: children \u4E0D\u80FD\u4E3A\u7A7A \u2014\u2014 \u5B83\u9700\u8981\u4E00\u4E2A\u5BBF\u4E3B\u5143\u7D20\u6765\u6302 hidden/inert\u3002");
1769
+ }
1770
+ const node = resolved;
1771
+ if (isVobsFragment(node) || node.nodeType !== 1) {
1772
+ throw new Error(
1773
+ "Vobs Show: children \u5FC5\u987B\u662F\u5355\u4E2A\u5143\u7D20\u3002\u300C\u4FDD\u7559\u6302\u8F7D + \u5207\u53EF\u89C1\u6027\u300D\u9700\u8981\u5BBF\u4E3B\u5143\u7D20\uFF0C\u800C\u6846\u67B6\u4E0D\u4F1A\u66FF\u4F60\u63D2\u5305\u88F9\u5C42\uFF08\u4F1A\u6539\u5E03\u5C40\uFF09\u3002\u8BF7\u628A\u5185\u5BB9\u5305\u8FDB\u4E00\u4E2A\u5143\u7D20\uFF0C\u4F8B\u5982 <Show when={\u2026}><div>\u2026</div></Show>\uFF1B\u82E5\u786E\u5B9E\u9700\u8981\u5378\u8F7D\u8BED\u4E49\uFF0C\u8BF7\u6539\u7528 JSX \u6761\u4EF6\u8868\u8FBE\u5F0F {cond ? <A/> : <B/>}\u3002"
1774
+ );
1775
+ }
1776
+ const element = node;
1777
+ effect4(() => {
1778
+ const visible = Boolean(readMaybeGetter(props.when));
1779
+ setProperty(element, "hidden", !visible);
1780
+ if (visible) removeAttribute(element, "inert");
1781
+ else setAttribute(element, "inert", "");
1782
+ if (props.hiddenClass !== void 0) applyExtraClass(element, props.hiddenClass, !visible);
1783
+ });
1784
+ return element;
1785
+ }
1786
+ __name(Show, "Show");
1787
+ function readMaybeGetter(value) {
1788
+ return typeof value === "function" ? value() : value;
1789
+ }
1790
+ __name(readMaybeGetter, "readMaybeGetter");
1791
+ function applyExtraClass(element, className, on) {
1792
+ const names = element.getAttribute("class")?.split(/\s+/u).filter(Boolean) ?? [];
1793
+ if (on) {
1794
+ if (names.includes(className)) return;
1795
+ setAttribute(element, "class", [...names, className].join(" "));
1796
+ return;
1797
+ }
1798
+ if (!names.includes(className)) return;
1799
+ setAttribute(element, "class", names.filter((name) => name !== className).join(" "));
1800
+ }
1801
+ __name(applyExtraClass, "applyExtraClass");
1802
+
1803
+ // packages/runtime/src/client-only.ts
1804
+ import { getCurrentOwner as getCurrentOwner4, state as state4 } from "@vobs/reactivity";
1805
+ function ClientOnly(props = {}) {
1806
+ return createFragment((parent, anchor) => {
1807
+ const ready = state4(false);
1808
+ if (typeof document !== "undefined") {
1809
+ const owner = getCurrentOwner4();
1810
+ queueMicrotask(() => {
1811
+ if (owner?.disposed) return;
1812
+ ready.value = true;
1813
+ });
1814
+ }
1815
+ insertDynamic(parent, anchor, () => {
1816
+ const slot = ready.value ? props.children : props.fallback;
1817
+ const value = typeof slot === "function" ? slot() : slot;
1818
+ return value === void 0 || value === null || value === false ? null : value;
1819
+ });
1820
+ });
1821
+ }
1822
+ __name(ClientOnly, "ClientOnly");
1360
1823
  export {
1361
1824
  AsyncBoundary,
1825
+ ClientOnly,
1362
1826
  ErrorBoundary,
1363
1827
  Profiler,
1828
+ Show,
1364
1829
  VobsError,
1365
1830
  addEventListener,
1831
+ applyClassList,
1366
1832
  bindAttribute,
1367
1833
  bindProperty,
1834
+ bindSpreadProps,
1368
1835
  bindText,
1369
1836
  clear,
1370
1837
  cloneTemplate,
@@ -1374,6 +1841,7 @@ export {
1374
1841
  createElement,
1375
1842
  createFragment,
1376
1843
  createHmrStateStore,
1844
+ createSvgElement,
1377
1845
  createTemplate,
1378
1846
  createText,
1379
1847
  createVobsError,
@@ -1399,9 +1867,11 @@ export {
1399
1867
  markHmrInstanceMounted,
1400
1868
  normalizeDynamicChild,
1401
1869
  normalizeVobsError,
1870
+ parseClassList,
1402
1871
  pushRuntimeDebugContext,
1403
1872
  ref,
1404
1873
  registerHmrInstance,
1874
+ removeAttribute,
1405
1875
  removeChild,
1406
1876
  removeEventListener,
1407
1877
  resolveComponent,