@wsxjs/wsx-core 0.0.7 → 0.0.9

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.
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Fragment,
3
3
  h
4
- } from "./chunk-VZQT7HU5.mjs";
4
+ } from "./chunk-CZII6RG2.mjs";
5
5
 
6
6
  // src/styles/style-manager.ts
7
7
  var StyleManager = class {
@@ -43,172 +43,6 @@ var StyleManager = class {
43
43
  };
44
44
  StyleManager.styleSheets = /* @__PURE__ */ new Map();
45
45
 
46
- // src/web-component.ts
47
- var WebComponent = class extends HTMLElement {
48
- constructor(config = {}) {
49
- super();
50
- this.connected = false;
51
- this.config = config;
52
- this.attachShadow({ mode: "open" });
53
- if (config.styles) {
54
- const styleName = config.styleName || this.constructor.name;
55
- StyleManager.applyStyles(this.shadowRoot, styleName, config.styles);
56
- }
57
- }
58
- /**
59
- * 子类应该重写这个方法来定义观察的属性
60
- * @returns 要观察的属性名数组
61
- */
62
- static get observedAttributes() {
63
- return [];
64
- }
65
- /**
66
- * Web Component生命周期:连接到DOM
67
- */
68
- connectedCallback() {
69
- this.connected = true;
70
- try {
71
- const content = this.render();
72
- this.shadowRoot.appendChild(content);
73
- this.onConnected?.();
74
- } catch (error) {
75
- console.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
76
- this.renderError(error);
77
- }
78
- }
79
- /**
80
- * Web Component生命周期:从DOM断开
81
- */
82
- disconnectedCallback() {
83
- this.onDisconnected?.();
84
- }
85
- /**
86
- * Web Component生命周期:属性变化
87
- */
88
- attributeChangedCallback(name, oldValue, newValue) {
89
- this.onAttributeChanged?.(name, oldValue, newValue);
90
- }
91
- /**
92
- * 查找Shadow DOM内的元素
93
- *
94
- * @param selector - CSS选择器
95
- * @returns 元素或null
96
- */
97
- querySelector(selector) {
98
- return this.shadowRoot.querySelector(selector);
99
- }
100
- /**
101
- * 查找Shadow DOM内的所有匹配元素
102
- *
103
- * @param selector - CSS选择器
104
- * @returns 元素列表
105
- */
106
- querySelectorAll(selector) {
107
- return this.shadowRoot.querySelectorAll(selector);
108
- }
109
- /**
110
- * 重新渲染组件
111
- */
112
- rerender() {
113
- if (!this.connected) {
114
- console.warn(
115
- `[${this.constructor.name}] Component is not connected, skipping rerender.`
116
- );
117
- return;
118
- }
119
- const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
120
- this.shadowRoot.innerHTML = "";
121
- if (this.shadowRoot.adoptedStyleSheets) {
122
- this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
123
- }
124
- if (adoptedStyleSheets.length === 0 && this.config.styles) {
125
- const styleName = this.config.styleName || this.constructor.name;
126
- StyleManager.applyStyles(this.shadowRoot, styleName, this.config.styles);
127
- }
128
- try {
129
- const content = this.render();
130
- this.shadowRoot.appendChild(content);
131
- } catch (error) {
132
- console.error(`[${this.constructor.name}] Error in rerender:`, error);
133
- this.renderError(error);
134
- }
135
- }
136
- /**
137
- * 渲染错误信息
138
- *
139
- * @param error - 错误对象
140
- */
141
- renderError(error) {
142
- this.shadowRoot.innerHTML = "";
143
- const errorElement = h(
144
- "div",
145
- {
146
- style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
147
- },
148
- [
149
- h("strong", {}, `[${this.constructor.name}] Component Error:`),
150
- h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
151
- ]
152
- );
153
- this.shadowRoot.appendChild(errorElement);
154
- }
155
- /**
156
- * 获取配置值
157
- *
158
- * @param key - 配置键
159
- * @param defaultValue - 默认值
160
- * @returns 配置值
161
- */
162
- getConfig(key, defaultValue) {
163
- return this.config[key] ?? defaultValue;
164
- }
165
- /**
166
- * 设置配置值
167
- *
168
- * @param key - 配置键
169
- * @param value - 配置值
170
- */
171
- setConfig(key, value) {
172
- this.config[key] = value;
173
- }
174
- /**
175
- * 获取属性值
176
- *
177
- * @param name - 属性名
178
- * @param defaultValue - 默认值
179
- * @returns 属性值
180
- */
181
- getAttr(name, defaultValue = "") {
182
- return this.getAttribute(name) || defaultValue;
183
- }
184
- /**
185
- * 设置属性值
186
- *
187
- * @param name - 属性名
188
- * @param value - 属性值
189
- */
190
- setAttr(name, value) {
191
- this.setAttribute(name, value);
192
- }
193
- /**
194
- * 移除属性
195
- *
196
- * @param name - 属性名
197
- */
198
- removeAttr(name) {
199
- this.removeAttribute(name);
200
- }
201
- /**
202
- * 检查是否有属性
203
- *
204
- * @param name - 属性名
205
- * @returns 是否存在
206
- */
207
- hasAttr(name) {
208
- return this.hasAttribute(name);
209
- }
210
- };
211
-
212
46
  // src/utils/logger.ts
213
47
  var WSXLogger = class {
214
48
  constructor(prefix = "[WSX]", enabled = true, level = "info") {
@@ -279,35 +113,107 @@ var UpdateScheduler = class {
279
113
  try {
280
114
  callback();
281
115
  } catch (error) {
282
- console.error("[WSX Reactive] Error in callback:", error);
116
+ logger2.error("[WSX Reactive] Error in callback:", error);
283
117
  }
284
118
  });
285
119
  }
286
120
  };
287
121
  var scheduler = new UpdateScheduler();
