@wsxjs/wsx-press 0.0.25 → 0.0.27
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/README.md +297 -0
- package/dist/client.cjs +1 -1
- package/dist/client.js +457 -424
- package/dist/node.cjs +7 -7
- package/dist/node.js +79 -79
- package/package.json +7 -7
- package/src/client/components/DocPage.wsx +57 -0
- package/src/client/components/DocTOC.css +1 -5
- package/src/client/components/DocTOC.wsx +45 -18
- package/src/node/toc.ts +6 -5
|
@@ -135,7 +135,8 @@ export default class DocTOC extends LightComponent {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
/**
|
|
138
|
-
*
|
|
138
|
+
* 收集文档中的标题元素(使用已有的 ID)
|
|
139
|
+
* 注意:不再重新设置 ID,而是使用 Heading 组件已经设置好的 ID
|
|
139
140
|
*/
|
|
140
141
|
private setupHeadingIds(): void {
|
|
141
142
|
const docContent = document.querySelector(".doc-content");
|
|
@@ -143,36 +144,52 @@ export default class DocTOC extends LightComponent {
|
|
|
143
144
|
return;
|
|
144
145
|
}
|
|
145
146
|
|
|
146
|
-
// 查找所有标题元素(包括 wsx-marked-heading 和标准 h1-h6)
|
|
147
|
-
const headings = docContent.querySelectorAll("h1, h2, h3, h4, h5, h6, wsx-marked-heading");
|
|
148
147
|
this.headingElements.clear();
|
|
149
148
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
149
|
+
// 查找 wsx-marked-heading 组件内的标题元素(它们已经有正确的 ID)
|
|
150
|
+
const markedHeadings = docContent.querySelectorAll("wsx-marked-heading");
|
|
151
|
+
markedHeadings.forEach((wrapper) => {
|
|
152
|
+
// 获取内部的 h1-h6 元素(Heading 组件渲染的带 ID 的元素)
|
|
153
|
+
const heading = wrapper.querySelector("h1, h2, h3, h4, h5, h6");
|
|
154
|
+
if (heading instanceof HTMLElement && heading.id) {
|
|
155
|
+
this.headingElements.set(heading.id, heading);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
157
158
|
|
|
158
|
-
|
|
159
|
+
// 也支持直接的 h1-h6 元素(非 wsx-marked-heading 的情况)
|
|
160
|
+
const directHeadings = docContent.querySelectorAll(
|
|
161
|
+
":scope > h1, :scope > h2, :scope > h3, :scope > h4, :scope > h5, :scope > h6"
|
|
162
|
+
);
|
|
163
|
+
directHeadings.forEach((heading) => {
|
|
159
164
|
if (heading instanceof HTMLElement) {
|
|
160
|
-
|
|
161
|
-
|
|
165
|
+
// 如果已经有 ID,直接使用
|
|
166
|
+
if (heading.id) {
|
|
167
|
+
this.headingElements.set(heading.id, heading);
|
|
168
|
+
} else {
|
|
169
|
+
// 否则生成 ID 并设置
|
|
170
|
+
const text = heading.textContent?.trim() || "";
|
|
171
|
+
if (text) {
|
|
172
|
+
const id = this.generateId(text);
|
|
173
|
+
heading.id = id;
|
|
174
|
+
this.headingElements.set(id, heading);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
162
177
|
}
|
|
163
178
|
});
|
|
164
179
|
}
|
|
165
180
|
|
|
166
181
|
/**
|
|
167
182
|
* 生成锚点 ID
|
|
183
|
+
* 必须与服务端 toc.ts 和 marked-utils.ts 中的 generateId 保持一致
|
|
184
|
+
* 保留中文等 Unicode 字符,只移除特殊符号
|
|
168
185
|
*/
|
|
169
186
|
private generateId(text: string): string {
|
|
170
187
|
return text
|
|
171
188
|
.toLowerCase()
|
|
172
|
-
.replace(
|
|
173
|
-
.replace(
|
|
174
|
-
.replace(/-+/g, "-")
|
|
175
|
-
.
|
|
189
|
+
.replace(/\s+/g, "-") // 空格转连字符
|
|
190
|
+
.replace(/[^\p{L}\p{N}-]/gu, "") // 保留字母、数字、连字符(Unicode-aware)
|
|
191
|
+
.replace(/-+/g, "-") // 合并多个连字符
|
|
192
|
+
.replace(/^-+|-+$/g, ""); // 移除首尾连字符
|
|
176
193
|
}
|
|
177
194
|
|
|
178
195
|
/**
|
|
@@ -214,11 +231,21 @@ export default class DocTOC extends LightComponent {
|
|
|
214
231
|
*/
|
|
215
232
|
private handleTOCClick = (id: string, e: Event): void => {
|
|
216
233
|
e.preventDefault();
|
|
217
|
-
|
|
234
|
+
// 优先从缓存中获取,如果没有则通过 DOM 查找
|
|
235
|
+
let element = this.headingElements.get(id);
|
|
236
|
+
if (!element) {
|
|
237
|
+
element = document.getElementById(id) as HTMLElement | null;
|
|
238
|
+
if (element) {
|
|
239
|
+
// 缓存找到的元素
|
|
240
|
+
this.headingElements.set(id, element);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
218
243
|
if (element) {
|
|
219
244
|
element.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
220
245
|
// 更新 URL hash(不触发滚动)
|
|
221
246
|
window.history.replaceState(null, "", `#${id}`);
|
|
247
|
+
} else {
|
|
248
|
+
logger.warn(`Heading element not found for id: ${id}`);
|
|
222
249
|
}
|
|
223
250
|
};
|
|
224
251
|
|
package/src/node/toc.ts
CHANGED
|
@@ -64,7 +64,7 @@ export function extractTOCFromMarkdown(markdown: string): TOCItem[] {
|
|
|
64
64
|
|
|
65
65
|
const item: TOCItem = {
|
|
66
66
|
level,
|
|
67
|
-
text,
|
|
67
|
+
text: text.trim(),
|
|
68
68
|
id,
|
|
69
69
|
children: [],
|
|
70
70
|
};
|
|
@@ -112,14 +112,15 @@ function extractTextFromTokens(tokens: Token[]): string {
|
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* 生成锚点 ID
|
|
115
|
+
* 保留中文等 Unicode 字符,只移除特殊符号
|
|
115
116
|
*/
|
|
116
117
|
function generateId(text: string): string {
|
|
117
118
|
return text
|
|
118
119
|
.toLowerCase()
|
|
119
|
-
.replace(
|
|
120
|
-
.replace(
|
|
121
|
-
.replace(/-+/g, "-")
|
|
122
|
-
.
|
|
120
|
+
.replace(/\s+/g, "-") // 空格转连字符
|
|
121
|
+
.replace(/[^\p{L}\p{N}-]/gu, "") // 保留字母、数字、连字符(Unicode-aware)
|
|
122
|
+
.replace(/-+/g, "-") // 合并多个连字符
|
|
123
|
+
.replace(/^-+|-+$/g, ""); // 移除首尾连字符
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
/**
|