@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.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,91 +512,23 @@ 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
- try {
725
- const content = this.render();
726
- this.appendChild(content);
727
- } catch (error) {
728
- logger3.error(`[${this.constructor.name}] Error in rerender:`, error);
729
- this.renderError(error);
730
- }
521
+ getConfig(key, defaultValue) {
522
+ return this.config[key] ?? defaultValue;
731
523
  }
732
524
  /**
733
- * 渲染错误信息
525
+ * 设置配置值
734
526
  *
735
- * @param error - 错误对象
527
+ * @param key - 配置键
528
+ * @param value - 配置值
736
529
  */
737
- renderError(error) {
738
- this.innerHTML = "";
739
- const errorElement = h(
740
- "div",
741
- {
742
- style: "color: red; padding: 10px; border: 1px solid red; background: #ffe6e6; font-family: monospace;"
743
- },
744
- [
745
- h("strong", {}, `[${this.constructor.name}] Component Error:`),
746
- h("pre", { style: "margin: 10px 0; white-space: pre-wrap;" }, String(error))
747
- ]
748
- );
749
- this.appendChild(errorElement);
750
- }
751
- /**
752
- * 为Light DOM组件应用样式
753
- * 直接将样式注入到组件自身,避免全局污染
754
- */
755
- applyScopedStyles(styleName, cssText) {
756
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
757
- if (existingStyle) {
758
- return;
759
- }
760
- const styleElement = document.createElement("style");
761
- styleElement.setAttribute("data-wsx-light-component", styleName);
762
- styleElement.textContent = cssText;
763
- this.insertBefore(styleElement, this.firstChild);
764
- }
765
- /**
766
- * 获取配置值
767
- *
768
- * @param key - 配置键
769
- * @param defaultValue - 默认值
770
- * @returns 配置值
771
- */
772
- getConfig(key, defaultValue) {
773
- return this.config[key] ?? defaultValue;
774
- }
775
- /**
776
- * 设置配置值
777
- *
778
- * @param key - 配置键
779
- * @param value - 配置值
780
- */
781
- setConfig(key, value) {
782
- this.config[key] = value;
783
- }
784
- /**
785
- * 清理响应式状态
786
- */
787
- cleanupReactiveStates() {
788
- this._reactiveStates.clear();
789
- }
790
- /**
791
- * 清理组件样式
792
- */
793
- cleanupStyles() {
794
- const styleName = this.config.styleName || this.constructor.name;
795
- const existingStyle = this.querySelector(`style[data-wsx-light-component="${styleName}"]`);
796
- if (existingStyle) {
797
- existingStyle.remove();
798
- }
530
+ setConfig(key, value) {
531
+ this.config[key] = value;
799
532
  }
800
533
  /**
801
534
  * 获取属性值
@@ -833,92 +566,102 @@ var LightComponent = class extends HTMLElement {
833
566
  hasAttr(name) {
834
567
  return this.hasAttribute(name);
835
568
  }
836
- };
837
-
838
- // src/auto-register.ts
839
- function autoRegister(options = {}) {
840
- return function(constructor) {
841
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
842
- if (!customElements.get(tagName)) {
843
- customElements.define(tagName, constructor);
844
- }
845
- return constructor;
846
- };
847
- }
848
- function registerComponent(constructor, options = {}) {
849
- const tagName = options.tagName || deriveTagName(constructor.name, options.prefix);
850
- if (!customElements.get(tagName)) {
851
- customElements.define(tagName, constructor);
852
- }
853
- }
854
- function deriveTagName(className, prefix) {
855
- let kebabCase = className.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
856
- if (!kebabCase.includes("-")) {
857
- kebabCase = `${kebabCase}-component`;
569
+ /**
570
+ * 清理响应式状态
571
+ */
572
+ cleanupReactiveStates() {
573
+ this._reactiveStates.clear();
858
574
  }
859
- return prefix ? `${prefix}${kebabCase}` : kebabCase;
860
- }
575
+ };
861
576
 
