@wsxjs/wsx-core 0.0.7 → 0.0.8

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
@@ -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") {
@@ -375,16 +209,26 @@ function reactiveWithDebug(obj, onChange, debugName) {
375
209
  });
376
210
  }
377
211
 
378
- // src/light-component.ts
379
- var logger3 = createLogger("LightComponent");
380
- var LightComponent = class extends HTMLElement {
212
+ // src/base-component.ts
213
+ var BaseComponent = class extends HTMLElement {
381
214
  constructor(config = {}) {
382
215
  super();
383
216
  this.connected = false;
384
217
  this._isDebugEnabled = false;
385
218
  this._reactiveStates = /* @__PURE__ */ new Map();
386
- this.config = config;
387
219
  this._isDebugEnabled = config.debug ?? false;
220
+ const host = this;
221
+ const originalStyles = config.styles;
222
+ this.config = {
223
+ ...config,
224
+ get styles() {
225
+ const result = originalStyles || host._autoStyles || "";
226
+ return result;
227
+ },
228
+ set styles(value) {
229
+ config.styles = value;
230
+ }
231
+ };
388
232
  }
389
233
  /**
390
234
  * 子类应该重写这个方法来定义观察的属性
@@ -393,56 +237,12 @@ var LightComponent = class extends HTMLElement {
393
237
  static get observedAttributes() {
394
238
  return [];
395
239
  }
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
240
  /**
423
241
  * Web Component生命周期:属性变化
424
242
  */
425
243
  attributeChangedCallback(name, oldValue, newValue) {
426
244
  this.onAttributeChanged?.(name, oldValue, newValue);
427
245
  }
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
246
  /**
447
247
  * 创建响应式对象
448
248
  *
@@ -465,10 +265,16 @@ var LightComponent = class extends HTMLElement {
465
265
  useState(key, initialValue) {
466
266
  if (!this._reactiveStates.has(key)) {
467
267
  const [getter, setter] = createState(initialValue, () => this.scheduleRerender());
468
- this._reactiveStates.set(key, { getter, setter });
268
+ this._reactiveStates.set(key, {
269
+ getter,
270
+ setter
271
+ });
272
+ }
273
+ const state2 = this._reactiveStates.get(key);
274
+ if (!state2) {
275
+ throw new Error(`State ${key} not found`);
469
276
  }
470
- const state = this._reactiveStates.get(key);
471
- return [state.getter, state.setter];
277
+ return [state2.getter, state2.setter];
472
278
  }
473
279
  /**
474
280
  * 调度重渲染
@@ -480,107 +286,24 @@ var LightComponent = class extends HTMLElement {
480
286
  }
481
287
  }
482
288
  /**
483
- * 重新渲染组件
289
+ * 获取配置值
290
+ *
291
+ * @param key - 配置键
292
+ * @param defaultValue - 默认值
293
+ * @returns 配置值
484
294
  */
485
- rerender() {
486
- if (!this.connected) {
487
- logger3.warn(
488
- `[${this.constructor.name}] Component is not connected, skipping rerender.`
489
- );
490
- return;
491
- }
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);
499
- }
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
- }
510
- }
511
- } catch (error) {
512
- logger3.error(`[${this.constructor.name}] Error in rerender:`, error);
513
- this.renderError(error);
514
- }
295
+ getConfig(key, defaultValue) {
296
+ return this.config[key] ?? defaultValue;
515
297
  }
516
298
  /**
517
- * 渲染错误信息
299
+ * 设置配置值
518
300
  *
519
- * @param error - 错误对象
520
- */
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);
534
- }
535
- /**
536
- * 为Light DOM组件应用样式
537
- * 直接将样式注入到组件自身,避免全局污染
538
- */
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);
548
- }
549
- /**
550
- * 获取配置值
551
- *
552
- * @param key - 配置键
553
- * @param defaultValue - 默认值
554
- * @returns 配置值
555
- */
556
- getConfig(key, defaultValue) {
557
- return this.config[key] ?? defaultValue;
558
- }
559
- /**
560
- * 设置配置值
561
- *
562
- * @param key - 配置键
563
- * @param value - 配置值
301
+ * @param key - 配置键
302
+ * @param value - 配置值
564
303
  */
