@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.js CHANGED
@@ -22,22 +22,17 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Fragment: () => Fragment,
24
24
  LightComponent: () => LightComponent,
25
- ReactiveDebug: () => ReactiveDebug,
26
- ReactiveWebComponent: () => ReactiveWebComponent,
27
25
  StyleManager: () => StyleManager,
28
26
  WSXLogger: () => WSXLogger,
29
27
  WebComponent: () => WebComponent,
30
28
  autoRegister: () => autoRegister,
31
29
  createLogger: () => createLogger,
32
- createReactiveComponent: () => createReactiveComponent,
33
- createState: () => createState,
34
30
  h: () => h,
35
31
  jsx: () => h,
36
32
  jsxs: () => h,
37
33
  logger: () => logger,
38
- makeReactive: () => makeReactive,
39
- reactive: () => reactive,
40
- registerComponent: () => registerComponent
34
+ registerComponent: () => registerComponent,
35
+ state: () => state
41
36
  });
42
37
  module.exports = __toCommonJS(index_exports);
43
38
 
@@ -274,172 +269,6 @@ var StyleManager = class {
274
269
  };
275
270
  StyleManager.styleSheets = /* @__PURE__ */ new Map();
276
271
 
277
- // src/web-component.ts
278
- var WebComponent = class extends HTMLElement {
279
- constructor(config = {}) {
280
- super();
281
- this.connected = false;
282
- this.config = config;
283
- this.attachShadow({ mode: "open" });
284
- if (config.styles) {
285
- const styleName = config.styleName || this.constructor.name;
286
- StyleManager.applyStyles(this.shadowRoot, styleName, config.styles);
287
- }
288
- }
289
- /**
290
- * 子类应该重写这个方法来定义观察的属性
291
- * @returns 要观察的属性名数组
292
- */
293
- static get observedAttributes() {
294
- return [];
295
- }
296
- /**
297
- * Web Component生命周期:连接到DOM
298
- */
299
- connectedCallback() {
300
- this.connected = true;
301
- try {
302
- const content = this.render();
303
- this.shadowRoot.appendChild(content);
304
- this.onConnected?.();
305
- } catch (error) {
306
- console.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
307
- this.renderError(error);
308
- }
309
- }
310
- /**
311
- * Web Component生命周期:从DOM断开
312
- */
313
- disconnectedCallback() {
314
- this.onDisconnected?.();
315
- }
316
- /**
317
- * Web Component生命周期:属性变化
318
- */
319
- attributeChangedCallback(name, oldValue, newValue) {
320
- this.onAttributeChanged?.(name, oldValue, newValue);
321
- }
322
- /**
323
- * 查找Shadow DOM内的元素
324
- *
325
- * @param selector - CSS选择器
326
- * @returns 元素或null
327
- */
328
- querySelector(selector) {
329
- return this.shadowRoot.querySelector(selector);
330
- }
331
- /**
332
- * 查找Shadow DOM内的所有匹配元素
333
- *
334
- * @param selector - CSS选择器
335
- * @returns 元素列表
336
- */
337
- querySelectorAll(selector) {
338
- return this.shadowRoot.querySelectorAll(selector);
339
- }
340
- /**
341
- * 重新渲染组件
342
- */
343
- rerender() {
344
- if (!this.connected) {
345
- console.warn(
346
- `[${this.constructor.name}] Component is not connected, skipping rerender.`
347
- );
348
- return;
349
- }
350
- const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
351
- this.shadowRoot.innerHTML = "";
352
- if (this.shadowRoot.adoptedStyleSheets) {
353
- this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
354
- }
355
- if (adoptedStyleSheets.length === 0 && this.config.styles) {
356
- const styleName = this.config.styleName || this.constructor.name;
357
- StyleManager.applyStyles(this.shadowRoot, styleName, this.config.styles);
358
- }
359
- try {
360
- const content = this.render();
361
- this.shadowRoot.appendChild(content);
362
- } catch (error) {
363
- console.error(`[${this.constructor.name}] Error in rerender:`, error);
364
- this.renderError(error);
365
- }
366
- }
367
- /**
368
- * 渲染错误信息
369
- *
370
- * @param error - 错误对象
371
- */
372
- renderError(error) {
373
- this.shadowRoot.innerHTML = "";
374
- const errorElement = h(
375
- "div",
376
- {
377
- style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
378
- },
379
- [
380
- h("strong", {}, `[${this.constructor.name}] Component Error:`),
381
- h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
382
- ]
383
- );
384
- this.shadowRoot.appendChild(errorElement);
385
- }
386
- /**
387
- * 获取配置值
388
- *
389
- * @param key - 配置键
390
- * @param defaultValue - 默认值
391
- * @returns 配置值
392
- */
393
- getConfig(key, defaultValue) {
394
- return this.config[key] ?? defaultValue;
395
- }
396
- /**
397
- * 设置配置值
398
- *
399
- * @param key - 配置键
400
- * @param value - 配置值
401
- */
402
- setConfig(key, value) {
403
- this.config[key] = value;
404
- }
405
- /**
406
- * 获取属性值
407
- *
408
- * @param name - 属性名
409
- * @param defaultValue - 默认值
410
- * @returns 属性值
411
- */
412
- getAttr(name, defaultValue = "") {
413
- return this.getAttribute(name) || defaultValue;
414
- }
415
- /**
416
- * 设置属性值
417
- *
418
- * @param name - 属性名
419
- * @param value - 属性值
420
- */
421
- setAttr(name, value) {
422
- this.setAttribute(name, value);
423
- }
424
- /**
425
- * 移除属性
426
- *
427
- * @param name - 属性名
428
- */
429
- removeAttr(name) {
430
- this.removeAttribute(name);
431
- }
432
- /**
433
- * 检查是否有属性
434
- *
435
- * @param name - 属性名
436
- * @returns 是否存在
437
- */
438
- hasAttr(name) {
439
- return this.hasAttribute(name);
440
- }
441
- };
442
-
443
272
  // src/utils/logger.ts
