@wsxjs/wsx-core 0.0.6 → 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,91 +286,23 @@ 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
- try {
494
- const content = this.render();
495
- this.appendChild(content);
496
- } catch (error) {
497
- logger3.error(`[${this.constructor.name}] Error in rerender:`, error);
498
- this.renderError(error);
499
- }
295
+ getConfig(key, defaultValue) {
296
+ return this.config[key] ?? defaultValue;
500
297
  }
501
298
  /**
502
- * 渲染错误信息
299
+ * 设置配置值
503
300
  *
504
- * @param error - 错误对象
301
+ * @param key - 配置键
302
+ * @param value - 配置值
505
303
  */
506
- renderError(error) {
507
- this.innerHTML = "";
508
- const errorElement = h(
509
- "div",
510
- {
511
- style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
512
- },
513
- [
514
- h("strong", {}, `[${this.constructor.name}] Component Error:`),
515
- h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
516
- ]
517
- );
518
- this.appendChild(errorElement);
519
- }
520
- /**
521
- * 为Light DOM组件应用样式
522
- * 直接将样式注入到组件自身,避免全局污染
523
- */
524
- applyScopedStyles(styleName, cssText) {
525
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
526
- if (existingStyle) {
527
- return;
528
- }
529
- const styleElement = document.createElement("style");
530
- styleElement.setAttribute("data-wsx-light-component", styleName);
531
- styleElement.textContent = cssText;
532
- this.insertBefore(styleElement, this.firstChild);
533
- }
534
- /**
535
- * 获取配置值
536
- *
537
- * @param key - 配置键
538
- * @param defaultValue - 默认值
539
- * @returns 配置值
540
- */
541
- getConfig(key, defaultValue) {
542
- return this.config[key] ?? defaultValue;
543
- }
544
- /**
545
- * 设置配置值
546
- *
547
- * @param key - 配置键
548
- * @param value - 配置值
549
- */
550
- setConfig(key, value) {
551
- this.config[key] = value;
552
- }
553
- /**
554
- * 清理响应式状态
555
- */
556
- cleanupReactiveStates() {
557
- this._reactiveStates.clear();
558
- }
559
- /**
560
- * 清理组件样式
561
- */
562
- cleanupStyles() {
563
- const styleName = this.config.styleName || this.constructor.name;
564
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
565
- if (existingStyle) {
566
- existingStyle.remove();
567
- }
304
+ setConfig(key, value) {
305
+ this.config[key] = value;
568
306
  }
569
307
  /**
570
308
  * 获取属性值
@@ -602,92 +340,102 @@ var LightComponent = class extends HTMLElement {
602
340
  hasAttr(name) {
603
341
  return this.hasAttribute(name);
604
342
  }
605
- };
606
-
607
- // src/auto-register.ts
608
- function autoRegister(options = {}) {
609
- return function(constructor) {
610
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
611
- if (!customElements.get(tagName)) {
612
- customElements.define(tagName, constructor);
613
- }
614
- return constructor;
615
- };
616
- }
617
- function registerComponent(constructor, options = {}) {
618
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
619
- if (!customElements.get(tagName)) {
620
- customElements.define(tagName, constructor);
621
- }
622
- }
623
- function deriveTagName(className, prefix) {
624
- let kebabCase = className.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
625
- if (!kebabCase.includes("-")) {
626
- kebabCase = `${kebabCase}-component`;
343
+ /**
344
+ * 清理响应式状态
345
+ */
346
+ cleanupReactiveStates() {
347
+ this._reactiveStates.clear();
627
348
  }
628
- return prefix ? `${prefix}${kebabCase}` : kebabCase;
629
- }
349
+ };
630
350
 