565
304
  setConfig(key, value) {
566
305
  this.config[key] = value;
567
306
  }
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
307
  /**
585
308
  * 获取属性值
586
309
  *
@@ -617,92 +340,102 @@ var LightComponent = class extends HTMLElement {
617
340
  hasAttr(name) {
618
341
  return this.hasAttribute(name);
619
342
  }
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`;
343
+ /**
344
+ * 清理响应式状态
345
+ */
346
+ cleanupReactiveStates() {
347
+ this._reactiveStates.clear();
642
348
  }
643
- return prefix ? `${prefix}${kebabCase}` : kebabCase;
644
- }
349
+ };
645
350
 
646
- // src/reactive-component.ts
647
- var ReactiveWebComponent = class extends WebComponent {
351
+ // src/web-component.ts
352
+ var WebComponent = class extends BaseComponent {
648
353
  constructor(config = {}) {
649
354
  super(config);
650
- this._isDebugEnabled = false;
355
+ // Initialized by BaseComponent constructor
651
356
  this._preserveFocus = true;
652
- this._reactiveStates = /* @__PURE__ */ new Map();
653
- this._isDebugEnabled = config.debug ?? false;
654
357
  this._preserveFocus = config.preserveFocus ?? true;
358
+ this.attachShadow({ mode: "open" });
655
359
  }
656
360
  /**
657
- * 创建响应式对象
658
- *
659
- * @param obj 要变为响应式的对象
660
- * @param debugName 调试名称(可选)
661
- * @returns 响应式代理对象
361
+ * Web Component生命周期:连接到DOM
662
362
  */
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());
363
+ connectedCallback() {
364
+ this.connected = true;
365
+ try {
366
+ const stylesToApply = this._getAutoStyles?.() || this.config.styles;
367
+ if (stylesToApply) {
368
+ const styleName = this.config.styleName || this.constructor.name;
369
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
370
+ }
371
+ const content = this.render();
372
+ this.shadowRoot.appendChild(content);
373
+ this.onConnected?.();
374
+ } catch (error) {
375
+ console.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
376
+ this.renderError(error);
377
+ }
667
378
  }
668
379
  /**
669
- * 创建响应式状态
380
+ * Web Component生命周期:从DOM断开
381
+ */
382
+ disconnectedCallback() {
383
+ this.connected = false;
384
+ this.onDisconnected?.();
385
+ }
386
+ /**
387
+ * 查找Shadow DOM内的元素
670
388
  *
671
- * @param key 状态标识符
672
- * @param initialValue 初始值
673
- * @returns [getter, setter] 元组
389
+ * @param selector - CSS选择器
390
+ * @returns 元素或null
674
391
  */
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];
392
+ querySelector(selector) {
393
+ return this.shadowRoot.querySelector(selector);
682
394
  }
683
395
  /**
684
- * 调度重渲染
685
- * 这个方法被响应式系统调用,开发者通常不需要直接调用
396
+ * 查找Shadow DOM内的所有匹配元素
397
+ *
398
+ * @param selector - CSS选择器
399
+ * @returns 元素列表
686
400
  */