122
+ var proxyCache = /* @__PURE__ */ new WeakMap();
123
+ var originalCache = /* @__PURE__ */ new WeakMap();
124
+ var unwrappingSet = /* @__PURE__ */ new WeakSet();
125
+ function unwrapProxy(value) {
126
+ if (value == null || typeof value !== "object") {
127
+ return value;
128
+ }
129
+ let original = value;
130
+ if (originalCache.has(value)) {
131
+ original = originalCache.get(value);
132
+ }
133
+ if (unwrappingSet.has(original)) {
134
+ return null;
135
+ }
136
+ unwrappingSet.add(original);
137
+ try {
138
+ if (Array.isArray(original)) {
139
+ return original.map((item) => unwrapProxy(item));
140
+ }
141
+ const result = {};
142
+ for (const key in original) {
143
+ if (Object.prototype.hasOwnProperty.call(original, key)) {
144
+ const propValue = original[key];
145
+ if (propValue != null && typeof propValue === "object" && originalCache.has(propValue)) {
146
+ result[key] = unwrapProxy(originalCache.get(propValue));
147
+ } else {
148
+ result[key] = unwrapProxy(propValue);
149
+ }
150
+ }
151
+ }
152
+ return result;
153
+ } finally {
154
+ unwrappingSet.delete(original);
155
+ }
156
+ }
157
+ var ARRAY_MUTATION_METHODS = [
158
+ "push",
159
+ "pop",
160
+ "shift",
161
+ "unshift",
162
+ "splice",
163
+ "sort",
164
+ "reverse"
165
+ ];
288
166
  function reactive(obj, onChange) {
289
- return new Proxy(obj, {
167
+ if (proxyCache.has(obj)) {
168
+ return proxyCache.get(obj);
169
+ }
170
+ const isArray = Array.isArray(obj);
171
+ const proxy = new Proxy(obj, {
290
172
  set(target, key, value) {
291
173
  const oldValue = target[key];
292
- if (oldValue !== value) {
293
- target[key] = value;
174
+ const oldOriginal = originalCache.get(oldValue) || oldValue;
175
+ const newOriginal = value != null && typeof value === "object" ? originalCache.get(value) || value : value;
176
+ if (oldOriginal !== newOriginal) {
177
+ if (value != null && typeof value === "object") {
178
+ const reactiveValue = reactive(value, onChange);
179
+ target[key] = reactiveValue;
180
+ } else {
181
+ target[key] = value;
182
+ }
294
183
  scheduler.schedule(onChange);
295
184
  }
296
185
  return true;
297
186
  },
298
187
  get(target, key) {
299
- return target[key];
188
+ if (key === "toJSON") {
189
+ return function() {
190
+ return unwrapProxy(obj);
191
+ };
192
+ }
193
+ const value = target[key];
194
+ if (isArray && typeof key === "string" && ARRAY_MUTATION_METHODS.includes(key)) {
195
+ return function(...args) {
196
+ const arrayMethod = Array.prototype[key];
197
+ const result = arrayMethod.apply(target, args);
198
+ scheduler.schedule(onChange);
199
+ return result;
200
+ };
201
+ }
202
+ if (value != null && typeof value === "object") {
203
+ if (proxyCache.has(value)) {
204
+ return proxyCache.get(value);
205
+ }
206
+ return reactive(value, onChange);
207
+ }
208
+ return value;
300
209
  },
301
210
  has(target, key) {
302
211
  return key in target;
303
- },
304
- ownKeys(target) {
305
- return Reflect.ownKeys(target);
306
- },
307
- getOwnPropertyDescriptor(target, key) {
308
- return Reflect.getOwnPropertyDescriptor(target, key);
309
212
  }
310
213
  });
214
+ proxyCache.set(obj, proxy);
215
+ originalCache.set(proxy, obj);
216
+ return proxy;
311
217
  }
312
218
  function createState(initialValue, onChange) {
313
219
  let currentValue = initialValue;
@@ -355,6 +261,7 @@ var ReactiveDebug = {
355
261
  };
356
262
  function reactiveWithDebug(obj, onChange, debugName) {
357
263
  const name = debugName || obj.constructor.name || "Unknown";
264
+ const isArray = Array.isArray(obj);
358
265
  return new Proxy(obj, {
359
266
  set(target, key, value) {
360
267
  const oldValue = target[key];
@@ -370,21 +277,89 @@ function reactiveWithDebug(obj, onChange, debugName) {
370
277
  return true;
371
278
  },
372
279
  get(target, key) {
373
- return target[key];
280
+ if (key === "toJSON") {
281
+ return function() {
282
+ return unwrapProxy(obj);
283
+ };
284
+ }
285
+ const value = target[key];
286
+ if (isArray && typeof key === "string" && ARRAY_MUTATION_METHODS.includes(key)) {
287
+ return function(...args) {
288
+ ReactiveDebug.log(`Array mutation in ${name}:`, {
289
+ method: key,
290
+ args
291
+ });
292
+ const arrayMethod = Array.prototype[key];
293
+ const result = arrayMethod.apply(target, args);
294
+ scheduler.schedule(onChange);
295
+ return result;
296
+ };
297
+ }
298
+ if (value != null && typeof value === "object") {
299
+ return reactiveWithDebug(value, onChange, `${name}.${String(key)}`);
300
+ }
301
+ return value;
374
302
  }
375
303
  });
376
304
  }
377
305
 
378
- // src/light-component.ts
379
- var logger3 = createLogger("LightComponent");
380
- var LightComponent = class extends HTMLElement {
306
+ // src/base-component.ts
307
+ var BaseComponent = class extends HTMLElement {
381
308
  constructor(config = {}) {
382
309
  super();
383
310
  this.connected = false;
384
311
  this._isDebugEnabled = false;
385
312
  this._reactiveStates = /* @__PURE__ */ new Map();
386
- this.config = config;
313
+ /**
314
+ * 当前捕获的焦点状态(用于在 render 时使用捕获的值)
315
+ * @internal - 由 rerender() 方法管理
316
+ */
317
+ this._pendingFocusState = null;
318
+ /**
319
+ * 防抖定时器,用于延迟重渲染(当用户正在输入时)
320
+ * @internal
321
+ */
322
+ this._rerenderDebounceTimer = null;
323
+ /**
324
+ * 待处理的重渲染标志(当用户正在输入时,标记需要重渲染但延迟执行)
325
+ * @internal
326
+ */
327
+ this._pendingRerender = false;
328
+ /**
329
+ * 处理 blur 事件,在用户停止输入时执行待处理的重渲染
330
+ * @internal
331
+ */
332
+ this.handleGlobalBlur = (event) => {
333
+ const root = this.getActiveRoot();
334
+ const target = event.target;
335
+ if (target && root.contains(target)) {
336
+ if (this._pendingRerender && this.connected) {
337
+ if (this._rerenderDebounceTimer !== null) {
338
+ clearTimeout(this._rerenderDebounceTimer);
339
+ this._rerenderDebounceTimer = null;
340
+ }
341
+ requestAnimationFrame(() => {
342
+ if (this._pendingRerender && this.connected) {
343
+ this._pendingRerender = false;
344
+ this.rerender();
345
+ }
346
+ });
347
+ }
348
+ }
349
+ };
387
350
  this._isDebugEnabled = config.debug ?? false;
351
+ const host = this;
352
+ const originalStyles = config.styles;
353
+ this.config = {
354
+ ...config,
355
+ get styles() {
356
+ const result = originalStyles || host._autoStyles || "";
357
+ return result;
358
+ },
359
+ set styles(value) {
360
+ config.styles = value;
361
+ }
362
+ };
388
363
  }
389
364
  /**
390
365
  * 子类应该重写这个方法来定义观察的属性
@@ -393,56 +368,12 @@ var LightComponent = class extends HTMLElement {
393
368
  static get observedAttributes() {
394
369
  return [];
395
370
  }
396
- /**
397
- * Web Component生命周期:连接到DOM
398
- */
399
- connectedCallback() {
400
- this.connected = true;
401
- try {
402
- if (this.config.styles) {
403
- const styleName = this.config.styleName || this.constructor.name;
404
- this.applyScopedStyles(styleName, this.config.styles);
405
- }
406
- const content = this.render();
407
- this.appendChild(content);
408
- this.onConnected?.();
409
- } catch (error) {
410
- logger3.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
411
- this.renderError(error);
412
- }
413
- }
414
- /**
415
- * Web Component生命周期:从DOM断开
416
- */
417
- disconnectedCallback() {
418
- this.cleanupReactiveStates();
419
- this.cleanupStyles();
420
- this.onDisconnected?.();
421
- }
422
371
  /**
423
372
  * Web Component生命周期:属性变化
424
373
  */
425
374
  attributeChangedCallback(name, oldValue, newValue) {
426
375
  this.onAttributeChanged?.(name, oldValue, newValue);
427
376
  }
428
- /**
429
- * 查找组件内的元素
430
- *
431
- * @param selector - CSS选择器
432
- * @returns 元素或null
433
- */
434
- querySelector(selector) {
435
- return HTMLElement.prototype.querySelector.call(this, selector);
436
- }
437
- /**
438
- * 查找组件内的所有匹配元素
439
- *
440
- * @param selector - CSS选择器
441
- * @returns 元素列表
442
- */
443
- querySelectorAll(selector) {
444
- return HTMLElement.prototype.querySelectorAll.call(this, selector);
445
- }
446
377
  /**
447
378
  * 创建响应式对象
448
379
  *
@@ -465,86 +396,73 @@ var LightComponent = class extends HTMLElement {
465
396
  useState(key, initialValue) {
466
397
  if (!this._reactiveStates.has(key)) {
467
398
  const [getter, setter] = createState(initialValue, () => this.scheduleRerender());
468
- this._reactiveStates.set(key, { getter, setter });
399
+ this._reactiveStates.set(key, {
400
+ getter,
401
+ setter
402
+ });
403
+ }
404
+ const state2 = this._reactiveStates.get(key);
405
+ if (!state2) {
406
+ throw new Error(`State ${key} not found`);
469
407
  }
470
- const state = this._reactiveStates.get(key);
471
- return [state.getter, state.setter];
408
+ return [state2.getter, state2.setter];
472
409
  }
473
410
  /**
474
411
  * 调度重渲染
475
412
  * 这个方法被响应式系统调用,开发者通常不需要直接调用
413
+ * 使用 queueMicrotask 进行异步调度,与 reactive() 系统保持一致
476
414
  */
477
415
  scheduleRerender() {
478
- if (this.connected) {
479
- this.rerender();
480
- }
481
- }
482
- /**
483
- * 重新渲染组件
484
- */
485
- rerender() {
486
416
  if (!this.connected) {
487
- logger3.warn(
488
- `[${this.constructor.name}] Component is not connected, skipping rerender.`
489
- );
417
+ if (this._rerenderDebounceTimer !== null) {
418
+ clearTimeout(this._rerenderDebounceTimer);
419
+ this._rerenderDebounceTimer = null;
420
+ }
490
421
  return;
491
422
  }
492
- this.innerHTML = "";
493
- if (this.config.styles) {
494
- const styleName = this.config.styleName || this.constructor.name;
495
- const styleElement = document.createElement("style");
496
- styleElement.setAttribute("data-wsx-light-component", styleName);
497
- styleElement.textContent = this.config.styles;
498
- this.appendChild(styleElement);
423
+ const root = this.getActiveRoot();
424
+ let hasActiveElement = false;
425
+ if (root instanceof ShadowRoot) {
426
+ hasActiveElement = root.activeElement !== null;
427
+ } else {
428
+ const docActiveElement = document.activeElement;
429
+ hasActiveElement = docActiveElement !== null && root.contains(docActiveElement);
499
430
  }
500
- try {
501
- const content = this.render();
502
- this.appendChild(content);
503
- if (this.config.styles && this.children.length > 1) {
504
- const styleElement = this.querySelector(
505
- `style[data-wsx-light-component="${this.config.styleName || this.constructor.name}"]`
506
- );
507
- if (styleElement && styleElement !== this.firstChild) {
508
- this.insertBefore(styleElement, this.firstChild);
509
- }
431
+ if (hasActiveElement) {
432
+ this._pendingRerender = true;
433
+ if (this._rerenderDebounceTimer !== null) {
434
+ clearTimeout(this._rerenderDebounceTimer);
435
+ this._rerenderDebounceTimer = null;
510
436
  }
511
- } catch (error) {
512
- logger3.error(`[${this.constructor.name}] Error in rerender:`, error);
513
- this.renderError(error);
437
+ return;
514
438
  }
439
+ if (this._pendingRerender) {
440
+ this._pendingRerender = false;
441
+ }
442
+ queueMicrotask(() => {
443
+ if (this.connected) {
444
+ this.rerender();
445
+ }
446
+ });
515
447
  }
516
448
  /**
517
- * 渲染错误信息
518
- *
519
- * @param error - 错误对象
449
+ * 清理资源(在组件断开连接时调用)
450
+ * @internal
520
451
  */
521
- renderError(error) {
522
- this.innerHTML = "";
523
- const errorElement = h(
524
- "div",
525
- {
526
- style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
527
- },
528
- [
529
- h("strong", {}, `[${this.constructor.name}] Component Error:`),
530
- h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
531
- ]
532
- );
533
- this.appendChild(errorElement);
452
+ cleanup() {
453
+ if (this._rerenderDebounceTimer !== null) {
454
+ clearTimeout(this._rerenderDebounceTimer);
455
+ this._rerenderDebounceTimer = null;
456
+ }
457
+ document.removeEventListener("blur", this.handleGlobalBlur, true);
458
+ this._pendingRerender = false;
534
459
  }
535
460
  /**
536
- * 为Light DOM组件应用样式
537
- * 直接将样式注入到组件自身,避免全局污染
461
+ * 初始化事件监听器(在组件连接时调用)
462
+ * @internal
538
463
  */
539
- applyScopedStyles(styleName, cssText) {
540
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
541
- if (existingStyle) {
542
- return;
543
- }
544
- const styleElement = document.createElement("style");
545
- styleElement.setAttribute("data-wsx-light-component", styleName);
546
- styleElement.textContent = cssText;
547
- this.insertBefore(styleElement, this.firstChild);
464
+ initializeEventListeners() {
465
+ document.addEventListener("blur", this.handleGlobalBlur, true);
548
466
  }
549
467
  /**
550
468
  * 获取配置值
@@ -565,22 +483,6 @@ var LightComponent = class extends HTMLElement {
565
483
  setConfig(key, value) {
566
484
  this.config[key] = value;
567
485
  }
568
- /**
569
- * 清理响应式状态
570
- */
571
- cleanupReactiveStates() {
572
- this._reactiveStates.clear();
573
- }
574
- /**
575
- * 清理组件样式
576
- */
577
- cleanupStyles() {
578
- const styleName = this.config.styleName || this.constructor.name;
579
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
580
- if (existingStyle) {
581
- existingStyle.remove();
582
- }
583
- }
584
486
  /**
585
487
  * 获取属性值
586
488
  *
@@ -617,253 +519,527 @@ var LightComponent = class extends HTMLElement {
617
519
  hasAttr(name) {
618
520
  return this.hasAttribute(name);
619
521
  }
620
- };
621
-
622
- // src/auto-register.ts
623
- function autoRegister(options = {}) {
624
- return function(constructor) {
625
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
626
- if (!customElements.get(tagName)) {
627
- customElements.define(tagName, constructor);
628
- }
629
- return constructor;
630
- };
631
- }
632
- function registerComponent(constructor, options = {}) {
633
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
634
- if (!customElements.get(tagName)) {
635
- customElements.define(tagName, constructor);
636
- }
637
- }
638
- function deriveTagName(className, prefix) {
639
- let kebabCase = className.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
640
- if (!kebabCase.includes("-")) {
641
- kebabCase = `${kebabCase}-component`;
642
- }
643
- return prefix ? `${prefix}${kebabCase}` : kebabCase;
644
- }
645
-
646
- // src/reactive-component.ts
647
- var ReactiveWebComponent = class extends WebComponent {
648
- constructor(config = {}) {
649
- super(config);
650
- this._isDebugEnabled = false;
651
- this._preserveFocus = true;
652
- this._reactiveStates = /* @__PURE__ */ new Map();
653
- this._isDebugEnabled = config.debug ?? false;
654
- this._preserveFocus = config.preserveFocus ?? true;
655
- }
656
522
  /**
657
- * 创建响应式对象
658
- *
659
- * @param obj 要变为响应式的对象
660
- * @param debugName 调试名称(可选)
661
- * @returns 响应式代理对象
662
- */
663
- reactive(obj, debugName) {
664
- const reactiveFn = this._isDebugEnabled ? reactiveWithDebug : reactive;
665
- const name = debugName || `${this.constructor.name}.reactive`;
666
- return this._isDebugEnabled ? reactiveFn(obj, () => this.scheduleRerender(), name) : reactiveFn(obj, () => this.scheduleRerender());
667
- }
668
- /**
669
- * 创建响应式状态
670
- *
671
- * @param key 状态标识符
672
- * @param initialValue 初始值
673
- * @returns [getter, setter] 元组
523
+ * 清理响应式状态
674
524
  */
675
- useState(key, initialValue) {
676
- if (!this._reactiveStates.has(key)) {
677
- const [getter, setter] = createState(initialValue, () => this.scheduleRerender());
678
- this._reactiveStates.set(key, { getter, setter });
679
- }
680
- const state = this._reactiveStates.get(key);
681
- return [state.getter, state.setter];
525
+ cleanupReactiveStates() {
526
+ this._reactiveStates.clear();
682
527
  }
683
528
  /**
684
- * 调度重渲染
685
- * 这个方法被响应式系统调用,开发者通常不需要直接调用
529
+ * 获取当前活动的 DOM 根(Shadow DOM 或 Light DOM)
530
+ * @returns 活动的 DOM 根元素
686
531
  */
687
- scheduleRerender() {
688
- if (this.connected) {
689
- this.rerender();
532
+ getActiveRoot() {
533
+ if ("shadowRoot" in this && this.shadowRoot) {
534
+ return this.shadowRoot;
690
535
  }
536
+ return this;
691
537
  }
692
538
  /**
693
- * 重写 rerender 方法以支持焦点保持
539
+ * 捕获当前焦点状态(在重渲染之前调用)
540
+ * @returns 焦点状态,如果没有焦点元素则返回 null
694
541
  */
695
- rerender() {
696
- if (!this.connected) {
697
- return;
698
- }
699
- let focusData = null;
700
- if (this._preserveFocus) {
701
- const activeElement = this.shadowRoot.activeElement;
702
- focusData = this.saveFocusState(activeElement);
542
+ captureFocusState() {
543
+ const root = this.getActiveRoot();
544
+ let activeElement = null;
545
+ if (root instanceof ShadowRoot) {
546
+ activeElement = root.activeElement;
547
+ } else {
548
+ const docActiveElement = document.activeElement;
549
+ if (docActiveElement && root.contains(docActiveElement)) {
550
+ activeElement = docActiveElement;
551
+ }
703
552
  }
704
- super.rerender();
705
- if (this._preserveFocus && focusData) {
706
- this.restoreFocusState(focusData);
553
+ if (!activeElement || !(activeElement instanceof HTMLElement)) {
554
+ return null;
707
555
  }
708
- }
709
- /**
710
- * 保存焦点状态
711
- */
712
- saveFocusState(activeElement) {
713
- if (!activeElement) {
556
+ const key = activeElement.getAttribute("data-wsx-key");
557
+ if (!key) {
714
558
  return null;
715
559
  }
716
- const focusData = {
717
- tagName: activeElement.tagName.toLowerCase(),
718
- className: activeElement.className
560
+ const tagName = activeElement.tagName.toLowerCase();
561
+ const state2 = {
562
+ key,
563
+ elementType: tagName
719
564
  };
720
- if (activeElement.hasAttribute("contenteditable")) {
565
+ if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement) {
566
+ state2.value = activeElement.value;
567
+ state2.selectionStart = activeElement.selectionStart ?? void 0;
568
+ state2.selectionEnd = activeElement.selectionEnd ?? void 0;
569
+ if (activeElement instanceof HTMLTextAreaElement) {
570
+ state2.scrollTop = activeElement.scrollTop;
571
+ }
572
+ } else if (activeElement instanceof HTMLSelectElement) {
573
+ state2.elementType = "select";
574
+ state2.selectedIndex = activeElement.selectedIndex;
575
+ } else if (activeElement.hasAttribute("contenteditable")) {
576
+ state2.elementType = "contenteditable";
721
577
  const selection = window.getSelection();
722
578
  if (selection && selection.rangeCount > 0) {
723
579
  const range = selection.getRangeAt(0);
724
- focusData.selectionStart = range.startOffset;
725
- focusData.selectionEnd = range.endOffset;
726
- }
727
- }
728
- if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLSelectElement) {
729
- focusData.value = activeElement.value;
730
- if ("selectionStart" in activeElement) {
731
- focusData.selectionStart = activeElement.selectionStart;
732
- focusData.selectionEnd = activeElement.selectionEnd;
580
+ state2.selectionStart = range.startOffset;
581
+ state2.selectionEnd = range.endOffset;
733
582
  }
734
583
  }
735
- return focusData;
584
+ return state2;
736
585
  }
737
586
  /**
738
- * 恢复焦点状态
587
+ * 恢复焦点状态(在重渲染之后调用)
588
+ * @param state - 之前捕获的焦点状态
739
589
  */
740
- restoreFocusState(focusData) {
741
- if (!focusData) return;
742
- try {
743
- let targetElement = null;
744
- if (focusData.className) {
745
- targetElement = this.shadowRoot.querySelector(
746
- `.${focusData.className.split(" ")[0]}`
747
- );
590
+ restoreFocusState(state2) {
591
+ if (!state2 || !state2.key) {
592
+ return;
593
+ }
594
+ const root = this.getActiveRoot();
595
+ const target = root.querySelector(`[data-wsx-key="${state2.key}"]`);
596
+ if (!target) {
597
+ return;
598
+ }
599
+ if (state2.value !== void 0) {
600
+ if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
601
+ target.value = state2.value;
748
602
  }
749
- if (!targetElement) {
750
- targetElement = this.shadowRoot.querySelector(focusData.tagName);
603
+ }
604
+ if (state2.selectedIndex !== void 0 && target instanceof HTMLSelectElement) {
605
+ target.selectedIndex = state2.selectedIndex;
606
+ }
607
+ requestAnimationFrame(() => {
608
+ const currentTarget = root.querySelector(
609
+ `[data-wsx-key="${state2.key}"]`
610
+ );
611
+ if (!currentTarget) {
612
+ return;
751
613
  }
752
- if (targetElement) {
753
- targetElement.focus({ preventScroll: true });
754
- if (focusData.selectionStart !== void 0) {
755
- if (targetElement instanceof HTMLInputElement) {
756
- targetElement.setSelectionRange(
757
- focusData.selectionStart,
758
- focusData.selectionEnd
759
- );
760
- } else if (targetElement instanceof HTMLSelectElement) {
761
- targetElement.value = focusData.value;
762
- } else if (targetElement.hasAttribute("contenteditable")) {
763
- this.setCursorPosition(targetElement, focusData.selectionStart);
614
+ if (state2.value !== void 0) {
615
+ if (currentTarget instanceof HTMLInputElement || currentTarget instanceof HTMLTextAreaElement) {
616
+ if (currentTarget.value !== state2.value) {
617
+ currentTarget.value = state2.value;
764
618
  }
765
619
  }
766
620
  }
767
- } catch {
621
+ currentTarget.focus({ preventScroll: true });
622
+ if (state2.selectionStart !== void 0) {
623
+ if (currentTarget instanceof HTMLInputElement || currentTarget instanceof HTMLTextAreaElement) {
624
+ const start = state2.selectionStart;
625
+ const end = state2.selectionEnd ?? start;
626
+ currentTarget.setSelectionRange(start, end);
627
+ if (state2.scrollTop !== void 0 && currentTarget instanceof HTMLTextAreaElement) {
628
+ currentTarget.scrollTop = state2.scrollTop;
629
+ }
630
+ } else if (currentTarget.hasAttribute("contenteditable")) {
631
+ const selection = window.getSelection();
632
+ if (selection) {
633
+ const range = document.createRange();
634
+ const textNode = currentTarget.childNodes[0];
635
+ if (textNode && textNode.nodeType === Node.TEXT_NODE) {
636
+ const maxPos = Math.min(
637
+ state2.selectionStart,
638
+ textNode.textContent?.length || 0
639
+ );
640
+ range.setStart(textNode, maxPos);
641
+ range.setEnd(textNode, state2.selectionEnd ?? maxPos);
642
+ selection.removeAllRanges();
643
+ selection.addRange(range);
644
+ }
645
+ }
646
+ }
647
+ }
648
+ });
649
+ }
650
+ };
651
+
652
+ // src/web-component.ts
653
+ var logger3 = createLogger("WebComponent");
654
+ var WebComponent = class extends BaseComponent {
655
+ // Initialized by BaseComponent constructor
656
+ constructor(config = {}) {
657
+ super(config);
658
+ this.attachShadow({ mode: "open" });
659
+ }
660
+ /**
661
+ * Web Component生命周期:连接到DOM
662
+ */
663
+ connectedCallback() {
664
+ this.connected = true;
665
+ try {
666
+ const stylesToApply = this._autoStyles || this.config.styles;
667
+ if (stylesToApply) {
668
+ const styleName = this.config.styleName || this.constructor.name;
669
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
670
+ }
671
+ const content = this.render();
672
+ this.shadowRoot.appendChild(content);
673
+ this.initializeEventListeners();
674
+ this.onConnected?.();
675
+ } catch (error) {
676
+ logger3.error(`Error in connectedCallback:`, error);
677
+ this.renderError(error);
768
678
  }
769
679
  }
770
680
  /**
771
- * 设置光标位置
681
+ * Web Component生命周期:从DOM断开
682
+ */
683
+ disconnectedCallback() {
684
+ this.connected = false;
685
+ this.cleanup();
686
+ this.onDisconnected?.();
687
+ }
688
+ /**
689
+ * 查找Shadow DOM内的元素
690
+ *
691
+ * @param selector - CSS选择器
692
+ * @returns 元素或null
693
+ */
694
+ querySelector(selector) {
695
+ return this.shadowRoot.querySelector(selector);
696
+ }
697
+ /**
698
+ * 查找Shadow DOM内的所有匹配元素
699
+ *
700
+ * @param selector - CSS选择器
701
+ * @returns 元素列表
702
+ */
703
+ querySelectorAll(selector) {
704
+ return this.shadowRoot.querySelectorAll(selector);
705
+ }
706
+ /**
707
+ * 重新渲染组件
772
708
  */
773
- setCursorPosition(element, position) {
709
+ rerender() {
710
+ if (!this.connected) {
711
+ logger3.warn("Component is not connected, skipping rerender.");
712
+ return;
713
+ }
714
+ const focusState = this.captureFocusState();
715
+ this._pendingFocusState = focusState;
716
+ const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
774
717
  try {
775
- const selection = window.getSelection();
776
- if (selection) {
777
- const range = document.createRange();
778
- const textNode = element.childNodes[0];
779
- if (textNode) {
780
- const maxPos = Math.min(position, textNode.textContent?.length || 0);
781
- range.setStart(textNode, maxPos);
782
- range.setEnd(textNode, maxPos);
783
- selection.removeAllRanges();
784
- selection.addRange(range);
718
+ if (adoptedStyleSheets.length === 0) {
719
+ const stylesToApply = this._autoStyles || this.config.styles;
720
+ if (stylesToApply) {
721
+ const styleName = this.config.styleName || this.constructor.name;
722
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
785
723
  }
786
724
  }
787
- } catch {
725
+ const content = this.render();
726
+ if (focusState && focusState.key && focusState.value !== void 0) {
727
+ const target = content.querySelector(
728
+ `[data-wsx-key="${focusState.key}"]`
729
+ );
730
+ if (target) {
731
+ if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
732
+ target.value = focusState.value;
733
+ }
734
+ }
735
+ }
736
+ if (this.shadowRoot.adoptedStyleSheets) {
737
+ this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
738
+ }
739
+ requestAnimationFrame(() => {
740
+ this.shadowRoot.appendChild(content);
741
+ const oldChildren = Array.from(this.shadowRoot.children).filter(
742
+ (child) => child !== content
743
+ );
744
+ oldChildren.forEach((child) => child.remove());
745
+ requestAnimationFrame(() => {
746
+ this.restoreFocusState(focusState);
747
+ this._pendingFocusState = null;
748
+ });
749
+ });
750
+ } catch (error) {
751
+ logger3.error("Error in rerender:", error);
752
+ this.renderError(error);
788
753
  }
789
754
  }
790
755
  /**
791
- * 获取所有响应式状态的快照(用于调试)
756
+ * 渲染错误信息
757
+ *
758
+ * @param error - 错误对象
792
759
  */
793
- getStateSnapshot() {
794
- const snapshot = {};
795
- this._reactiveStates.forEach((state, key) => {
796
- snapshot[key] = state.getter();
797
- });
798
- return snapshot;
760
+ renderError(error) {
761
+ this.shadowRoot.innerHTML = "";
762
+ const errorElement = h(
763
+ "div",
764
+ {
765
+ style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
766
+ },
767
+ [
768
+ h("strong", {}, `[${this.constructor.name}] Component Error:`),
769
+ h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
770
+ ]
771
+ );
772
+ this.shadowRoot.appendChild(errorElement);
773
+ }
774
+ };
775
+
776
+ // src/light-component.ts
777
+ var logger4 = createLogger("LightComponent");
778
+ var LightComponent = class extends BaseComponent {
779
+ // Initialized by BaseComponent constructor
780
+ constructor(config = {}) {
781
+ super(config);
799
782
  }
800
783
  /**
801
- * 清理响应式状态(组件销毁时)
784
+ * Web Component生命周期:连接到DOM
802
785
  */
803
- cleanupReactiveStates() {
804
- this._reactiveStates.clear();
786
+ connectedCallback() {
787
+ this.connected = true;
788
+ try {
789
+ const stylesToApply = this._autoStyles || this.config.styles;
790
+ if (stylesToApply) {
791
+ const styleName = this.config.styleName || this.constructor.name;
792
+ this.applyScopedStyles(styleName, stylesToApply);
793
+ }
794
+ const content = this.render();
795
+ this.appendChild(content);
796
+ this.initializeEventListeners();
797
+ this.onConnected?.();
798
+ } catch (error) {
799
+ logger4.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
800
+ this.renderError(error);
801
+ }
805
802
  }
806
803
  /**
807
- * 重写 disconnectedCallback 以清理状态
804
+ * Web Component生命周期:从DOM断开
808
805
  */
809
806
  disconnectedCallback() {
810
- super.disconnectedCallback();
807
+ this.connected = false;
808
+ this.cleanup();
811
809
  this.cleanupReactiveStates();
810
+ this.cleanupStyles();
811
+ this.onDisconnected?.();
812
812
  }
813
813
  /**
814
- * 启用调试模式
814
+ * 查找组件内的元素
815
+ *
816
+ * @param selector - CSS选择器
817
+ * @returns 元素或null
815
818
  */
816
- enableDebug() {
817
- this._isDebugEnabled = true;
819
+ querySelector(selector) {
820
+ return HTMLElement.prototype.querySelector.call(this, selector);
818
821
  }
819
822
  /**
820
- * 禁用调试模式
823
+ * 查找组件内的所有匹配元素
824
+ *
825
+ * @param selector - CSS选择器
826
+ * @returns 元素列表
821
827
  */
822
- disableDebug() {
823
- this._isDebugEnabled = false;
828
+ querySelectorAll(selector) {
829
+ return HTMLElement.prototype.querySelectorAll.call(this, selector);
824
830
  }
825
- };
826
- function makeReactive(_debugMode = false) {
827
- return function(constructor) {
828
- return class ReactiveComponent extends constructor {
829
- constructor(...args) {
830
- super(...args);
831
- if (!(this instanceof ReactiveWebComponent)) {
832
- this.reactive = function(obj) {
833
- return reactive(obj, () => this.rerender());
834
- };
831
+ /**
832
+ * 重新渲染组件
833
+ */
834
+ rerender() {
835
+ if (!this.connected) {
836
+ logger4.warn(
837
+ `[${this.constructor.name}] Component is not connected, skipping rerender.`
838
+ );
839
+ return;
840
+ }
841
+ const focusState = this.captureFocusState();
842
+ this._pendingFocusState = focusState;
843
+ try {
844
+ const content = this.render();
845
+ if (focusState && focusState.key && focusState.value !== void 0) {
846
+ const target = content.querySelector(
847
+ `[data-wsx-key="${focusState.key}"]`
848
+ );
849
+ if (target) {
850
+ if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
851
+ target.value = focusState.value;
852
+ }
835
853
  }
836
854
  }
837
- render() {
838
- throw new Error("render() method must be implemented by subclass");
855
+ const stylesToApply = this._autoStyles || this.config.styles;
856
+ if (stylesToApply) {
857
+ const styleName = this.config.styleName || this.constructor.name;
858
+ let styleElement = this.querySelector(
859
+ `style[data-wsx-light-component="${styleName}"]`
860
+ );
861
+ if (!styleElement) {
862
+ styleElement = document.createElement("style");
863
+ styleElement.setAttribute("data-wsx-light-component", styleName);
864
+ styleElement.textContent = stylesToApply;
865
+ this.insertBefore(styleElement, this.firstChild);
866
+ } else if (styleElement.textContent !== stylesToApply) {
867
+ styleElement.textContent = stylesToApply;
868
+ }
839
869
  }
840
- };
870
+ requestAnimationFrame(() => {
871
+ this.appendChild(content);
872
+ const oldChildren = Array.from(this.children).filter((child) => {
873
+ if (child === content) {
874
+ return false;
875
+ }
876
+ if (stylesToApply && child instanceof HTMLStyleElement && child.getAttribute("data-wsx-light-component") === (this.config.styleName || this.constructor.name)) {
877
+ return false;
878
+ }
879
+ return true;
880
+ });
881
+ oldChildren.forEach((child) => child.remove());
882
+ if (stylesToApply && this.children.length > 1) {
883
+ const styleElement = this.querySelector(
884
+ `style[data-wsx-light-component="${this.config.styleName || this.constructor.name}"]`
885
+ );
886
+ if (styleElement && styleElement !== this.firstChild) {
887
+ this.insertBefore(styleElement, this.firstChild);
888
+ }
889
+ }
890
+ requestAnimationFrame(() => {
891
+ this.restoreFocusState(focusState);
892
+ this._pendingFocusState = null;
893
+ });
894
+ });
895
+ } catch (error) {
896
+ logger4.error(`[${this.constructor.name}] Error in rerender:`, error);
897
+ this.renderError(error);
898
+ }
899
+ }
900
+ /**
901
+ * 渲染错误信息
902
+ *
903
+ * @param error - 错误对象
904
+ */
905
+ renderError(error) {
906
+ this.innerHTML = "";
907
+ const errorElement = h(
908
+ "div",
909
+ {
910
+ style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
911
+ },
912
+ [
913
+ h("strong", {}, `[${this.constructor.name}] Component Error:`),
914
+ h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
915
+ ]
916
+ );
917
+ this.appendChild(errorElement);
918
+ }
919
+ /**
920
+ * 为Light DOM组件应用样式
921
+ * 直接将样式注入到组件自身,避免全局污染
922
+ */
923
+ applyScopedStyles(styleName, cssText) {
924
+ const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
925
+ if (existingStyle) {
926
+ return;
927
+ }
928
+ const styleElement = document.createElement("style");
929
+ styleElement.setAttribute("data-wsx-light-component", styleName);
930
+ styleElement.textContent = cssText;
931
+ this.insertBefore(styleElement, this.firstChild);
932
+ }
933
+ /**
934
+ * 清理组件样式
935
+ */
936
+ cleanupStyles() {
937
+ const styleName = this.config.styleName || this.constructor.name;
938
+ const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
939
+ if (existingStyle) {
940
+ existingStyle.remove();
941
+ }
942
+ }
943
+ };
944
+
945
+ // src/auto-register.ts
946
+ function autoRegister(options = {}) {
947
+ return function(constructor) {
948
+ const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
949
+ if (!customElements.get(tagName)) {
950
+ customElements.define(tagName, constructor);
951
+ }
952
+ return constructor;
841
953
  };
842
954
  }
843
- function createReactiveComponent(ComponentClass, config) {
844
- if (ComponentClass.prototype instanceof ReactiveWebComponent) {
845
- return new ComponentClass(config);
955
+ function registerComponent(constructor, options = {}) {
956
+ const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
957
+ if (!customElements.get(tagName)) {
958
+ customElements.define(tagName, constructor);
959
+ }
960
+ }
961
+ function deriveTagName(className, prefix) {
962
+ let kebabCase = className.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
963
+ if (!kebabCase.includes("-")) {
964
+ kebabCase = `${kebabCase}-component`;
965
+ }
966
+ return prefix ? `${prefix}${kebabCase}` : kebabCase;
967
+ }
968
+
969
+ // src/reactive-decorator.ts
970
+ function state(target, propertyKey) {
971
+ let normalizedPropertyKey;
972
+ if (typeof propertyKey === "string" || typeof propertyKey === "symbol") {
973
+ normalizedPropertyKey = propertyKey;
974
+ } else {
975
+ const propertyKeyStr = String(propertyKey);
976
+ if (propertyKeyStr === "[object Object]") {
977
+ throw new Error(
978
+ `@state decorator: Invalid propertyKey detected.
979
+
980
+ The @state decorator MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
981
+
982
+ To fix this, please:
983
+ 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
984
+ 2. Configure it in vite.config.ts:
985
+ import { wsx } from '@wsxjs/wsx-vite-plugin';
986
+ export default defineConfig({ plugins: [wsx()] });
987
+ 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
988
+ npm install --save-dev @wsxjs/wsx-tsconfig
989
+ Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
990
+ Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
991
+
992
+ See: https://github.com/wsxjs/wsxjs#setup for more details.`
993
+ );
994
+ }
995
+ normalizedPropertyKey = propertyKeyStr;
996
+ }
997
+ if (target == null) {
998
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
999
+ throw new Error(
1000
+ `@state decorator: Cannot access property "${propertyKeyStr}". Target is ${target === null ? "null" : "undefined"}.
1001
+
1002
+ The @state decorator MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
1003
+
1004
+ To fix this, please:
1005
+ 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1006
+ 2. Configure it in vite.config.ts:
1007
+ import { wsx } from '@wsxjs/wsx-vite-plugin';
1008
+ export default defineConfig({ plugins: [wsx()] });
1009
+ 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1010
+ npm install --save-dev @wsxjs/wsx-tsconfig
1011
+ Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1012
+ Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1013
+
1014
+ See: https://github.com/wsxjs/wsxjs#setup for more details.`
1015
+ );
1016
+ }
1017
+ if (typeof target !== "object") {
1018
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1019
+ throw new Error(
1020
+ `@state decorator: Cannot be used on "${propertyKeyStr}". @state is for properties only, not methods.`
1021
+ );
1022
+ }
1023
+ const descriptor = Object.getOwnPropertyDescriptor(target, normalizedPropertyKey);
1024
+ if (descriptor?.get) {
1025
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1026
+ throw new Error(
1027
+ `@state decorator cannot be used with getter properties. Property: "${propertyKeyStr}"`
1028
+ );
846
1029
  }
847
- const ReactiveComponent = makeReactive(config?.debug)(ComponentClass);
848
- return new ReactiveComponent(config);
849
1030
  }
850
1031
  export {
851
1032
  Fragment,
852
1033
  LightComponent,
853
- ReactiveDebug,
854
- ReactiveWebComponent,
855
1034
  StyleManager,
856
1035
  WSXLogger,
857
1036
  WebComponent,
858
1037
  autoRegister,
859
1038
  createLogger,
860
- createReactiveComponent,
861
- createState,
862
1039
  h,
863
1040
  h as jsx,
864
1041
  h as jsxs,
865
1042
  logger,
866
- makeReactive,
867
- reactive,
868
- registerComponent
1043
+ registerComponent,
1044
+ state
869
1045
  };