@wsxjs/wsx-core 0.0.15 → 0.0.16

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
@@ -898,6 +898,12 @@ var WebComponent = class extends BaseComponent {
898
898
  }
899
899
  /**
900
900
  * Web Component生命周期:连接到DOM
901
+ *
902
+ * 渲染策略:
903
+ * 1. 检查 Shadow DOM 中是否已有实际内容(排除样式和 slot)
904
+ * 2. 如果有内容,先清空再渲染(避免重复元素)
905
+ * 3. 如果没有内容,直接渲染
906
+ * 4. Slot 元素会被重新添加,浏览器会自动将 Light DOM 中的内容分配到 slot
901
907
  */
902
908
  connectedCallback() {
903
909
  this.connected = true;
@@ -907,8 +913,23 @@ var WebComponent = class extends BaseComponent {
907
913
  const styleName = this.config.styleName || this.constructor.name;
908
914
  StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
909
915
  }
910
- const content = this.render();
911
- this.shadowRoot.appendChild(content);
916
+ const allChildren = Array.from(this.shadowRoot.children);
917
+ const styleElements = allChildren.filter((child) => child instanceof HTMLStyleElement);
918
+ const slotElements = allChildren.filter((child) => child instanceof HTMLSlotElement);
919
+ const hasErrorElement = allChildren.some(
920
+ (child) => child instanceof HTMLElement && child.style.color === "red" && child.textContent?.includes("Component Error")
921
+ );
922
+ const hasActualContent = allChildren.length > styleElements.length + slotElements.length;
923
+ if (hasActualContent && !hasErrorElement) {
924
+ } else {
925
+ this.shadowRoot.innerHTML = "";
926
+ if (stylesToApply) {
927
+ const styleName = this.config.styleName || this.constructor.name;
928
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
929
+ }
930
+ const content = this.render();
931
+ this.shadowRoot.appendChild(content);
932
+ }
912
933
  this.initializeEventListeners();
913
934
  this.onConnected?.();
914
935
  } catch (error) {
@@ -1021,17 +1042,45 @@ var LightComponent = class extends BaseComponent {
1021
1042
  }
1022
1043
  /**
1023
1044
  * Web Component生命周期:连接到DOM
1045
+ *
1046
+ * 渲染策略:
1047
+ * 1. 检查组件中是否已有实际内容(排除样式元素)
1048
+ * 2. 如果有内容且完整,跳过渲染(避免重复元素和性能优化)
1049
+ * 3. 如果没有内容或不完整,清空后重新渲染
1050
+ * 4. 样式元素需要保留
1024
1051
  */
1025
1052
  connectedCallback() {
1026
1053
  this.connected = true;
1027
1054
  try {
1028
1055
  const stylesToApply = this._autoStyles || this.config.styles;
1056
+ const styleName = this.config.styleName || this.constructor.name;
1029
1057
  if (stylesToApply) {
1030
- const styleName = this.config.styleName || this.constructor.name;
1031
1058
  this.applyScopedStyles(styleName, stylesToApply);
1032
1059
  }
1033
- const content = this.render();
1034
- this.appendChild(content);
1060
+ const styleElement = this.querySelector(
1061
+ `style[data-wsx-light-component="${styleName}"]`
1062
+ );
1063
+ const hasErrorElement = Array.from(this.children).some(
1064
+ (child) => child instanceof HTMLElement && child !== styleElement && child.style.color === "red" && child.textContent?.includes("Component Error")
1065
+ );
1066
+ const hasActualContent = Array.from(this.children).some(
1067
+ (child) => child !== styleElement
1068
+ );
1069
+ if (hasActualContent && !hasErrorElement) {
1070
+ if (styleElement && styleElement !== this.firstChild) {
1071
+ this.insertBefore(styleElement, this.firstChild);
1072
+ }
1073
+ } else {
1074
+ const childrenToRemove = Array.from(this.children).filter(
1075
+ (child) => child !== styleElement
1076
+ );
1077
+ childrenToRemove.forEach((child) => child.remove());
1078
+ const content = this.render();
1079
+ this.appendChild(content);
1080
+ if (styleElement && styleElement !== this.firstChild) {
1081
+ this.insertBefore(styleElement, this.firstChild);
1082
+ }
1083
+ }
1035
1084
  this.initializeEventListeners();
1036
1085
  this.onConnected?.();
1037
1086
  } catch (error) {
@@ -1206,230 +1255,76 @@ function deriveTagName(className, prefix) {
1206
1255
  }
1207
1256
 
1208
1257
  // src/reactive-decorator.ts
1258
+ function createBabelPluginError(propertyName) {
1259
+ return `@state decorator on property "${propertyName}" MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
1260
+
1261
+ The @state decorator cannot work without the Babel plugin.
1262
+
1263
+ To fix this, please:
1264
+ 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1265
+ 2. Configure it in vite.config.ts:
1266
+ import { wsx } from '@wsxjs/wsx-vite-plugin';
1267
+ export default defineConfig({ plugins: [wsx()] });
1268
+ 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1269
+ npm install --save-dev @wsxjs/wsx-tsconfig
1270
+ Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1271
+ Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1272
+
1273
+ See: https://github.com/wsxjs/wsxjs#setup for more details.`;
1274
+ }
1209
1275
  function state(targetOrContext, propertyKey) {
1210
- let propertyName;
1276
+ let propertyName = "unknown";
1211
1277
  const propertyKeyIsObject = typeof propertyKey === "object" && propertyKey !== null;
1212
1278
  const targetIsObject = typeof targetOrContext === "object" && targetOrContext !== null;
1213
1279
  const hasStage3Indicators = targetIsObject && ("kind" in targetOrContext || "addInitializer" in targetOrContext || "access" in targetOrContext);
1214
1280
  const hasName = hasStage3Indicators && "name" in targetOrContext;
1215
1281
  const isStage3Decorator = propertyKeyIsObject || hasName || hasStage3Indicators && (propertyKey === void 0 || propertyKey === null) || targetIsObject && "addInitializer" in targetOrContext;
1216
1282
  if (isStage3Decorator) {
1217
- const context = targetOrContext;
1218
- if (context.name) {
1219
- propertyName = typeof context.name === "string" ? context.name : context.name.toString();
1283
+ if (hasStage3Indicators && targetOrContext && typeof targetOrContext === "object") {
1284
+ const context = targetOrContext;
1285
+ if (context.name) {
1286
+ propertyName = typeof context.name === "string" ? context.name : context.name.toString();
1287
+ }
1220
1288
  } else if (propertyKeyIsObject) {
1221
- if ("name" in propertyKey) {
1222
- const keyObj = propertyKey;
1223
- propertyName = keyObj.name ? typeof keyObj.name === "string" ? keyObj.name : keyObj.name.toString() : "unknown";
1224
- } else if ("key" in propertyKey) {
1225
- const keyObj = propertyKey;
1226
- propertyName = keyObj.key ? typeof keyObj.key === "string" ? keyObj.key : keyObj.key.toString() : "unknown";
1289
+ const keyObj = propertyKey;
1290
+ const targetObj = targetOrContext;
1291
+ const nameValue = targetObj?.name || keyObj.name || keyObj.key;
1292
+ if (nameValue) {
1293
+ propertyName = typeof nameValue === "string" ? nameValue : nameValue.toString();
1227
1294
  } else {
1228
1295
  const keyStr = String(propertyKey);
1229
1296
  if (keyStr !== "[object Object]") {
1230
1297
  propertyName = keyStr;
1231
- } else {
1232
- propertyName = "unknown";
1233
1298
  }
1234
1299
  }
1235
- } else {
1236
- propertyName = "unknown";
1237
1300
  }
1238
- } else {
1239
- if (typeof propertyKey === "string" || typeof propertyKey === "symbol") {
1240
- propertyName = typeof propertyKey === "string" ? propertyKey : propertyKey.toString();
1241
- } else if (propertyKey != null) {
1242
- const propertyKeyStr = String(propertyKey);
1243
- if (propertyKeyStr === "[object Object]") {
1244
- propertyName = "unknown";
1245
- } else {
1246
- propertyName = propertyKeyStr;
1301
+ if (targetIsObject && "kind" in targetOrContext) {
1302
+ const context = targetOrContext;
1303
+ if (context.kind && context.kind !== "field") {
1304
+ const nameStr = typeof context.name === "string" ? context.name : context.name.toString();
1305
+ throw new Error(
1306
+ `@state decorator can only be used on class fields, not ${context.kind}. Property: "${nameStr}"`
1307
+ );
1247
1308
  }
1248
- } else {
1249
- propertyName = "unknown";
1250
1309
  }
1310
+ throw new Error(createBabelPluginError(propertyName));
1251
1311
  }
1252
- console.warn(
1253
- `[WSX] @state decorator is using runtime fallback. Property "${propertyName}" will work but with reduced performance.
1254
-
1255
- To fix this and enable compile-time processing, please:
1256
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1257
- 2. Configure it in vite.config.ts:
1258
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1259
- export default defineConfig({ plugins: [wsx()] });
1260
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1261
- npm install --save-dev @wsxjs/wsx-tsconfig
1262
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1263
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1264
-
1265
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1266
- );
1267
- if (isStage3Decorator) {
1268
- let context;
1269
- if (hasStage3Indicators) {
1270
- context = targetOrContext;
1271
- } else if (propertyKeyIsObject) {
1272
- const keyObj = propertyKey;
1273
- const targetObj = targetOrContext;
1274
- const nameValue = targetObj.name || keyObj.name || keyObj.key || "unknown";
1275
- context = {
1276
- kind: targetObj.kind || "field",
1277
- name: nameValue,
1278
- addInitializer: targetObj.addInitializer || keyObj.addInitializer,
1279
- access: targetObj.access || keyObj.access
1280
- };
1281
- } else {
1282
- context = targetOrContext;
1283
- }
1284
- if (context.kind && context.kind !== "field") {
1285
- const nameStr = typeof context.name === "string" ? context.name : context.name.toString();
1286
- throw new Error(
1287
- `@state decorator can only be used on class fields, not ${context.kind}. Property: "${nameStr}"`
1288
- );
1289
- }
1290
- if (!context.addInitializer) {
1291
- console.warn(
1292
- `[WSX] @state decorator: addInitializer not available for property "${propertyName}". The property will not be reactive. This usually means the decorator system is not properly configured.`
1293
- );
1294
- } else {
1295
- context.addInitializer(function() {
1296
- if (!this || typeof this.reactive !== "function" || typeof this.useState !== "function") {
1297
- throw new Error(
1298
- `@state decorator runtime fallback: Component does not extend WebComponent or LightComponent. Property "${propertyName}" cannot be made reactive.
1299
-
1300
- The @state decorator can only be used in classes that extend WebComponent or LightComponent. Please ensure your component class extends one of these base classes.`
1301
- );
1302
- }
1303
- let initialValue = void 0;
1304
- if (context.access?.get) {
1305
- try {
1306
- initialValue = context.access.get();
1307
- } catch {
1308
- initialValue = this[propertyName];
1309
- }
1310
- } else {
1311
- initialValue = this[propertyName];
1312
- }
1313
- const isObject = initialValue !== null && initialValue !== void 0 && (typeof initialValue === "object" || Array.isArray(initialValue));
1314
- if (isObject) {
1315
- let reactiveValue = this.reactive(initialValue);
1316
- Object.defineProperty(this, propertyName, {
1317
- get: () => reactiveValue,
1318
- set: (newValue) => {
1319
- if (newValue !== null && newValue !== void 0 && (typeof newValue === "object" || Array.isArray(newValue))) {
1320
- reactiveValue = this.reactive(newValue);
1321
- this.scheduleRerender();
1322
- } else {
1323
- reactiveValue = newValue;
1324
- this.scheduleRerender();
1325
- }
1326
- },
1327
- enumerable: true,
1328
- configurable: true
1329
- });
1330
- } else {
1331
- const [getState, setState] = this.useState(propertyName, initialValue);
1332
- Object.defineProperty(this, propertyName, {
1333
- get: getState,
1334
- set: setState,
1335
- enumerable: true,
1336
- configurable: true
1337
- });
1338
- }
1339
- });
1340
- }
1341
- return context;
1342
- }
1343
- const target = targetOrContext;
1344
- let normalizedPropertyKey;
1345
1312
  if (typeof propertyKey === "string" || typeof propertyKey === "symbol") {
1346
- normalizedPropertyKey = propertyKey;
1313
+ propertyName = typeof propertyKey === "string" ? propertyKey : propertyKey.toString();
1347
1314
  } else if (propertyKey != null) {
1348
1315
  const propertyKeyStr = String(propertyKey);
1349
1316
  if (propertyKeyStr === "[object Object]") {
1350
1317
  if (typeof targetOrContext === "object" && targetOrContext !== null && ("kind" in targetOrContext || "addInitializer" in targetOrContext)) {
1351
- console.warn(
1352
- `[WSX] @state decorator: Detected potential Stage 3 decorator format but with unexpected propertyKey. This might be a compatibility issue. The decorator will attempt to work in runtime fallback mode.`
1353
- );
1354
1318
  const context = targetOrContext;
1355
1319
  if (context.name) {
1356
- const name = typeof context.name === "string" ? context.name : context.name.toString();
1357
- throw new Error(
1358
- `@state decorator: Detected Stage 3 decorator format but with invalid propertyKey. Property name: "${name}".
1359
-
1360
- This usually means the decorator is being called in an unexpected format. Please ensure you have configured the Babel plugin correctly.
1361
-
1362
- To fix this, please:
1363
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1364
- 2. Configure it in vite.config.ts:
1365
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1366
- export default defineConfig({ plugins: [wsx()] });
1367
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1368
- npm install --save-dev @wsxjs/wsx-tsconfig
1369
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1370
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1371
-
1372
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1373
- );
1320
+ propertyName = typeof context.name === "string" ? context.name : context.name.toString();
1374
1321
  }
1375
1322
  }
1376
- throw new Error(
1377
- `@state decorator: Invalid propertyKey detected (received object instead of string/symbol).
1378
-
1379
- The @state decorator MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
1380
-
1381
- To fix this, please:
1382
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1383
- 2. Configure it in vite.config.ts:
1384
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1385
- export default defineConfig({ plugins: [wsx()] });
1386
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1387
- npm install --save-dev @wsxjs/wsx-tsconfig
1388
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1389
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1390
-
1391
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1392
- );
1323
+ } else {
1324
+ propertyName = propertyKeyStr;
1393
1325
  }
1394
- normalizedPropertyKey = propertyKeyStr;
1395
- } else {
1396
- throw new Error(
1397
- `@state decorator: propertyKey is missing. This usually means the decorator is not being called correctly. Please ensure you're using @state on a class field, not a method or other construct.`
1398
- );
1399
- }
1400
- if (target == null) {
1401
- const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1402
- throw new Error(
1403
- `@state decorator: Cannot access property "${propertyKeyStr}". Target is ${target === null ? "null" : "undefined"}.
1404
-
1405
- The @state decorator MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
1406
-
1407
- To fix this, please:
1408
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1409
- 2. Configure it in vite.config.ts:
1410
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1411
- export default defineConfig({ plugins: [wsx()] });
1412
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1413
- npm install --save-dev @wsxjs/wsx-tsconfig
1414
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1415
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1416
-
1417
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1418
- );
1419
- }
1420
- if (typeof target !== "object") {
1421
- const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1422
- throw new Error(
1423
- `@state decorator: Cannot be used on "${propertyKeyStr}". @state is for properties only, not methods.`
1424
- );
1425
- }
1426
- const descriptor = Object.getOwnPropertyDescriptor(target, normalizedPropertyKey);
1427
- if (descriptor?.get) {
1428
- const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1429
- throw new Error(
1430
- `@state decorator cannot be used with getter properties. Property: "${propertyKeyStr}"`
1431
- );
1432
1326
  }
1327
+ throw new Error(createBabelPluginError(propertyName));
1433
1328
  }
1434
1329
  // Annotate the CommonJS export names for ESM import in node:
1435
1330
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -665,6 +665,12 @@ var WebComponent = class extends BaseComponent {
665
665
  }
666
666
  /**
667
667
  * Web Component生命周期:连接到DOM
668
+ *
669
+ * 渲染策略:
670
+ * 1. 检查 Shadow DOM 中是否已有实际内容(排除样式和 slot)
671
+ * 2. 如果有内容,先清空再渲染(避免重复元素)
672
+ * 3. 如果没有内容,直接渲染
673
+ * 4. Slot 元素会被重新添加,浏览器会自动将 Light DOM 中的内容分配到 slot
668
674
  */
669
675
  connectedCallback() {
670
676
  this.connected = true;
@@ -674,8 +680,23 @@ var WebComponent = class extends BaseComponent {
674
680
  const styleName = this.config.styleName || this.constructor.name;
675
681
  StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
676
682
  }
677
- const content = this.render();
678
- this.shadowRoot.appendChild(content);
683
+ const allChildren = Array.from(this.shadowRoot.children);
684
+ const styleElements = allChildren.filter((child) => child instanceof HTMLStyleElement);
685
+ const slotElements = allChildren.filter((child) => child instanceof HTMLSlotElement);
686
+ const hasErrorElement = allChildren.some(
687
+ (child) => child instanceof HTMLElement && child.style.color === "red" && child.textContent?.includes("Component Error")
688
+ );
689
+ const hasActualContent = allChildren.length > styleElements.length + slotElements.length;
690
+ if (hasActualContent && !hasErrorElement) {
691
+ } else {
692
+ this.shadowRoot.innerHTML = "";
693
+ if (stylesToApply) {
694
+ const styleName = this.config.styleName || this.constructor.name;
695
+ StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
696
+ }
697
+ const content = this.render();
698
+ this.shadowRoot.appendChild(content);
699
+ }
679
700
  this.initializeEventListeners();
680
701
  this.onConnected?.();
681
702
  } catch (error) {
@@ -788,17 +809,45 @@ var LightComponent = class extends BaseComponent {
788
809
  }
789
810
  /**
790
811
  * Web Component生命周期:连接到DOM
812
+ *
813
+ * 渲染策略:
814
+ * 1. 检查组件中是否已有实际内容(排除样式元素)
815
+ * 2. 如果有内容且完整,跳过渲染(避免重复元素和性能优化)
816
+ * 3. 如果没有内容或不完整,清空后重新渲染
817
+ * 4. 样式元素需要保留
791
818
  */
792
819
  connectedCallback() {
793
820
  this.connected = true;
794
821
  try {
795
822
  const stylesToApply = this._autoStyles || this.config.styles;
823
+ const styleName = this.config.styleName || this.constructor.name;
796
824
  if (stylesToApply) {
797
- const styleName = this.config.styleName || this.constructor.name;
798
825
  this.applyScopedStyles(styleName, stylesToApply);
799
826
  }
800
- const content = this.render();
801
- this.appendChild(content);
827
+ const styleElement = this.querySelector(
828
+ `style[data-wsx-light-component="${styleName}"]`
829
+ );
830
+ const hasErrorElement = Array.from(this.children).some(
831
+ (child) => child instanceof HTMLElement && child !== styleElement && child.style.color === "red" && child.textContent?.includes("Component Error")
832
+ );
833
+ const hasActualContent = Array.from(this.children).some(
834
+ (child) => child !== styleElement
835
+ );
836
+ if (hasActualContent && !hasErrorElement) {
837
+ if (styleElement && styleElement !== this.firstChild) {
838
+ this.insertBefore(styleElement, this.firstChild);
839
+ }
840
+ } else {
841
+ const childrenToRemove = Array.from(this.children).filter(
842
+ (child) => child !== styleElement
843
+ );
844
+ childrenToRemove.forEach((child) => child.remove());
845
+ const content = this.render();
846
+ this.appendChild(content);
847
+ if (styleElement && styleElement !== this.firstChild) {
848
+ this.insertBefore(styleElement, this.firstChild);
849
+ }
850
+ }
802
851
  this.initializeEventListeners();
803
852
  this.onConnected?.();
804
853
  } catch (error) {
@@ -973,230 +1022,76 @@ function deriveTagName(className, prefix) {
973
1022
  }
974
1023
 
975
1024
  // src/reactive-decorator.ts
1025
+ function createBabelPluginError(propertyName) {
1026
+ return `@state decorator on property "${propertyName}" MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
1027
+
1028
+ The @state decorator cannot work without the Babel plugin.
1029
+
1030
+ To fix this, please:
1031
+ 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1032
+ 2. Configure it in vite.config.ts:
1033
+ import { wsx } from '@wsxjs/wsx-vite-plugin';
1034
+ export default defineConfig({ plugins: [wsx()] });
1035
+ 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1036
+ npm install --save-dev @wsxjs/wsx-tsconfig
1037
+ Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1038
+ Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1039
+
1040
+ See: https://github.com/wsxjs/wsxjs#setup for more details.`;
1041
+ }
976
1042
  function state(targetOrContext, propertyKey) {
977
- let propertyName;
1043
+ let propertyName = "unknown";
978
1044
  const propertyKeyIsObject = typeof propertyKey === "object" && propertyKey !== null;
979
1045
  const targetIsObject = typeof targetOrContext === "object" && targetOrContext !== null;
980
1046
  const hasStage3Indicators = targetIsObject && ("kind" in targetOrContext || "addInitializer" in targetOrContext || "access" in targetOrContext);
981
1047
  const hasName = hasStage3Indicators && "name" in targetOrContext;
982
1048
  const isStage3Decorator = propertyKeyIsObject || hasName || hasStage3Indicators && (propertyKey === void 0 || propertyKey === null) || targetIsObject && "addInitializer" in targetOrContext;
983
1049
  if (isStage3Decorator) {
984
- const context = targetOrContext;
985
- if (context.name) {
986
- propertyName = typeof context.name === "string" ? context.name : context.name.toString();
1050
+ if (hasStage3Indicators && targetOrContext && typeof targetOrContext === "object") {
1051
+ const context = targetOrContext;
1052
+ if (context.name) {
1053
+ propertyName = typeof context.name === "string" ? context.name : context.name.toString();
1054
+ }
987
1055
  } else if (propertyKeyIsObject) {
988
- if ("name" in propertyKey) {
989
- const keyObj = propertyKey;
990
- propertyName = keyObj.name ? typeof keyObj.name === "string" ? keyObj.name : keyObj.name.toString() : "unknown";
991
- } else if ("key" in propertyKey) {
992
- const keyObj = propertyKey;
993
- propertyName = keyObj.key ? typeof keyObj.key === "string" ? keyObj.key : keyObj.key.toString() : "unknown";
1056
+ const keyObj = propertyKey;
1057
+ const targetObj = targetOrContext;
1058
+ const nameValue = targetObj?.name || keyObj.name || keyObj.key;
1059
+ if (nameValue) {
1060
+ propertyName = typeof nameValue === "string" ? nameValue : nameValue.toString();
994
1061
  } else {
995
1062
  const keyStr = String(propertyKey);
996
1063
  if (keyStr !== "[object Object]") {
997
1064
  propertyName = keyStr;
998
- } else {
999
- propertyName = "unknown";
1000
1065
  }
1001
1066
  }
1002
- } else {
1003
- propertyName = "unknown";
1004
1067
  }
1005
- } else {
1006
- if (typeof propertyKey === "string" || typeof propertyKey === "symbol") {
1007
- propertyName = typeof propertyKey === "string" ? propertyKey : propertyKey.toString();
1008
- } else if (propertyKey != null) {
1009
- const propertyKeyStr = String(propertyKey);
1010
- if (propertyKeyStr === "[object Object]") {
1011
- propertyName = "unknown";
1012
- } else {
1013
- propertyName = propertyKeyStr;
1068
+ if (targetIsObject && "kind" in targetOrContext) {
1069
+ const context = targetOrContext;
1070
+ if (context.kind && context.kind !== "field") {
1071
+ const nameStr = typeof context.name === "string" ? context.name : context.name.toString();
1072
+ throw new Error(
1073
+ `@state decorator can only be used on class fields, not ${context.kind}. Property: "${nameStr}"`
1074
+ );
1014
1075
  }
1015
- } else {
1016
- propertyName = "unknown";
1017
1076
  }
1077
+ throw new Error(createBabelPluginError(propertyName));
1018
1078
  }
1019
- console.warn(
1020
- `[WSX] @state decorator is using runtime fallback. Property "${propertyName}" will work but with reduced performance.
1021
-
1022
- To fix this and enable compile-time processing, please:
1023
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1024
- 2. Configure it in vite.config.ts:
1025
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1026
- export default defineConfig({ plugins: [wsx()] });
1027
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1028
- npm install --save-dev @wsxjs/wsx-tsconfig
1029
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1030
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1031
-
1032
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1033
- );
1034
- if (isStage3Decorator) {
1035
- let context;
1036
- if (hasStage3Indicators) {
1037
- context = targetOrContext;
1038
- } else if (propertyKeyIsObject) {
1039
- const keyObj = propertyKey;
1040
- const targetObj = targetOrContext;
1041
- const nameValue = targetObj.name || keyObj.name || keyObj.key || "unknown";
1042
- context = {
1043
- kind: targetObj.kind || "field",
1044
- name: nameValue,
1045
- addInitializer: targetObj.addInitializer || keyObj.addInitializer,
1046
- access: targetObj.access || keyObj.access
1047
- };
1048
- } else {
1049
- context = targetOrContext;
1050
- }
1051
- if (context.kind && context.kind !== "field") {
1052
- const nameStr = typeof context.name === "string" ? context.name : context.name.toString();
1053
- throw new Error(
1054
- `@state decorator can only be used on class fields, not ${context.kind}. Property: "${nameStr}"`
1055
- );
1056
- }
1057
- if (!context.addInitializer) {
1058
- console.warn(
1059
- `[WSX] @state decorator: addInitializer not available for property "${propertyName}". The property will not be reactive. This usually means the decorator system is not properly configured.`
1060
- );
1061
- } else {
1062
- context.addInitializer(function() {
1063
- if (!this || typeof this.reactive !== "function" || typeof this.useState !== "function") {
1064
- throw new Error(
1065
- `@state decorator runtime fallback: Component does not extend WebComponent or LightComponent. Property "${propertyName}" cannot be made reactive.
1066
-
1067
- The @state decorator can only be used in classes that extend WebComponent or LightComponent. Please ensure your component class extends one of these base classes.`
1068
- );
1069
- }
1070
- let initialValue = void 0;
1071
- if (context.access?.get) {
1072
- try {
1073
- initialValue = context.access.get();
1074
- } catch {
1075
- initialValue = this[propertyName];
1076
- }
1077
- } else {
1078
- initialValue = this[propertyName];
1079
- }
1080
- const isObject = initialValue !== null && initialValue !== void 0 && (typeof initialValue === "object" || Array.isArray(initialValue));
1081
- if (isObject) {
1082
- let reactiveValue = this.reactive(initialValue);
1083
- Object.defineProperty(this, propertyName, {
1084
- get: () => reactiveValue,
1085
- set: (newValue) => {
1086
- if (newValue !== null && newValue !== void 0 && (typeof newValue === "object" || Array.isArray(newValue))) {
1087
- reactiveValue = this.reactive(newValue);
1088
- this.scheduleRerender();
1089
- } else {
1090
- reactiveValue = newValue;
1091
- this.scheduleRerender();
1092
- }
1093
- },
1094
- enumerable: true,
1095
- configurable: true
1096
- });
1097
- } else {
1098
- const [getState, setState] = this.useState(propertyName, initialValue);
1099
- Object.defineProperty(this, propertyName, {
1100
- get: getState,
1101
- set: setState,
1102
- enumerable: true,
1103
- configurable: true
1104
- });
1105
- }
1106
- });
1107
- }
1108
- return context;
1109
- }
1110
- const target = targetOrContext;
1111
- let normalizedPropertyKey;
1112
1079
  if (typeof propertyKey === "string" || typeof propertyKey === "symbol") {
1113
- normalizedPropertyKey = propertyKey;
1080
+ propertyName = typeof propertyKey === "string" ? propertyKey : propertyKey.toString();
1114
1081
  } else if (propertyKey != null) {
1115
1082
  const propertyKeyStr = String(propertyKey);
1116
1083
  if (propertyKeyStr === "[object Object]") {
1117
1084
  if (typeof targetOrContext === "object" && targetOrContext !== null && ("kind" in targetOrContext || "addInitializer" in targetOrContext)) {
1118
- console.warn(
1119
- `[WSX] @state decorator: Detected potential Stage 3 decorator format but with unexpected propertyKey. This might be a compatibility issue. The decorator will attempt to work in runtime fallback mode.`
1120
- );
1121
1085
  const context = targetOrContext;
1122
1086
  if (context.name) {
1123
- const name = typeof context.name === "string" ? context.name : context.name.toString();
1124
- throw new Error(
1125
- `@state decorator: Detected Stage 3 decorator format but with invalid propertyKey. Property name: "${name}".
1126
-
1127
- This usually means the decorator is being called in an unexpected format. Please ensure you have configured the Babel plugin correctly.
1128
-
1129
- To fix this, please:
1130
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1131
- 2. Configure it in vite.config.ts:
1132
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1133
- export default defineConfig({ plugins: [wsx()] });
1134
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1135
- npm install --save-dev @wsxjs/wsx-tsconfig
1136
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1137
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1138
-
1139
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1140
- );
1087
+ propertyName = typeof context.name === "string" ? context.name : context.name.toString();
1141
1088
  }
1142
1089
  }
1143
- throw new Error(
1144
- `@state decorator: Invalid propertyKey detected (received object instead of string/symbol).
1145
-
1146
- The @state decorator MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
1147
-
1148
- To fix this, please:
1149
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1150
- 2. Configure it in vite.config.ts:
1151
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1152
- export default defineConfig({ plugins: [wsx()] });
1153
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1154
- npm install --save-dev @wsxjs/wsx-tsconfig
1155
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1156
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1157
-
1158
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1159
- );
1090
+ } else {
1091
+ propertyName = propertyKeyStr;
1160
1092
  }
1161
- normalizedPropertyKey = propertyKeyStr;
1162
- } else {
1163
- throw new Error(
1164
- `@state decorator: propertyKey is missing. This usually means the decorator is not being called correctly. Please ensure you're using @state on a class field, not a method or other construct.`
1165
- );
1166
- }
1167
- if (target == null) {
1168
- const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1169
- throw new Error(
1170
- `@state decorator: Cannot access property "${propertyKeyStr}". Target is ${target === null ? "null" : "undefined"}.
1171
-
1172
- The @state decorator MUST be processed by Babel plugin at compile time. It appears the Babel plugin is not configured in your build setup.
1173
-
1174
- To fix this, please:
1175
- 1. Install @wsxjs/wsx-vite-plugin: npm install @wsxjs/wsx-vite-plugin
1176
- 2. Configure it in vite.config.ts:
1177
- import { wsx } from '@wsxjs/wsx-vite-plugin';
1178
- export default defineConfig({ plugins: [wsx()] });
1179
- 3. Configure TypeScript (recommended: use @wsxjs/wsx-tsconfig):
1180
- npm install --save-dev @wsxjs/wsx-tsconfig
1181
- Then in tsconfig.json: { "extends": "@wsxjs/wsx-tsconfig/tsconfig.base.json" }
1182
- Or manually: { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
1183
-
1184
- See: https://github.com/wsxjs/wsxjs#setup for more details.`
1185
- );
1186
- }
1187
- if (typeof target !== "object") {
1188
- const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1189
- throw new Error(
1190
- `@state decorator: Cannot be used on "${propertyKeyStr}". @state is for properties only, not methods.`
1191
- );
1192
- }
1193
- const descriptor = Object.getOwnPropertyDescriptor(target, normalizedPropertyKey);
1194
- if (descriptor?.get) {
1195
- const propertyKeyStr = typeof normalizedPropertyKey === "string" ? normalizedPropertyKey : normalizedPropertyKey.toString();
1196
- throw new Error(
1197
- `@state decorator cannot be used with getter properties. Property: "${propertyKeyStr}"`
1198
- );
1199
1093
  }
1094
+ throw new Error(createBabelPluginError(propertyName));
1200
1095
  }
1201
1096
  export {
1202
1097
  Fragment,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wsxjs/wsx-core",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "Core WSX Framework - Web Components with JSX syntax",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -101,7 +101,7 @@ function unwrapProxy(value: unknown): unknown {
101
101
  // 直接访问原始对象的属性,不通过 Proxy
102
102
  for (const key in original) {
103
103
  if (Object.prototype.hasOwnProperty.call(original, key)) {
104
- const propValue = original[key];
104
+ const propValue = (original as Record<string, unknown>)[key];
105
105
  // 如果属性值是 Proxy,先获取原始对象再递归
106
106
  if (
107
107
  propValue != null &&
@@ -1,221 +0,0 @@
1
- // src/utils/svg-utils.ts
2
- var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
3
- var SVG_ONLY_ELEMENTS = /* @__PURE__ */ new Set([
4
- // 结构元素 (Structural elements)
5
- "svg",
6
- "defs",
7
- "g",
8
- "symbol",
9
- "use",
10
- // 图形元素 (Graphics elements)
11
- "circle",
12
- "ellipse",
13
- "line",
14
- "path",
15
- "polygon",
16
- "polyline",
17
- "rect",
18
- // 文本元素 (Text elements)
19
- "textPath",
20
- "tspan",
21
- // 渐变和模式 (Gradients and patterns)
22
- "linearGradient",
23
- "radialGradient",
24
- "stop",
25
- "pattern",
26
- // 滤镜 (Filter elements)
27
- "filter",
28
- "feBlend",
29
- "feColorMatrix",
30
- "feComponentTransfer",
31
- "feComposite",
32
- "feConvolveMatrix",
33
- "feDiffuseLighting",
34
- "feDisplacementMap",
35
- "feDistantLight",
36
- "feDropShadow",
37
- "feFlood",
38
- "feFuncA",
39
- "feFuncB",
40
- "feFuncG",
41
- "feFuncR",
42
- "feGaussianBlur",
43
- "feImage",
44
- "feMerge",
45
- "feMergeNode",
46
- "feMorphology",
47
- "feOffset",
48
- "fePointLight",
49
- "feSpecularLighting",
50
- "feSpotLight",
51
- "feTile",
52
- "feTurbulence",
53
- // 动画元素 (Animation elements)
54
- "animate",
55
- "animateMotion",
56
- "animateTransform",
57
- "set",
58
- // 其他元素 (Other elements)
59
- "clipPath",
60
- "foreignObject",
61
- "marker",
62
- "mask",
63
- "metadata",
64
- "switch",
65
- "desc"
66
- ]);
67
- var DUAL_ELEMENTS = /* @__PURE__ */ new Set(["image", "style", "title", "text"]);
68
- var FORCE_HTML_ELEMENTS = /* @__PURE__ */ new Set(["a"]);
69
- var SVG_ELEMENTS = /* @__PURE__ */ new Set([
70
- ...SVG_ONLY_ELEMENTS,
71
- ...DUAL_ELEMENTS,
72
- ...FORCE_HTML_ELEMENTS
73
- ]);
74
- var svgContext = false;
75
- function isSVGOnlyElement(tagName) {
76
- return SVG_ONLY_ELEMENTS.has(tagName);
77
- }
78
- function isDualElement(tagName) {
79
- return DUAL_ELEMENTS.has(tagName);
80
- }
81
- function isForceHTMLElement(tagName) {
82
- return FORCE_HTML_ELEMENTS.has(tagName);
83
- }
84
- function setSVGContext(inSVG) {
85
- svgContext = inSVG;
86
- }
87
- function createElement(tagName) {
88
- if (isForceHTMLElement(tagName)) {
89
- return document.createElement(tagName);
90
- }
91
- if (isSVGOnlyElement(tagName)) {
92
- setSVGContext(true);
93
- return document.createElementNS(SVG_NAMESPACE, tagName);
94
- }
95
- if (isDualElement(tagName)) {
96
- if (svgContext) {
97
- return document.createElementNS(SVG_NAMESPACE, tagName);
98
- }
99
- }
100
- return document.createElement(tagName);
101
- }
102
- function shouldUseSVGNamespace(tagName) {
103
- return isSVGOnlyElement(tagName) || isDualElement(tagName) && svgContext;
104
- }
105
- var SVG_ATTRIBUTE_MAP = /* @__PURE__ */ new Map([
106
- ["className", "class"],
107
- ["htmlFor", "for"]
108
- ]);
109
- function getSVGAttributeName(attributeName) {
110
- return SVG_ATTRIBUTE_MAP.get(attributeName) || attributeName;
111
- }
112
-
113
- // src/jsx-factory.ts
114
- function h(tag, props = {}, ...children) {
115
- if (typeof tag === "function") {
116
- return tag(props, children);
117
- }
118
- const element = createElement(tag);
119
- if (props) {
120
- const isSVG = shouldUseSVGNamespace(tag);
121
- Object.entries(props).forEach(([key, value]) => {
122
- if (value === null || value === void 0 || value === false) {
123
- return;
124
- }
125
- if (key === "ref" && typeof value === "function") {
126
- value(element);
127
- } else if (key === "className" || key === "class") {
128
- if (isSVG) {
129
- element.setAttribute("class", value);
130
- } else {
131
- element.className = value;
132
- }
133
- } else if (key === "style" && typeof value === "string") {
134
- element.setAttribute("style", value);
135
- } else if (key.startsWith("on") && typeof value === "function") {
136
- const eventName = key.slice(2).toLowerCase();
137
- element.addEventListener(eventName, value);
138
- } else if (typeof value === "boolean") {
139
- if (value) {
140
- element.setAttribute(key, "");
141
- }
142
- } else {
143
- const attributeName = isSVG ? getSVGAttributeName(key) : key;
144
- element.setAttribute(attributeName, String(value));
145
- }
146
- });
147
- }
148
- const flatChildren = flattenChildren(children);
149
- flatChildren.forEach((child) => {
150
- if (child === null || child === void 0 || child === false) {
151
- return;
152
- }
153
- if (typeof child === "string" || typeof child === "number") {
154
- element.appendChild(document.createTextNode(String(child)));
155
- } else if (child instanceof HTMLElement || child instanceof SVGElement) {
156
- element.appendChild(child);
157
- } else if (child instanceof DocumentFragment) {
158
- element.appendChild(child);
159
- }
160
- });
161
- return element;
162
- }
163
- function flattenChildren(children) {
164
- const result = [];
165
- for (const child of children) {
166
- if (child === null || child === void 0 || child === false) {
167
- continue;
168
- } else if (Array.isArray(child)) {
169
- result.push(...flattenChildren(child));
170
- } else {
171
- result.push(child);
172
- }
173
- }
174
- return result;
175
- }
176
- function Fragment(_props, children) {
177
- const fragment = document.createDocumentFragment();
178
- const flatChildren = flattenChildren(children);
179
- flatChildren.forEach((child) => {
180
- if (child === null || child === void 0 || child === false) {
181
- return;
182
- }
183
- if (typeof child === "string" || typeof child === "number") {
184
- fragment.appendChild(document.createTextNode(String(child)));
185
- } else if (child instanceof HTMLElement || child instanceof SVGElement) {
186
- fragment.appendChild(child);
187
- } else if (child instanceof DocumentFragment) {
188
- fragment.appendChild(child);
189
- }
190
- });
191
- return fragment;
192
- }
193
- function jsx(tag, props) {
194
- if (!props) {
195
- return h(tag, null);
196
- }
197
- const { children, ...restProps } = props;
198
- if (children !== void 0) {
199
- return h(tag, restProps, children);
200
- }
201
- return h(tag, restProps);
202
- }
203
- function jsxs(tag, props) {
204
- if (!props) {
205
- return h(tag, null);
206
- }
207
- const { children, ...restProps } = props;
208
- if (Array.isArray(children)) {
209
- return h(tag, restProps, ...children);
210
- } else if (children !== void 0) {
211
- return h(tag, restProps, children);
212
- }
213
- return h(tag, restProps);
214
- }
215
-
216
- export {
217
- h,
218
- Fragment,
219
- jsx,
220
- jsxs
221
- };
@@ -1,222 +0,0 @@
1
- // src/utils/svg-utils.ts
2
- var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
3
- var SVG_ONLY_ELEMENTS = /* @__PURE__ */ new Set([
4
- // 结构元素 (Structural elements)
5
- "svg",
6
- "defs",
7
- "g",
8
- "symbol",
9
- "use",
10
- // 图形元素 (Graphics elements)
11
- "circle",
12
- "ellipse",
13
- "line",
14
- "path",
15
- "polygon",
16
- "polyline",
17
- "rect",
18
- // 文本元素 (Text elements)
19
- "textPath",
20
- "tspan",
21
- // 渐变和模式 (Gradients and patterns)
22
- "linearGradient",
23
- "radialGradient",
24
- "stop",
25
- "pattern",
26
- // 滤镜 (Filter elements)
27
- "filter",
28
- "feBlend",
29
- "feColorMatrix",
30
- "feComponentTransfer",
31
- "feComposite",
32
- "feConvolveMatrix",
33
- "feDiffuseLighting",
34
- "feDisplacementMap",
35
- "feDistantLight",
36
- "feDropShadow",
37
- "feFlood",
38
- "feFuncA",
39
- "feFuncB",
40
- "feFuncG",
41
- "feFuncR",
42
- "feGaussianBlur",
43
- "feImage",
44
- "feMerge",
45
- "feMergeNode",
46
- "feMorphology",
47
- "feOffset",
48
- "fePointLight",
49
- "feSpecularLighting",
50
- "feSpotLight",
51
- "feTile",
52
- "feTurbulence",
53
- // 动画元素 (Animation elements)
54
- "animate",
55
- "animateMotion",
56
- "animateTransform",
57
- "set",
58
- // 其他元素 (Other elements)
59
- "clipPath",
60
- "foreignObject",
61
- "marker",
62
- "mask",
63
- "metadata",
64
- "switch",
65
- "desc"
66
- ]);
67
- var DUAL_ELEMENTS = /* @__PURE__ */ new Set(["image", "style", "title", "text"]);
68
- var FORCE_HTML_ELEMENTS = /* @__PURE__ */ new Set(["a"]);
69
- var SVG_ELEMENTS = /* @__PURE__ */ new Set([
70
- ...SVG_ONLY_ELEMENTS,
71
- ...DUAL_ELEMENTS,
72
- ...FORCE_HTML_ELEMENTS
73
- ]);
74
- var svgContext = false;
75
- function isSVGOnlyElement(tagName) {
76
- return SVG_ONLY_ELEMENTS.has(tagName);
77
- }
78
- function isDualElement(tagName) {
79
- return DUAL_ELEMENTS.has(tagName);
80
- }
81
- function isForceHTMLElement(tagName) {
82
- return FORCE_HTML_ELEMENTS.has(tagName);
83
- }
84
- function setSVGContext(inSVG) {
85
- svgContext = inSVG;
86
- }
87
- function createElement(tagName) {
88
- if (isForceHTMLElement(tagName)) {
89
- return document.createElement(tagName);
90
- }
91
- if (isSVGOnlyElement(tagName)) {
92
- setSVGContext(true);
93
- return document.createElementNS(SVG_NAMESPACE, tagName);
94
- }
95
- if (isDualElement(tagName)) {
96
- if (svgContext) {
97
- return document.createElementNS(SVG_NAMESPACE, tagName);
98
- }
99
- }
100
- return document.createElement(tagName);
101
- }
102
- function shouldUseSVGNamespace(tagName) {
103
- return isSVGOnlyElement(tagName) || isDualElement(tagName) && svgContext;
104
- }
105
- var SVG_ATTRIBUTE_MAP = /* @__PURE__ */ new Map([
106
- ["className", "class"],
107
- ["htmlFor", "for"]
108
- ]);
109
- function getSVGAttributeName(attributeName) {
110
- return SVG_ATTRIBUTE_MAP.get(attributeName) || attributeName;
111
- }
112
-
113
- // src/jsx-factory.ts
114
- function h(tag, props = {}, ...children) {
115
- if (typeof tag === "function") {
116
- return tag(props, children);
117
- }
118
- const element = createElement(tag);
119
- if (props) {
120
- const isSVG = shouldUseSVGNamespace(tag);
121
- Object.entries(props).forEach(([key, value]) => {
122
- if (value === null || value === void 0 || value === false) {
123
- return;
124
- }
125
- if (key === "ref" && typeof value === "function") {
126
- value(element);
127
- } else if (key === "className" || key === "class") {
128
- if (isSVG) {
129
- element.setAttribute("class", value);
130
- } else {
131
- element.className = value;
132
- }
133
- } else if (key === "style" && typeof value === "string") {
134
- element.setAttribute("style", value);
135
- } else if (key.startsWith("on") && typeof value === "function") {
136
- const eventName = key.slice(2).toLowerCase();
137
- element.addEventListener(eventName, value);
138
- } else if (typeof value === "boolean") {
139
- if (value) {
140
- element.setAttribute(key, "");
141
- }
142
- } else {
143
- const attributeName = isSVG ? getSVGAttributeName(key) : key;
144
- element.setAttribute(attributeName, String(value));
145
- }
146
- });
147
- }
148
- const flatChildren = flattenChildren(children);
149
- flatChildren.forEach((child) => {
150
- if (child === null || child === void 0 || child === false) {
151
- return;
152
- }
153
- if (typeof child === "string" || typeof child === "number") {
154
- element.appendChild(document.createTextNode(String(child)));
155
- } else if (child instanceof HTMLElement || child instanceof SVGElement) {
156
- element.appendChild(child);
157
- } else if (child instanceof DocumentFragment) {
158
- element.appendChild(child);
159
- }
160
- });
161
- return element;
162
- }
163
- function flattenChildren(children) {
164
- const result = [];
165
- for (const child of children) {
166
- if (child === null || child === void 0 || child === false) {
167
- continue;
168
- } else if (Array.isArray(child)) {
169
- result.push(...flattenChildren(child));
170
- } else {
171
- result.push(child);
172
- }
173
- }
174
- return result;
175
- }
176
- function Fragment(_props, children) {
177
- const fragment = document.createDocumentFragment();
178
- const flatChildren = flattenChildren(children);
179
- flatChildren.forEach((child) => {
180
- if (child === null || child === void 0 || child === false) {
181
- return;
182
- }
183
- if (typeof child === "string" || typeof child === "number") {
184
- fragment.appendChild(document.createTextNode(String(child)));
185
- } else if (child instanceof HTMLElement || child instanceof SVGElement) {
186
- fragment.appendChild(child);
187
- } else if (child instanceof DocumentFragment) {
188
- fragment.appendChild(child);
189
- }
190
- });
191
- return fragment;
192
- }
193
- function jsx(tag, props) {
194
- if (!props) {
195
- return h(tag, null);
196
- }
197
- const { children, ...restProps } = props;
198
- if (children !== void 0 && children !== null) {
199
- const childrenArray = Array.isArray(children) ? children : [children];
200
- return h(tag, restProps, ...childrenArray);
201
- }
202
- return h(tag, restProps);
203
- }
204
- function jsxs(tag, props) {
205
- if (!props) {
206
- return h(tag, null);
207
- }
208
- const { children, ...restProps } = props;
209
- if (Array.isArray(children)) {
210
- return h(tag, restProps, ...children);
211
- } else if (children !== void 0 && children !== null) {
212
- return h(tag, restProps, children);
213
- }
214
- return h(tag, restProps);
215
- }
216
-
217
- export {
218
- h,
219
- Fragment,
220
- jsx,
221
- jsxs
222
- };