@vobs/runtime 1.7.8 → 1.8.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.
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/ops.cjs CHANGED
@@ -24,17 +24,22 @@ var ops_exports = {};
24
24
  __export(ops_exports, {
25
25
  SVG_NAMESPACE: () => SVG_NAMESPACE,
26
26
  addEventListener: () => addEventListener,
27
+ applyClassList: () => applyClassList,
27
28
  associateNodeOwner: () => associateNodeOwner,
29
+ bindSpreadProps: () => bindSpreadProps,
28
30
  clear: () => clear,
29
31
  createBlock: () => createBlock,
30
32
  createComment: () => createComment,
31
33
  createComponent: () => createComponent,
32
34
  createElement: () => createElement,
35
+ createSvgElement: () => createSvgElement,
33
36
  createText: () => createText,
34
37
  disposeNodeOwner: () => disposeNodeOwner,
35
38
  getRenderer: () => getRenderer,
36
39
  insertBefore: () => insertBefore,
40
+ parseClassList: () => parseClassList,
37
41
  registerSelectValueBinding: () => registerSelectValueBinding,
42
+ removeAttribute: () => removeAttribute,
38
43
  removeChild: () => removeChild,
39
44
  removeEventListener: () => removeEventListener,
40
45
  setAttribute: () => setAttribute,
@@ -54,6 +59,337 @@ function isVobsFragment(value) {
54
59
  }
55
60
  __name(isVobsFragment, "isVobsFragment");
56
61
 
62
+ // packages/runtime/src/dom-props.ts
63
+ var PROPERTY_NAMES = /* @__PURE__ */ new Set([
64
+ // 表单状态
65
+ "value",
66
+ "checked",
67
+ "selected",
68
+ "disabled",
69
+ "multiple",
70
+ "readOnly",
71
+ "required",
72
+ "defaultValue",
73
+ "defaultChecked",
74
+ "indeterminate",
75
+ /*
76
+ * `autoFocus` 用**驼峰**(与同表 readOnly/tabIndex/defaultChecked 一致),且必须走
77
+ * **property 通道**:`autofocus` 是**布尔属性**(只看存在与否、与值无关),
78
+ * 所以 `autoFocus={false}` 必须"移除属性"而不是写 `autofocus="false"`
79
+ * (attribute 通道只能把 false 序列化成字符串,属性照样存在 = 仍然聚焦)。
80
+ *
81
+ * ⚠️ 但 `setProperty` 必须把它映射成 **IDL 名 `autofocus`(全小写)** ——
82
+ * `Reflect.set(el, 'autoFocus', …)` 只会挂一个不反射的 expando,**静默无效**。
83
+ * 映射表见 ops.ts 的 `PROPERTY_IDL_NAMES`。实测(jsdom,与真实 DOM 同语义):
84
+ * IDL `autofocus` → 写 true 得 has=true/idl=true;写 false 得 has=false/idl=false ✓
85
+ * JSX `autoFocus` → 属性与 IDL 都不变(只是 expando) ✗
86
+ */
87
+ "autoFocus",
88
+ "hidden",
89
+ "tabIndex",
90
+ "colSpan",
91
+ "rowSpan",
92
+ "open",
93
+ // 只能走 property 的(attribute 路径会静默无效)
94
+ "innerHTML",
95
+ "innerText",
96
+ "textContent",
97
+ // 媒体
98
+ "muted",
99
+ "volume",
100
+ "currentTime",
101
+ "playbackRate"
102
+ ]);
103
+ var ATTRIBUTE_ALIASES = {
104
+ className: "class",
105
+ htmlFor: "for",
106
+ autoComplete: "autocomplete",
107
+ spellCheck: "spellcheck"
108
+ };
109
+ var SVG_KEBAB_ATTRIBUTES = /* @__PURE__ */ new Set([
110
+ // stroke
111
+ "strokeWidth",
112
+ "strokeLinecap",
113
+ "strokeLinejoin",
114
+ "strokeDasharray",
115
+ "strokeDashoffset",
116
+ "strokeMiterlimit",
117
+ "strokeOpacity",
118
+ // fill
119
+ "fillOpacity",
120
+ "fillRule",
121
+ // clip(注意 clipPathUnits 是结构属性,不在这里)
122
+ "clipPath",
123
+ "clipRule",
124
+ // 文本对齐
125
+ "textAnchor",
126
+ "dominantBaseline",
127
+ "alignmentBaseline",
128
+ "baselineShift",
129
+ // 字体
130
+ "fontFamily",
131
+ "fontSize",
132
+ "fontSizeAdjust",
133
+ "fontStretch",
134
+ "fontStyle",
135
+ "fontVariant",
136
+ "fontWeight",
137
+ "letterSpacing",
138
+ "wordSpacing",
139
+ // marker 的表现属性(markerWidth / markerHeight / markerUnits 是结构属性,不在这里)
140
+ "markerStart",
141
+ "markerMid",
142
+ "markerEnd",
143
+ // 颜色
144
+ "colorInterpolation",
145
+ "colorInterpolationFilters",
146
+ "colorProfile",
147
+ "colorRendering",
148
+ "floodColor",
149
+ "floodOpacity",
150
+ "lightingColor",
151
+ "stopColor",
152
+ "stopOpacity",
153
+ "glyphOrientationHorizontal",
154
+ "glyphOrientationVertical",
155
+ // 渲染与合成
156
+ "imageRendering",
157
+ "paintOrder",
158
+ "pointerEvents",
159
+ "shapeRendering",
160
+ "textDecoration",
161
+ "textRendering",
162
+ "transformOrigin",
163
+ "vectorEffect",
164
+ "writingMode"
165
+ ]);
166
+ function isPropertyName(name) {
167
+ return PROPERTY_NAMES.has(name);
168
+ }
169
+ __name(isPropertyName, "isPropertyName");
170
+ function domAttributeName(name) {
171
+ const alias = ATTRIBUTE_ALIASES[name];
172
+ if (alias !== void 0) return alias;
173
+ if (SVG_KEBAB_ATTRIBUTES.has(name)) return name.replace(/[A-Z]/gu, (letter) => `-${letter.toLowerCase()}`);
174
+ return name;
175
+ }
176
+ __name(domAttributeName, "domAttributeName");
177
+
178
+ // packages/runtime/src/dom-events.ts
179
+ var EVENT_NAME_ALIASES = {
180
+ // React 风格的 onDoubleClick 对应的 DOM 事件是 dblclick
181
+ doubleclick: "dblclick",
182
+ // 少数人按 addEventListener 的写法写成 onDblClick
183
+ dblclick: "dblclick"
184
+ };
185
+ function resolveEventName(attributeName) {
186
+ if (!attributeName.startsWith("on") || attributeName.length <= 2) return void 0;
187
+ const lowered = attributeName.slice(2).toLowerCase();
188
+ return EVENT_NAME_ALIASES[lowered] ?? lowered;
189
+ }
190
+ __name(resolveEventName, "resolveEventName");
191
+
192
+ // packages/runtime/src/svg.ts
193
+ var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
194
+ var SVG_TAGS = /* @__PURE__ */ new Set([
195
+ "animate",
196
+ "animateMotion",
197
+ "animateTransform",
198
+ "circle",
199
+ "clipPath",
200
+ "defs",
201
+ "desc",
202
+ "ellipse",
203
+ "feBlend",
204
+ "feColorMatrix",
205
+ "feComponentTransfer",
206
+ "feComposite",
207
+ "feConvolveMatrix",
208
+ "feDiffuseLighting",
209
+ "feDisplacementMap",
210
+ "feDistantLight",
211
+ "feDropShadow",
212
+ "feFlood",
213
+ "feFuncA",
214
+ "feFuncB",
215
+ "feFuncG",
216
+ "feFuncR",
217
+ "feGaussianBlur",
218
+ "feImage",
219
+ "feMerge",
220
+ "feMergeNode",
221
+ "feMorphology",
222
+ "feOffset",
223
+ "fePointLight",
224
+ "feSpecularLighting",
225
+ "feSpotLight",
226
+ "feTile",
227
+ "feTurbulence",
228
+ "filter",
229
+ "foreignObject",
230
+ "g",
231
+ "image",
232
+ "line",
233
+ "linearGradient",
234
+ "marker",
235
+ "mask",
236
+ "metadata",
237
+ "mpath",
238
+ "path",
239
+ "pattern",
240
+ "polygon",
241
+ "polyline",
242
+ "radialGradient",
243
+ "rect",
244
+ "set",
245
+ "stop",
246
+ "svg",
247
+ "switch",
248
+ "symbol",
249
+ "text",
250
+ "textPath",
251
+ "tspan",
252
+ "use",
253
+ "view"
254
+ ]);
255
+ function isSvgTag(tag) {
256
+ return SVG_TAGS.has(tag);
257
+ }
258
+ __name(isSvgTag, "isSvgTag");
259
+
260
+ // packages/runtime/src/error.ts
261
+ var _VobsError = class _VobsError extends Error {
262
+ constructor(options) {
263
+ super(options.message);
264
+ this.name = "VobsError";
265
+ this.code = options.code;
266
+ this.severity = options.severity ?? "error";
267
+ this.layer = options.layer ?? "runtime";
268
+ this.cause = options.cause;
269
+ this.fix = options.fix;
270
+ this.location = options.location;
271
+ this.trace = options.trace;
272
+ this.example = options.example;
273
+ this.docs = options.docs;
274
+ this.codeFrame = options.codeFrame;
275
+ }
276
+ };
277
+ __name(_VobsError, "VobsError");
278
+ var VobsError = _VobsError;
279
+ function isVobsError(value) {
280
+ return value instanceof VobsError || Boolean(value && typeof value === "object" && typeof value.code === "string" && typeof value.message === "string");
281
+ }
282
+ __name(isVobsError, "isVobsError");
283
+ function isForeignVobsError(value) {
284
+ return value instanceof Error && value.name === "VobsError" && typeof value.code === "string";
285
+ }
286
+ __name(isForeignVobsError, "isForeignVobsError");
287
+ function describeUnknown(value) {
288
+ if (value === null || value === void 0) return String(value);
289
+ if (typeof value === "string") return value;
290
+ if (typeof value === "object") {
291
+ const message = value.message;
292
+ if (typeof message === "string" && message !== "") return message;
293
+ try {
294
+ return JSON.stringify(value) ?? String(value);
295
+ } catch {
296
+ return String(value);
297
+ }
298
+ }
299
+ return String(value);
300
+ }
301
+ __name(describeUnknown, "describeUnknown");
302
+ function adoptVobsError(value, defaults) {
303
+ return new VobsError({
304
+ code: value.code,
305
+ message: value.message,
306
+ severity: value.severity ?? defaults.severity,
307
+ layer: value.layer ?? defaults.layer,
308
+ cause: value.cause ?? (value instanceof Error ? value : void 0),
309
+ fix: value.fix ?? defaults.fix,
310
+ location: value.location,
311
+ trace: value.trace,
312
+ example: value.example,
313
+ docs: value.docs,
314
+ codeFrame: value.codeFrame
315
+ });
316
+ }
317
+ __name(adoptVobsError, "adoptVobsError");
318
+ function normalizeVobsError(value, defaults = {}) {
319
+ if (value instanceof VobsError) return value;
320
+ if (isForeignVobsError(value)) return adoptVobsError(value, defaults);
321
+ if (value instanceof Error) {
322
+ const metadata = value;
323
+ const code = defaults.code ?? (typeof metadata.vobsCode === "string" ? metadata.vobsCode : void 0);
324
+ if (code) {
325
+ defineErrorMetadata(value, "code", code);
326
+ if (value.code !== code) {
327
+ return new VobsError({
328
+ code,
329
+ message: value.message,
330
+ severity: defaults.severity ?? "error",
331
+ layer: defaults.layer ?? "runtime",
332
+ cause: value,
333
+ fix: defaults.fix ?? (typeof metadata.vobsHint === "string" ? metadata.vobsHint : void 0)
334
+ });
335
+ }
336
+ }
337
+ defineErrorMetadata(value, "severity", defaults.severity ?? "error");
338
+ defineErrorMetadata(value, "layer", defaults.layer ?? "runtime");
339
+ const fix = defaults.fix ?? (typeof metadata.vobsHint === "string" ? metadata.vobsHint : void 0);
340
+ if (fix) defineErrorMetadata(value, "fix", fix);
341
+ const source = metadata.vobsSource;
342
+ if (source && typeof source === "object" && typeof source.file === "string" && typeof source.line === "number" && typeof source.column === "number") {
343
+ defineErrorMetadata(value, "location", source);
344
+ }
345
+ return value;
346
+ }
347
+ if (isVobsError(value)) return adoptVobsError(value, defaults);
348
+ return new VobsError({
349
+ code: defaults.code ?? "VOBS_UNKNOWN",
350
+ message: describeUnknown(value),
351
+ severity: defaults.severity ?? "error",
352
+ layer: defaults.layer ?? "runtime",
353
+ cause: void 0,
354
+ fix: defaults.fix
355
+ });
356
+ }
357
+ __name(normalizeVobsError, "normalizeVobsError");
358
+ function defineErrorMetadata(target, key, value) {
359
+ if (key in target) return;
360
+ try {
361
+ Object.defineProperty(target, key, { configurable: true, enumerable: false, value, writable: true });
362
+ } catch {
363
+ }
364
+ }
365
+ __name(defineErrorMetadata, "defineErrorMetadata");
366
+ function formatVobsError(value, options = {}) {
367
+ const error = normalizeVobsError(value);
368
+ const code = error.code || "VOBS_UNKNOWN";
369
+ const severity = error.severity || "error";
370
+ if (options.environment === "production") return `[Vobs ${code}] ${error.message}`;
371
+ const lines = [`[Vobs ${capitalize(severity)}] ${error.message}`, `Code: ${code}`];
372
+ if (error.location) lines.push(`Location: ${error.location.file}:${error.location.line}:${error.location.column}`);
373
+ if (error.codeFrame) lines.push("", error.codeFrame);
374
+ if (error.cause !== void 0) lines.push(`Cause: ${formatCause(error.cause)}`);
375
+ if (error.trace?.length) lines.push("", `Trace: ${error.trace.join(" \u2192 ")}`);
376
+ if (error.fix) lines.push("", `Fix: ${error.fix}`);
377
+ if (error.example) lines.push("", `Example:
378
+ ${error.example}`);
379
+ if (error.docs) lines.push(`Docs: ${error.docs}`);
380
+ if (options.includeStack && error.stack) lines.push("", error.stack);
381
+ return lines.join("\n");
382
+ }
383
+ __name(formatVobsError, "formatVobsError");
384
+ function formatCause(value) {
385
+ return value instanceof Error ? `${value.name}: ${value.message}` : String(value);
386
+ }
387
+ __name(formatCause, "formatCause");
388
+ function capitalize(value) {
389
+ return value.slice(0, 1).toUpperCase() + value.slice(1);
390
+ }
391
+ __name(capitalize, "capitalize");
392
+
57
393
  // packages/runtime/src/debug.ts
58
394
  var activeRuntimeDebugHooks = null;
59
395
  function getRuntimeDebugHooks() {
@@ -119,15 +455,34 @@ __name(associateHmrInstance, "associateHmrInstance");
119
455
 
120
456
  // packages/runtime/src/ref.ts
121
457
  var import_reactivity2 = require("@vobs/reactivity");
458
+ var refCleanups = /* @__PURE__ */ new WeakMap();
459
+ function rememberRefCleanup(owner, target, cleanup) {
460
+ let byTarget = refCleanups.get(owner);
461
+ if (!byTarget) {
462
+ byTarget = /* @__PURE__ */ new WeakMap();
463
+ refCleanups.set(owner, byTarget);
464
+ }
465
+ const previous = byTarget.get(target);
466
+ if (previous) owner.removeCleanup(previous);
467
+ byTarget.set(target, cleanup);
468
+ }
469
+ __name(rememberRefCleanup, "rememberRefCleanup");
122
470
  function setRef(node, target) {
123
471
  if (!isRefTarget(target)) return;
124
472
  if (isSSRNode(node)) return;
125
473
  const owner = (0, import_reactivity2.getCurrentOwner)();
126
474
  assignRef(target, node);
127
- owner?.onDispose(() => {
128
- if (isObjectRef(target) && target.current !== node) return;
129
- assignRef(target, null);
130
- });
475
+ if (!owner) return;
476
+ const cleanup = /* @__PURE__ */ __name(() => {
477
+ try {
478
+ if (isObjectRef(target) && target.current !== node) return;
479
+ assignRef(target, null);
480
+ } catch (error) {
481
+ console.error(formatVobsError(error, { includeStack: true }));
482
+ }
483
+ }, "cleanup");
484
+ rememberRefCleanup(owner, target, cleanup);
485
+ owner.onDispose(cleanup);
131
486
  }
132
487
  __name(setRef, "setRef");
133
488
  function isSSRNode(value) {
@@ -147,7 +502,8 @@ function assignRef(target, value) {
147
502
  try {
148
503
  if (typeof target === "function") target(value);
149
504
  else target.current = value;
150
- } catch {
505
+ } catch (error) {
506
+ console.error(formatVobsError(error, { includeStack: true }));
151
507
  }
152
508
  }
153
509
  __name(assignRef, "assignRef");
@@ -156,8 +512,22 @@ __name(assignRef, "assignRef");
156
512
  var currentRenderer = null;
157
513
  var nodeOwners = /* @__PURE__ */ new WeakMap();
158
514
  var eventBindings = /* @__PURE__ */ new WeakMap();
515
+ var eventCleanupSlots = /* @__PURE__ */ new WeakMap();
516
+ var eventCleanupNodeIds = /* @__PURE__ */ new WeakMap();
517
+ var nextEventCleanupNodeId = 0;
518
+ function eventCleanupKey(node, event) {
519
+ let id = eventCleanupNodeIds.get(node);
520
+ if (id === void 0) {
521
+ id = ++nextEventCleanupNodeId;
522
+ eventCleanupNodeIds.set(node, id);
523
+ }
524
+ return `${id}:${event}`;
525
+ }
526
+ __name(eventCleanupKey, "eventCleanupKey");
159
527
  function setRenderer(renderer) {
160
- currentRenderer = renderer;
528
+ const previous = currentRenderer;
529
+ currentRenderer = renderer ?? null;
530
+ return previous;
161
531
  }
162
532
  __name(setRenderer, "setRenderer");
163
533
  function getRenderer() {
@@ -171,76 +541,20 @@ function createText(content) {
171
541
  return getRenderer().createText(content);
172
542
  }
173
543
  __name(createText, "createText");
174
- var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
175
- var SVG_TAGS = /* @__PURE__ */ new Set([
176
- "animate",
177
- "animateMotion",
178
- "animateTransform",
179
- "circle",
180
- "clipPath",
181
- "defs",
182
- "desc",
183
- "ellipse",
184
- "feBlend",
185
- "feColorMatrix",
186
- "feComponentTransfer",
187
- "feComposite",
188
- "feConvolveMatrix",
189
- "feDiffuseLighting",
190
- "feDisplacementMap",
191
- "feDistantLight",
192
- "feDropShadow",
193
- "feFlood",
194
- "feFuncA",
195
- "feFuncB",
196
- "feFuncG",
197
- "feFuncR",
198
- "feGaussianBlur",
199
- "feImage",
200
- "feMerge",
201
- "feMergeNode",
202
- "feMorphology",
203
- "feOffset",
204
- "fePointLight",
205
- "feSpecularLighting",
206
- "feSpotLight",
207
- "feTile",
208
- "feTurbulence",
209
- "filter",
210
- "foreignObject",
211
- "g",
212
- "image",
213
- "line",
214
- "linearGradient",
215
- "marker",
216
- "mask",
217
- "metadata",
218
- "mpath",
219
- "path",
220
- "pattern",
221
- "polygon",
222
- "polyline",
223
- "radialGradient",
224
- "rect",
225
- "set",
226
- "stop",
227
- "svg",
228
- "switch",
229
- "symbol",
230
- "text",
231
- "textPath",
232
- "tspan",
233
- "use",
234
- "view"
235
- ]);
236
544
  function createElement(tag) {
237
- if (SVG_TAGS.has(tag)) {
545
+ if (isSvgTag(tag)) {
238
546
  const renderer = getRenderer();
239
547
  if (renderer.createSvgElement) return renderer.createSvgElement(tag);
240
548
  }
241
549
  return getRenderer().createElement(tag);
242
550
  }
243
551
  __name(createElement, "createElement");
552
+ function createSvgElement(tag) {
553
+ const renderer = getRenderer();
554
+ if (renderer.createSvgElement) return renderer.createSvgElement(tag);
555
+ return renderer.createElement(tag);
556
+ }
557
+ __name(createSvgElement, "createSvgElement");
244
558
  function createComment(content) {
245
559
  return getRenderer().createComment(content);
246
560
  }
@@ -274,7 +588,7 @@ function syncSelectValue(parent) {
274
588
  while (current !== null) {
275
589
  if (current.nodeName === "SELECT") {
276
590
  const read = selectValueReaders.get(current);
277
- if (read !== void 0) setProperty(current, "value", read());
591
+ if (read !== void 0) setProperty(current, "value", (0, import_reactivity3.untrack)(read));
278
592
  return;
279
593
  }
280
594
  current = current.parentNode;
@@ -282,9 +596,9 @@ function syncSelectValue(parent) {
282
596
  }
283
597
  __name(syncSelectValue, "syncSelectValue");
284
598
  function removeChild(parent, child) {
285
- disposeNodeOwner(child);
286
599
  if (isVobsFragment(child)) {
287
600
  child.unmount(parent);
601
+ disposeNodeOwner(child);
288
602
  return;
289
603
  }
290
604
  getRenderer().removeChild(parent, child);
@@ -295,6 +609,7 @@ function removeChild(parent, child) {
295
609
  parent: describeDebugNode(parent)
296
610
  });
297
611
  }
612
+ disposeNodeOwner(child);
298
613
  }
299
614
  __name(removeChild, "removeChild");
300
615
  function setTextContent(node, content) {
@@ -312,7 +627,7 @@ function setTextContent(node, content) {
312
627
  __name(setTextContent, "setTextContent");
313
628
  function setProperty(node, key, value) {
314
629
  const previousValue = getRuntimeDebugHooks() ? readDebugValue(() => Reflect.get(node, key)) : void 0;
315
- getRenderer().setProperty(node, key, value);
630
+ getRenderer().setProperty(node, PROPERTY_IDL_NAMES[key] ?? key, value);
316
631
  if (key === "value" && node.tagName === "SELECT") {
317
632
  scheduleSelectValueSync(node, value);
318
633
  }
@@ -333,12 +648,13 @@ function scheduleSelectValueSync(node, value) {
333
648
  pendingSelectValues.set(node, value);
334
649
  if (selectSyncScheduled.has(node)) return;
335
650
  selectSyncScheduled.add(node);
651
+ const renderer = getRenderer();
336
652
  queueMicrotask(() => {
337
653
  selectSyncScheduled.delete(node);
338
654
  if (!pendingSelectValues.has(node)) return;
339
655
  const pending = pendingSelectValues.get(node);
340
656
  pendingSelectValues.delete(node);
341
- getRenderer().setProperty(node, "value", pending);
657
+ renderer.setProperty(node, "value", pending);
342
658
  });
343
659
  }
344
660
  __name(scheduleSelectValueSync, "scheduleSelectValueSync");
@@ -357,48 +673,131 @@ function setAttribute(node, key, value) {
357
673
  }
358
674
  __name(setAttribute, "setAttribute");
359
675
  function spreadProps(node, props) {
360
- for (const [key, value] of Object.entries(props)) {
361
- if (key === "key" || value === null || value === void 0) continue;
676
+ applySpreadProps(node, null, props);
677
+ }
678
+ __name(spreadProps, "spreadProps");
679
+ function removeAttribute(node, key) {
680
+ const renderer = getRenderer();
681
+ if (renderer.removeAttribute) {
682
+ renderer.removeAttribute(node, key);
683
+ return;
684
+ }
685
+ renderer.setAttribute(node, key, "");
686
+ }
687
+ __name(removeAttribute, "removeAttribute");
688
+ var BOOLEAN_PROPERTIES = /* @__PURE__ */ new Set([
689
+ "checked",
690
+ "selected",
691
+ "disabled",
692
+ "multiple",
693
+ "readOnly",
694
+ "required",
695
+ "hidden",
696
+ "open",
697
+ "indeterminate",
698
+ "defaultChecked",
699
+ "muted",
700
+ "autoFocus"
701
+ ]);
702
+ var PROPERTY_IDL_NAMES = {
703
+ autoFocus: "autofocus"
704
+ };
705
+ function applySpreadProps(node, previous, next) {
706
+ for (const [key, value] of Object.entries(next)) {
707
+ if (key === "key") continue;
708
+ if (previous !== null && Object.is(previous[key], value)) continue;
709
+ if (key.startsWith("on")) {
710
+ const eventName = resolveEventName(key) ?? key.slice(2).toLowerCase();
711
+ const previousHandler = previous?.[key];
712
+ if (typeof previousHandler === "function") {
713
+ removeEventListener(node, eventName, previousHandler);
714
+ }
715
+ if (typeof value === "function") {
716
+ addEventListener(node, eventName, value);
717
+ }
718
+ continue;
719
+ }
362
720
  if (key === "ref") {
363
721
  setRef(node, value);
364
722
  continue;
365
723
  }
366
- if (key.startsWith("on") && typeof value === "function") addEventListener(node, key.slice(2).toLowerCase(), value);
367
- else if (isPropertyKey(key)) setProperty(node, key, value);
724
+ if (value === null || value === void 0) continue;
725
+ else if (isClassListKey(key)) applyClassList(node, value);
726
+ else if (isPropertyName(key)) setProperty(node, key, value);
368
727
  else if (value === false) continue;
369
728
  else setAttribute(node, domAttributeName(key), key === "style" && isStyleObject(value) ? formatStyle(value) : String(value));
370
729
  }
730
+ if (previous === null) return;
731
+ for (const key of Object.keys(previous)) {
732
+ if (key in next || key === "key") continue;
733
+ if (key.startsWith("on")) {
734
+ const eventName = resolveEventName(key) ?? key.slice(2).toLowerCase();
735
+ const previousHandler = previous[key];
736
+ if (typeof previousHandler === "function") {
737
+ removeEventListener(node, eventName, previousHandler);
738
+ }
739
+ continue;
740
+ }
741
+ if (key === "ref") continue;
742
+ if (isPropertyName(key)) setProperty(node, key, BOOLEAN_PROPERTIES.has(key) ? false : "");
743
+ else removeAttribute(node, domAttributeName(key));
744
+ }
371
745
  }
372
- __name(spreadProps, "spreadProps");
746
+ __name(applySpreadProps, "applySpreadProps");
747
+ var classListContributions = /* @__PURE__ */ new WeakMap();
748
+ function parseClassList(value) {
749
+ const names = [];
750
+ const push = /* @__PURE__ */ __name((candidate) => {
751
+ if (typeof candidate === "string") {
752
+ for (const name of candidate.split(/\s+/u)) if (name !== "") names.push(name);
753
+ }
754
+ }, "push");
755
+ if (Array.isArray(value)) {
756
+ for (const entry of value) {
757
+ if (entry !== null && typeof entry === "object") {
758
+ for (const [name, on] of Object.entries(entry)) if (on) push(name);
759
+ } else push(entry);
760
+ }
761
+ } else if (value !== null && typeof value === "object") {
762
+ for (const [name, on] of Object.entries(value)) if (on) push(name);
763
+ } else push(value);
764
+ return names;
765
+ }
766
+ __name(parseClassList, "parseClassList");
767
+ function applyClassList(node, value) {
768
+ const next = parseClassList(value);
769
+ const previous = classListContributions.get(node) ?? [];
770
+ classListContributions.set(node, next);
771
+ const base = (node.getAttribute("class") ?? "").split(/\s+/u).filter((name) => name !== "" && !previous.includes(name));
772
+ const merged = [.../* @__PURE__ */ new Set([...base, ...next])];
773
+ setAttribute(node, "class", merged.join(" "));
774
+ }
775
+ __name(applyClassList, "applyClassList");
776
+ function isClassListKey(key) {
777
+ return key === "classList";
778
+ }
779
+ __name(isClassListKey, "isClassListKey");
780
+ function bindSpreadProps(node, source) {
781
+ let previous = null;
782
+ (0, import_reactivity3.effect)(() => {
783
+ const next = source() ?? {};
784
+ const snapshot = { ...next };
785
+ applySpreadProps(node, previous, next);
786
+ previous = snapshot;
787
+ });
788
+ }
789
+ __name(bindSpreadProps, "bindSpreadProps");
373
790
  function setStaticProps(node, props) {
374
791
  for (const [key, value] of Object.entries(props)) {
375
792
  if (key === "key" || key === "ref" || key.startsWith("on")) continue;
376
793
  if (value === null || value === void 0) continue;
377
- if (isPropertyKey(key)) setProperty(node, key, value);
794
+ if (isClassListKey(key)) applyClassList(node, value);
795
+ else if (isPropertyName(key)) setProperty(node, key, value);
378
796
  else if (value === false) continue;
379
797
  else setAttribute(node, domAttributeName(key), key === "style" && isStyleObject(value) ? formatStyle(value) : String(value));
380
798
  }
381
799
  }
382
800
  __name(setStaticProps, "setStaticProps");
383
- function isPropertyKey(key) {
384
- 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";
385
- }
386
- __name(isPropertyKey, "isPropertyKey");
387
- function domAttributeName(key) {
388
- switch (key) {
389
- case "className":
390
- return "class";
391
- case "htmlFor":
392
- return "for";
393
- case "autoComplete":
394
- return "autocomplete";
395
- case "spellCheck":
396
- return "spellcheck";
397
- default:
398
- return key;
399
- }
400
- }
401
- __name(domAttributeName, "domAttributeName");
402
801
  function isStyleObject(value) {
403
802
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
404
803
  }
@@ -417,7 +816,9 @@ function addEventListener(node, event, handler) {
417
816
  }
418
817
  const previous = bindings.get(event);
419
818
  if (previous && previous.original === handler && previous.owner === owner) return;
420
- if (previous) renderer.removeEventListener(node, event, previous.handler);
819
+ if (previous) {
820
+ renderer.removeEventListener(node, event, previous.handler);
821
+ }
421
822
  const listener = owner ? (reason) => {
422
823
  if (owner.disposed) return;
423
824
  try {
@@ -431,28 +832,66 @@ function addEventListener(node, event, handler) {
431
832
  handled,
432
833
  recovery: handled ? "handled" : "propagated"
433
834
  });
835
+ if (handled && getRuntimeDebugHooks()?.error === void 0) {
836
+ console.error(formatVobsError(error, { includeStack: true }));
837
+ }
434
838
  if (!handled) throw error;
435
839
  }
436
840
  } : handler;
437
841
  const binding = { handler: listener, owner, original: handler };
438
842
  bindings.set(event, binding);
439
843
  renderer.addEventListener(node, event, listener);
440
- owner?.onDispose(() => {
441
- if (bindings?.get(event) !== binding) return;
442
- bindings.delete(event);
443
- renderer.removeEventListener(node, event, listener);
844
+ if (!owner) return;
845
+ const key = eventCleanupKey(node, event);
846
+ let slots = eventCleanupSlots.get(owner);
847
+ if (!slots) {
848
+ slots = /* @__PURE__ */ new Map();
849
+ eventCleanupSlots.set(owner, slots);
850
+ }
851
+ const hasSlot = slots.has(key);
852
+ slots.set(key, binding);
853
+ if (hasSlot) return;
854
+ owner.onDispose(() => {
855
+ const current = eventCleanupSlots.get(owner)?.get(key);
856
+ if (!current) return;
857
+ eventCleanupSlots.get(owner)?.delete(key);
858
+ const map = eventBindings.get(node);
859
+ if (map?.get(event) === current) map.delete(event);
860
+ renderer.removeEventListener(node, event, current.handler);
444
861
  });
445
862
  }
446
863
  __name(addEventListener, "addEventListener");
447
864
  function removeEventListener(node, event, handler) {
448
865
  const renderer = getRenderer();
449
- const binding = eventBindings.get(node)?.get(event);
866
+ const map = eventBindings.get(node);
867
+ const binding = map?.get(event);
868
+ if (binding) {
869
+ if (binding.handler !== handler) return;
870
+ map?.delete(event);
871
+ }
450
872
  renderer.removeEventListener(node, event, binding?.handler ?? handler);
451
- eventBindings.get(node)?.delete(event);
452
873
  }
453
874
  __name(removeEventListener, "removeEventListener");
454
875
  function clear(container) {
876
+ let firstError;
877
+ const walk = /* @__PURE__ */ __name((node) => {
878
+ try {
879
+ disposeNodeOwner(node);
880
+ } catch (error) {
881
+ firstError ?? (firstError = error);
882
+ }
883
+ for (const child of Array.from(node.childNodes)) walk(child);
884
+ }, "walk");
885
+ for (const child of Array.from(container.childNodes)) walk(child);
455
886
  getRenderer().clear(container);
887
+ if (getRuntimeDebugHooks()) {
888
+ invokeRuntimeDebug("domMutation", {
889
+ operation: "clear",
890
+ target: describeDebugNode(container),
891
+ parent: describeDebugNode(container)
892
+ });
893
+ }
894
+ if (firstError) throw firstError;
456
895
  }
457
896
  __name(clear, "clear");
458
897
  function createComponent(component, props, source) {
@@ -474,15 +913,16 @@ function createComponent(component, props, source) {
474
913
  owner.onDispose(cleanup);
475
914
  }
476
915
  const renderScope = owner.mark();
477
- let node;
916
+ let rendered;
478
917
  try {
479
- node = owner.run(() => (0, import_reactivity3.untrack)(() => component(props)));
918
+ rendered = owner.run(() => (0, import_reactivity3.untrack)(() => component(props)));
480
919
  } catch (error) {
481
920
  owner.dispose();
482
921
  attachSourceLocation(error, source);
483
922
  attachComponentContext(error, componentName, owner.id);
484
923
  throw error;
485
924
  }
925
+ const node = isRenderableNode(rendered) ? rendered : createComment("vobs:empty");
486
926
  associateNodeOwner(node, owner);
487
927
  if (instance) {
488
928
  instance.node = node;
@@ -553,7 +993,16 @@ function createBlock(factory) {
553
993
  return node;
554
994
  }
555
995
  __name(createBlock, "createBlock");
996
+ function isRenderableNode(value) {
997
+ return typeof value === "object" && value !== null || typeof value === "function";
998
+ }
999
+ __name(isRenderableNode, "isRenderableNode");
556
1000
  function associateNodeOwner(node, owner) {
1001
+ if (node === null || node === void 0 || typeof node !== "object" && typeof node !== "function") {
1002
+ throw new Error(
1003
+ `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`
1004
+ );
1005
+ }
557
1006
  nodeOwners.set(node, owner);
558
1007
  }
559
1008
  __name(associateNodeOwner, "associateNodeOwner");
@@ -568,17 +1017,22 @@ __name(disposeNodeOwner, "disposeNodeOwner");
568
1017
  0 && (module.exports = {
569
1018
  SVG_NAMESPACE,
570
1019
  addEventListener,
1020
+ applyClassList,
571
1021
  associateNodeOwner,
1022
+ bindSpreadProps,
572
1023
  clear,
573
1024
  createBlock,
574
1025
  createComment,
575
1026
  createComponent,
576
1027
  createElement,
1028
+ createSvgElement,
577
1029
  createText,
578
1030
  disposeNodeOwner,
579
1031
  getRenderer,
580
1032
  insertBefore,
1033
+ parseClassList,
581
1034
  registerSelectValueBinding,
1035
+ removeAttribute,
582
1036
  removeChild,
583
1037
  removeEventListener,
584
1038
  setAttribute,