From 48b8efbfde0bc29d955392b5c2681a19bf383f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9D=91=BE=F0=9D=92=96=F0=9D=92=99=F0=9D=92=89?= Date: Wed, 2 Apr 2025 11:03:02 +0800 Subject: [PATCH] chore(site): markdown supports custom anchors (#53316) * chore(site): markdown supports custom anchors wait: https://github.com/umijs/dumi/pull/2268 * chore: update deps * chore: update * chore: comment * chore(deps): bump dumi to `2.4.20` * chore: temp scripts * Revert "chore: temp scripts" This reverts commit 49a2ab86c45575ce65acbc024fa96307a5941f72. --- .dumi/remarkAnchor.ts | 86 ++++++++++++++++++++++++++++++++ .dumirc.ts | 3 +- components/button/index.en-US.md | 4 +- components/button/index.zh-CN.md | 14 +++--- package.json | 3 +- 5 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 .dumi/remarkAnchor.ts diff --git a/.dumi/remarkAnchor.ts b/.dumi/remarkAnchor.ts new file mode 100644 index 0000000000..25df220873 --- /dev/null +++ b/.dumi/remarkAnchor.ts @@ -0,0 +1,86 @@ +import { unistUtilVisit } from 'dumi'; +import type { UnifiedTransformer } from 'dumi'; + +let toSlug: typeof import('github-slugger').slug; + +// workaround to import pure esm module +(async () => { + ({ slug: toSlug } = await import('github-slugger')); +})(); + +const isNil = (value: any) => value == null; + +const toArr = (value: T | T[]) => { + if (isNil(value)) return []; + return Array.isArray(value) ? value : [value]; +}; + +const patch = (context: Record, key: string, value: any) => { + if (!context[key]) { + context[key] = value; + } + return context[key]; +}; + +interface Options { + level?: number; +} + +const remarkAnchor = (opt: Options = {}): UnifiedTransformer => { + // https://regex101.com/r/WDjkK0/1 + const RE = /\s*\{#([^}]+)\}$/; + + const realOpt = { + level: [1, 2, 3, 4, 5, 6], + ...opt, + }; + + return function transformer(tree) { + const ids = new Set(); + + unistUtilVisit.visit(tree, 'heading', (node) => { + if (toArr(realOpt.level).indexOf(node.depth) === -1) { + return unistUtilVisit.CONTINUE; + } + + const lastChild = node.children.at(-1); + + if (lastChild?.type === 'text') { + const text = lastChild.value; + const match = text.match(RE); + if (match) { + const id = match[1]; + if (id !== toSlug(id)) { + throw new Error( + `Expected header ID to be a valid slug. You specified: {#${id}}. Replace it with: {#${toSlug(id)}}`, + ); + } + + node.data ??= {}; + node.data.hProperties = { ...node.data.hProperties, id }; + + lastChild.value = text.replace(RE, ''); + + if (lastChild.value === '') { + node.children.pop(); + } + if (ids.has(id)) { + throw new Error(`Cannot have a duplicate header with id "${id}" on the page. + Rename the section or give it an explicit unique ID. For example: #### Arguments {#setstate-arguments}`); + } + + ids.add(id); + + const data = patch(node, 'data', {}); + patch(data, 'id', id); + patch(data, 'htmlAttributes', {}); + patch(data, 'hProperties', {}); + patch(data.htmlAttributes, 'id', id); + patch(data.hProperties, 'id', id); + } + } + }); + }; +}; + +export default remarkAnchor; diff --git a/.dumirc.ts b/.dumirc.ts index 57672e5d8e..f645c2d937 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -5,6 +5,7 @@ import os from 'node:os'; import rehypeAntd from './.dumi/rehypeAntd'; import remarkAntd from './.dumi/remarkAntd'; +import remarkAnchor from './.dumi/remarkAnchor'; import { version } from './package.json'; export default defineConfig({ @@ -52,7 +53,7 @@ export default defineConfig({ '@ant-design/icons$': '@ant-design/icons/lib', }, extraRehypePlugins: [rehypeAntd], - extraRemarkPlugins: [remarkAntd], + extraRemarkPlugins: [remarkAntd, remarkAnchor], metas: [ { name: 'theme-color', content: '#1677ff' }, { name: 'build-time', content: Date.now().toString() }, diff --git a/components/button/index.en-US.md b/components/button/index.en-US.md index 3c7964fda6..0cac255a4c 100644 --- a/components/button/index.en-US.md +++ b/components/button/index.en-US.md @@ -96,7 +96,7 @@ It accepts all props which native buttons support. ## FAQ -### How to choose type and color & variant? +### How to choose type and color & variant? {#faq-type-color-variant} Type is essentially syntactic sugar for colors and variants. It internally provides a set of mapping relationships between colors and variants for the type. If both exist at the same time, the colors and variants will be used first. @@ -112,7 +112,7 @@ Equivalent ``` -### How to close the click wave effect? +### How to close the click wave effect? {#faq-close-wave-effect} If you don't need this feature, you can set `disabled` of `wave` in [ConfigProvider](/components/config-provider#api) as `true`. diff --git a/components/button/index.zh-CN.md b/components/button/index.zh-CN.md index e281fc491d..d6428867c5 100644 --- a/components/button/index.zh-CN.md +++ b/components/button/index.zh-CN.md @@ -12,7 +12,7 @@ group: order: 1 --- -## 何时使用 +## 何时使用 {#when-to-use} 标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。 @@ -33,7 +33,7 @@ group: [完整设计指南](https://ant.design/docs/spec/buttons-cn) -## 代码演示 +## 代码演示 {#examples} 语法糖 @@ -92,17 +92,17 @@ group: > type PresetColors = 'blue' | 'purple' | 'cyan' | 'green' | 'magenta' | 'pink' | 'red' | 'orange' | 'yellow' | 'volcano' | 'geekblue' | 'lime' | 'gold'; -## Semantic DOM +## Semantic DOM {#semantic-dom} -## 主题变量(Design Token) +## 主题变量(Design Token){#design-token} ## FAQ -### 类型和颜色与变体如何选择? +### 类型和颜色与变体如何选择? {#faq-type-color-variant} 类型本质上是颜色与变体的语法糖,内部为其提供了一组颜色与变体的映射关系。如果两者同时存在,优先使用颜色与变体。 @@ -118,7 +118,7 @@ group: ``` -### 如何关闭点击波纹效果? +### 如何关闭点击波纹效果? {#faq-close-wave-effect} 如果你不需要这个特性,可以设置 [ConfigProvider](/components/config-provider-cn#api) 的 `wave` 的 `disabled` 为 `true`。 @@ -135,6 +135,6 @@ group: } -## 设计指引 +## 设计指引 {#design-guide} - [我的按钮究竟该放哪儿!?| Ant Design 4.0 系列分享](https://zhuanlan.zhihu.com/p/109644406) diff --git a/package.json b/package.json index a017de3f8f..3ad4a690ac 100644 --- a/package.json +++ b/package.json @@ -239,7 +239,7 @@ "cypress-image-diff-html-report": "2.2.0", "dekko": "^0.2.1", "dotenv": "^16.4.5", - "dumi": "~2.4.17", + "dumi": "~2.4.20", "dumi-plugin-color-chunk": "^2.1.0", "env-paths": "^3.0.0", "eslint": "^9.23.0", @@ -251,6 +251,7 @@ "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", "gh-pages": "^6.2.0", + "github-slugger": "^2.0.0", "glob": "^11.0.0", "html2sketch": "^1.0.2", "http-server": "^14.1.1",