diff --git a/.dumi/rehypeChangelog.ts b/.dumi/rehypeChangelog.ts new file mode 100644 index 0000000000..0dce3d2ba0 --- /dev/null +++ b/.dumi/rehypeChangelog.ts @@ -0,0 +1,89 @@ +import type { UnifiedTransformer } from 'dumi'; +import { unistUtilVisit } from 'dumi'; +import set from 'lodash/set'; +let hastToString: typeof import('hast-util-to-string').toString; + +// workaround to import pure esm module +(async () => { + ({ toString: hastToString } = await import('hast-util-to-string')); +})(); + +const COMPONENT_NAME = 'RefinedChangelog'; + +function rehypeChangelog(): UnifiedTransformer { + return (tree, vFile) => { + const { filename } = vFile.data.frontmatter as any; + + // 只处理 changelog 文件 + if (!/^changelog\.\S+\.md$/i.test(filename)) return; + + const nodesToWrap: { parent: any; startIdx: number }[] = []; + const WRAPPER_FLAG = 'data-changelog-wrapped'; // 包裹容器唯一标识 + + unistUtilVisit.visit(tree, 'element', (node, idx, parent) => { + if (node.properties?.[WRAPPER_FLAG]) return unistUtilVisit.SKIP; + + if ( + idx !== undefined && + parent && + idx! + 2 < parent.children.length && + node.tagName === 'h2' && + parent.children[idx! + 1].tagName === 'p' && + parent.children[idx! + 2].tagName === 'ul' + ) { + nodesToWrap.push({ parent, startIdx: idx! }); + } + }); + + nodesToWrap.reverse().forEach(({ parent, startIdx }) => { + const [heading, date, list] = parent.children.splice(startIdx, 3); + + const version = hastToString(heading); + const dateStr = hastToString(date); + + const headingWrap = { + type: 'element', + tagName: `${COMPONENT_NAME}.Version`, + // 为标签添加语义化 className (下面同理) + children: [set(heading, 'properties.className', 'changelog-version')], + }; + + const dateWrap = { + type: 'element', + tagName: `${COMPONENT_NAME}.Date`, + children: [set(date, 'properties.className', 'changelog-date')], + }; + + const listWrap = { + type: 'element', + tagName: `${COMPONENT_NAME}.Details`, + children: [set(list, 'properties.className', 'changelog-details')], + }; + + const wrapper = { + type: 'element', + tagName: COMPONENT_NAME, + properties: { + [WRAPPER_FLAG]: true, + }, + JSXAttributes: [ + { + type: 'JSXAttribute', + name: 'version', + value: JSON.stringify(version), + }, + { + type: 'JSXAttribute', + name: 'date', + value: JSON.stringify(dateStr), + }, + ], + children: [headingWrap, dateWrap, listWrap], + }; + + parent.children.splice(startIdx, 0, wrapper); + }); + }; +} + +export default rehypeChangelog; diff --git a/.dumi/theme/builtins/RefinedChangelog/index.tsx b/.dumi/theme/builtins/RefinedChangelog/index.tsx new file mode 100644 index 0000000000..9095d95646 --- /dev/null +++ b/.dumi/theme/builtins/RefinedChangelog/index.tsx @@ -0,0 +1,131 @@ +import * as React from 'react'; +import { BugOutlined } from '@ant-design/icons'; +import { Button, Flex, Popover, theme } from 'antd'; +import { createStyles } from 'antd-style'; +import dayjs, { Dayjs } from 'dayjs'; + +import useLocale from '../../../hooks/useLocale'; +import { matchDeprecated } from '../../utils'; + +interface RefinedChangelogProps { + version?: string; + date?: string; +} + +interface ContextProps { + version: string; + date?: Dayjs; + isDeprecated?: boolean; + reason?: string[]; +} + +const ChangelogContext = React.createContext({ + version: '0.0.0', +}); + +const locales = { + cn: { + deprecatedTitle: '🚨 该版本存在缺陷, 请升级至下一个新版本', + }, + en: { + deprecatedTitle: '🚨 This version has defects, please upgrade to the next version', + }, +}; + +const useStyle = createStyles(({ token, css }) => ({ + container: css` + margin-block: ${token.margin}px; + padding: ${token.padding}px; + + .changelog-version { + line-height: ${token.lineHeight} !important; + margin: 0 !important; + } + `, + isDeprecated: css``, +})); + +function RefinedChangelog(props: React.PropsWithChildren) { + const { version, date, children } = props; + + const { styles, cx } = useStyle(); + + const memoizedValue = React.useMemo(() => { + const realVersion = version || '0.0.0'; + const bugVersionInfo = matchDeprecated(realVersion); + return { + version: realVersion, + isDeprecated: !!bugVersionInfo?.match, + reason: bugVersionInfo?.reason, + date: date ? dayjs(date) : undefined, + }; + }, [version, date]); + + return ( + +
+ {children} +
+
+ ); +} + +function Version({ children }: React.PropsWithChildren) { + const { isDeprecated, reason } = React.use(ChangelogContext); + const { token } = theme.useToken(); + const [locale] = useLocale(locales); + + if (!isDeprecated) { + return children; + } + + const reasonContent = ( + + {reason?.map((item, index) => ( + + ))} + + ); + + return ( + + {children} + + + + + ); +} + +function DateComp(props: React.PropsWithChildren) { + return props.children; +} + +function Details(props: React.PropsWithChildren) { + return props.children; +} + +export default Object.assign(RefinedChangelog, { + Version, + Date: DateComp, + Details, +}); diff --git a/.dumi/theme/common/ComponentChangelog/ComponentChangelog.tsx b/.dumi/theme/common/ComponentChangelog/ComponentChangelog.tsx index 72979a13a1..ed22fe1c85 100644 --- a/.dumi/theme/common/ComponentChangelog/ComponentChangelog.tsx +++ b/.dumi/theme/common/ComponentChangelog/ComponentChangelog.tsx @@ -3,19 +3,13 @@ import { BugOutlined } from '@ant-design/icons'; import { Button, Drawer, Flex, Grid, Popover, Tag, Timeline, Typography } from 'antd'; import type { TimelineItemProps } from 'antd'; import { createStyles } from 'antd-style'; -import semver from 'semver'; -import deprecatedVersions from '../../../../BUG_VERSIONS.json'; import useFetch from '../../../hooks/useFetch'; import useLocale from '../../../hooks/useLocale'; import useLocation from '../../../hooks/useLocation'; +import { matchDeprecated } from '../../utils'; import Link from '../Link'; -interface MatchDeprecatedResult { - match?: string; - reason: string[]; -} - interface ChangelogInfo { version: string; changelog: string; @@ -24,17 +18,6 @@ interface ChangelogInfo { releaseDate: string; } -function matchDeprecated(v: string): MatchDeprecatedResult { - const match = Object.keys(deprecatedVersions).find((depreciated) => - semver.satisfies(v, depreciated), - ); - const reason = deprecatedVersions[match as keyof typeof deprecatedVersions] || []; - return { - match, - reason: Array.isArray(reason) ? reason : [reason], - }; -} - const useStyle = createStyles(({ token, css }) => ({ listWrap: css` > li { diff --git a/.dumi/theme/slots/Content/index.tsx b/.dumi/theme/slots/Content/index.tsx index 01c5c49f31..17b0100867 100644 --- a/.dumi/theme/slots/Content/index.tsx +++ b/.dumi/theme/slots/Content/index.tsx @@ -1,5 +1,5 @@ import React, { useLayoutEffect, useMemo, useState } from 'react'; -import { Col, Flex, Skeleton, Space, Typography } from 'antd'; +import { Col, Flex, FloatButton, Skeleton, Space, Typography } from 'antd'; import classNames from 'classnames'; import { FormattedMessage, useRouteMeta } from 'dumi'; @@ -92,7 +92,10 @@ const Content: React.FC = ({ children }) => { designUrl={meta.frontmatter.designUrl} /> )} -
{children}
+
+ {children} + +
+ semver.satisfies(v, depreciated), + ); + const reason = deprecatedVersions[match as keyof typeof deprecatedVersions] || []; + return { + match, + reason: Array.isArray(reason) ? reason : [reason], + }; +} + export const getThemeConfig = () => themeConfig; diff --git a/.dumirc.ts b/.dumirc.ts index f645c2d937..3bea8e16b8 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -4,6 +4,7 @@ import * as fs from 'fs-extra'; import os from 'node:os'; import rehypeAntd from './.dumi/rehypeAntd'; +import rehypeChangelog from './.dumi/rehypeChangelog'; import remarkAntd from './.dumi/remarkAntd'; import remarkAnchor from './.dumi/remarkAnchor'; import { version } from './package.json'; @@ -52,7 +53,7 @@ export default defineConfig({ // https://github.com/ant-design/ant-design/issues/46628 '@ant-design/icons$': '@ant-design/icons/lib', }, - extraRehypePlugins: [rehypeAntd], + extraRehypePlugins: [rehypeAntd, rehypeChangelog], extraRemarkPlugins: [remarkAntd, remarkAnchor], metas: [ { name: 'theme-color', content: '#1677ff' }, diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 435481cc6e..33d70cb1fb 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -544,7 +544,7 @@ Last version of the Dragon Year, Happy Chinese New Year! 🐲 - 🐞 Fix Transfer width issue when customized as TableTransfer. [#50974](https://github.com/ant-design/ant-design/pull/50974) [@zombieJ](https://github.com/zombieJ) - 🇹🇷 Add Turkish text for `filterCheckall` in Table component. [#51000](https://github.com/ant-design/ant-design/pull/51000) [@ytahirkose](https://github.com/ytahirkose) -## 5.21.0 🔥 +## 5.21.0 `2024-09-22` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index d69841f359..6b8713e69f 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -547,7 +547,7 @@ tag: vVERSION - 💄 修复 Transfer 在自定义为 TableTransfer 时,宽度不正确的问题。[#50974](https://github.com/ant-design/ant-design/pull/50974) [@zombieJ](https://github.com/zombieJ) - 🇹🇷 补充 Table 组件 `filterCheckall` 的土耳其语文案。[#51000](https://github.com/ant-design/ant-design/pull/51000) [@ytahirkose](https://github.com/ytahirkose) -## 5.21.0 🔥 +## 5.21.0 `2024-09-22` diff --git a/package.json b/package.json index 40982bf347..2f59502588 100644 --- a/package.json +++ b/package.json @@ -254,6 +254,7 @@ "gh-pages": "^6.2.0", "github-slugger": "^2.0.0", "glob": "^11.0.0", + "hast-util-to-string": "^3.0.1", "html2sketch": "^1.0.2", "http-server": "^14.1.1", "husky": "^9.1.6",