@wsxjs/wsx-core 0.0.17 → 0.0.18

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.
@@ -11,7 +11,7 @@
11
11
  import { h, type JSXChildren } from "./jsx-factory";
12
12
  import { StyleManager } from "./styles/style-manager";
13
13
  import { BaseComponent, type BaseComponentConfig } from "./base-component";
14
- import { createLogger } from "./utils/logger";
14
+ import { createLogger } from "@wsxjs/wsx-logger";
15
15
 
16
16
  const logger = createLogger("WebComponent");
17
17
 
@@ -86,6 +86,8 @@ export abstract class WebComponent extends BaseComponent {
86
86
  } else {
87
87
  // 没有内容,需要渲染
88
88
  // 清空 Shadow DOM(包括可能的旧内容)
89
+ // Note: innerHTML is used here for framework-level DOM management
90
+ // This is an exception to the no-inner-html rule for framework code
89
91
  this.shadowRoot.innerHTML = "";
90
92
 
91
93
  // 重新应用样式(因为上面清空了)
@@ -106,6 +108,14 @@ export abstract class WebComponent extends BaseComponent {
106
108
 
107
109
  // 调用子类的初始化钩子
108
110
  this.onConnected?.();
111
+
112
+ // 如果进行了渲染,调用 onRendered 钩子
113
+ if (hasActualContent === false || hasErrorElement) {
114
+ // 使用 requestAnimationFrame 确保 DOM 已完全更新
115
+ requestAnimationFrame(() => {
116
+ this.onRendered?.();
117
+ });
118
+ }
109
119
  } catch (error) {
110
120
  logger.error(`Error in connectedCallback:`, error);
111
121
  this.renderError(error);
@@ -142,25 +152,28 @@ export abstract class WebComponent extends BaseComponent {
142
152
  }
143
153
 
144
154
  /**
145
- * 重新渲染组件
155
+ * 内部重渲染实现
156
+ * 包含从 rerender() 方法迁移的实际渲染逻辑
157
+ * WebComponent 使用 Shadow DOM,不存在 JSX children 问题
158
+ *
159
+ * @override
146
160
  */
147
- protected rerender(): void {
161
+ protected _rerender(): void {
148
162
  if (!this.connected) {
149
- logger.warn("Component is not connected, skipping rerender.");
163
+ // 如果组件未连接,清除渲染标志
164
+ this._isRendering = false;
150
165
  return;
151
166
  }
152
167
 
153
168
  // 1. 捕获焦点状态(在 DOM 替换之前)
154
169
  const focusState = this.captureFocusState();
155
- // 保存到实例变量,供 render() 使用(如果需要)
156
170
  this._pendingFocusState = focusState;
157
171
 
158
- // 保存当前的 adopted stylesheets (jsdom may not support this)
172
+ // 2. 保存当前的 adopted stylesheets
159
173
  const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
160
174
 
161
175
  try {
162
- // 只有在没有 adopted stylesheets 时才重新应用样式
163
- // Check both _autoStyles getter and config.styles getter
176
+ // 3. 只有在没有 adopted stylesheets 时才重新应用样式
164
177
  if (adoptedStyleSheets.length === 0) {
165
178
  const stylesToApply = this._autoStyles || this.config.styles;
166
179
  if (stylesToApply) {
@@ -169,13 +182,11 @@ export abstract class WebComponent extends BaseComponent {
169
182
  }
170
183
  }
171
184
 
172
- // 重新渲染JSX
185
+ // 4. 重新渲染JSX
173
186
  const content = this.render();
174
187
 
175
- // 在添加到 DOM 之前恢复值,避免浏览器渲染状态值
176
- // 这样可以确保值在元素添加到 DOM 之前就是正确的
188
+ // 5. 在添加到 DOM 之前恢复值
177
189
  if (focusState && focusState.key && focusState.value !== undefined) {
178
- // 在 content 树中查找目标元素
179
190
  const target = content.querySelector(
180
191
  `[data-wsx-key="${focusState.key}"]`
181
192
  ) as HTMLElement;
@@ -190,35 +201,37 @@ export abstract class WebComponent extends BaseComponent {
190
201
  }
191
202
  }
192
203
 
193
- // 恢复 adopted stylesheets (避免重新应用样式)
204
+ // 6. 恢复 adopted stylesheets
194
205
  if (this.shadowRoot.adoptedStyleSheets) {
195
206
  this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
196
207
  }
197
208
 
198
- // 使用 requestAnimationFrame 批量执行 DOM 操作,减少重绘
199
- // 在同一帧中完成添加和移除,避免中间状态
209
+ // 7. 使用 requestAnimationFrame 批量执行 DOM 操作
200
210
  requestAnimationFrame(() => {
201
- // 先添加新内容
211
+ // 添加新内容
202
212
  this.shadowRoot.appendChild(content);
203
213
 
204
- // 立即移除旧内容(在同一帧中,浏览器会批量处理)
214
+ // 移除旧内容
205
215
  const oldChildren = Array.from(this.shadowRoot.children).filter(
206
216
  (child) => child !== content
207
217
  );
208
218
  oldChildren.forEach((child) => child.remove());
209
219
 
210
- // 恢复焦点状态(在 DOM 替换之后)
211
- // 值已经在添加到 DOM 之前恢复了,这里只需要恢复焦点和光标位置
212
- // 使用另一个 requestAnimationFrame 确保 DOM 已完全更新
220
+ // 恢复焦点状态
213
221
  requestAnimationFrame(() => {
214
222
  this.restoreFocusState(focusState);
215
- // 清除待处理的焦点状态
216
223
  this._pendingFocusState = null;
224
+ // 调用 onRendered 生命周期钩子
225
+ this.onRendered?.();
226
+ // 在 onRendered() 完成后清除渲染标志,允许后续的 scheduleRerender()
227
+ this._isRendering = false;
217
228
  });
218
229
  });
219
230
  } catch (error) {
220
- logger.error("Error in rerender:", error);
231
+ logger.error("Error in _rerender:", error);
221
232
  this.renderError(error);
233
+ // 即使出错也要清除渲染标志,允许后续的 scheduleRerender()
234
+ this._isRendering = false;
222
235
  }
223
236
  }
224
237
 
@@ -229,6 +242,8 @@ export abstract class WebComponent extends BaseComponent {
229
242
  */
230
243
  private renderError(error: unknown): void {
231
244
  // 清空现有内容
245
+ // Note: innerHTML is used here for framework-level error handling
246
+ // This is an exception to the no-inner-html rule for framework code
232
247
  this.shadowRoot.innerHTML = "";
233
248
 
234
249
  const errorElement = h(
package/types/index.d.ts CHANGED
@@ -28,9 +28,12 @@ export type { AutoRegistrationOptions } from "../src/auto-register";
28
28
  // 导出 StyleManager
29
29
  export { StyleManager } from "../src/styles/style-manager";
30
30
 
31
- // 导出 Logger 相关类型和函数
32
- export { WSXLogger, logger, createLogger } from "../src/utils/logger.ts";
33
- export type { Logger, LogLevel } from "../src/utils/logger.ts";
31
+ // 导出 Logger 相关类型和函数 (re-exported from @wsxjs/wsx-logger for backward compatibility)
32
+ export type { Logger, LogLevel } from "@wsxjs/wsx-logger";
33
+ export { WSXLogger, logger, createLogger, createLoggerWithConfig } from "@wsxjs/wsx-logger";
34
+
35
+ // 导出 DOM 工具函数
36
+ export { parseHTMLToNodes } from "../src/utils/dom-utils";
34
37
 
35
38
  // 重新导出 JSX 运行时
36
39
  export { h as jsx, h as jsxs, Fragment as F } from "../src/jsx-factory";