mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 02:49:18 +08:00
@@ -1,67 +1,60 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { RightCircleOutlined } from '@ant-design/icons';
|
||||
import type { TreeGraph } from '@antv/g6';
|
||||
import { Flex } from 'antd';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import { renderReactToHTMLString } from '../../../theme/utils/renderReactToHTML';
|
||||
import { useMermaidCode } from './useMermaidCode';
|
||||
|
||||
interface BehaviorMapItem {
|
||||
export interface BehaviorMapItem {
|
||||
id: string;
|
||||
label: string;
|
||||
targetType?: 'mvp' | 'extension';
|
||||
children?: BehaviorMapItem[];
|
||||
link?: string;
|
||||
collapsed?: boolean;
|
||||
type?: 'behavior-start-node' | 'behavior-sub-node';
|
||||
}
|
||||
|
||||
const dataTransform = (rootData: BehaviorMapItem) => {
|
||||
const changeData = (data: BehaviorMapItem, level = 0) => {
|
||||
const clonedData: BehaviorMapItem = { ...data };
|
||||
switch (level) {
|
||||
case 0:
|
||||
clonedData.type = 'behavior-start-node';
|
||||
break;
|
||||
case 1:
|
||||
clonedData.type = 'behavior-sub-node';
|
||||
clonedData.collapsed = true;
|
||||
break;
|
||||
default:
|
||||
clonedData.type = 'behavior-sub-node';
|
||||
break;
|
||||
}
|
||||
if (Array.isArray(data.children)) {
|
||||
clonedData.children = data.children.map((child) => changeData(child, level + 1));
|
||||
}
|
||||
return clonedData;
|
||||
};
|
||||
return changeData(rootData);
|
||||
};
|
||||
export interface BehaviorMapProps {
|
||||
data: BehaviorMapItem;
|
||||
}
|
||||
|
||||
const useStyle = createStyles(({ cssVar }) => ({
|
||||
container: css`
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
min-height: 600px;
|
||||
height: fit-content;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: ${cssVar.borderRadiusLG};
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`,
|
||||
chartContainer: css`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
> svg {
|
||||
margin: auto;
|
||||
}
|
||||
`,
|
||||
title: css`
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
inset-inline-start: 20px;
|
||||
font-size: ${cssVar.fontSizeLG};
|
||||
z-index: 10;
|
||||
`,
|
||||
tips: css`
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
inset-inline-end: 20px;
|
||||
z-index: 10;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
`,
|
||||
mvp: css`
|
||||
margin-inline-end: ${cssVar.marginMD};
|
||||
@@ -72,7 +65,7 @@ const useStyle = createStyles(({ cssVar }) => ({
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-inline-end: ${cssVar.marginXS};
|
||||
background-color: #1677ff;
|
||||
background-color: rgb(22, 119, 255);
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
}
|
||||
@@ -85,7 +78,7 @@ const useStyle = createStyles(({ cssVar }) => ({
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-inline-end: ${cssVar.marginXS};
|
||||
background-color: #a0a0a0;
|
||||
background-color: rgb(160, 160, 160);
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
}
|
||||
@@ -105,219 +98,66 @@ const locales = {
|
||||
},
|
||||
};
|
||||
|
||||
export interface BehaviorMapProps {
|
||||
data: BehaviorMapItem;
|
||||
}
|
||||
|
||||
const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const chartRef = useRef<HTMLDivElement>(null);
|
||||
const { styles } = useStyle();
|
||||
const [locale] = useLocale(locales);
|
||||
|
||||
const meta = useRouteMeta();
|
||||
|
||||
const graphRef = useRef<TreeGraph>(null);
|
||||
const mermaidCode = useMermaidCode(data);
|
||||
|
||||
useEffect(() => {
|
||||
import('@antv/g6').then((G6) => {
|
||||
G6.registerNode('behavior-start-node', {
|
||||
draw: (cfg, group) => {
|
||||
const textWidth = G6.Util.getTextSize(cfg!.label, 16)[0];
|
||||
const size = [textWidth + 20 * 2, 48];
|
||||
const keyShape = group!.addShape('rect', {
|
||||
name: 'start-node',
|
||||
attrs: {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
y: -size[1] / 2,
|
||||
radius: 8,
|
||||
fill: '#fff',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
attrs: {
|
||||
text: `${cfg!.label}`,
|
||||
fill: 'rgba(0, 0, 0, 0.88)',
|
||||
fontSize: 16,
|
||||
fontWeight: 500,
|
||||
x: 20,
|
||||
textBaseline: 'middle',
|
||||
},
|
||||
name: 'start-node-text',
|
||||
});
|
||||
return keyShape;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0, 0.5],
|
||||
[1, 0.5],
|
||||
];
|
||||
},
|
||||
});
|
||||
let isCancelled = false;
|
||||
|
||||
G6.registerNode(
|
||||
'behavior-sub-node',
|
||||
{
|
||||
draw: (cfg, group) => {
|
||||
const textWidth = G6.Util.getTextSize(cfg!.label, 14)[0];
|
||||
const padding = 16;
|
||||
const size = [
|
||||
textWidth + 16 * 2 + (cfg!.targetType ? 12 : 0) + (cfg!.link ? 20 : 0),
|
||||
40,
|
||||
];
|
||||
const keyShape = group!.addShape('rect', {
|
||||
name: 'sub-node',
|
||||
attrs: {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
y: -size[1] / 2,
|
||||
radius: 8,
|
||||
fill: '#fff',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
attrs: {
|
||||
text: `${cfg!.label}`,
|
||||
x: cfg!.targetType ? 12 + 16 : padding,
|
||||
fill: 'rgba(0, 0, 0, 0.88)',
|
||||
fontSize: 14,
|
||||
textBaseline: 'middle',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
name: 'sub-node-text',
|
||||
});
|
||||
if (cfg!.targetType) {
|
||||
group!.addShape('rect', {
|
||||
name: 'sub-node-type',
|
||||
attrs: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
radius: 4,
|
||||
y: -4,
|
||||
x: 12,
|
||||
fill: cfg!.targetType === 'mvp' ? '#1677ff' : '#A0A0A0',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (cfg!.children) {
|
||||
const { length } = cfg!.children as any;
|
||||
group!.addShape('rect', {
|
||||
name: 'sub-node-children-length',
|
||||
attrs: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
radius: 10,
|
||||
y: -10,
|
||||
x: size[0] - 4,
|
||||
fill: '#404040',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
name: 'sub-node-children-length-text',
|
||||
attrs: {
|
||||
text: `${length}`,
|
||||
x: size[0] + 6 - G6.Util.getTextSize(`${length}`, 12)[0] / 2,
|
||||
textBaseline: 'middle',
|
||||
fill: '#fff',
|
||||
fontSize: 12,
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (cfg!.link) {
|
||||
group!.addShape('dom', {
|
||||
attrs: {
|
||||
width: 16,
|
||||
height: 16,
|
||||
x: size[0] - 12 - 16,
|
||||
y: -8,
|
||||
cursor: 'pointer',
|
||||
// DOM's html
|
||||
html: renderReactToHTMLString(
|
||||
<Flex align="center" justify="center">
|
||||
<RightCircleOutlined style={{ color: '#BFBFBF' }} />
|
||||
</Flex>,
|
||||
),
|
||||
},
|
||||
// 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
|
||||
name: 'sub-node-link',
|
||||
});
|
||||
}
|
||||
return keyShape;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0, 0.5],
|
||||
[1, 0.5],
|
||||
];
|
||||
},
|
||||
options: {
|
||||
stateStyles: {
|
||||
hover: {
|
||||
stroke: '#1677ff',
|
||||
'sub-node-link': {
|
||||
html: renderReactToHTMLString(
|
||||
<Flex align="center" justify="center">
|
||||
<RightCircleOutlined style={{ color: '#1677ff' }} />
|
||||
</Flex>,
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'rect',
|
||||
);
|
||||
graphRef.current = new G6.TreeGraph({
|
||||
container: ref.current!,
|
||||
width: ref.current!.scrollWidth,
|
||||
height: ref.current!.scrollHeight,
|
||||
renderer: 'svg',
|
||||
modes: {
|
||||
default: ['collapse-expand', 'drag-canvas'],
|
||||
},
|
||||
defaultEdge: {
|
||||
type: 'cubic-horizontal',
|
||||
style: { lineWidth: 1, stroke: '#BFBFBF' },
|
||||
},
|
||||
layout: {
|
||||
type: 'mindmap',
|
||||
direction: 'LR',
|
||||
getHeight: () => 48,
|
||||
getWidth: (node: any) => G6.Util.getTextSize(node.label, 16)[0] + 20 * 2,
|
||||
getVGap: () => 10,
|
||||
getHGap: () => 60,
|
||||
getSide: (node: any) => node.data.direction,
|
||||
},
|
||||
});
|
||||
const renderChart = async () => {
|
||||
if (!chartRef.current || !mermaidCode) return;
|
||||
|
||||
graphRef.current?.on('node:mouseenter', (e) => {
|
||||
graphRef.current?.setItemState(e.item!, 'hover', true);
|
||||
});
|
||||
graphRef.current?.on('node:mouseleave', (e) => {
|
||||
graphRef.current?.setItemState(e.item!, 'hover', false);
|
||||
});
|
||||
graphRef.current?.on('node:click', (e) => {
|
||||
const { link } = e.item!.getModel();
|
||||
if (link) {
|
||||
window.location.hash = link as string;
|
||||
try {
|
||||
const mermaidModule = await import('mermaid');
|
||||
const mermaid = mermaidModule.default;
|
||||
|
||||
if (isCancelled) return;
|
||||
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'base',
|
||||
securityLevel: 'strict',
|
||||
flowchart: {
|
||||
htmlLabels: true,
|
||||
curve: 'linear',
|
||||
rankSpacing: 150,
|
||||
nodeSpacing: 10,
|
||||
},
|
||||
});
|
||||
|
||||
let mermaidChartCounter = 0;
|
||||
mermaidChartCounter += 1;
|
||||
const id = `mermaid-${Date.now()}-${mermaidChartCounter}`;
|
||||
|
||||
const { svg } = await mermaid.render(id, mermaidCode);
|
||||
|
||||
if (!isCancelled && chartRef.current) {
|
||||
chartRef.current.innerHTML = svg;
|
||||
}
|
||||
});
|
||||
graphRef.current?.data(dataTransform(data));
|
||||
graphRef.current?.render();
|
||||
graphRef.current?.fitCenter();
|
||||
});
|
||||
return () => {
|
||||
graphRef.current?.destroy();
|
||||
} catch (error) {
|
||||
if (!isCancelled && chartRef.current) {
|
||||
console.error('Mermaid render error:', error);
|
||||
chartRef.current.innerHTML = 'Render Error';
|
||||
}
|
||||
}
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
renderChart();
|
||||
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [mermaidCode]);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={styles.container}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.title}>{`${meta.frontmatter.title} ${locale.behaviorMap}`}</div>
|
||||
<div ref={chartRef} className={styles.chartContainer} />
|
||||
<div className={styles.tips}>
|
||||
<div className={styles.mvp}>{locale.MVPPurpose}</div>
|
||||
<div className={styles.extension}>{locale.extensionPurpose}</div>
|
||||
|
||||
51
.dumi/theme/common/BehaviorMap/useMermaidCode.ts
Normal file
51
.dumi/theme/common/BehaviorMap/useMermaidCode.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { BehaviorMapItem } from './BehaviorMap';
|
||||
|
||||
export const useMermaidCode = (data: BehaviorMapItem): string => {
|
||||
const generateMermaidCode = (root: BehaviorMapItem): string => {
|
||||
const lines: string[] = [];
|
||||
|
||||
lines.push('graph LR');
|
||||
|
||||
lines.push(`classDef baseNode fill:#fff,stroke:none,stroke-width:0px,rx:5,ry:5,font-size:14px`);
|
||||
|
||||
const traverse = (node: BehaviorMapItem, parentId?: string) => {
|
||||
const safeId = `node_${node.id.replace(/[^a-z0-9]/gi, '_')}`;
|
||||
let labelText = node.label.replace(/"/g, "'");
|
||||
|
||||
if (!parentId) {
|
||||
lines.push(`style ${safeId} font-size:16px`);
|
||||
labelText = `**${labelText}**`;
|
||||
} else if (node.targetType === 'mvp') {
|
||||
const blueDot = `<span style="display:inline-block;width:8px;height:8px;background-color:rgb(22, 119, 255);border-radius:50%;margin-right:8px;vertical-align:middle;"></span>`;
|
||||
labelText = `${blueDot}${labelText}`;
|
||||
} else if (node.targetType === 'extension') {
|
||||
const grayDot = `<span style="display:inline-block;width:8px;height:8px;background-color:rgb(160, 160, 160);border-radius:50%;margin-right:8px;vertical-align:middle;"></span>`;
|
||||
labelText = `${grayDot}${labelText}`;
|
||||
}
|
||||
lines.push(`${safeId}["${labelText}"]:::baseNode`);
|
||||
|
||||
if (node.link) {
|
||||
lines.push(`click ${safeId} "#${node.link}"`);
|
||||
}
|
||||
|
||||
if (parentId) {
|
||||
lines.push(`${parentId} --> ${safeId}`);
|
||||
}
|
||||
|
||||
if (node.children && node.children.length > 0) {
|
||||
node.children.forEach((child) => traverse(child, safeId));
|
||||
}
|
||||
};
|
||||
|
||||
traverse(root);
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
const mermaidCode = useMemo(() => {
|
||||
return generateMermaidCode(data);
|
||||
}, [data]);
|
||||
|
||||
return mermaidCode;
|
||||
};
|
||||
2
.github/workflows/pr-check-merge.yml
vendored
2
.github/workflows/pr-check-merge.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: (github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'feature' || github.event.pull_request.head.ref == 'master') && github.event.pull_request.head.user.login == 'ant-design'
|
||||
steps:
|
||||
- uses: actions-cool/issues-helper@9861779a695cf1898bd984c727f685f351cfc372
|
||||
- uses: actions-cool/issues-helper@cbca8dff5d68beaba6fa47e9f49608ed2de544d6
|
||||
with:
|
||||
actions: create-comment
|
||||
issue-number: ${{ github.event.number }}
|
||||
|
||||
4
.github/workflows/preview-build.yml
vendored
4
.github/workflows/preview-build.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: run e2e test
|
||||
run: ut test:site
|
||||
- name: upload site artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: site
|
||||
path: _site/
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
- name: Upload PR number
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: pr
|
||||
path: ./pr-id.txt
|
||||
|
||||
6
.github/workflows/site-deploy.yml
vendored
6
.github/workflows/site-deploy.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: upload site artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: real-site
|
||||
path: _site/
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
- uses: utooland/setup-utoo@v1
|
||||
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
needs: build-site
|
||||
steps:
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
|
||||
6
.github/workflows/test-v6.yml
vendored
6
.github/workflows/test-v6.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
mkdir persist-coverage
|
||||
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v6
|
||||
name: upload coverages
|
||||
with:
|
||||
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: utooland/setup-utoo@v1
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -177,7 +177,7 @@ jobs:
|
||||
run: ut test:dekko
|
||||
|
||||
# Artifact build files
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v6
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/next'
|
||||
with:
|
||||
name: build artifacts
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
||||
mkdir persist-coverage
|
||||
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v6
|
||||
name: upload coverages
|
||||
with:
|
||||
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
- uses: utooland/setup-utoo@v1
|
||||
- run: ut
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -182,7 +182,7 @@ jobs:
|
||||
run: ut test:dekko
|
||||
|
||||
# Artifact build files
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v6
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
with:
|
||||
name: build artifacts
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v6
|
||||
name: artifact snapshot
|
||||
with:
|
||||
name: snapshot-artifacts-${{ strategy.job-index }}
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
- uses: utooland/setup-utoo@v1
|
||||
- run: ut
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: snapshot-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
|
||||
# Upload report in `visualRegressionReport`
|
||||
- name: upload report artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: visual-regression-report
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
|
||||
- name: Upload persist key
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: visual-regression-diff-ref
|
||||
path: ./visual-regression-pr-id.txt
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
# Upload `imageSnapshots` on master
|
||||
- name: upload report artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: image-snapshots
|
||||
path: imageSnapshots.tar.gz
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
|
||||
- name: Upload persist key
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: visual-regression-ref
|
||||
path: ./visual-regression-ref.txt
|
||||
|
||||
@@ -15,6 +15,23 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 6.1.1
|
||||
|
||||
`2025-12-15`
|
||||
|
||||
- 🐞 Fix DatePicker cannot support webpack 4: Can't resolve '@rc-component/picker/locale/en_US'. [#56219](https://github.com/ant-design/ant-design/pull/56219) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix ColorPicker inconsistent input heights. [#56220](https://github.com/ant-design/ant-design/pull/56220) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 Fix notification default background color not white when cssVar is disabled. [#56169](https://github.com/ant-design/ant-design/pull/56169) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 Fix Input border missing when focused on Space.Compact with `allowClear` prop. [#56105](https://github.com/ant-design/ant-design/pull/56105) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 Fix vertical Splitter incorrect collapse behavior in RTL mode, RTL flipping is now applied only to horizontal layouts [#56179](https://github.com/ant-design/ant-design/pull/56179) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 Fix Result not passing through `data-*` and `aria-*` attributes to the root DOM element. [#56165](https://github.com/ant-design/ant-design/pull/56165) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 MISC: `theme.cssVar.prefix` and `theme.cssVar.key` now respect empty string value. [#56146](https://github.com/ant-design/ant-design/pull/56146) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 💄 Lift Breadcrumb link style priority. [#56137](https://github.com/ant-design/ant-design/pull/56137) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 Fix ConfigProvider `closable.placement` not working. [#55985](https://github.com/ant-design/ant-design/pull/55985) [@meet-student](https://github.com/meet-student)
|
||||
- 🐞 Fix Form `onValuesChange` params missing Form.List nested content. [#56129](https://github.com/ant-design/ant-design/pull/56129) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Select `selectorBg` token not working. [#56052](https://github.com/ant-design/ant-design/pull/56052) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 Fix Upload incorrect progress position style. [#56194](https://github.com/ant-design/ant-design/pull/56194) [@QDyanbing](https://github.com/QDyanbing)
|
||||
|
||||
## 6.1.0
|
||||
|
||||
`2025-12-08`
|
||||
@@ -30,7 +47,7 @@ tag: vVERSION
|
||||
- 🐞 Fix the「Select」option was not enabled when Select contained interactive content. [#56054](https://github.com/ant-design/ant-design/pull/56054) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 Fix Table `cellFontSizeSM` and `cellFontSizeLG` tokens not working. [#55770](https://github.com/ant-design/ant-design/pull/55770) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 Fix Button tokens (primaryColor, dangerColor, defaultHoverBg, defaultActiveBg) not working with specific variants (solid, outlined, dashed). [#55934](https://github.com/ant-design/ant-design/pull/55934) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 💄 Fix Menu item styles not taking effect. [#56041](https://github.com/ant-design/ant-design/pull/56041) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 💄 Fix Menu item styles not taking effect. [#56041](https://github.com/ant-design/ant-design/pull/56041) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🛠 MISC: `@ant-design/react-slick` remove `classnames`. [#56080](https://github.com/ant-design/ant-design/pull/56080) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🛠 MISC: Migrate `rc-overflow` to `@rc-component/overflow`, `rc-virtual-list` to `@rc-component/virtual-list` in order to remove `rc-util`. [#56074](https://github.com/ant-design/ant-design/pull/56074) [@yoyo837](https://github.com/yoyo837)
|
||||
- TypeScript
|
||||
|
||||
@@ -15,6 +15,23 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 6.1.1
|
||||
|
||||
`2025-12-15`
|
||||
|
||||
- 🐞 修复 DatePicker 不兼容 webpack 4 的问题:Can't resolve '@rc-component/picker/locale/en_US'。[#56219](https://github.com/ant-design/ant-design/pull/56219) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 ColorPicker 弹层内输入框高度不一致问题。[#56220](https://github.com/ant-design/ant-design/pull/56220) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 修复 notification 在 cssVar 未启用时默认背景色不为白色的问题。[#56169](https://github.com/ant-design/ant-design/pull/56169) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 修复 Input 在 Space.Compact 下配置 `allowClear` 时聚焦边框丢失的问题。[#56105](https://github.com/ant-design/ant-design/pull/56105) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 修复 Splitter 在 RTL + 垂直模式下折叠方向错误的问题,RTL 逻辑现在仅在横向布局下生效。[#56179](https://github.com/ant-design/ant-design/pull/56179) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 修复 Result 未向根节点透传 `data-*` 与 `aria-*` 属性的问题。[#56165](https://github.com/ant-design/ant-design/pull/56165) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 MISC: 修复:`theme.cssVar.prefix` 与 `theme.cssVar.key` 不支持传入空字符串的问题。[#56146](https://github.com/ant-design/ant-design/pull/56146) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 💄 提升 Breadcrumb 链接样式优先级以避免被全局样式覆盖。[#56137](https://github.com/ant-design/ant-design/pull/56137) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 ConfigProvider `closable.placement` 配置失效的问题。[#55985](https://github.com/ant-design/ant-design/pull/55985) [@meet-student](https://github.com/meet-student)
|
||||
- 🐞 修复 Form `onValuesChange` 对存在嵌套数据的 Form.List 缺失内容的问题。[#56129](https://github.com/ant-design/ant-design/pull/56129) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Select `selectorBg` token 不生效的问题。[#56052](https://github.com/ant-design/ant-design/pull/56052) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 修复 Upload 进度条位置样式错误的问题。[#56194](https://github.com/ant-design/ant-design/pull/56194) [@QDyanbing](https://github.com/QDyanbing)
|
||||
|
||||
## 6.1.0
|
||||
|
||||
`2025-12-08`
|
||||
@@ -30,7 +47,7 @@ tag: vVERSION
|
||||
- 🐞 修复 Select 包含交互内容时「选择」选项未打开的问题。[#56054](https://github.com/ant-design/ant-design/pull/56054) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 修复 Table `cellFontSizeSM` 和 `cellFontSizeLG` token 不生效的问题。[#55770](https://github.com/ant-design/ant-design/pull/55770) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 Button 部分 Token(primaryColor, dangerColor, defaultHoverBg, defaultActiveBg)在特定变体(solid, outlined, dashed)下不生效的问题。[#55934](https://github.com/ant-design/ant-design/pull/55934) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 💄 修复 Menu 组件 item 中定义的 style 不生效错误。[#56041](https://github.com/ant-design/ant-design/pull/56041) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 💄 修复 Menu 组件 item 中定义的 style 不生效错误。[#56041](https://github.com/ant-design/ant-design/pull/56041) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🛠 杂项:更新 `@ant-design/react-slick` 版本以删除 `classnames`。[#56080](https://github.com/ant-design/ant-design/pull/56080) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🛠 杂项:迁移 `rc-overflow` 到 `@rc-component/overflow`、`rc-virtual-list` 到 `@rc-component/virtual-list` 以删除 `rc-util`。[#56074](https://github.com/ant-design/ant-design/pull/56074) [@yoyo837](https://github.com/yoyo837)
|
||||
- TypeScript
|
||||
|
||||
@@ -77,6 +77,7 @@ const genInputStyle: GenerateStyle<ColorPickerToken, CSSObject> = (token) => {
|
||||
flex: 1,
|
||||
width: 0,
|
||||
[`${componentCls}-hsb-input,${componentCls}-rgb-input`]: {
|
||||
height: controlHeightSM,
|
||||
display: 'flex',
|
||||
gap: marginXXS,
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -9,7 +9,7 @@ const Demo: React.FC = () => {
|
||||
ConfigProvider.config({
|
||||
holderRender: (children) => (
|
||||
<StyleProvider hashPriority="high">
|
||||
<ConfigProvider prefixCls="static" iconPrefixCls="icon" locale={locale} theme={theme}>
|
||||
<ConfigProvider componentSize="small" locale={locale} theme={theme}>
|
||||
<App message={{ maxCount: 1 }} notification={{ maxCount: 1 }}>
|
||||
{children}
|
||||
</App>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### Why does the warning `findDOMNode is deprecated` sometimes appear in strict mode?
|
||||
|
||||
This is due to the implementation of `rc-trigger`. `rc-trigger` forces children to accept ref, otherwise it will fall back to findDOMNode, so children need to be native html tags. If not, you need to use `React.forwardRef` transparently passes `ref` to native html tags.
|
||||
This is due to the implementation of `@rc-component/trigger`. `@rc-component/trigger` forces children to accept ref, otherwise it will fall back to findDOMNode, so children need to be native html tags. If not, you need to use `React.forwardRef` transparently passes `ref` to native html tags.
|
||||
|
||||
- `findDOMNode is deprecated` reproduce: <https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- Using `forwardRef` to fix: <https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### 为何在严格模式中有时候会出现 `findDOMNode is deprecated` 这个警告?
|
||||
|
||||
这是由于 `rc-trigger` 的实现方式导致的,`rc-trigger` 强制要求 children 能够接受 ref,否则就会 fallback 到 findDOMNode,所以 children 需要是原生 html 标签,如果不是,则需要使用 `React.forwardRef` 把 `ref` 透传到原生 html 标签。
|
||||
这是由于 `@rc-component/trigger` 的实现方式导致的,`@rc-component/trigger` 强制要求 children 能够接受 ref,否则就会 fallback 到 findDOMNode,所以 children 需要是原生 html 标签,如果不是,则需要使用 `React.forwardRef` 把 `ref` 透传到原生 html 标签。
|
||||
|
||||
- `findDOMNode is deprecated` 重现:<https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- 使用 `forwardRef` 消除警告:<https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
@@ -66,11 +66,11 @@ export const prepareComponentToken: GetDefaultToken<'Upload'> = (token) => ({
|
||||
export default genStyleHooks(
|
||||
'Upload',
|
||||
(token) => {
|
||||
const { fontSizeHeading3, fontHeight, lineWidth, pictureCardSize, calc } = token;
|
||||
const { fontSizeHeading3, marginXS, lineWidth, pictureCardSize, calc } = token;
|
||||
|
||||
const uploadToken = mergeToken<UploadToken>(token, {
|
||||
uploadThumbnailSize: calc(fontSizeHeading3).mul(2).equal(),
|
||||
uploadProgressOffset: calc(calc(fontHeight).div(2)).add(lineWidth).equal(),
|
||||
uploadProgressOffset: calc(calc(marginXS).div(2)).add(lineWidth).equal(),
|
||||
uploadPicCardSize: pictureCardSize,
|
||||
});
|
||||
|
||||
|
||||
@@ -54,7 +54,11 @@ const genPictureStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
},
|
||||
|
||||
[`${itemCls}-progress`]: {
|
||||
bottom: uploadProgressOffset,
|
||||
bottom: calc(token.fontSize)
|
||||
.mul(token.lineHeight)
|
||||
.div(2)
|
||||
.add(uploadProgressOffset)
|
||||
.equal(),
|
||||
width: `calc(100% - ${unit(calc(token.paddingSM).mul(2).equal())})`,
|
||||
marginTop: 0,
|
||||
paddingInlineStart: calc(uploadThumbnailSize).add(token.paddingXS).equal(),
|
||||
|
||||
@@ -28,7 +28,7 @@ In order to implement a good font system, the first thing is to choose an approp
|
||||
|
||||
> References:https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ and http://markdotto.com/2018/02/07/github-system-fonts/
|
||||
|
||||
In addition, in many applications, numbers often need to be displayed vertically. We set the CSS property `font-variant-numeric` to `tabular-nums;` to use [tabular figures](https://www.fonts.com/content/learning/fontology/level-3/numbers/proportional-vs-tabular-figures).
|
||||
In addition, in many applications, numbers often need to be displayed vertically. We recommend setting the CSS property `font-variant-numeric` to `tabular-nums` to use [tabular figures](https://www.fonts.com/content/learning/fontology/level-3/numbers/proportional-vs-tabular-figures).
|
||||
|
||||
> References:https://stackoverflow.com/questions/32660748/how-to-use-apples-new-san-francisco-font-on-a-webpage#comment78509178_32660790
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ title: 字体
|
||||
|
||||
> 参考自 https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ 和 http://markdotto.com/2018/02/07/github-system-fonts/
|
||||
|
||||
另外,在中后台系统中,数字经常需要进行纵向对比展示,我们单独将数字的字体 [font-variant-numeric](https://www.fonts.com/content/learning/fontology/level-3/numbers/proportional-vs-tabular-figures) 设置为 `tabular-nums`,使其为等宽字体。
|
||||
另外,在中后台系统中,数字经常需要进行纵向对比展示,我们推荐将数字的字体 [font-variant-numeric](https://www.fonts.com/content/learning/fontology/level-3/numbers/proportional-vs-tabular-figures) 设置为 `tabular-nums`,使其为等宽字体。
|
||||
|
||||
> 参考 https://stackoverflow.com/questions/32660748/how-to-use-apples-new-san-francisco-font-on-a-webpage#comment78509178_32660790
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "6.1.0",
|
||||
"version": "6.1.1",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -45,7 +45,6 @@
|
||||
"authors": "tsx scripts/generate-authors.ts",
|
||||
"build": "npm run compile && cross-env NODE_OPTIONS='--max-old-space-size=4096' npm run dist",
|
||||
"changelog": "npm run lint:changelog && tsx scripts/print-changelog.ts",
|
||||
"check-commit": "tsx scripts/check-commit.ts",
|
||||
"clean": "antd-tools run clean && rimraf es lib coverage locale dist report.html artifacts.zip oss-artifacts.zip",
|
||||
"clean:lockfiles": "rimraf package-lock.json yarn.lock",
|
||||
"precompile": "npm run prestart",
|
||||
@@ -133,7 +132,7 @@
|
||||
"@rc-component/mutate-observer": "^2.0.1",
|
||||
"@rc-component/notification": "~1.2.0",
|
||||
"@rc-component/pagination": "~1.2.0",
|
||||
"@rc-component/picker": "~1.8.0",
|
||||
"@rc-component/picker": "~1.9.0",
|
||||
"@rc-component/progress": "~1.0.2",
|
||||
"@rc-component/qrcode": "~1.1.1",
|
||||
"@rc-component/rate": "~1.0.1",
|
||||
@@ -164,7 +163,6 @@
|
||||
"@ant-design/tools": "^19.1.0",
|
||||
"@ant-design/x": "^1.6.1",
|
||||
"@antfu/eslint-config": "^6.6.1",
|
||||
"@antv/g6": "^4.8.25",
|
||||
"@biomejs/biome": "^2.3.8",
|
||||
"@blazediff/core": "^1.7.0",
|
||||
"@codecov/webpack-plugin": "^1.9.1",
|
||||
@@ -277,6 +275,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lunar-typescript": "^1.8.6",
|
||||
"lz-string": "^1.5.0",
|
||||
"mermaid": "^11.12.2",
|
||||
"minimist": "^1.2.8",
|
||||
"mockdate": "^3.0.5",
|
||||
"node-fetch": "^3.3.2",
|
||||
|
||||
@@ -12,12 +12,10 @@ import { version as packageVersion } from '../package.json';
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
const CONCH_TAG = 'conch-v5';
|
||||
const CONCH_V5_TAG = 'conch-v5';
|
||||
|
||||
function matchDeprecated(v: string) {
|
||||
const match = Object.keys(deprecatedVersions).find((depreciated) =>
|
||||
semver.satisfies(v, depreciated),
|
||||
);
|
||||
const match = Object.keys(deprecatedVersions).find((item) => semver.satisfies(v, item));
|
||||
|
||||
const reason = deprecatedVersions[match as keyof typeof deprecatedVersions] || [];
|
||||
|
||||
@@ -48,7 +46,7 @@ const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be
|
||||
(res: Response) => res.json(),
|
||||
);
|
||||
|
||||
console.log('🐚 Latest Conch Version:', chalk.green(distTags[CONCH_TAG] || 'null'), '\n');
|
||||
console.log('🐚 Latest Conch Version:', chalk.green(distTags[CONCH_V5_TAG] || 'null'), '\n');
|
||||
|
||||
// Sort and get the latest versions
|
||||
const versionList = Object.keys(time)
|
||||
@@ -101,12 +99,12 @@ const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be
|
||||
let defaultVersion = defaultVersionObj ? defaultVersionObj.value : null;
|
||||
|
||||
// If default version is less than current, use current
|
||||
if (semver.compare(defaultVersion!, distTags[CONCH_TAG]) < 0) {
|
||||
defaultVersion = distTags[CONCH_TAG];
|
||||
if (semver.compare(defaultVersion ?? '', distTags[CONCH_V5_TAG]) < 0) {
|
||||
defaultVersion = distTags[CONCH_V5_TAG];
|
||||
}
|
||||
|
||||
let conchVersion = await select({
|
||||
default: defaultVersion,
|
||||
default: defaultVersion ?? '',
|
||||
message: 'Please select Conch Version:',
|
||||
choices: latestVersions.map((info) => {
|
||||
const { value, publishTime, depreciated } = info;
|
||||
@@ -123,7 +121,7 @@ const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be
|
||||
// Default Mark
|
||||
value === defaultVersion ? '(default)' : '',
|
||||
// Current Mark
|
||||
value === distTags[CONCH_TAG] ? chalk.gray('- current') : '',
|
||||
value === distTags[CONCH_V5_TAG] ? chalk.gray('- current') : '',
|
||||
]
|
||||
.filter((str) => Boolean(String(str).trim()))
|
||||
.join(' '),
|
||||
@@ -152,10 +150,12 @@ const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be
|
||||
}
|
||||
|
||||
// Check if need to update
|
||||
if (!conchVersion || distTags[CONCH_TAG] === conchVersion) {
|
||||
if (!conchVersion || distTags[CONCH_V5_TAG] === conchVersion) {
|
||||
console.log(`🎃 Conch Version not change. Safe to ${chalk.green('ignore')}.`);
|
||||
} else {
|
||||
console.log('💾 Tagging Conch Version:', chalk.green(conchVersion));
|
||||
spawnSync('npm', ['dist-tag', 'add', `antd@${conchVersion}`, CONCH_TAG], { stdio: 'inherit' });
|
||||
spawnSync('npm', ['dist-tag', 'add', `antd@${conchVersion}`, CONCH_V5_TAG], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Full skip argms
|
||||
# npm run test-all -- --skip-changelog --skip-commit --skip-lint --skip-build --skip-dekko --skip-dist --skip-es --skip-lib --skip-test --skip-node
|
||||
# npm run test-all -- --skip-changelog --skip-lint --skip-build --skip-dekko --skip-dist --skip-es --skip-lib --skip-test --skip-node
|
||||
|
||||
# Check exist argument
|
||||
has_arg() {
|
||||
@@ -27,14 +27,6 @@ else
|
||||
echo "[TEST ALL] test changelog...skip"
|
||||
fi
|
||||
|
||||
if ! has_arg '--skip-commit' "$@"; then
|
||||
echo "[TEST ALL] check-commit"
|
||||
echo "[TEST ALL] check-commit" > ~test-all.txt
|
||||
npm run check-commit
|
||||
else
|
||||
echo "[TEST ALL] check-commit...skip"
|
||||
fi
|
||||
|
||||
if ! has_arg '--skip-lint' "$@"; then
|
||||
echo "[TEST ALL] lint"
|
||||
echo "[TEST ALL] lint" > ~test-all.txt
|
||||
|
||||
Reference in New Issue
Block a user