@deot/docs-markdown 1.1.0 → 1.1.2
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 +36 -2
- package/dist/index.cjs +289 -29
- package/dist/index.d.ts +16 -0
- package/dist/index.js +288 -31
- package/dist/index.style.css +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fragment, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, h, inject, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, ref, renderList, shallowRef, toDisplayString, unref, watch, withDirectives } from "vue";
|
|
1
|
+
import { Fragment, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, h, inject, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, shallowRef, toDisplayString, unref, watch, withDirectives } from "vue";
|
|
2
2
|
import { provideLocale, useLocale } from "@deot/docs-locale";
|
|
3
3
|
import Config from "markdown-it-chain";
|
|
4
4
|
import anchor from "markdown-it-anchor";
|
|
@@ -9,9 +9,11 @@ import { getScroller } from "@deot/helper-dom";
|
|
|
9
9
|
//#region packages/markdown/src/markdown.ts
|
|
10
10
|
var HTML_MD_SIGN = "md";
|
|
11
11
|
var PLAYGROUND = "playground";
|
|
12
|
+
var TABS = "tabs";
|
|
12
13
|
var TIP = "tip";
|
|
13
14
|
var WARNING = "warning";
|
|
14
15
|
var CALLOUT_FILLED_RE = /(^|\s)filled(\s|$)/;
|
|
16
|
+
var TAB_MARKDOWN_INFO_RE = /^markdown(?:\s+(.*))?$/i;
|
|
15
17
|
var CALLOUT_INFO_ICON = [
|
|
16
18
|
"<svg width=\"22\" height=\"28\" viewBox=\"0 0 22 28\" fill=\"none\" aria-hidden=\"true\">",
|
|
17
19
|
"<circle class=\"docs-markdown-callout-icon__fill\" cx=\"11\" cy=\"14\" r=\"11\"></circle>",
|
|
@@ -44,9 +46,13 @@ config.options.html(true).typographer(true).linkify(true).end().plugin("anchor")
|
|
|
44
46
|
placement: "before",
|
|
45
47
|
symbol: "#"
|
|
46
48
|
}) }]).end().plugin("container").use(($md) => {
|
|
47
|
-
const
|
|
49
|
+
const playgroundReg = new RegExp(`^${PLAYGROUND}\\s*(.*)$`);
|
|
48
50
|
$md.use(mdContainer, PLAYGROUND, { validate(params) {
|
|
49
|
-
return params.trim().match(
|
|
51
|
+
return params.trim().match(playgroundReg);
|
|
52
|
+
} });
|
|
53
|
+
const tabsReg = new RegExp(`^${TABS}\\s*$`);
|
|
54
|
+
$md.use(mdContainer, TABS, { validate(params) {
|
|
55
|
+
return tabsReg.test(params.trim());
|
|
50
56
|
} });
|
|
51
57
|
$md.use(mdContainer, TIP, { render: renderCallout(TIP, CALLOUT_INFO_ICON) });
|
|
52
58
|
$md.use(mdContainer, WARNING, { render: renderCallout(WARNING, CALLOUT_WARNING_ICON) });
|
|
@@ -54,9 +60,33 @@ config.options.html(true).typographer(true).linkify(true).end().plugin("anchor")
|
|
|
54
60
|
var md = config.toMd(markdownIt);
|
|
55
61
|
var playgroundOpen = `container_${PLAYGROUND}_open`;
|
|
56
62
|
var playgroundClose = `container_${PLAYGROUND}_close`;
|
|
63
|
+
var tabsOpen = `container_${TABS}_open`;
|
|
64
|
+
var tabsClose = `container_${TABS}_close`;
|
|
57
65
|
var htmlCommentRE = /<!--([\s\S]*?)-->/g;
|
|
58
66
|
var runtimeConfigRE = /<config\s+lang\s*=\s*["']json5["']\s*>([\s\S]*?)<\/config>/i;
|
|
59
67
|
var renderPlaygroundError = (message) => `<div class="docs-playground-error">PLAYGROUND: ${md.utils.escapeHtml(message)}</div>\n`;
|
|
68
|
+
var renderTabsError = (message) => `<div class="docs-markdown-tabs-error">TABS: ${md.utils.escapeHtml(message)}</div>\n`;
|
|
69
|
+
/**
|
|
70
|
+
* 从 fence info 解析 Tab 显示名:去掉可选的 `markdown` 语言前缀。
|
|
71
|
+
* @param info fence 的 info 字符串,如 `markdown Linux` 或 `Android`。
|
|
72
|
+
* @returns 显示标题(可能为空)。
|
|
73
|
+
*/
|
|
74
|
+
var parseTabFenceTitle = (info) => {
|
|
75
|
+
const trimmed = info.trim();
|
|
76
|
+
const match = trimmed.match(TAB_MARKDOWN_INFO_RE);
|
|
77
|
+
if (match) return (match[1] || "").trim();
|
|
78
|
+
return trimmed;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* 生成 `?tab=` 使用的 id:小写、空白变 `-`;含非 ASCII 时与标题锚点一致做 encodeURIComponent。
|
|
82
|
+
* @param title Tab 显示名。
|
|
83
|
+
* @returns 可写入 query 的 id;标题为空时返回空串。
|
|
84
|
+
*/
|
|
85
|
+
var toMarkdownTabId = (title) => {
|
|
86
|
+
const normalized = title.trim().toLowerCase().replace(/\s+/gu, "-");
|
|
87
|
+
if (!normalized) return "";
|
|
88
|
+
return /[^\x20-\x7E]/u.test(normalized) ? encodeURIComponent(normalized) : normalized;
|
|
89
|
+
};
|
|
60
90
|
var PLAYGROUND_VIEWS = ["runtime", "files"];
|
|
61
91
|
var isPlaygroundView = (value) => typeof value === "string" && PLAYGROUND_VIEWS.includes(value);
|
|
62
92
|
var isRuntimeViewport = (viewport) => {
|
|
@@ -113,6 +143,11 @@ var validateTitleId = (propsData) => {
|
|
|
113
143
|
if (typeof propsData.id === "string") return "";
|
|
114
144
|
return "id 必须是字符串";
|
|
115
145
|
};
|
|
146
|
+
var validatePreviewScroller = (propsData) => {
|
|
147
|
+
if (!("previewScroller" in propsData)) return "";
|
|
148
|
+
if (typeof propsData.previewScroller === "boolean") return "";
|
|
149
|
+
return "previewScroller 必须是布尔值";
|
|
150
|
+
};
|
|
116
151
|
var parseRuntimeProps = (tokens) => {
|
|
117
152
|
for (const token of tokens) {
|
|
118
153
|
const sources = [];
|
|
@@ -134,7 +169,61 @@ var parseRuntimeProps = (tokens) => {
|
|
|
134
169
|
return {};
|
|
135
170
|
};
|
|
136
171
|
var renderPlaygroundAttrs = (propsData) => `data-props="${md.utils.escapeHtml(JSON.stringify(propsData))}"`;
|
|
137
|
-
|
|
172
|
+
var renderTabsHtml = (panels) => {
|
|
173
|
+
const parts = ["<div class=\"docs-markdown-tabs\" md data-tabs>", "<div class=\"docs-markdown-tabs__nav\" data-tabs-nav></div>"];
|
|
174
|
+
panels.forEach((panel, index) => {
|
|
175
|
+
const hidden = index === 0 ? "" : " hidden";
|
|
176
|
+
const id = md.utils.escapeHtml(panel.id);
|
|
177
|
+
const title = md.utils.escapeHtml(panel.title);
|
|
178
|
+
parts.push(`<div class="docs-markdown-tabs__panel" role="tabpanel" data-tab="${id}" data-tab-title="${title}"${hidden}>`, md.render(panel.content), "</div>");
|
|
179
|
+
});
|
|
180
|
+
parts.push("</div>\n");
|
|
181
|
+
return parts.join("");
|
|
182
|
+
};
|
|
183
|
+
md.core.ruler.after("block", "markdown-tabs", (state) => {
|
|
184
|
+
const panelSources = Array.isArray(state.env?.tabsPanelSources) ? state.env.tabsPanelSources : void 0;
|
|
185
|
+
for (let index = 0; index < state.tokens.length; index++) {
|
|
186
|
+
if (state.tokens[index].type !== tabsOpen) continue;
|
|
187
|
+
let depth = 1;
|
|
188
|
+
let closeIndex = index + 1;
|
|
189
|
+
for (; closeIndex < state.tokens.length; closeIndex++) {
|
|
190
|
+
if (state.tokens[closeIndex].type === tabsOpen) depth++;
|
|
191
|
+
if (state.tokens[closeIndex].type === tabsClose) depth--;
|
|
192
|
+
if (depth === 0) break;
|
|
193
|
+
}
|
|
194
|
+
const fences = state.tokens.slice(index + 1, closeIndex).filter((token) => token.type === "fence");
|
|
195
|
+
const placeholder = new state.Token("html_block", "", 0);
|
|
196
|
+
placeholder.block = true;
|
|
197
|
+
if (!fences.length) placeholder.content = renderTabsError("至少需要声明一个分栏");
|
|
198
|
+
else {
|
|
199
|
+
const panels = [];
|
|
200
|
+
const seen = /* @__PURE__ */ new Set();
|
|
201
|
+
let error = "";
|
|
202
|
+
for (const fence of fences) {
|
|
203
|
+
const title = parseTabFenceTitle(fence.info);
|
|
204
|
+
const id = toMarkdownTabId(title);
|
|
205
|
+
if (!title || !id) {
|
|
206
|
+
error = "每个分栏都必须声明标题";
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
if (seen.has(id)) {
|
|
210
|
+
error = `分栏 ${title} 的 id 重复`;
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
seen.add(id);
|
|
214
|
+
panels.push({
|
|
215
|
+
id,
|
|
216
|
+
title,
|
|
217
|
+
content: fence.content
|
|
218
|
+
});
|
|
219
|
+
panelSources?.push(fence.content);
|
|
220
|
+
}
|
|
221
|
+
placeholder.content = error ? renderTabsError(error) : renderTabsHtml(panels);
|
|
222
|
+
}
|
|
223
|
+
state.tokens.splice(index, closeIndex - index + 1, placeholder);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
md.core.ruler.after("markdown-tabs", "runtime-files", (state) => {
|
|
138
227
|
for (let index = 0; index < state.tokens.length; index++) {
|
|
139
228
|
if (state.tokens[index].type !== playgroundOpen) continue;
|
|
140
229
|
let depth = 1;
|
|
@@ -149,7 +238,7 @@ md.core.ruler.after("block", "runtime-files", (state) => {
|
|
|
149
238
|
const placeholder = new state.Token("html_block", "", 0);
|
|
150
239
|
placeholder.block = true;
|
|
151
240
|
const propsData = parseRuntimeProps(innerTokens);
|
|
152
|
-
const propsError = validateRuntimeViews(propsData) || validateRuntimeViewport(propsData) || validatePreviewInset(propsData) || validateExpandable(propsData) || validateTitle(propsData) || validateTitleId(propsData);
|
|
241
|
+
const propsError = validateRuntimeViews(propsData) || validateRuntimeViewport(propsData) || validatePreviewInset(propsData) || validateExpandable(propsData) || validateTitle(propsData) || validateTitleId(propsData) || validatePreviewScroller(propsData);
|
|
153
242
|
const propsAttr = renderPlaygroundAttrs(propsData);
|
|
154
243
|
if (!fences.length) placeholder.content = renderPlaygroundError("至少需要声明一个代码文件");
|
|
155
244
|
else if (propsError) placeholder.content = renderPlaygroundError(propsError);
|
|
@@ -187,7 +276,7 @@ md.core.ruler.after("block", "runtime-files", (state) => {
|
|
|
187
276
|
});
|
|
188
277
|
var renderAttrs = md.renderer.renderAttrs;
|
|
189
278
|
md.renderer.renderAttrs = (token) => {
|
|
190
|
-
const reg = new RegExp(`container_${PLAYGROUND}|fence|text`);
|
|
279
|
+
const reg = new RegExp(`container_${PLAYGROUND}|container_${TABS}|fence|text`);
|
|
191
280
|
if (token.nesting !== -1 && token.type && !reg.test(token.type)) token.attrPush([HTML_MD_SIGN, ""]);
|
|
192
281
|
return renderAttrs(token);
|
|
193
282
|
};
|
|
@@ -215,32 +304,39 @@ var getInlineSearchText = (token) => {
|
|
|
215
304
|
* @returns 文档标题、正文和按标题划分的小节。
|
|
216
305
|
*/
|
|
217
306
|
var parseMarkdownSearchSections = (content) => {
|
|
218
|
-
const tokens = md.parse(content, {});
|
|
219
307
|
const sections = [];
|
|
220
308
|
const documentParts = [];
|
|
221
309
|
let activeSection;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (token.type === "heading_open") {
|
|
225
|
-
const inline = tokens[index + 1];
|
|
226
|
-
if (inline?.type !== "inline") continue;
|
|
227
|
-
const title = getInlineSearchText(inline);
|
|
228
|
-
if (!title) continue;
|
|
229
|
-
activeSection = {
|
|
230
|
-
title,
|
|
231
|
-
anchor: token.attrGet("id") || "",
|
|
232
|
-
level: Number(token.tag.slice(1)) || 1,
|
|
233
|
-
text: ""
|
|
234
|
-
};
|
|
235
|
-
sections.push(activeSection);
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
if (token.type !== "inline" || tokens[index - 1]?.type === "heading_open") continue;
|
|
239
|
-
const text = getInlineSearchText(token);
|
|
240
|
-
if (!text) continue;
|
|
310
|
+
const consumeInline = (text) => {
|
|
311
|
+
if (!text) return;
|
|
241
312
|
documentParts.push(text);
|
|
242
313
|
if (activeSection) activeSection.text = normalizeSearchText(`${activeSection.text} ${text}`);
|
|
243
|
-
}
|
|
314
|
+
};
|
|
315
|
+
const walk = (source, withHeadings) => {
|
|
316
|
+
const tabsPanelSources = [];
|
|
317
|
+
const tokens = md.parse(source, { tabsPanelSources });
|
|
318
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
319
|
+
const token = tokens[index];
|
|
320
|
+
if (withHeadings && token.type === "heading_open") {
|
|
321
|
+
const inline = tokens[index + 1];
|
|
322
|
+
if (inline?.type !== "inline") continue;
|
|
323
|
+
const title = getInlineSearchText(inline);
|
|
324
|
+
if (!title) continue;
|
|
325
|
+
activeSection = {
|
|
326
|
+
title,
|
|
327
|
+
anchor: token.attrGet("id") || "",
|
|
328
|
+
level: Number(token.tag.slice(1)) || 1,
|
|
329
|
+
text: ""
|
|
330
|
+
};
|
|
331
|
+
sections.push(activeSection);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (token.type !== "inline" || tokens[index - 1]?.type === "heading_open") continue;
|
|
335
|
+
consumeInline(getInlineSearchText(token));
|
|
336
|
+
}
|
|
337
|
+
for (const panelSource of tabsPanelSources) walk(panelSource, false);
|
|
338
|
+
};
|
|
339
|
+
walk(content, true);
|
|
244
340
|
return {
|
|
245
341
|
title: sections.find((section) => section.level === 1)?.title || sections[0]?.title || "",
|
|
246
342
|
text: normalizeSearchText(documentParts.join(" ")),
|
|
@@ -248,11 +344,137 @@ var parseMarkdownSearchSections = (content) => {
|
|
|
248
344
|
};
|
|
249
345
|
};
|
|
250
346
|
//#endregion
|
|
347
|
+
//#region packages/markdown/src/tab-query.ts
|
|
348
|
+
var markdownTabQueryKey = Symbol("docs-markdown-tab-query");
|
|
349
|
+
var TAB_QUERY = "tab";
|
|
350
|
+
/**
|
|
351
|
+
* 不依赖 Vue Router 的默认适配器:读写 `location.search` 的 `tab`,
|
|
352
|
+
* 并用 `history.replaceState` 更新(供 examples / 单测使用)。
|
|
353
|
+
* @returns 可注入 TabsNav 的 get/set/subscribe 适配器。
|
|
354
|
+
*/
|
|
355
|
+
var createHistoryTabQueryAdapter = () => {
|
|
356
|
+
const read = () => {
|
|
357
|
+
try {
|
|
358
|
+
return new URLSearchParams(window.location.search).get(TAB_QUERY) || "";
|
|
359
|
+
} catch {
|
|
360
|
+
return "";
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
const write = (tab) => {
|
|
364
|
+
try {
|
|
365
|
+
const url = new URL(window.location.href);
|
|
366
|
+
if (tab) url.searchParams.set(TAB_QUERY, tab);
|
|
367
|
+
else url.searchParams.delete(TAB_QUERY);
|
|
368
|
+
window.history.replaceState(window.history.state, "", `${url.pathname}${url.search}${url.hash}`);
|
|
369
|
+
} catch {}
|
|
370
|
+
};
|
|
371
|
+
return {
|
|
372
|
+
get: read,
|
|
373
|
+
set: write,
|
|
374
|
+
subscribe: (listener) => {
|
|
375
|
+
const onPopState = () => listener();
|
|
376
|
+
window.addEventListener("popstate", onPopState);
|
|
377
|
+
return () => window.removeEventListener("popstate", onPopState);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region packages/markdown/src/tabs-nav.vue?vue&type=script&setup=true&lang.ts
|
|
383
|
+
var _hoisted_1$1 = ["aria-label"];
|
|
384
|
+
var _hoisted_2$1 = [
|
|
385
|
+
"id",
|
|
386
|
+
"aria-selected",
|
|
387
|
+
"aria-controls",
|
|
388
|
+
"tabindex",
|
|
389
|
+
"onClick"
|
|
390
|
+
];
|
|
391
|
+
//#endregion
|
|
392
|
+
//#region packages/markdown/src/tabs-nav.vue
|
|
393
|
+
var tabs_nav_default = /* @__PURE__ */ defineComponent({
|
|
394
|
+
__name: "tabs-nav",
|
|
395
|
+
props: {
|
|
396
|
+
items: {},
|
|
397
|
+
label: {},
|
|
398
|
+
adapter: {},
|
|
399
|
+
root: {},
|
|
400
|
+
groupId: {}
|
|
401
|
+
},
|
|
402
|
+
setup(__props) {
|
|
403
|
+
const props = __props;
|
|
404
|
+
const activeId = ref("");
|
|
405
|
+
let unsubscribe;
|
|
406
|
+
const tabButtonId = (id) => `${props.groupId}-tab-${id}`;
|
|
407
|
+
const tabPanelId = (id) => `${props.groupId}-panel-${id}`;
|
|
408
|
+
const resolveActive = () => {
|
|
409
|
+
const fromQuery = props.adapter.get();
|
|
410
|
+
const matched = props.items.find((item) => item.id === fromQuery);
|
|
411
|
+
activeId.value = matched?.id || props.items[0]?.id || "";
|
|
412
|
+
};
|
|
413
|
+
const syncPanels = () => {
|
|
414
|
+
props.root.querySelectorAll(".docs-markdown-tabs__panel").forEach((panel) => {
|
|
415
|
+
const id = panel.dataset.tab || "";
|
|
416
|
+
const selected = id === activeId.value;
|
|
417
|
+
panel.hidden = !selected;
|
|
418
|
+
panel.setAttribute("aria-labelledby", tabButtonId(id));
|
|
419
|
+
if (selected) {
|
|
420
|
+
panel.removeAttribute("hidden");
|
|
421
|
+
panel.id = tabPanelId(id);
|
|
422
|
+
} else {
|
|
423
|
+
panel.setAttribute("hidden", "");
|
|
424
|
+
panel.id = tabPanelId(id);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
};
|
|
428
|
+
const select = (id) => {
|
|
429
|
+
if (!id) return;
|
|
430
|
+
activeId.value = id;
|
|
431
|
+
props.adapter.set(id);
|
|
432
|
+
syncPanels();
|
|
433
|
+
};
|
|
434
|
+
onMounted(() => {
|
|
435
|
+
resolveActive();
|
|
436
|
+
syncPanels();
|
|
437
|
+
unsubscribe = props.adapter.subscribe?.(() => {
|
|
438
|
+
resolveActive();
|
|
439
|
+
syncPanels();
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
onBeforeUnmount(() => {
|
|
443
|
+
unsubscribe?.();
|
|
444
|
+
unsubscribe = void 0;
|
|
445
|
+
});
|
|
446
|
+
watch(() => props.items.map((item) => item.id).join("\0"), () => {
|
|
447
|
+
resolveActive();
|
|
448
|
+
syncPanels();
|
|
449
|
+
});
|
|
450
|
+
return (_ctx, _cache) => {
|
|
451
|
+
return openBlock(), createElementBlock("div", {
|
|
452
|
+
class: "docs-markdown-tabs__list",
|
|
453
|
+
role: "tablist",
|
|
454
|
+
"aria-label": __props.label
|
|
455
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
|
|
456
|
+
return openBlock(), createElementBlock("button", {
|
|
457
|
+
key: item.id,
|
|
458
|
+
type: "button",
|
|
459
|
+
class: normalizeClass(["docs-markdown-tabs__tab", { "docs-markdown-tabs__tab--active": item.id === activeId.value }]),
|
|
460
|
+
role: "tab",
|
|
461
|
+
id: tabButtonId(item.id),
|
|
462
|
+
"aria-selected": item.id === activeId.value,
|
|
463
|
+
"aria-controls": tabPanelId(item.id),
|
|
464
|
+
tabindex: item.id === activeId.value ? 0 : -1,
|
|
465
|
+
onClick: ($event) => select(item.id)
|
|
466
|
+
}, toDisplayString(item.title), 11, _hoisted_2$1);
|
|
467
|
+
}), 128))], 8, _hoisted_1$1);
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
//#endregion
|
|
251
472
|
//#region packages/markdown/src/directive.ts
|
|
252
473
|
var mountedApps = /* @__PURE__ */ new WeakMap();
|
|
253
474
|
var renderVersions = /* @__PURE__ */ new WeakMap();
|
|
254
475
|
var playgroundModule;
|
|
255
476
|
var loadPlayground = () => playgroundModule ||= import("@deot/docs-playground");
|
|
477
|
+
var defaultTabQuery = createHistoryTabQueryAdapter();
|
|
256
478
|
var cleanup = (el) => {
|
|
257
479
|
for (const app of mountedApps.get(el) || []) app.unmount();
|
|
258
480
|
mountedApps.delete(el);
|
|
@@ -261,12 +483,36 @@ var resolveBlockLanguage = (block) => {
|
|
|
261
483
|
return [...block.classList].find((className) => className.startsWith("language-"))?.slice(9) || "";
|
|
262
484
|
};
|
|
263
485
|
var serializePlaygroundDefaults = (value) => JSON.stringify(value || {});
|
|
486
|
+
var mountTabs = (el, apps, locale, adapter) => {
|
|
487
|
+
const label = locale.markdown?.tabs?.label || "Tabs";
|
|
488
|
+
el.querySelectorAll("[data-tabs]").forEach((root, index) => {
|
|
489
|
+
const nav = root.querySelector("[data-tabs-nav]");
|
|
490
|
+
if (!nav) return;
|
|
491
|
+
const items = [...root.querySelectorAll(".docs-markdown-tabs__panel")].map((panel) => ({
|
|
492
|
+
id: panel.dataset.tab || "",
|
|
493
|
+
title: panel.dataset.tabTitle || panel.dataset.tab || ""
|
|
494
|
+
})).filter((item) => item.id && item.title);
|
|
495
|
+
if (!items.length) return;
|
|
496
|
+
const groupId = `docs-markdown-tabs-${index}`;
|
|
497
|
+
const app = createApp({ render: () => h(tabs_nav_default, {
|
|
498
|
+
items,
|
|
499
|
+
label,
|
|
500
|
+
adapter,
|
|
501
|
+
root,
|
|
502
|
+
groupId
|
|
503
|
+
}) });
|
|
504
|
+
app.mount(nav);
|
|
505
|
+
apps.push(app);
|
|
506
|
+
});
|
|
507
|
+
};
|
|
264
508
|
var render = async (el, binding) => {
|
|
265
509
|
cleanup(el);
|
|
266
510
|
const version = (renderVersions.get(el) || 0) + 1;
|
|
267
511
|
renderVersions.set(el, version);
|
|
268
512
|
el.innerHTML = binding.value.source ? Markdown.render(binding.value.source) : "";
|
|
269
513
|
const apps = [];
|
|
514
|
+
const adapter = binding.value.tabQuery || defaultTabQuery;
|
|
515
|
+
mountTabs(el, apps, binding.value.locale, adapter);
|
|
270
516
|
const blocks = el.querySelectorAll("pre code");
|
|
271
517
|
const playgrounds = el.querySelectorAll("div[data-playground]");
|
|
272
518
|
if (!blocks.length && !playgrounds.length) {
|
|
@@ -316,7 +562,7 @@ var render = async (el, binding) => {
|
|
|
316
562
|
mountedApps.set(el, apps);
|
|
317
563
|
};
|
|
318
564
|
var update = (el, binding) => {
|
|
319
|
-
if (binding.value.source !== binding.oldValue?.source || binding.value.locale !== binding.oldValue?.locale || serializePlaygroundDefaults(binding.value.playground) !== serializePlaygroundDefaults(binding.oldValue?.playground)) render(el, binding);
|
|
565
|
+
if (binding.value.source !== binding.oldValue?.source || binding.value.locale !== binding.oldValue?.locale || binding.value.tabQuery !== binding.oldValue?.tabQuery || serializePlaygroundDefaults(binding.value.playground) !== serializePlaygroundDefaults(binding.oldValue?.playground)) render(el, binding);
|
|
320
566
|
};
|
|
321
567
|
var vMarkdown = {
|
|
322
568
|
mounted: (el, binding) => void render(el, binding),
|
|
@@ -427,7 +673,13 @@ var getIndicatorInlineOffset = (root, rail, side, viewportWidth) => {
|
|
|
427
673
|
//#endregion
|
|
428
674
|
//#region packages/markdown/src/headings.ts
|
|
429
675
|
var HEADING_SELECTOR = "h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]";
|
|
430
|
-
var SKIP_CLOSEST =
|
|
676
|
+
var SKIP_CLOSEST = [
|
|
677
|
+
"pre",
|
|
678
|
+
".docs-markdown-code-preview",
|
|
679
|
+
"[data-playground][data-code]",
|
|
680
|
+
"[data-playground][data-files]",
|
|
681
|
+
".docs-markdown-tabs__panel[hidden]"
|
|
682
|
+
].join(", ");
|
|
431
683
|
/**
|
|
432
684
|
* 去掉 markdown-it-anchor 的井号后,读取标题的可见文案。
|
|
433
685
|
* @param element 当前标题节点。
|
|
@@ -972,6 +1224,7 @@ var wrapper_default = /* @__PURE__ */ defineComponent({
|
|
|
972
1224
|
locale: {},
|
|
973
1225
|
theme: { default: "default" },
|
|
974
1226
|
playground: { default: () => ({}) },
|
|
1227
|
+
tabQuery: {},
|
|
975
1228
|
modelValue: {},
|
|
976
1229
|
value: {}
|
|
977
1230
|
},
|
|
@@ -987,11 +1240,15 @@ var wrapper_default = /* @__PURE__ */ defineComponent({
|
|
|
987
1240
|
return typeof props.indicator === "object" ? props.indicator : {};
|
|
988
1241
|
});
|
|
989
1242
|
const resolvedTheme = computed(() => props.theme === "traditional" ? "traditional" : "default");
|
|
1243
|
+
const injectedTabQuery = inject(markdownTabQueryKey, null);
|
|
1244
|
+
const historyTabQuery = createHistoryTabQueryAdapter();
|
|
1245
|
+
const resolvedTabQuery = computed(() => props.tabQuery || injectedTabQuery || historyTabQuery);
|
|
990
1246
|
const source = computed(() => typeof props.modelValue === "string" ? props.modelValue : props.value);
|
|
991
1247
|
const markdownBinding = computed(() => ({
|
|
992
1248
|
source: source.value,
|
|
993
1249
|
locale: locale.value,
|
|
994
|
-
playground: props.playground
|
|
1250
|
+
playground: props.playground,
|
|
1251
|
+
tabQuery: resolvedTabQuery.value
|
|
995
1252
|
}));
|
|
996
1253
|
return (_ctx, _cache) => {
|
|
997
1254
|
return openBlock(), createElementBlock("div", { class: normalizeClass(["docs-markdown", `docs-markdown--${resolvedTheme.value}`]) }, [indicatorOptions.value && content.value ? (openBlock(), createBlock(indicator_default, {
|
|
@@ -1007,4 +1264,4 @@ var wrapper_default = /* @__PURE__ */ defineComponent({
|
|
|
1007
1264
|
}
|
|
1008
1265
|
});
|
|
1009
1266
|
//#endregion
|
|
1010
|
-
export { wrapper_default as Markdown, collectMarkdownHeadings, getMarkdownHeadingTitle, parseMarkdownSearchSections };
|
|
1267
|
+
export { wrapper_default as Markdown, collectMarkdownHeadings, createHistoryTabQueryAdapter, getMarkdownHeadingTitle, markdownTabQueryKey, parseMarkdownSearchSections, toMarkdownTabId };
|