444
273
  var WSXLogger = class {
445
274
  constructor(prefix = "[WSX]", enabled = true, level = "info") {
@@ -606,16 +435,26 @@ function reactiveWithDebug(obj, onChange, debugName) {
606
435
  });
607
436
  }
608
437
 
609
- // src/light-component.ts
610
- var logger3 = createLogger("LightComponent");
611
- var LightComponent = class extends HTMLElement {
438
+ // src/base-component.ts
439
+ var BaseComponent = class extends HTMLElement {
612
440
  constructor(config = {}) {
613
441
  super();
614
442
  this.connected = false;
615
443
  this._isDebugEnabled = false;
616
444
  this._reactiveStates = /* @__PURE__ */ new Map();
617
- this.config = config;
618
445
  this._isDebugEnabled = config.debug ?? false;
446
+ const host = this;
447
+ const originalStyles = config.styles;
448
+ this.config = {
449
+ ...config,
450
+ get styles() {
451
+ const result = originalStyles || host._autoStyles || "";
452
+ return result;
453
+ },
454
+ set styles(value) {
455
+ config.styles = value;
456
+ }
457
+ };
619
458
  }
620
459
  /**
621
460
  * 子类应该重写这个方法来定义观察的属性
@@ -624,56 +463,12 @@ var LightComponent = class extends HTMLElement {
624
463
  static get observedAttributes() {
625
464
  return [];
626
465
  }
627
- /**
628
- * Web Component生命周期:连接到DOM
629
- */
630
- connectedCallback() {
631
- this.connected = true;
632
- try {
633
- if (this.config.styles) {
634
- const styleName = this.config.styleName || this.constructor.name;
635
- this.applyScopedStyles(styleName, this.config.styles);
636
- }
637
- const content = this.render();
638
- this.appendChild(content);
639
- this.onConnected?.();
640
- } catch (error) {
641
- logger3.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
642
- this.renderError(error);
643
- }
644
- }
645
- /**
646
- * Web Component生命周期:从DOM断开
647
- */
648
- disconnectedCallback() {
649
- this.cleanupReactiveStates();
650
- this.cleanupStyles();
651
- this.onDisconnected?.();
652
- }
653
466
  /**
654
467
  * Web Component生命周期:属性变化
655
468
  */
656
469
  attributeChangedCallback(name, oldValue, newValue) {
657
470
  this.onAttributeChanged?.(name, oldValue, newValue);
658
471
  }
659
- /**
660
- * 查找组件内的元素
661
- *
662
- * @param selector - CSS选择器
663
- * @returns 元素或null
664
- */
665
- querySelector(selector) {
666
- return HTMLElement.prototype.querySelector.call(this, selector);
667
- }
668
- /**
669
- * 查找组件内的所有匹配元素
670
- *
671
- * @param selector - CSS选择器
672
- * @returns 元素列表
673
- */
674
- querySelectorAll(selector) {
675
- return HTMLElement.prototype.querySelectorAll.call(this, selector);
676
- }
677
472
  /**
678
473
  * 创建响应式对象
679
474
  *
@@ -696,10 +491,16 @@ var LightComponent = class extends HTMLElement {
696
491
  useState(key, initialValue) {
697
492
  if (!this._reactiveStates.has(key)) {
698
493
  const [getter, setter] = createState(initialValue, () => this.scheduleRerender());
699
- this._reactiveStates.set(key, { getter, setter });
494
+ this._reactiveStates.set(key, {
495
+ getter,
496
+ setter
497
+ });
498
+ }
499
+ const state2 = this._reactiveStates.get(key);
500
+ if (!state2) {
501
+ throw new Error(`State ${key} not found`);
700
502
  }
701
- const state = this._reactiveStates.get(key);
702
- return [state.getter, state.setter];
503
+ return [state2.getter, state2.setter];
703
504
  }
704
505
  /**
705
506
  * 调度重渲染
@@ -711,107 +512,24 @@ var LightComponent = class extends HTMLElement {
711
512
  }
712
513
  }
713
514
  /**
714
- * 重新渲染组件
515
+ * 获取配置值
516
+ *
517
+ * @param key - 配置键
518
+ * @param defaultValue - 默认值
519
+ * @returns 配置值
715
520
  */
716
- rerender() {
717
- if (!this.connected) {
718
- logger3.warn(
719
- `[${this.constructor.name}] Component is not connected, skipping rerender.`
720
- );
721
- return;
722
- }
723
- this.innerHTML = "";
724
- if (this.config.styles) {
725
- const styleName = this.config.styleName || this.constructor.name;
726
- const styleElement = document.createElement("style");
727
- styleElement.setAttribute("data-wsx-light-component", styleName);
728
- styleElement.textContent = this.config.styles;
729
- this.appendChild(styleElement);
730
- }
731
- try {
732
- const content = this.render();
733
- this.appendChild(content);
734
- if (this.config.styles && this.children.length > 1) {
735
- const styleElement = this.querySelector(
736
- `style[data-wsx-light-component="${this.config.styleName || this.constructor.name}"]`
737
- );
738
- if (styleElement && styleElement !== this.firstChild) {
739
- this.insertBefore(styleElement, this.firstChild);
740
- }
741
- }
742
- } catch (error) {
743
- logger3.error(`[${this.constructor.name}] Error in rerender:`, error);
744
- this.renderError(error);
745
- }
521
+ getConfig(key, defaultValue) {
522
+ return this.config[key] ?? defaultValue;
746
523
  }
747
524
  /**
748
- * 渲染错误信息
525
+ * 设置配置值
749
526
  *
750
- * @param error - 错误对象
751
- */
752
- renderError(error) {
753
- this.innerHTML = "";
754
- const errorElement = h(
755
- "div",
756
- {
757
- style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
758
- },
759
- [
760
- h("strong", {}, `[${this.constructor.name}] Component Error:`),
761
- h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
762
- ]
763
- );
764
- this.appendChild(errorElement);
765
- }
766
- /**
767
- * 为Light DOM组件应用样式
768
- * 直接将样式注入到组件自身,避免全局污染
769
- */
770
- applyScopedStyles(styleName, cssText) {
771
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
772
- if (existingStyle) {
773
- return;
774
- }
775
- const styleElement = document.createElement("style");
776
- styleElement.setAttribute("data-wsx-light-component", styleName);
777
- styleElement.textContent = cssText;
778
- this.insertBefore(styleElement, this.firstChild);
779
- }
780
- /**
781
- * 获取配置值
782
- *
783
- * @param key - 配置键
784
- * @param defaultValue - 默认值
785
- * @returns 配置值
786
- */
787
- getConfig(key, defaultValue) {
788
- return this.config[key] ?? defaultValue;
789
- }
790
- /**
791
- * 设置配置值
792
- *
793
- * @param key - 配置键
794
- * @param value - 配置值
527
+ * @param key - 配置键
528
+ * @param value - 配置值
795
529
  */
796
530
  setConfig(key, value) {
797
531
  this.config[key] = value;
798
532
  }
799
- /**
800
- * 清理响应式状态
801
- */
802
- cleanupReactiveStates() {
803
- this._reactiveStates.clear();
804
- }
805
- /**
806
- * 清理组件样式
807
- */
808
- cleanupStyles() {
809
- const styleName = this.config.styleName || this.constructor.name;
810
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
811
- if (existingStyle) {
812
- existingStyle.remove();
813
- }
814
- }
815
533
  /**
816
534
  * 获取属性值
817
535
  *
@@ -848,92 +566,102 @@ var LightComponent = class extends HTMLElement {
848
566
  hasAttr(name) {
849
567
  return this.hasAttribute(name);
850
568
  }
851
- };
852
-
853
- // src/auto-register.ts
854
- function autoRegister(options = {}) {
855
- return function(constructor) {
856
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
857
- if (!customElements.get(tagName)) {
858
- customElements.define(tagName, constructor);
859
- }
860
- return constructor;
861
- };
862
- }
863
- function registerComponent(constructor, options = {}) {
864
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
865
- if (!customElements.get(tagName)) {
866
- customElements.define(tagName, constructor);
867
- }
868
- }
869
- function deriveTagName(className, prefix) {
870
- let kebabCase = className.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
871
- if (!kebabCase.includes("-")) {
872
- kebabCase = `${kebabCase}-component`;
569
+ /**
570
+ * 清理响应式状态
571
+ */
572
+ cleanupReactiveStates() {
573
+ this._reactiveStates.clear();
873
574
  }
874
- return prefix ? `${prefix}${kebabCase}` : kebabCase;
875
- }
575
+ };
876
576
 
877
- // src/reactive-component.ts
878
- var ReactiveWebComponent = class extends WebComponent {
577
+ // src/web-component.ts
578
+ var WebComponent = class extends BaseComponent {
879
579
  constructor(config = {}) {
880
580
  super(config);
881
- this._isDebugEnabled = false;
581
+ // Initialized by BaseComponent constructor
882
582
  this._preserveFocus = true;
883
- this._reactiveStates = /* @__PURE__ */ new Map();
884
- this._isDebugEnabled = config.debug ?? false;
885
583
  this._preserveFocus = config.preserveFocus ?? true;
584
+ this.attachShadow({ mode: "open" });
886
585
  }
887
586
  /**
888
- * 创建响应式对象
889
- *
890
- * @param obj 要变为响应式的对象
891
- * @param debugName 调试名称(可选)
892
- * @returns 响应式代理对象
587
+ * Web Component生命周期:连接到DOM
893
588
  */
894
- reactive(obj, debugName) {
895
- const reactiveFn = this._isDebugEnabled ? reactiveWithDebug : reactive;
896
- const name = debugName || `${this.constructor.name}.reactive`;
897
- return this._isDebugEnabled ? reactiveFn(obj, () => this.scheduleRerender(), name) : reactiveFn(obj, () => this.scheduleRerender());
589
+ connectedCallback() {
590
+ this.connected = true;
591
+ try {
592
+ const stylesToApply = this._getAutoStyles?.() || this.config.styles;
593
+ if (stylesToApply) {
594
+ const styleName = this.config.styleName || this.constructor.name;
595
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
596
+ }
597
+ const content = this.render();
598
+ this.shadowRoot.appendChild(content);
599
+ this.onConnected?.();
600
+ } catch (error) {
601
+ console.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
602
+ this.renderError(error);
603
+ }
898
604
  }
899
605
  /**
900
- * 创建响应式状态
606
+ * Web Component生命周期:从DOM断开
607
+ */
608
+ disconnectedCallback() {
609
+ this.connected = false;
610
+ this.onDisconnected?.();
611
+ }
612
+ /**
613
+ * 查找Shadow DOM内的元素
901
614
  *
902
- * @param key 状态标识符
903
- * @param initialValue 初始值
904
- * @returns [getter, setter] 元组
615
+ * @param selector - CSS选择器
616
+ * @returns 元素或null
905
617
  */
906
- useState(key, initialValue) {
907
- if (!this._reactiveStates.has(key)) {
908
- const [getter, setter] = createState(initialValue, () => this.scheduleRerender());
909
- this._reactiveStates.set(key, { getter, setter });
910
- }
911
- const state = this._reactiveStates.get(key);
912
- return [state.getter, state.setter];
618
+ querySelector(selector) {
619
+ return this.shadowRoot.querySelector(selector);
913
620
  }
914
621
  /**
915
- * 调度重渲染
916
- * 这个方法被响应式系统调用,开发者通常不需要直接调用
622
+ * 查找Shadow DOM内的所有匹配元素
623
+ *
624
+ * @param selector - CSS选择器
625
+ * @returns 元素列表
917
626
  */
918
- scheduleRerender() {
919
- if (this.connected) {
920
- this.rerender();
921
- }
627
+ querySelectorAll(selector) {
628
+ return this.shadowRoot.querySelectorAll(selector);
922
629
  }
923
630
  /**
924
- * 重写 rerender 方法以支持焦点保持
631
+ * 重新渲染组件
925
632
  */
926
633
  rerender() {
927
634
  if (!this.connected) {
635
+ console.warn(
636
+ `[${this.constructor.name}] Component is not connected, skipping rerender.`
637
+ );
928
638
  return;
929
639
  }
930
640
  let focusData = null;
931
- if (this._preserveFocus) {
641
+ if (this._preserveFocus && this.shadowRoot) {
932
642
  const activeElement = this.shadowRoot.activeElement;
933
643
  focusData = this.saveFocusState(activeElement);
934
644
  }
935
- super.rerender();
936
- if (this._preserveFocus && focusData) {
645
+ const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
646
+ this.shadowRoot.innerHTML = "";
647
+ if (this.shadowRoot.adoptedStyleSheets) {
648
+ this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
649
+ }
650
+ if (adoptedStyleSheets.length === 0) {
651
+ const stylesToApply = this._autoStyles || this.config.styles;
652
+ if (stylesToApply) {
653
+ const styleName = this.config.styleName || this.constructor.name;
654
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
655
+ }
656
+ }
657
+ try {
658
+ const content = this.render();
659
+ this.shadowRoot.appendChild(content);
660
+ } catch (error) {
661
+ console.error(`[${this.constructor.name}] Error in rerender:`, error);
662
+ this.renderError(error);
663
+ }
664
+ if (this._preserveFocus && focusData && this.shadowRoot) {
937
665
  this.restoreFocusState(focusData);
938
666
  }
939
667
  }
@@ -959,8 +687,8 @@ var ReactiveWebComponent = class extends WebComponent {
959
687
  if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLSelectElement) {
960
688
  focusData.value = activeElement.value;
961
689
  if ("selectionStart" in activeElement) {
962
- focusData.selectionStart = activeElement.selectionStart;
963
- focusData.selectionEnd = activeElement.selectionEnd;
690
+ focusData.selectionStart = activeElement.selectionStart ?? void 0;
691
+ focusData.selectionEnd = activeElement.selectionEnd ?? void 0;
964
692
  }
965
693
  }
966
694
  return focusData;
@@ -986,10 +714,10 @@ var ReactiveWebComponent = class extends WebComponent {
986
714
  if (targetElement instanceof HTMLInputElement) {
987
715
  targetElement.setSelectionRange(
988
716
  focusData.selectionStart,
989
- focusData.selectionEnd
717
+ focusData.selectionEnd ?? focusData.selectionStart
990
718
  );
991
719
  } else if (targetElement instanceof HTMLSelectElement) {
992
- targetElement.value = focusData.value;
720
+ targetElement.value = focusData.value ?? "";
993
721
  } else if (targetElement.hasAttribute("contenteditable")) {
994
722
  this.setCursorPosition(targetElement, focusData.selectionStart);
995
723
  }
@@ -1019,83 +747,228 @@ var ReactiveWebComponent = class extends WebComponent {
1019
747
  }
1020
748
  }
1021
749
  /**
1022
- * 获取所有响应式状态的快照(用于调试)
750
+ * 渲染错误信息
751
+ *
752
+ * @param error - 错误对象
1023
753
  */
1024
- getStateSnapshot() {
1025
- const snapshot = {};
1026
- this._reactiveStates.forEach((state, key) => {
1027
- snapshot[key] = state.getter();
1028
- });
1029
- return snapshot;
754
+ renderError(error) {
755
+ this.shadowRoot.innerHTML = "";
756
+ const errorElement = h(
757
+ "div",
758
+ {
759
+ style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
760
+ },
761
+ [
762
+ h("strong", {}, `[${this.constructor.name}] Component Error:`),
763
+ h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
764
+ ]
765
+ );
766
+ this.shadowRoot.appendChild(errorElement);
767
+ }
768
+ };
769
+
770
+ // src/light-component.ts
771
+ var logger3 = createLogger("LightComponent");
772
+ var LightComponent = class extends BaseComponent {
773
+ // Initialized by BaseComponent constructor
774
+ constructor(config = {}) {
775
+ super(config);
1030
776
  }
1031
777
  /**
1032
- * 清理响应式状态(组件销毁时)
778
+ * Web Component生命周期:连接到DOM
1033
779
  */
1034
- cleanupReactiveStates() {
1035
- this._reactiveStates.clear();
780
+ connectedCallback() {
781
+ this.connected = true;
782
+ try {
783
+ const stylesToApply = this._autoStyles || this.config.styles;
784
+ if (stylesToApply) {
785
+ const styleName = this.config.styleName || this.constructor.name;
786
+ this.applyScopedStyles(styleName, stylesToApply);
787
+ }
788
+ const content = this.render();
789
+ this.appendChild(content);
790
+ this.onConnected?.();
791
+ } catch (error) {
792
+ logger3.error(`[${this.constructor.name}] Error in connectedCallback:`, error);
793
+ this.renderError(error);
794
+ }
1036
795
  }
1037
796
  /**
1038
- * 重写 disconnectedCallback 以清理状态
797
+ * Web Component生命周期:从DOM断开
1039
798
  */
1040
799
  disconnectedCallback() {
1041
- super.disconnectedCallback();
1042
800
  this.cleanupReactiveStates();
801
+ this.cleanupStyles();
802
+ this.onDisconnected?.();
1043
803
  }
1044
804
  /**
1045
- * 启用调试模式
805
+ * 查找组件内的元素
806
+ *
807
+ * @param selector - CSS选择器
808
+ * @returns 元素或null
1046
809
  */
1047
- enableDebug() {
1048
- this._isDebugEnabled = true;
810
+ querySelector(selector) {
811
+ return HTMLElement.prototype.querySelector.call(this, selector);
1049
812
  }
1050
813
  /**
1051
- * 禁用调试模式
814
+ * 查找组件内的所有匹配元素
815
+ *
816
+ * @param selector - CSS选择器
817
+ * @returns 元素列表
1052
818
  */
1053
- disableDebug() {
1054
- this._isDebugEnabled = false;
819
+ querySelectorAll(selector) {
820
+ return HTMLElement.prototype.querySelectorAll.call(this, selector);
1055
821
  }
1056
- };
1057
- function makeReactive(_debugMode = false) {
1058
- return function(constructor) {
1059
- return class ReactiveComponent extends constructor {
1060
- constructor(...args) {
1061
- super(...args);
1062
- if (!(this instanceof ReactiveWebComponent)) {
1063
- this.reactive = function(obj) {
1064
- return reactive(obj, () => this.rerender());
1065
- };
822
+ /**
823
+ * 重新渲染组件
824
+ */
825
+ rerender() {
826
+ if (!this.connected) {
827
+ logger3.warn(
828
+ `[${this.constructor.name}] Component is not connected, skipping rerender.`
829
+ );
830
+ return;
831
+ }
832
+ this.innerHTML = "";
833
+ if (this.config.styles) {
834
+ const styleName = this.config.styleName || this.constructor.name;
835
+ const styleElement = document.createElement("style");
836
+ styleElement.setAttribute("data-wsx-light-component", styleName);
837
+ styleElement.textContent = this.config.styles;
838
+ this.appendChild(styleElement);
839
+ }
840
+ try {
841
+ const content = this.render();
842
+ this.appendChild(content);
843
+ if (this.config.styles && this.children.length > 1) {
844
+ const styleElement = this.querySelector(
845
+ `style[data-wsx-light-component="${this.config.styleName || this.constructor.name}"]`
846
+ );
847
+ if (styleElement && styleElement !== this.firstChild) {
848
+ this.insertBefore(styleElement, this.firstChild);
1066
849
  }
1067
850
  }
1068
- render() {
1069
- throw new Error("render() method must be implemented by subclass");
1070
- }
1071
- };
851
+ } catch (error) {
852
+ logger3.error(`[${this.constructor.name}] Error in rerender:`, error);
853
+ this.renderError(error);
854
+ }
855
+ }
856
+ /**
857
+ * 渲染错误信息
858
+ *
859
+ * @param error - 错误对象
860
+ */
861
+ renderError(error) {
862
+ this.innerHTML = "";
863
+ const errorElement = h(
864
+ "div",
865
+ {
866
+ style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
867
+ },
868
+ [
869
+ h("strong", {}, `[${this.constructor.name}] Component Error:`),
870
+ h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
871
+ ]
872
+ );
873
+ this.appendChild(errorElement);
874
+ }
875
+ /**
876
+ * 为Light DOM组件应用样式
877
+ * 直接将样式注入到组件自身,避免全局污染
878
+ */
879
+ applyScopedStyles(styleName, cssText) {
880
+ const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
881
+ if (existingStyle) {
882
+ return;
883
+ }
884
+ const styleElement = document.createElement("style");
885
+ styleElement.setAttribute("data-wsx-light-component", styleName);
886
+ styleElement.textContent = cssText;
887
+ this.insertBefore(styleElement, this.firstChild);
888
+ }
889
+ /**
890
+ * 清理组件样式
891
+ */
892
+ cleanupStyles() {
893
+ const styleName = this.config.styleName || this.constructor.name;
894
+ const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
895
+ if (existingStyle) {
896
+ existingStyle.remove();
897
+ }
898
+ }
899
+ };
900
+
901
+ // src/auto-register.ts
902
+ function autoRegister(options = {}) {
903
+ return function(constructor) {
904
+ const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
905
+ if (!customElements.get(tagName)) {
906
+ customElements.define(tagName, constructor);
907
+ }
908
+ return constructor;
1072
909
  };
1073
910
  }
1074
- function createReactiveComponent(ComponentClass, config) {
1075
- if (ComponentClass.prototype instanceof ReactiveWebComponent) {
1076
- return new ComponentClass(config);
911
+ function registerComponent(constructor, options = {}) {
912
+ const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
913
+ if (!customElements.get(tagName)) {
914
+ customElements.define(tagName, constructor);
915
+ }
916
+ }
917
+ function deriveTagName(className, prefix) {
918
+ let kebabCase = className.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
919
+ if (!kebabCase.includes("-")) {
920
+ kebabCase = `${kebabCase}-component`;
921
+ }
922
+ return prefix ? `${prefix}${kebabCase}` : kebabCase;
923
+ }
924
+
925
+ // src/reactive-decorator.ts
926
+ function state(target, propertyKey) {
927
+ let normalizedPropertyKey;
928
+ if (typeof propertyKey === "string" || typeof propertyKey === "symbol") {
929
+ normalizedPropertyKey = propertyKey;
930
+ } else {
931
+ const propertyKeyStr = String(propertyKey);
932
+ if (propertyKeyStr === "[object Object]") {
933
+ throw new Error(
934
+ `@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`
935
+ );
936
+ }
937
+ normalizedPropertyKey = propertyKeyStr;
938
+ }
939
+ if (target == null) {
940
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
941
+ throw new Error(
942
+ `@state decorator: Cannot access property "${propertyKeyStr}". Target is ${target === null ? "null" : "undefined"}. Please ensure Babel plugin is configured in vite.config.ts`
943
+ );
944
+ }
945
+ if (typeof target !== "object") {
946
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
947
+ throw new Error(
948
+ `@state decorator: Cannot be used on "${propertyKeyStr}". @state is for properties only, not methods.`
949
+ );
950
+ }
951
+ const descriptor = Object.getOwnPropertyDescriptor(target, normalizedPropertyKey);
952
+ if (descriptor?.get) {
953
+ const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
954
+ throw new Error(
955
+ `@state decorator cannot be used with getter properties. Property: "${propertyKeyStr}"`
956
+ );
1077
957
  }
1078
- const ReactiveComponent = makeReactive(config?.debug)(ComponentClass);
1079
- return new ReactiveComponent(config);
1080
958
  }
1081
959
  // Annotate the CommonJS export names for ESM import in node:
1082
960
  0 && (module.exports = {
1083
961
  Fragment,
1084
962
  LightComponent,
1085
- ReactiveDebug,
1086
- ReactiveWebComponent,
1087
963
  StyleManager,
1088
964
  WSXLogger,
1089
965
  WebComponent,
1090
966
  autoRegister,
1091
967
  createLogger,
1092
- createReactiveComponent,
1093
- createState,
1094
968
  h,
1095
969
  jsx,
1096
970
  jsxs,
1097
971
  logger,
1098
- makeReactive,
1099
- reactive,
1100
- registerComponent
972
+ registerComponent,
973
+ state
1101
974
  });