862
- // src/reactive-component.ts
863
- var ReactiveWebComponent = class extends WebComponent {
577
+ // src/web-component.ts
578
+ var WebComponent = class extends BaseComponent {
864
579
  constructor(config = {}) {
865
580
  super(config);
866
- this._isDebugEnabled = false;
581
+ // Initialized by BaseComponent constructor
867
582
  this._preserveFocus = true;
868
- this._reactiveStates = /* @__PURE__ */ new Map();
869
- this._isDebugEnabled = config.debug ?? false;
870
583
  this._preserveFocus = config.preserveFocus ?? true;
584
+ this.attachShadow({ mode: "open" });
871
585
  }
872
586
  /**
873
- * 创建响应式对象
874
- *
875
- * @param obj 要变为响应式的对象
876
- * @param debugName 调试名称(可选)
877
- * @returns 响应式代理对象
587
+ * Web Component生命周期:连接到DOM
878
588
  */
879
- reactive(obj, debugName) {
880
- const reactiveFn = this._isDebugEnabled ? reactiveWithDebug : reactive;
881
- const name = debugName || `${this.constructor.name}.reactive`;
882
- 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
+ }
883
604
  }
884
605
  /**
885
- * 创建响应式状态
606
+ * Web Component生命周期:从DOM断开
607
+ */
608
+ disconnectedCallback() {
609
+ this.connected = false;
610
+ this.onDisconnected?.();
611
+ }
612
+ /**
613
+ * 查找Shadow DOM内的元素
886
614
  *
887
- * @param key 状态标识符
888
- * @param initialValue 初始值
889
- * @returns [getter, setter] 元组
615
+ * @param selector - CSS选择器
616
+ * @returns 元素或null
890
617
  */
891
- useState(key, initialValue) {
892
- if (!this._reactiveStates.has(key)) {
893
- const [getter, setter] = createState(initialValue, () => this.scheduleRerender());
894
- this._reactiveStates.set(key, { getter, setter });
895
- }
896
- const state = this._reactiveStates.get(key);
897
- return [state.getter, state.setter];
618
+ querySelector(selector) {
619
+ return this.shadowRoot.querySelector(selector);
898
620
  }
899
621
  /**
900
- * 调度重渲染
901
- * 这个方法被响应式系统调用,开发者通常不需要直接调用
622
+ * 查找Shadow DOM内的所有匹配元素
623
+ *
624
+ * @param selector - CSS选择器
625
+ * @returns 元素列表
902
626
  */
903
- scheduleRerender() {
904
- if (this.connected) {
905
- this.rerender();
906
- }
627
+ querySelectorAll(selector) {
628
+ return this.shadowRoot.querySelectorAll(selector);
907
629
  }
908
630
  /**
909
- * 重写 rerender 方法以支持焦点保持
631
+ * 重新渲染组件
910
632
  */
911
633
  rerender() {
912
634
  if (!this.connected) {
635
+ console.warn(
636
+ `[${this.constructor.name}] Component is not connected, skipping rerender.`
637
+ );
913
638
  return;
914
639
  }
915
640
  let focusData = null;
916
- if (this._preserveFocus) {
641
+ if (this._preserveFocus && this.shadowRoot) {
917
642
  const activeElement = this.shadowRoot.activeElement;
918
643
  focusData = this.saveFocusState(activeElement);
919
644
  }
920
- super.rerender();
921
- 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) {
922
665
  this.restoreFocusState(focusData);
923
666
  }
924
667
  }
@@ -944,8 +687,8 @@ var ReactiveWebComponent = class extends WebComponent {
944
687
  if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLSelectElement) {
945
688
  focusData.value = activeElement.value;
946
689
  if ("selectionStart" in activeElement) {
947
- focusData.selectionStart = activeElement.selectionStart;
948
- focusData.selectionEnd = activeElement.selectionEnd;
690
+ focusData.selectionStart = activeElement.selectionStart ?? void 0;
691
+ focusData.selectionEnd = activeElement.selectionEnd ?? void 0;
949
692
  }
950
693
  }
951
694
  return focusData;
@@ -971,10 +714,10 @@ var ReactiveWebComponent = class extends WebComponent {
971
714
  if (targetElement instanceof HTMLInputElement) {
972
715
  targetElement.setSelectionRange(
973
716
  focusData.selectionStart,
974
- focusData.selectionEnd
717
+ focusData.selectionEnd ?? focusData.selectionStart
975
718
  );
976
719
  } else if (targetElement instanceof HTMLSelectElement) {
977
- targetElement.value = focusData.value;
720
+ targetElement.value = focusData.value ?? "";
978
721
  } else if (targetElement.hasAttribute("contenteditable")) {
979
722
  this.setCursorPosition(targetElement, focusData.selectionStart);
980
723
  }
@@ -1004,83 +747,228 @@ var ReactiveWebComponent = class extends WebComponent {
1004
747
  }
1005
748
  }
1006
749
  /**
1007
- * 获取所有响应式状态的快照(用于调试)
750
+ * 渲染错误信息
751
+ *
752
+ * @param error - 错误对象
1008
753
  */
1009
- getStateSnapshot() {
1010
- const snapshot = {};
1011
- this._reactiveStates.forEach((state, key) => {
1012
- snapshot[key] = state.getter();
1013
- });
1014
- 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);
1015
776
  }
1016
777
  /**
1017
- * 清理响应式状态(组件销毁时)
778
+ * Web Component生命周期:连接到DOM
1018
779
  */
1019
- cleanupReactiveStates() {
1020
- 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
+ }
1021
795
  }
1022
796
  /**
1023
- * 重写 disconnectedCallback 以清理状态
797
+ * Web Component生命周期:从DOM断开
1024
798
  */
1025
799
  disconnectedCallback() {
1026
- super.disconnectedCallback();
1027
800
  this.cleanupReactiveStates();
801
+ this.cleanupStyles();
802
+ this.onDisconnected?.();
1028
803
  }
1029
804
  /**
1030
- * 启用调试模式
805
+ * 查找组件内的元素
806
+ *
807
+ * @param selector - CSS选择器
808
+ * @returns 元素或null
1031
809
  */
1032
- enableDebug() {
1033
- this._isDebugEnabled = true;
810
+ querySelector(selector) {
811
+ return HTMLElement.prototype.querySelector.call(this, selector);
1034
812
  }
1035
813
  /**
1036
- * 禁用调试模式
814
+ * 查找组件内的所有匹配元素
815
+ *
816
+ * @param selector - CSS选择器
817
+ * @returns 元素列表
1037
818
  */
1038
- disableDebug() {
1039
- this._isDebugEnabled = false;
819
+ querySelectorAll(selector) {
820
+ return HTMLElement.prototype.querySelectorAll.call(this, selector);
1040
821
  }
1041
- };
1042
- function makeReactive(_debugMode = false) {
1043
- return function(constructor) {
1044
- return class ReactiveComponent extends constructor {
1045
- constructor(...args) {
1046
- super(...args);
1047
- if (!(this instanceof ReactiveWebComponent)) {
1048
- this.reactive = function(obj) {
1049
- return reactive(obj, () => this.rerender());
1050
- };
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);
1051
849
  }
1052
850
  }
1053
- render() {
1054
- throw new Error("render() method must be implemented by subclass");
1055
- }
1056
- };
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;
1057
909
  };
1058
910
  }
1059
- function createReactiveComponent(ComponentClass, config) {
1060
- if (ComponentClass.prototype instanceof ReactiveWebComponent) {
1061
- 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
+ );
1062
957
  }
1063
- const ReactiveComponent = makeReactive(config?.debug)(ComponentClass);
1064
- return new ReactiveComponent(config);
1065
958
  }
1066
959
  // Annotate the CommonJS export names for ESM import in node:
1067
960
  0 && (module.exports = {
1068
961
  Fragment,
1069
962
  LightComponent,
1070
- ReactiveDebug,
1071
- ReactiveWebComponent,
1072
963
  StyleManager,
1073
964
  WSXLogger,
1074
965
  WebComponent,
1075
966
  autoRegister,
1076
967
  createLogger,
1077
- createReactiveComponent,
1078
- createState,
1079
968
  h,
1080
969
  jsx,
1081
970
  jsxs,
1082
971
  logger,
1083
- makeReactive,
1084
- reactive,
1085
- registerComponent
972
+ registerComponent,
973
+ state
1086
974
  });