diff --git a/packages/md-enhance/__tests__/unit/__snapshots__/codeTabs.spec.ts.snap b/packages/md-enhance/__tests__/unit/__snapshots__/codeTabs.spec.ts.snap index c0c869ddd81e..82eac7461eb2 100644 --- a/packages/md-enhance/__tests__/unit/__snapshots__/codeTabs.spec.ts.snap +++ b/packages/md-enhance/__tests__/unit/__snapshots__/codeTabs.spec.ts.snap @@ -1,73 +1,97 @@ // Vitest Snapshot v1 exports[`code tabs > shoud render mutiple block 1`] = ` -" +" " `; exports[`code tabs > shoud render mutiple block 2`] = ` -" +" " `; exports[`code tabs > shoud render single block 1`] = ` -" +" " `; exports[`code tabs > shoud render single block 2`] = ` -" +" " `; exports[`code tabs > shoud support active 1`] = ` -" +" " `; exports[`code tabs > shoud support active 2`] = ` -" +" " `; exports[`code tabs > shoud support active 3`] = ` -" +" " `; exports[`code tabs > shoud support active 4`] = ` -" +" + +" +`; + +exports[`code tabs > shoud support id 1`] = ` +" + +" +`; + +exports[`code tabs > shoud support id 2`] = ` +" + +" +`; + +exports[`code tabs > shoud support id 3`] = ` +" + +" +`; + +exports[`code tabs > shoud support id 4`] = ` +" " `; exports[`code tabs > should ignore other items 1`] = ` -" +" " `; exports[`code tabs > should ignore other items 2`] = ` -" +" " `; exports[`code tabs > should ignore other items 3`] = ` -" +" " `; exports[`code tabs > should ignore other items 4`] = ` -" +" " `; diff --git a/packages/md-enhance/__tests__/unit/codeTabs.spec.ts b/packages/md-enhance/__tests__/unit/codeTabs.spec.ts index 79bc3da941e1..d8885d7314cf 100644 --- a/packages/md-enhance/__tests__/unit/codeTabs.spec.ts +++ b/packages/md-enhance/__tests__/unit/codeTabs.spec.ts @@ -69,6 +69,55 @@ const a = 1; ).toMatchSnapshot(); }); + it("shoud support id", () => { + expect( + markdownIt.render(` +::: code-tabs#event + +@tab js + +\`\`\`js +const a = 1; +\`\`\` + +::: + `) + ).toMatchSnapshot(); + + expect( + markdownIt.render(` +::: code-tabs#event-id +@tab js +\`\`\`js +const a = 1; +\`\`\` +::: + `) + ).toMatchSnapshot(); + + expect( + markdownIt.render(` +::: code-tabs#id with space +@tab js +\`\`\`js +const a = 1; +\`\`\` +::: + `) + ).toMatchSnapshot(); + + expect( + markdownIt.render(` +::: code-tabs # id starts and having space in the end +@tab js +\`\`\`js +const a = 1; +\`\`\` +::: + `) + ).toMatchSnapshot(); + }); + it("shoud support active", () => { expect( markdownIt.render(` diff --git a/packages/md-enhance/__tests__/unit/demo.spec.ts b/packages/md-enhance/__tests__/unit/demo.spec.ts index fbf91fc85edc..29fe89159ac0 100644 --- a/packages/md-enhance/__tests__/unit/demo.spec.ts +++ b/packages/md-enhance/__tests__/unit/demo.spec.ts @@ -110,8 +110,7 @@ h1 { \`\`\` ::: -`, - {} +` ) ).toMatchSnapshot(); }); diff --git a/packages/md-enhance/src/client/components/CodeTabs.ts b/packages/md-enhance/src/client/components/CodeTabs.ts index 877070cbe0ef..7ed2e02a9a8b 100644 --- a/packages/md-enhance/src/client/components/CodeTabs.ts +++ b/packages/md-enhance/src/client/components/CodeTabs.ts @@ -1,14 +1,19 @@ -import { defineComponent, h, ref } from "vue"; +import { useStorage } from "@vueuse/core"; +import { defineComponent, h, ref, watch } from "vue"; import type { PropType, VNode } from "vue"; import "../styles/code-tabs.scss"; +const codeTabStore = useStorage>( + "VUEPRESS_CODE_TAB_STORE", + {} +); + export default defineComponent({ name: "CodeTabs", props: { active: { type: Number, default: 0 }, - // active: { type: Number, required: true }, data: { type: Array as PropType< { @@ -16,17 +21,29 @@ export default defineComponent({ title: string; }[] >, - default: () => [], + required: true, + }, + codeId: { + type: String, + default: "", }, - // data: { type: Array as PropType, required: true }, }, setup(props) { + const getInitialIndex = (): number => { + if (props.codeId) { + const valueIndex = props.data.findIndex( + ({ title }) => codeTabStore.value[props.codeId] === title + ); + + if (valueIndex !== -1) return valueIndex; + } + + return props.active; + }; + // index of current active item - const activeIndex = ref( - // initialized by props - props.active - ); + const activeIndex = ref(getInitialIndex()); // refs of the tab buttons const tabRefs = ref([]); @@ -55,8 +72,22 @@ export default defineComponent({ event.preventDefault(); activatePrev(); } + + if (props.codeId) + codeTabStore.value[props.codeId] = props.data[activeIndex.value].title; }; + watch( + () => codeTabStore.value[props.codeId], + (newValue, oldValue) => { + if (props.codeId && newValue !== oldValue) { + const index = props.data.findIndex(({ title }) => title === newValue); + + if (index !== -1) activeIndex.value = index; + } + } + ); + return (): VNode | null => { return props.data.length ? h("div", { class: "code-tabs" }, [ diff --git a/packages/md-enhance/src/node/markdown-it/codeTabs.ts b/packages/md-enhance/src/node/markdown-it/codeTabs.ts index 69e562ec0fad..81a4181858b4 100644 --- a/packages/md-enhance/src/node/markdown-it/codeTabs.ts +++ b/packages/md-enhance/src/node/markdown-it/codeTabs.ts @@ -27,7 +27,9 @@ export const codeTabs: PluginSimple = (md) => { const markup = state.src.slice(start, pos); const params = state.src.slice(pos, max); - if (params.trim() !== "code-tabs") return false; + const [name, id = ""] = params.split("#", 2); + + if (name.trim() !== "code-tabs") return false; // Since start is found, we can report success here in validation mode if (silent) return true; @@ -91,7 +93,8 @@ export const codeTabs: PluginSimple = (md) => { openToken.markup = markup; openToken.block = true; - openToken.info = params; + openToken.info = name; + openToken.meta = { id: id.trim() }; openToken.map = [startLine, nextLine - (autoClosed ? 1 : 0)]; state.md.block.tokenize( @@ -227,10 +230,13 @@ export const codeTabs: PluginSimple = (md) => { env, self ): string => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { meta } = tokens[index]; + let inCodeTab = false; let foundFence = false; let codeTabIndex = -1; - let activeIndex = 0; + let activeIndex = -1; let title = ""; const codeTabsData: { code: string; title: string }[] = []; @@ -275,9 +281,13 @@ export const codeTabs: PluginSimple = (md) => { } } - return `\n`; + return `\n`; }; md.renderer.rules.code_tabs_close = (): string => "\n";