687
- scheduleRerender() {
688
- if (this.connected) {
689
- this.rerender();
690
- }
401
+ querySelectorAll(selector) {
402
+ return this.shadowRoot.querySelectorAll(selector);
691
403
  }
692
404
  /**
693
- * 重写 rerender 方法以支持焦点保持
405
+ * 重新渲染组件
694
406
  */
695
407
  rerender() {
696
408
  if (!this.connected) {
409
+ console.warn(
410
+ `[${this.constructor.name}] Component is not connected, skipping rerender.`
411
+ );
697
412
  return;
698
413
  }
699
414
  let focusData = null;
700
- if (this._preserveFocus) {
415
+ if (this._preserveFocus && this.shadowRoot) {
701
416
  const activeElement = this.shadowRoot.activeElement;
702
417
  focusData = this.saveFocusState(activeElement);
703
418
  }
704
- super.rerender();
705
- if (this._preserveFocus && focusData) {
419
+ const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
420
+ this.shadowRoot.innerHTML = "";
421
+ if (this.shadowRoot.adoptedStyleSheets) {
422
+ this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
423
+ }
424
+ if (adoptedStyleSheets.length === 0) {
425
+ const stylesToApply = this._autoStyles || this.config.styles;
426
+ if (stylesToApply) {
427
+ const styleName = this.config.styleName || this.constructor.name;
428
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
429
+ }
430
+ }
431
+ try {
432
+ const content = this.render();
433
+ this.shadowRoot.appendChild(content);
434
+ } catch (error) {
435
+ console.error(`[${this.constructor.name}] Error in rerender:`, error);
436
+ this.renderError(error);
437
+ }
438
+ if (this._preserveFocus && focusData && this.shadowRoot) {
706
439
  this.restoreFocusState(focusData);
707
440
  }
708
441
  }
@@ -728,8 +461,8 @@ var ReactiveWebComponent = class extends WebComponent {
728
461
  if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLSelectElement) {
729
462
  focusData.value = activeElement.value;
730
463
  if ("selectionStart" in activeElement) {
731
- focusData.selectionStart = activeElement.selectionStart;
732
- focusData.selectionEnd = activeElement.selectionEnd;
464
+ focusData.selectionStart = activeElement.selectionStart ?? void 0;
465
+ focusData.selectionEnd = activeElement.selectionEnd ?? void 0;
733
466
  }
734
467
  }
735
468
  return focusData;
@@ -755,10 +488,10 @@ var ReactiveWebComponent = class extends WebComponent {
755
488
  if (targetElement instanceof HTMLInputElement) {
756
489
  targetElement.setSelectionRange(
757
490
  focusData.selectionStart,
758
- focusData.selectionEnd
491
+ focusData.selectionEnd ?? focusData.selectionStart
759
492
  );
760
493
  } else if (targetElement instanceof HTMLSelectElement) {
761
- targetElement.value = focusData.value;
494
+ targetElement.value = focusData.value ?? "";
762
495
  } else if (targetElement.hasAttribute("contenteditable")) {
763
496
  this.setCursorPosition(targetElement, focusData.selectionStart);
764
497
  }
@@ -788,82 +521,227 @@ var ReactiveWebComponent = class extends WebComponent {
788
521
  }
789
522
  }
790
523
  /**
791
- * 获取所有响应式状态的快照(用于调试)
524
+ * 渲染错误信息
525
+ *
526
+ * @param error - 错误对象
792
527
  */
793
- getStateSnapshot() {
794
- const snapshot = {};
795
- this._reactiveStates.forEach((state, key) => {
796
- snapshot[key] = state.getter();
797
- });
798
- return snapshot;
528
+ renderError(error) {
529
+ this.shadowRoot.innerHTML = "";
530
+ const errorElement = h(
531
+ "div",
532
+ {
533
+ style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
534
+ },
535
+ [
536
+ h("strong", {}, `[${this.constructor.name}] Component Error:`),
537
+ h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
538
+ ]
539
+ );
540
+ this.shadowRoot.appendChild(errorElement);
541
+ }
542
+ };
543
+
544
+ // src/light-component.ts
545
+ var logger3 = createLogger("LightComponent");
546
+ var LightComponent = class extends BaseComponent {
547
+ // Initialized by BaseComponent constructor
548
+ constructor(config = {}) {
549
+ super(config);
799
550
  }
800
551
  /**
801
- * 清理响应式状态(组件销毁时)
552
+ * Web Component生命周期:连接到DOM
802
553
  */
803
- cleanupReactiveStates() {
804
- this._reactiveStates.clear();
554
+ connectedCallback() {
555
+ this.connected = true;
556
+ try {
557
+ const stylesToApply = this._autoStyles || this.config.styles;
558
+ if (stylesToApply) {
559
+ const styleName = this.config.styleName || this.constructor.name;
560
+ this.applyScopedStyles(styleName, stylesToApply);
561
+ }
562
+ const content = this.render();
563
+ this.appendChild(content);
564
+ this.onConnected?.();
565
+ } catch (error) {
566
+ logger3.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
567
+ this.renderError(error);
568
+ }
805
569
  }
806
570
  /**
807
- * 重写 disconnectedCallback 以清理状态
571
+ * Web Component生命周期:从DOM断开
808
572
  */
809
573
  disconnectedCallback() {
810
- super.disconnectedCallback();
811
574
  this.cleanupReactiveStates();
575
+ this.cleanupStyles();
576
+ this.onDisconnected?.();
812
577
  }
813
578
  /**
814
- * 启用调试模式
579
+ * 查找组件内的元素
580
+ *
581
+ * @param selector - CSS选择器
582
+ * @returns 元素或null
815
583
  */
816
- enableDebug() {
817
- this._isDebugEnabled = true;
584
+ querySelector(selector) {
585
+ return HTMLElement.prototype.querySelector.call(this, selector);
818
586
  }
819
587
  /**
820
- * 禁用调试模式
588
+ * 查找组件内的所有匹配元素
589
+ *
590
+ * @param selector - CSS选择器
591
+ * @returns 元素列表
821
592
  */
822
- disableDebug() {
823
- this._isDebugEnabled = false;
593
+ querySelectorAll(selector) {
594
+ return HTMLElement.prototype.querySelectorAll.call(this, selector);
824
595
  }
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
- };
596
+ /**
597
+ * 重新渲染组件
598
+ */
599
+ rerender() {
600
+ if (!this.connected) {
601
+ logger3.warn(
602
+ `[${this.constructor.name}] Component is not connected, skipping rerender.`
603
+ );
604
+ return;
605
+ }
606
+ this.innerHTML = "";
607
+ if (this.config.styles) {
608
+ const styleName = this.config.styleName || this.constructor.name;
609
+ const styleElement = document.createElement("style");
610
+ styleElement.setAttribute("data-wsx-light-component", styleName);
611
+ styleElement.textContent = this.config.styles;
612
+ this.appendChild(styleElement);
613
+ }
614
+ try {
615
+ const content = this.render();
616
+ this.appendChild(content);
617
+ if (this.config.styles && this.children.length > 1) {
618
+ const styleElement = this.querySelector(
619
+ `style[data-wsx-light-component="${this.config.styleName || this.constructor.name}"]`
620
+ );
621
+ if (styleElement && styleElement !== this.firstChild) {
622
+ this.insertBefore(styleElement, this.firstChild);
835
623
  }
836
624
  }
837
- render() {
838
- throw new Error("render() method must be implemented by subclass");
839
- }
840
- };
625
+ } catch (error) {
626
+ logger3.error(`[${this.constructor.name}] Error in rerender:`, error);
627
+ this.renderError(error);
628
+ }
629
+ }
630
+ /**
631
+ * 渲染错误信息
632
+ *
633
+ * @param error - 错误对象
634
+ */
635
+ renderError(error) {
636
+ this.innerHTML = "";
637
+ const errorElement = h(
638
+ "div",
639
+ {
640
+ style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
641
+ },
642
+ [
643
+ h("strong", {}, `[${this.constructor.name}] Component Error:`),
644
+ h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
645
+ ]
646
+ );
647
+ this.appendChild(errorElement);
648
+ }
649
+ /**
650
+ * 为Light DOM组件应用样式
651
+ * 直接将样式注入到组件自身,避免全局污染
652
+ */
653
+ applyScopedStyles(styleName, cssText) {
654
+ const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
655
+ if (existingStyle) {
656
+ return;
657
+ }
658
+ const styleElement = document.createElement("style");
659
+ styleElement.setAttribute("data-wsx-light-component", styleName);
660
+ styleElement.textContent = cssText;
661
+ this.insertBefore(styleElement, this.firstChild);
662
+ }
663
+ /**
664
+ * 清理组件样式
665
+ */
666
+ cleanupStyles() {
667
+ const styleName = this.config.styleName || this.constructor.name;
668
+ const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
669
+ if (existingStyle) {
670
+ existingStyle.remove();
671
+ }
672
+ }
673
+ };
674
+
675
+ // src/auto-register.ts
676
+ function autoRegister(options = {}) {
677
+ return function(constructor) {
678
+ const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
679
+ if (!customElements.get(tagName)) {
680
+ customElements.define(tagName, constructor);
681
+ }
682
+ return constructor;
841
683
  };
842
684
  }
843
- function createReactiveComponent(ComponentClass, config) {
844
- if (ComponentClass.prototype instanceof ReactiveWebComponent) {
845
- return new ComponentClass(config);
685
+ function registerComponent(constructor, options = {}) {
686
+ const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
687
+ if (!customElements.get(tagName)) {
688
+ customElements.define(tagName, constructor);
689
+ }
690
+ }
691
+ function deriveTagName(className, prefix) {
692
+ let kebabCase = className.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
693
+ if (!kebabCase.includes("-")) {
694
+ kebabCase = `${kebabCase}-component`;
695
+ }
696
+ return prefix ? `${prefix}${kebabCase}` : kebabCase;
697
+ }
698
+
699
+ // src/reactive-decorator.ts
700
+ function state(target, propertyKey) {
701
+ let normalizedPropertyKey;
702
+ if (typeof propertyKey === "string" || typeof propertyKey === "symbol") {
703
+ normalizedPropertyKey = propertyKey;
704
+ } else {
705
+ const propertyKeyStr = String(propertyKey);
706
+ if (propertyKeyStr === "[object Object]") {
707
+ throw new Error(
708
+ `@state decorator: Invalid propertyKey. This usually means the build tool doesn't support decorators properly. Please ensure Babel plugin is configured in vite.config.ts`
709
+ );
710
+ }
711
+ normalizedPropertyKey = propertyKeyStr;
712
+ }
713
+ if (target == null) {
714
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
715
+ throw new Error(
716
+ `@state decorator: Cannot access property "${propertyKeyStr}". Target is ${target === null ? "null" : "undefined"}. Please ensure Babel plugin is configured in vite.config.ts`
717
+ );
718
+ }
719
+ if (typeof target !== "object") {
720
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
721
+ throw new Error(
722
+ `@state decorator: Cannot be used on "${propertyKeyStr}". @state is for properties only, not methods.`
723
+ );
724
+ }
725
+ const descriptor = Object.getOwnPropertyDescriptor(target, normalizedPropertyKey);
726
+ if (descriptor?.get) {
727
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
728
+ throw new Error(
729
+ `@state decorator cannot be used with getter properties. Property: "${propertyKeyStr}"`
730
+ );
846
731
  }
847
- const ReactiveComponent = makeReactive(config?.debug)(ComponentClass);
848
- return new ReactiveComponent(config);
849
732
  }
850
733
  export {
851
734
  Fragment,
852
735
  LightComponent,
853
- ReactiveDebug,
854
- ReactiveWebComponent,
855
736
  StyleManager,
856
737
  WSXLogger,
857
738
  WebComponent,
858
739
  autoRegister,
859
740
  createLogger,
860
- createReactiveComponent,
861
- createState,
862
741
  h,
863
742
  h as jsx,
864
743
  h as jsxs,
865
744
  logger,
866
- makeReactive,
867
- reactive,
868
- registerComponent
745
+ registerComponent,
746
+ state
869
747
  };