631
- // src/reactive-component.ts
632
- var ReactiveWebComponent = class extends WebComponent {
351
+ // src/web-component.ts
352
+ var WebComponent = class extends BaseComponent {
633
353
  constructor(config = {}) {
634
354
  super(config);
635
- this._isDebugEnabled = false;
355
+ // Initialized by BaseComponent constructor
636
356
  this._preserveFocus = true;
637
- this._reactiveStates = /* @__PURE__ */ new Map();
638
- this._isDebugEnabled = config.debug ?? false;
639
357
  this._preserveFocus = config.preserveFocus ?? true;
358
+ this.attachShadow({ mode: "open" });
640
359
  }
641
360
  /**
642
- * 创建响应式对象
643
- *
644
- * @param obj 要变为响应式的对象
645
- * @param debugName 调试名称(可选)
646
- * @returns 响应式代理对象
361
+ * Web Component生命周期:连接到DOM
647
362
  */
648
- reactive(obj, debugName) {
649
- const reactiveFn = this._isDebugEnabled ? reactiveWithDebug : reactive;
650
- const name = debugName || `${this.constructor.name}.reactive`;
651
- 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
+ }
652
378
  }
653
379
  /**
654
- * 创建响应式状态
380
+ * Web Component生命周期:从DOM断开
381
+ */
382
+ disconnectedCallback() {
383
+ this.connected = false;
384
+ this.onDisconnected?.();
385
+ }
386
+ /**
387
+ * 查找Shadow DOM内的元素
655
388
  *
656
- * @param key 状态标识符
657
- * @param initialValue 初始值
658
- * @returns [getter, setter] 元组
389
+ * @param selector - CSS选择器
390
+ * @returns 元素或null
659
391
  */
660
- useState(key, initialValue) {
661
- if (!this._reactiveStates.has(key)) {
662
- const [getter, setter] = createState(initialValue, () => this.scheduleRerender());
663
- this._reactiveStates.set(key, { getter, setter });
664
- }
665
- const state = this._reactiveStates.get(key);
666
- return [state.getter, state.setter];
392
+ querySelector(selector) {
393
+ return this.shadowRoot.querySelector(selector);
667
394
  }
668
395
  /**
669
- * 调度重渲染
670
- * 这个方法被响应式系统调用,开发者通常不需要直接调用
396
+ * 查找Shadow DOM内的所有匹配元素
397
+ *
398
+ * @param selector - CSS选择器
399
+ * @returns 元素列表
671
400
  */
672
- scheduleRerender() {
673
- if (this.connected) {
674
- this.rerender();
675
- }
401
+ querySelectorAll(selector) {
402
+ return this.shadowRoot.querySelectorAll(selector);
676
403
  }
677
404
  /**
678
- * 重写 rerender 方法以支持焦点保持
405
+ * 重新渲染组件
679
406
  */
680
407
  rerender() {
681
408
  if (!this.connected) {
409
+ console.warn(
410
+ `[${this.constructor.name}] Component is not connected, skipping rerender.`
411
+ );
682
412
  return;
683
413
  }
684
414
  let focusData = null;
685
- if (this._preserveFocus) {
415
+ if (this._preserveFocus && this.shadowRoot) {
686
416
  const activeElement = this.shadowRoot.activeElement;
687
417
  focusData = this.saveFocusState(activeElement);
688
418
  }
689
- super.rerender();
690
- 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) {
691
439
  this.restoreFocusState(focusData);
692
440
  }
693
441
  }
@@ -713,8 +461,8 @@ var ReactiveWebComponent = class extends WebComponent {
713
461
  if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLSelectElement) {
714
462
  focusData.value = activeElement.value;
715
463
  if ("selectionStart" in activeElement) {
716
- focusData.selectionStart = activeElement.selectionStart;
717
- focusData.selectionEnd = activeElement.selectionEnd;
464
+ focusData.selectionStart = activeElement.selectionStart ?? void 0;
465
+ focusData.selectionEnd = activeElement.selectionEnd ?? void 0;
718
466
  }
719
467
  }
720
468
  return focusData;
@@ -740,10 +488,10 @@ var ReactiveWebComponent = class extends WebComponent {
740
488
  if (targetElement instanceof HTMLInputElement) {
741
489
  targetElement.setSelectionRange(
742
490
  focusData.selectionStart,
743
- focusData.selectionEnd
491
+ focusData.selectionEnd ?? focusData.selectionStart
744
492
  );
745
493
  } else if (targetElement instanceof HTMLSelectElement) {
746
- targetElement.value = focusData.value;
494
+ targetElement.value = focusData.value ?? "";
747
495
  } else if (targetElement.hasAttribute("contenteditable")) {
748
496
  this.setCursorPosition(targetElement, focusData.selectionStart);
749
497
  }
@@ -773,82 +521,227 @@ var ReactiveWebComponent = class extends WebComponent {
773
521
  }
774
522
  }
775
523
  /**
776
- * 获取所有响应式状态的快照(用于调试)
524
+ * 渲染错误信息
525
+ *
526
+ * @param error - 错误对象
777
527
  */
778
- getStateSnapshot() {
779
- const snapshot = {};
780
- this._reactiveStates.forEach((state, key) => {
781
- snapshot[key] = state.getter();
782
- });
783
- 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);
784
550
  }
785
551
  /**
786
- * 清理响应式状态(组件销毁时)
552
+ * Web Component生命周期:连接到DOM
787
553
  */
788
- cleanupReactiveStates() {
789
- 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
+ }
790
569
  }
791
570
  /**
792
- * 重写 disconnectedCallback 以清理状态
571
+ * Web Component生命周期:从DOM断开
793
572
  */
794
573
  disconnectedCallback() {
795
- super.disconnectedCallback();
796
574
  this.cleanupReactiveStates();
575
+ this.cleanupStyles();
576
+ this.onDisconnected?.();
797
577
  }
798
578
  /**
799
- * 启用调试模式
579
+ * 查找组件内的元素
580
+ *
581
+ * @param selector - CSS选择器
582
+ * @returns 元素或null
800
583
  */
801
- enableDebug() {
802
- this._isDebugEnabled = true;
584
+ querySelector(selector) {
585
+ return HTMLElement.prototype.querySelector.call(this, selector);
803
586
  }
804
587
  /**
805
- * 禁用调试模式
588
+ * 查找组件内的所有匹配元素
589
+ *
590
+ * @param selector - CSS选择器
591
+ * @returns 元素列表
806
592
  */
807
- disableDebug() {
808
- this._isDebugEnabled = false;
593
+ querySelectorAll(selector) {
594
+ return HTMLElement.prototype.querySelectorAll.call(this, selector);
809
595
  }
810
- };
811
- function makeReactive(_debugMode = false) {
812
- return function(constructor) {
813
- return class ReactiveComponent extends constructor {
814
- constructor(...args) {
815
- super(...args);
816
- if (!(this instanceof ReactiveWebComponent)) {
817
- this.reactive = function(obj) {
818
- return reactive(obj, () => this.rerender());
819
- };
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);
820
623
  }
821
624
  }
822
- render() {
823
- throw new Error("render() method must be implemented by subclass");
824
- }
825
- };
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;
826
683
  };
827
684
  }
828
- function createReactiveComponent(ComponentClass, config) {
829
- if (ComponentClass.prototype instanceof ReactiveWebComponent) {
830
- 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
+ );
831
731
  }
832
- const ReactiveComponent = makeReactive(config?.debug)(ComponentClass);
833
- return new ReactiveComponent(config);
834
732
  }
835
733
  export {
836
734
  Fragment,
837
735
  LightComponent,
838
- ReactiveDebug,
839
- ReactiveWebComponent,
840
736
  StyleManager,
841
737
  WSXLogger,
842
738
  WebComponent,
843
739
  autoRegister,
844
740
  createLogger,
845
- createReactiveComponent,
846
- createState,
847
741
  h,
848
742
  h as jsx,
849
743
  h as jsxs,
850
744
  logger,
851
- makeReactive,
852
- reactive,
853
- registerComponent
745
+ registerComponent,
746
+ state
854
747
  };