mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 19:09:21 +08:00
Compare commits
254 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
822dec20a4 | ||
|
|
fb5ed95853 | ||
|
|
b4a4c93800 | ||
|
|
e0c79ec5dc | ||
|
|
d5ef496bb6 | ||
|
|
b915094498 | ||
|
|
ec33f75bc0 | ||
|
|
41c4386181 | ||
|
|
16f0b576a7 | ||
|
|
00bbd66064 | ||
|
|
20816a2184 | ||
|
|
49c932a102 | ||
|
|
ef39c3cf26 | ||
|
|
241b9465c8 | ||
|
|
37353e0ef3 | ||
|
|
0f1bc24285 | ||
|
|
de04b0d183 | ||
|
|
3ed7895596 | ||
|
|
6c02a0e14c | ||
|
|
6c8082a474 | ||
|
|
39adae8e5c | ||
|
|
844905774a | ||
|
|
b5d3f9cd81 | ||
|
|
af0dbbd5d3 | ||
|
|
74e2e9850f | ||
|
|
1177762cff | ||
|
|
649788e49f | ||
|
|
980e9cb08b | ||
|
|
0e62931d48 | ||
|
|
12d85256a7 | ||
|
|
7c5e4469ba | ||
|
|
31555161e9 | ||
|
|
6770b7fb22 | ||
|
|
50da0ca0a7 | ||
|
|
384b1ea9ff | ||
|
|
5c0bc214cc | ||
|
|
d196c7a87b | ||
|
|
09817c3b37 | ||
|
|
cf8a0b0a48 | ||
|
|
57df8e1c09 | ||
|
|
d70f599a7e | ||
|
|
989d033978 | ||
|
|
571224efa1 | ||
|
|
669e58c380 | ||
|
|
2f02fe01f0 | ||
|
|
c666b066d6 | ||
|
|
8109f47de7 | ||
|
|
c7832505ae | ||
|
|
c0d275b4ff | ||
|
|
a6b07948a7 | ||
|
|
03bdab6e3c | ||
|
|
4dea745e40 | ||
|
|
5b78c6a542 | ||
|
|
b3a0496ad5 | ||
|
|
9642564eea | ||
|
|
828305bea3 | ||
|
|
38b47f68f9 | ||
|
|
98939365dd | ||
|
|
62b18ba0de | ||
|
|
36f44575c8 | ||
|
|
1df1034f20 | ||
|
|
c3f8424c98 | ||
|
|
2bc16980ab | ||
|
|
bc804166b4 | ||
|
|
3266635fa0 | ||
|
|
245a2ccc80 | ||
|
|
87f13b3ddc | ||
|
|
dcbf0d7b5c | ||
|
|
704d2e78b0 | ||
|
|
53b9559cc6 | ||
|
|
5c1c5f7e9e | ||
|
|
c2f5ed0bfc | ||
|
|
3eacb8f036 | ||
|
|
5577d1abf0 | ||
|
|
5ed7da0ed4 | ||
|
|
767db3c6ca | ||
|
|
48d9c625df | ||
|
|
b09153c4fc | ||
|
|
ca64edc898 | ||
|
|
c38108a63c | ||
|
|
55166d4272 | ||
|
|
4660dd9ca7 | ||
|
|
7a7305ce5a | ||
|
|
1d923e5daf | ||
|
|
6c32399bd4 | ||
|
|
2e9d14f282 | ||
|
|
413e44a170 | ||
|
|
2aa1e2b7e5 | ||
|
|
8467428528 | ||
|
|
43e4d28979 | ||
|
|
8ae56f2371 | ||
|
|
9c45647556 | ||
|
|
79ac80a0a2 | ||
|
|
673d8a029b | ||
|
|
d7378a09ba | ||
|
|
39c645bbb7 | ||
|
|
9d546ed51a | ||
|
|
a268fdde8f | ||
|
|
ec34bc1874 | ||
|
|
8cf4a4cb15 | ||
|
|
83cb884196 | ||
|
|
745015ef09 | ||
|
|
5bdc15ea37 | ||
|
|
f8b1e96448 | ||
|
|
0322964b75 | ||
|
|
b896d0ede9 | ||
|
|
059042b2cd | ||
|
|
986718c81f | ||
|
|
849dd97456 | ||
|
|
da3babbe39 | ||
|
|
e7acb487f3 | ||
|
|
e56184aaa3 | ||
|
|
3ed967ab4a | ||
|
|
bd13944c4e | ||
|
|
94bf744acd | ||
|
|
88d5c67594 | ||
|
|
1130bf01ea | ||
|
|
4581b706e3 | ||
|
|
5007b7df68 | ||
|
|
c89640d843 | ||
|
|
c4273ec49b | ||
|
|
e4b8593b72 | ||
|
|
c3f7783a89 | ||
|
|
8a25a926c4 | ||
|
|
ab83c1b6cb | ||
|
|
7b051735cc | ||
|
|
623f44917f | ||
|
|
567ce9886f | ||
|
|
11011ba64a | ||
|
|
895f2591b4 | ||
|
|
f217bc3361 | ||
|
|
bd3401f737 | ||
|
|
1a4dc9eb36 | ||
|
|
b82710fe9e | ||
|
|
51c615dd42 | ||
|
|
947f86f178 | ||
|
|
14dd2cdcdb | ||
|
|
ed94e03705 | ||
|
|
412fe13d0c | ||
|
|
433a73c53b | ||
|
|
fd0d8b6031 | ||
|
|
6b552d53f6 | ||
|
|
01a6da37a9 | ||
|
|
a89d0f4861 | ||
|
|
9cfc03c042 | ||
|
|
cd9ad445ea | ||
|
|
b6c0030d58 | ||
|
|
ea6acbc592 | ||
|
|
be25ee2a0b | ||
|
|
288b10bd10 | ||
|
|
5459bf65b5 | ||
|
|
40a7e7a142 | ||
|
|
36b47f6233 | ||
|
|
f9a38af179 | ||
|
|
bce4245d4f | ||
|
|
8d09425e2d | ||
|
|
b241900428 | ||
|
|
f97984e507 | ||
|
|
b9a1e08ba4 | ||
|
|
e5930e61ed | ||
|
|
42e2b73cdf | ||
|
|
16e90b2301 | ||
|
|
9f64386d0b | ||
|
|
1fdd45ef10 | ||
|
|
6fc08687ae | ||
|
|
7043cadab0 | ||
|
|
6c49fc9422 | ||
|
|
f76e5bb954 | ||
|
|
8f7f3608f8 | ||
|
|
9fa24c231d | ||
|
|
4bb102474e | ||
|
|
0bfdff2086 | ||
|
|
da441ae35f | ||
|
|
853283b7e4 | ||
|
|
33275b6e80 | ||
|
|
3e5058c8c3 | ||
|
|
8e93ae76d0 | ||
|
|
c32e5e38ef | ||
|
|
3b2cd725cb | ||
|
|
e142e2436d | ||
|
|
9b25304c29 | ||
|
|
6fa4c2e59f | ||
|
|
76dc87f1c3 | ||
|
|
f8c511045d | ||
|
|
d39aa653ec | ||
|
|
54d3a738f6 | ||
|
|
5dfce54437 | ||
|
|
0a24676845 | ||
|
|
108129641f | ||
|
|
66e2b146dd | ||
|
|
12a6f7182d | ||
|
|
de82a15b22 | ||
|
|
51200e7732 | ||
|
|
5199344d09 | ||
|
|
fd2db7614f | ||
|
|
1ebdfb7049 | ||
|
|
40abef340a | ||
|
|
12a734adac | ||
|
|
0aac2f0a05 | ||
|
|
03ef8225cf | ||
|
|
0c0faaa9e1 | ||
|
|
c4f83649ae | ||
|
|
d2ab2722b4 | ||
|
|
c53330d90e | ||
|
|
6234509d18 | ||
|
|
9f98fc243e | ||
|
|
5c1162a140 | ||
|
|
910d0fc340 | ||
|
|
41d9efd29f | ||
|
|
86b5c50cb4 | ||
|
|
75c8451f7d | ||
|
|
185c276c01 | ||
|
|
213efa2cf1 | ||
|
|
0d67bde239 | ||
|
|
4c6f7c12ee | ||
|
|
d823f60edf | ||
|
|
2c694258d2 | ||
|
|
f7232ebeb5 | ||
|
|
0fed01f47b | ||
|
|
fb5305d4c6 | ||
|
|
c885a42e3b | ||
|
|
14c5d685c1 | ||
|
|
9d9eca7a9d | ||
|
|
34c63ca41b | ||
|
|
4299a0b28b | ||
|
|
9632b36b04 | ||
|
|
f646ba9c3a | ||
|
|
c48c712371 | ||
|
|
774bd8e6aa | ||
|
|
766e7f8f6b | ||
|
|
c5dc6a4b92 | ||
|
|
3cd756a514 | ||
|
|
2c6d9eaaf6 | ||
|
|
35094551c1 | ||
|
|
3449ff0825 | ||
|
|
8d291ed3ee | ||
|
|
e11ef765a1 | ||
|
|
40e77c40d3 | ||
|
|
3669d8e226 | ||
|
|
d39765ba50 | ||
|
|
31cbbce825 | ||
|
|
6be7aa5eef | ||
|
|
2cd53e0ec5 | ||
|
|
654897e151 | ||
|
|
b0ea26bf64 | ||
|
|
8ecb4cdc60 | ||
|
|
a76c2f4d07 | ||
|
|
9ad1a8e091 | ||
|
|
0e974511ad | ||
|
|
10f78a916a | ||
|
|
650f0e5473 | ||
|
|
21da39ae33 | ||
|
|
8d8d93249c | ||
|
|
9fd6159772 |
@@ -7,7 +7,7 @@ version: 2.1
|
||||
jobs:
|
||||
test-argos-ci:
|
||||
docker:
|
||||
- image: cimg/node:16.19.0-browsers
|
||||
- image: cimg/node:16.19.1-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
|
||||
@@ -147,15 +147,15 @@ export default function ComponentsList() {
|
||||
node: (
|
||||
<Space direction="vertical">
|
||||
<Space>
|
||||
<Progress type="circle" trailColor="#e6f4ff" percent={60} width={14} />
|
||||
<Progress type="circle" trailColor="#e6f4ff" percent={60} size={14} />
|
||||
{locale.inProgress}
|
||||
</Space>
|
||||
<Space>
|
||||
<Progress type="circle" percent={100} width={14} />
|
||||
<Progress type="circle" percent={100} size={14} />
|
||||
{locale.success}
|
||||
</Space>
|
||||
<Space>
|
||||
<Progress type="circle" status="exception" percent={88} width={14} />
|
||||
<Progress type="circle" status="exception" percent={88} size={14} />
|
||||
{locale.taskFailed}
|
||||
</Space>
|
||||
</Space>
|
||||
|
||||
12
.dumi/remarkAntd.ts
Normal file
12
.dumi/remarkAntd.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { unistUtilVisit } from 'dumi';
|
||||
|
||||
export default function remarkMeta() {
|
||||
return (tree, vFile) => {
|
||||
// read frontmatter
|
||||
unistUtilVisit.visit(tree, 'yaml', (node) => {
|
||||
if (!/(^|[\n\r])description:/.test(node.value)) {
|
||||
vFile.data.frontmatter.__autoDescription = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@ export type Component = {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
cover: string;
|
||||
coverDark?: string;
|
||||
link: string;
|
||||
tag?: string;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { memo, useMemo, useRef, useState } from 'react';
|
||||
import React, { memo, useContext, useMemo, useRef, useState } from 'react';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { Link, useIntl, useSidebarData, useLocation } from 'dumi';
|
||||
import { css } from '@emotion/react';
|
||||
@@ -8,6 +8,7 @@ import { SearchOutlined } from '@ant-design/icons';
|
||||
import type { Component } from './ProComponentsList';
|
||||
import proComponentsList from './ProComponentsList';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
|
||||
const useStyle = () => {
|
||||
const { token } = useSiteToken();
|
||||
@@ -79,6 +80,7 @@ const { Title } = Typography;
|
||||
|
||||
const Overview: React.FC = () => {
|
||||
const style = useStyle();
|
||||
const { theme } = useContext(SiteContext);
|
||||
|
||||
const data = useSidebarData();
|
||||
const [searchBarAffixed, setSearchBarAffixed] = useState<boolean>(false);
|
||||
@@ -97,7 +99,13 @@ const Overview: React.FC = () => {
|
||||
const { search: urlSearch } = useLocation();
|
||||
const { locale, formatMessage } = useIntl();
|
||||
|
||||
const [search, setSearch] = useState<string>('');
|
||||
const [search, setSearch] = useState<string>(() => {
|
||||
const params = new URLSearchParams(urlSearch);
|
||||
if (params.has('s')) {
|
||||
return params.get('s');
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
const sectionRef = useRef<HTMLElement>(null);
|
||||
|
||||
@@ -117,6 +125,7 @@ const Overview: React.FC = () => {
|
||||
title: child.frontmatter?.title,
|
||||
subtitle: child.frontmatter.subtitle,
|
||||
cover: child.frontmatter.cover,
|
||||
coverDark: child.frontmatter.coverDark,
|
||||
link: child.link,
|
||||
})),
|
||||
}))
|
||||
@@ -202,7 +211,14 @@ const Overview: React.FC = () => {
|
||||
}
|
||||
>
|
||||
<div css={style.componentsOverviewImg}>
|
||||
<img src={component.cover} alt={component?.title} />
|
||||
<img
|
||||
src={
|
||||
theme.includes('dark') && component.coverDark
|
||||
? component.coverDark
|
||||
: component.cover
|
||||
}
|
||||
alt={component?.title}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</ComponentLink>
|
||||
|
||||
95
.dumi/theme/builtins/ComponentTokenTable/index.tsx
Normal file
95
.dumi/theme/builtins/ComponentTokenTable/index.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
/* eslint import/no-unresolved: 0 */
|
||||
import { ConfigProvider, Table } from 'antd';
|
||||
import { getDesignToken } from 'antd-token-previewer';
|
||||
import tokenMeta from 'antd/es/version/token-meta.json';
|
||||
import tokenData from 'antd/es/version/token.json';
|
||||
import React from 'react';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import { useColumns } from '../TokenTable';
|
||||
|
||||
const defaultToken = getDesignToken();
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
token: 'Token 名称',
|
||||
description: '描述',
|
||||
type: '类型',
|
||||
value: '默认值',
|
||||
},
|
||||
en: {
|
||||
token: 'Token Name',
|
||||
description: 'Description',
|
||||
type: 'Type',
|
||||
value: 'Default Value',
|
||||
},
|
||||
};
|
||||
|
||||
interface SubTokenTableProps {
|
||||
defaultOpen?: boolean;
|
||||
title: string;
|
||||
tokens: string[];
|
||||
}
|
||||
|
||||
function SubTokenTable({ defaultOpen, tokens, title }: SubTokenTableProps) {
|
||||
const [, lang] = useLocale(locales);
|
||||
const { token } = useSiteToken();
|
||||
const columns = useColumns();
|
||||
|
||||
if (!tokens.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = tokens.map((name) => {
|
||||
const meta = tokenMeta[name];
|
||||
|
||||
return {
|
||||
name,
|
||||
desc: lang === 'cn' ? meta.desc : meta.descEn,
|
||||
type: meta.type,
|
||||
value: (defaultToken as any)[name],
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
// Reuse `.markdown` style
|
||||
<details className="markdown" open={defaultOpen}>
|
||||
<summary>
|
||||
<h3 style={{ display: 'inline' }}>{title}</h3>
|
||||
</summary>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
borderRadius: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Table
|
||||
size="middle"
|
||||
columns={columns}
|
||||
bordered
|
||||
dataSource={data}
|
||||
style={{ marginBottom: token.margin }}
|
||||
pagination={false}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
</details>
|
||||
);
|
||||
}
|
||||
|
||||
export interface ComponentTokenTableProps {
|
||||
component: string;
|
||||
}
|
||||
|
||||
function ComponentTokenTable({ component }: ComponentTokenTableProps) {
|
||||
const { global: globalTokens = [], component: componentTokens = [] } = tokenData[component] || {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubTokenTable title="Component Token" tokens={componentTokens} defaultOpen />
|
||||
<SubTokenTable title="Global Token" tokens={globalTokens} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(ComponentTokenTable);
|
||||
557
.dumi/theme/builtins/Previewer/CodePreviewer.tsx
Normal file
557
.dumi/theme/builtins/Previewer/CodePreviewer.tsx
Normal file
@@ -0,0 +1,557 @@
|
||||
import {
|
||||
CheckOutlined,
|
||||
LinkOutlined,
|
||||
SnippetsOutlined,
|
||||
ThunderboltOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { Project } from '@stackblitz/sdk';
|
||||
import stackblitzSdk from '@stackblitz/sdk';
|
||||
import { Alert, Badge, Space, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
import { FormattedMessage, useSiteData } from 'dumi';
|
||||
import toReactElement from 'jsonml-to-react-element';
|
||||
import JsonML from 'jsonml.js/lib/utils';
|
||||
import LZString from 'lz-string';
|
||||
import Prism from 'prismjs';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import useLocation from '../../../hooks/useLocation';
|
||||
import BrowserFrame from '../../common/BrowserFrame';
|
||||
import ClientOnly from '../../common/ClientOnly';
|
||||
import CodePenIcon from '../../common/CodePenIcon';
|
||||
import CodePreview from '../../common/CodePreview';
|
||||
import CodeSandboxIcon from '../../common/CodeSandboxIcon';
|
||||
import EditButton from '../../common/EditButton';
|
||||
import ExternalLinkIcon from '../../common/ExternalLinkIcon';
|
||||
import RiddleIcon from '../../common/RiddleIcon';
|
||||
import type { SiteContextProps } from '../../slots/SiteContext';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import { ping } from '../../utils';
|
||||
|
||||
const { ErrorBoundary } = Alert;
|
||||
|
||||
function toReactComponent(jsonML: any) {
|
||||
return toReactElement(jsonML, [
|
||||
[
|
||||
(node: any) => JsonML.isElement(node) && JsonML.getTagName(node) === 'pre',
|
||||
(node: any, index: any) => {
|
||||
// ref: https://github.com/benjycui/bisheng/blob/master/packages/bisheng/src/bisheng-plugin-highlight/lib/browser.js#L7
|
||||
const attr = JsonML.getAttributes(node);
|
||||
return React.createElement(
|
||||
'pre',
|
||||
{
|
||||
key: index,
|
||||
className: `language-${attr.lang}`,
|
||||
},
|
||||
React.createElement('code', {
|
||||
dangerouslySetInnerHTML: { __html: attr.highlighted },
|
||||
}),
|
||||
);
|
||||
},
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
function compress(string: string): string {
|
||||
return LZString.compressToBase64(string)
|
||||
.replace(/\+/g, '-') // Convert '+' to '-'
|
||||
.replace(/\//g, '_') // Convert '/' to '_'
|
||||
.replace(/=+$/, ''); // Remove ending '='
|
||||
}
|
||||
|
||||
const track = ({ type, demo }: { type: string; demo: string }) => {
|
||||
if (!window.gtag) {
|
||||
return;
|
||||
}
|
||||
window.gtag('event', 'demo', { event_category: type, event_label: demo });
|
||||
};
|
||||
|
||||
let pingDeferrer: PromiseLike<boolean>;
|
||||
|
||||
function useShowRiddleButton() {
|
||||
const [showRiddleButton, setShowRiddleButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
pingDeferrer ??= new Promise<boolean>((resolve) => {
|
||||
ping((status) => {
|
||||
if (status !== 'timeout' && status !== 'error') {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
pingDeferrer.then(setShowRiddleButton);
|
||||
}, []);
|
||||
|
||||
return showRiddleButton;
|
||||
}
|
||||
|
||||
const CodePreviewer: React.FC<IPreviewerProps> = (props) => {
|
||||
const {
|
||||
asset,
|
||||
expand,
|
||||
iframe,
|
||||
demoUrl,
|
||||
children,
|
||||
title,
|
||||
description,
|
||||
debug,
|
||||
jsx,
|
||||
style,
|
||||
compact,
|
||||
background,
|
||||
filePath,
|
||||
version,
|
||||
} = props;
|
||||
|
||||
const { pkg } = useSiteData();
|
||||
const location = useLocation();
|
||||
|
||||
const entryCode = asset.dependencies['index.tsx'].value;
|
||||
const showRiddleButton = useShowRiddleButton();
|
||||
|
||||
const liveDemo = useRef<React.ReactNode>(null);
|
||||
const anchorRef = useRef<HTMLAnchorElement>(null);
|
||||
const codeSandboxIconRef = useRef<HTMLFormElement>(null);
|
||||
const riddleIconRef = useRef<HTMLFormElement>(null);
|
||||
const codepenIconRef = useRef<HTMLFormElement>(null);
|
||||
const [codeExpand, setCodeExpand] = useState<boolean>(false);
|
||||
const [copyTooltipOpen, setCopyTooltipOpen] = useState<boolean>(false);
|
||||
const [copied, setCopied] = useState<boolean>(false);
|
||||
const [codeType, setCodeType] = useState<string>('tsx');
|
||||
const { theme } = useContext<SiteContextProps>(SiteContext);
|
||||
|
||||
const { hash, pathname, search } = location;
|
||||
const docsOnlineUrl = `https://ant.design${pathname}${search}#${asset.id}`;
|
||||
|
||||
const [showOnlineUrl, setShowOnlineUrl] = useState<boolean>(false);
|
||||
|
||||
const highlightedCodes = {
|
||||
jsx: Prism.highlight(jsx, Prism.languages.javascript, 'jsx'),
|
||||
tsx: Prism.highlight(entryCode, Prism.languages.javascript, 'jsx'),
|
||||
};
|
||||
|
||||
const highlightedStyle = style ? Prism.highlight(style, Prism.languages.css, 'css') : '';
|
||||
|
||||
useEffect(() => {
|
||||
const regexp = /preview-(\d+)-ant-design/; // matching PR preview addresses
|
||||
setShowOnlineUrl(
|
||||
process.env.NODE_ENV === 'development' || regexp.test(window.location.hostname),
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleCodeExpand = (demo: string) => {
|
||||
setCodeExpand((prev) => !prev);
|
||||
track({ type: 'expand', demo });
|
||||
};
|
||||
|
||||
const handleCodeCopied = (demo: string) => {
|
||||
setCopied(true);
|
||||
track({ type: 'copy', demo });
|
||||
};
|
||||
|
||||
const onCopyTooltipOpenChange = (open: boolean) => {
|
||||
setCopyTooltipOpen(open);
|
||||
if (open) {
|
||||
setCopied(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (asset.id === hash.slice(1)) {
|
||||
anchorRef.current?.click();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setCodeExpand(expand);
|
||||
}, [expand]);
|
||||
|
||||
if (!liveDemo.current) {
|
||||
liveDemo.current = iframe ? (
|
||||
<BrowserFrame>
|
||||
<iframe
|
||||
src={demoUrl}
|
||||
height={iframe === true ? undefined : iframe}
|
||||
title="demo"
|
||||
className="iframe-demo"
|
||||
/>
|
||||
</BrowserFrame>
|
||||
) : (
|
||||
children
|
||||
);
|
||||
}
|
||||
|
||||
const codeBoxClass = classNames('code-box', {
|
||||
expand: codeExpand,
|
||||
'code-box-debug': debug,
|
||||
});
|
||||
|
||||
const localizedTitle = title;
|
||||
const introChildren = <div dangerouslySetInnerHTML={{ __html: description }} />;
|
||||
const highlightClass = classNames('highlight-wrapper', {
|
||||
'highlight-wrapper-expand': codeExpand,
|
||||
});
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" style="padding: 24px" />
|
||||
<script>const mountNode = document.getElementById('container');</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const tsconfig = {
|
||||
compilerOptions: {
|
||||
target: 'esnext',
|
||||
module: 'esnext',
|
||||
esModuleInterop: true,
|
||||
moduleResolution: 'node',
|
||||
jsx: 'react',
|
||||
jsxFactory: 'React.createElement',
|
||||
jsxFragmentFactory: 'React.Fragment',
|
||||
},
|
||||
};
|
||||
|
||||
const suffix = codeType === 'tsx' ? 'tsx' : 'js';
|
||||
|
||||
const dependencies: Record<PropertyKey, string> = jsx.split('\n').reduce(
|
||||
(acc, line) => {
|
||||
const matches = line.match(/import .+? from '(.+)';$/);
|
||||
if (matches && matches[1] && !line.includes('antd')) {
|
||||
const paths = matches[1].split('/');
|
||||
if (paths.length) {
|
||||
const dep = paths[0].startsWith('@') ? `${paths[0]}/${paths[1]}` : paths[0];
|
||||
acc[dep] = 'latest';
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ antd: pkg.version },
|
||||
);
|
||||
|
||||
dependencies['@ant-design/icons'] = 'latest';
|
||||
|
||||
if (suffix === 'tsx') {
|
||||
dependencies['@types/react'] = '^18.0.0';
|
||||
dependencies['@types/react-dom'] = '^18.0.0';
|
||||
}
|
||||
|
||||
dependencies.react = '^18.0.0';
|
||||
dependencies['react-dom'] = '^18.0.0';
|
||||
|
||||
const codepenPrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
html,
|
||||
js: `const { createRoot } = ReactDOM;\n${jsx
|
||||
.replace(/import\s+(?:React,\s+)?{(\s+[^}]*\s+)}\s+from\s+'react'/, `const { $1 } = React;`)
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'antd';/, 'const { $1 } = antd;')
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'@ant-design\/icons';/, 'const { $1 } = icons;')
|
||||
.replace("import moment from 'moment';", '')
|
||||
.replace("import React from 'react';", '')
|
||||
.replace(/import\s+{\s+(.*)\s+}\s+from\s+'react-router';/, 'const { $1 } = ReactRouter;')
|
||||
.replace(
|
||||
/import\s+{\s+(.*)\s+}\s+from\s+'react-router-dom';/,
|
||||
'const { $1 } = ReactRouterDOM;',
|
||||
)
|
||||
.replace(/([A-Za-z]*)\s+as\s+([A-Za-z]*)/, '$1:$2')
|
||||
.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
editors: '001',
|
||||
css: '',
|
||||
js_external: [
|
||||
'react@18/umd/react.development.js',
|
||||
'react-dom@18/umd/react-dom.development.js',
|
||||
'dayjs@1/dayjs.min.js',
|
||||
`antd@${pkg.version}/dist/antd-with-locales.js`,
|
||||
`@ant-design/icons/dist/index.umd.js`,
|
||||
'react-router-dom/dist/umd/react-router-dom.production.min.js',
|
||||
'react-router/dist/umd/react-router.production.min.js',
|
||||
]
|
||||
.map((url) => `https://unpkg.com/${url}`)
|
||||
.join(';'),
|
||||
js_pre_processor: 'typescript',
|
||||
};
|
||||
|
||||
const riddlePrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
js: `${
|
||||
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
|
||||
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
css: '',
|
||||
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
|
||||
};
|
||||
|
||||
// Reorder source code
|
||||
let parsedSourceCode = suffix === 'tsx' ? entryCode : jsx;
|
||||
let importReactContent = "import React from 'react';";
|
||||
const importReactReg = /import React(\D*)from 'react';/;
|
||||
const matchImportReact = parsedSourceCode.match(importReactReg);
|
||||
if (matchImportReact) {
|
||||
[importReactContent] = matchImportReact;
|
||||
parsedSourceCode = parsedSourceCode.replace(importReactReg, '').trim();
|
||||
}
|
||||
const demoJsContent = `
|
||||
${importReactContent}
|
||||
import './index.css';
|
||||
${parsedSourceCode}
|
||||
`.trim();
|
||||
const indexCssContent = (style || '')
|
||||
.trim()
|
||||
.replace(new RegExp(`#${asset.id}\\s*`, 'g'), '')
|
||||
.replace('</style>', '')
|
||||
.replace('<style>', '');
|
||||
|
||||
const indexJsContent = `import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import Demo from './demo';
|
||||
|
||||
createRoot(document.getElementById('container')).render(<Demo />);
|
||||
`;
|
||||
|
||||
const codesandboxPackage = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
main: 'index.js',
|
||||
dependencies: {
|
||||
...dependencies,
|
||||
react: '^18.0.0',
|
||||
'react-dom': '^18.0.0',
|
||||
'react-scripts': '^4.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
typescript: '^4.0.5',
|
||||
},
|
||||
scripts: {
|
||||
start: 'react-scripts start',
|
||||
build: 'react-scripts build',
|
||||
test: 'react-scripts test --env=jsdom',
|
||||
eject: 'react-scripts eject',
|
||||
},
|
||||
browserslist: ['>0.2%', 'not dead'],
|
||||
};
|
||||
|
||||
const codesanboxPrefillConfig = {
|
||||
files: {
|
||||
'package.json': { content: codesandboxPackage },
|
||||
'index.css': { content: indexCssContent },
|
||||
[`index.${suffix}`]: { content: indexJsContent },
|
||||
[`demo.${suffix}`]: { content: demoJsContent },
|
||||
'index.html': {
|
||||
content: html,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const stackblitzPrefillConfig: Project = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
template: 'create-react-app',
|
||||
dependencies,
|
||||
description: '',
|
||||
files: {
|
||||
'index.css': indexCssContent,
|
||||
[`index.${suffix}`]: indexJsContent,
|
||||
[`demo.${suffix}`]: demoJsContent,
|
||||
'index.html': html,
|
||||
},
|
||||
};
|
||||
|
||||
if (suffix === 'tsx') {
|
||||
stackblitzPrefillConfig.files['tsconfig.json'] = JSON.stringify(tsconfig, null, 2);
|
||||
}
|
||||
|
||||
const backgroundGrey = theme.includes('dark') ? '#303030' : '#f0f2f5';
|
||||
|
||||
const codeBoxDemoStyle: React.CSSProperties = {
|
||||
padding: iframe || compact ? 0 : undefined,
|
||||
overflow: iframe || compact ? 'hidden' : undefined,
|
||||
backgroundColor: background === 'grey' ? backgroundGrey : undefined,
|
||||
};
|
||||
|
||||
const codeBox: React.ReactNode = (
|
||||
<section className={codeBoxClass} id={asset.id}>
|
||||
<section className="code-box-demo" style={codeBoxDemoStyle}>
|
||||
<ErrorBoundary>
|
||||
<React.StrictMode>{liveDemo.current}</React.StrictMode>
|
||||
</ErrorBoundary>
|
||||
{style ? <style dangerouslySetInnerHTML={{ __html: style }} /> : null}
|
||||
</section>
|
||||
<section className="code-box-meta markdown">
|
||||
<div className="code-box-title">
|
||||
<Tooltip title={debug ? <FormattedMessage id="app.demo.debug" /> : ''}>
|
||||
<a href={`#${asset.id}`} ref={anchorRef}>
|
||||
{localizedTitle}
|
||||
</a>
|
||||
</Tooltip>
|
||||
<EditButton title={<FormattedMessage id="app.content.edit-demo" />} filename={filePath} />
|
||||
</div>
|
||||
<div className="code-box-description">{introChildren}</div>
|
||||
<Space wrap size="middle" className="code-box-actions">
|
||||
{showOnlineUrl && (
|
||||
<Tooltip title={<FormattedMessage id="app.demo.online" />}>
|
||||
<a
|
||||
className="code-box-code-action"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={docsOnlineUrl}
|
||||
>
|
||||
<LinkOutlined className="code-box-online" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showRiddleButton ? (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="//riddle.alibaba-inc.com/riddles/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={riddleIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'riddle', demo: asset.id });
|
||||
riddleIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
|
||||
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
|
||||
<RiddleIcon className="code-box-riddle" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
) : null}
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codesandbox.io/api/v1/sandboxes/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codeSandboxIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codesandbox', demo: asset.id });
|
||||
codeSandboxIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
name="parameters"
|
||||
value={compress(JSON.stringify(codesanboxPrefillConfig))}
|
||||
/>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
|
||||
<CodeSandboxIcon className="code-box-codesandbox" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codepen.io/pen/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codepenIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codepen', demo: asset.id });
|
||||
codepenIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<ClientOnly>
|
||||
<input type="hidden" name="data" value={JSON.stringify(codepenPrefillConfig)} />
|
||||
</ClientOnly>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codepen" />}>
|
||||
<CodePenIcon className="code-box-codepen" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.stackblitz" />}>
|
||||
<span
|
||||
className="code-box-code-action"
|
||||
onClick={() => {
|
||||
track({ type: 'stackblitz', demo: asset.id });
|
||||
stackblitzSdk.openProject(stackblitzPrefillConfig, {
|
||||
openFile: [`demo.${suffix}`],
|
||||
});
|
||||
}}
|
||||
>
|
||||
<ThunderboltOutlined className="code-box-stackblitz" />
|
||||
</span>
|
||||
</Tooltip>
|
||||
<CopyToClipboard text={entryCode} onCopy={() => handleCodeCopied(asset.id)}>
|
||||
<Tooltip
|
||||
open={copyTooltipOpen as boolean}
|
||||
onOpenChange={onCopyTooltipOpenChange}
|
||||
title={<FormattedMessage id={`app.demo.${copied ? 'copied' : 'copy'}`} />}
|
||||
>
|
||||
{React.createElement(copied && copyTooltipOpen ? CheckOutlined : SnippetsOutlined, {
|
||||
className: 'code-box-code-copy code-box-code-action',
|
||||
})}
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.separate" />}>
|
||||
<a className="code-box-code-action" target="_blank" rel="noreferrer" href={demoUrl}>
|
||||
<ExternalLinkIcon className="code-box-separate" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
title={<FormattedMessage id={`app.demo.code.${codeExpand ? 'hide' : 'show'}`} />}
|
||||
>
|
||||
<div className="code-expand-icon code-box-code-action">
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/btT3qDZn1U/wSAkBuJFbdxsosKKpqyq.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/Z5c7kzvi30/expand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'}
|
||||
onClick={() => handleCodeExpand(asset.id)}
|
||||
/>
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'}
|
||||
onClick={() => handleCodeExpand(asset.id)}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</section>
|
||||
<section className={highlightClass} key="code">
|
||||
<CodePreview
|
||||
codes={highlightedCodes}
|
||||
toReactComponent={toReactComponent}
|
||||
onCodeTypeChange={(type) => setCodeType(type)}
|
||||
/>
|
||||
{highlightedStyle ? (
|
||||
<div key="style" className="highlight">
|
||||
<pre>
|
||||
<code className="css" dangerouslySetInnerHTML={{ __html: highlightedStyle }} />
|
||||
</pre>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
|
||||
if (version) {
|
||||
return (
|
||||
<Badge.Ribbon text={version} color={version.includes('<') ? 'red' : null}>
|
||||
{codeBox}
|
||||
</Badge.Ribbon>
|
||||
);
|
||||
}
|
||||
|
||||
return codeBox;
|
||||
};
|
||||
|
||||
export default CodePreviewer;
|
||||
102
.dumi/theme/builtins/Previewer/DesignPreviewer.tsx
Normal file
102
.dumi/theme/builtins/Previewer/DesignPreviewer.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { useRef } from 'react';
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { CheckOutlined, SketchOutlined } from '@ant-design/icons';
|
||||
import { nodeToGroup } from 'html2sketch';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import { App } from 'antd';
|
||||
|
||||
const useStyle = createStyles(({ token }) => ({
|
||||
wrapper: css`
|
||||
border: 1px solid ${token.colorBorderSecondary};
|
||||
border-radius: ${token.borderRadius}px;
|
||||
padding: 20px 24px 40px;
|
||||
position: relative;
|
||||
margin-bottom: ${token.marginLG}px;
|
||||
`,
|
||||
title: css`
|
||||
font-size: ${token.fontSizeLG}px;
|
||||
font-weight: ${token.fontWeightStrong};
|
||||
color: ${token.colorTextHeading};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorTextHeading};
|
||||
}
|
||||
`,
|
||||
description: css`
|
||||
margin-top: ${token.margin}px;
|
||||
`,
|
||||
demo: css`
|
||||
margin-top: ${token.marginLG}px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
`,
|
||||
copy: css`
|
||||
position: absolute;
|
||||
inset-inline-end: 20px;
|
||||
inset-block-start: 20px;
|
||||
cursor: pointer;
|
||||
`,
|
||||
copyTip: css`
|
||||
color: ${token.colorTextTertiary};
|
||||
`,
|
||||
copiedTip: css`
|
||||
.anticon {
|
||||
color: ${token.colorSuccess};
|
||||
}
|
||||
`,
|
||||
tip: css`
|
||||
color: ${token.colorTextTertiary};
|
||||
margin-top: 40px;
|
||||
`,
|
||||
}));
|
||||
|
||||
const DesignPreviewer: FC<IPreviewerProps> = ({ children, title, description, tip, asset }) => {
|
||||
const { styles } = useStyle();
|
||||
const demoRef = useRef<HTMLDivElement>(null);
|
||||
const [copied, setCopied] = React.useState<boolean>(false);
|
||||
const { message } = App.useApp();
|
||||
|
||||
const handleCopy = async () => {
|
||||
try {
|
||||
const group = await nodeToGroup(demoRef.current);
|
||||
copy(JSON.stringify(group.toSketchJSON()));
|
||||
setCopied(true);
|
||||
setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 5000);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
message.error('复制失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper} id={asset.id}>
|
||||
<a className={styles.title} href={`#${asset.id}`}>
|
||||
{title}
|
||||
</a>
|
||||
<div className={styles.description} dangerouslySetInnerHTML={{ __html: description }} />
|
||||
<div className={styles.copy}>
|
||||
{copied ? (
|
||||
<div className={styles.copiedTip}>
|
||||
<CheckOutlined />
|
||||
<span style={{ marginLeft: 8 }}>已复制,使用 Kitchen 插件即可粘贴</span>
|
||||
</div>
|
||||
) : (
|
||||
<div onClick={handleCopy} className={styles.copyTip}>
|
||||
<SketchOutlined />
|
||||
<span style={{ marginLeft: 8 }}>复制 Sketch JSON</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.demo} ref={demoRef}>
|
||||
{children}
|
||||
</div>
|
||||
<div className={styles.tip}>{tip}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DesignPreviewer;
|
||||
@@ -1,95 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import JsonML from 'jsonml.js/lib/utils';
|
||||
import toReactComponent from 'jsonml-to-react-element';
|
||||
import Prism from 'prismjs';
|
||||
import 'prismjs/components/prism-typescript';
|
||||
import { useLocation, useIntl, type IPreviewerProps } from 'dumi';
|
||||
import { ping } from '../../utils';
|
||||
|
||||
let pingDeferrer: PromiseLike<boolean>;
|
||||
|
||||
function useShowRiddleButton() {
|
||||
const [showRiddleButton, setShowRiddleButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
pingDeferrer ??= new Promise<boolean>((resolve) => {
|
||||
ping((status) => {
|
||||
if (status !== 'timeout' && status !== 'error') {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
pingDeferrer.then(setShowRiddleButton);
|
||||
}, []);
|
||||
|
||||
return showRiddleButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* HOC for convert dumi previewer props to bisheng previewer props
|
||||
*/
|
||||
export default function fromDumiProps<P extends object>(
|
||||
WrappedComponent: React.ComponentType<P>,
|
||||
): React.FC<IPreviewerProps> {
|
||||
const hoc = function DumiPropsAntdPreviewer(props: IPreviewerProps) {
|
||||
const showRiddleButton = useShowRiddleButton();
|
||||
const location = useLocation();
|
||||
const { asset, children, demoUrl, expand, description = '', ...meta } = props;
|
||||
const intl = useIntl();
|
||||
const entryCode = asset.dependencies['index.tsx'].value;
|
||||
const transformedProps = {
|
||||
meta: {
|
||||
id: asset.id,
|
||||
title: '',
|
||||
filename: meta.filePath,
|
||||
...meta,
|
||||
},
|
||||
content: description,
|
||||
preview: () => children,
|
||||
utils: {
|
||||
toReactComponent(jsonML: any) {
|
||||
return toReactComponent(jsonML, [
|
||||
[
|
||||
(node: any) => JsonML.isElement(node) && JsonML.getTagName(node) === 'pre',
|
||||
(node: any, index: any) => {
|
||||
// ref: https://github.com/benjycui/bisheng/blob/master/packages/bisheng/src/bisheng-plugin-highlight/lib/browser.js#L7
|
||||
const attr = JsonML.getAttributes(node);
|
||||
return React.createElement(
|
||||
'pre',
|
||||
{
|
||||
key: index,
|
||||
className: `language-${attr.lang}`,
|
||||
},
|
||||
React.createElement('code', {
|
||||
dangerouslySetInnerHTML: { __html: attr.highlighted },
|
||||
}),
|
||||
);
|
||||
},
|
||||
],
|
||||
]);
|
||||
},
|
||||
},
|
||||
intl: { locale: intl.locale },
|
||||
showRiddleButton,
|
||||
sourceCodes: {
|
||||
jsx: meta.jsx,
|
||||
tsx: entryCode,
|
||||
},
|
||||
highlightedCodes: {
|
||||
jsx: Prism.highlight(meta.jsx, Prism.languages.javascript, 'jsx'),
|
||||
tsx: Prism.highlight(entryCode, Prism.languages.typescript, 'tsx'),
|
||||
},
|
||||
style: meta.style,
|
||||
location,
|
||||
src: demoUrl,
|
||||
expand,
|
||||
highlightedStyle: meta.style ? Prism.highlight(meta.style, Prism.languages.css, 'css') : '',
|
||||
} as P;
|
||||
|
||||
return <WrappedComponent {...transformedProps} />;
|
||||
};
|
||||
|
||||
return hoc;
|
||||
}
|
||||
@@ -1,507 +1,18 @@
|
||||
import {
|
||||
CheckOutlined,
|
||||
SnippetsOutlined,
|
||||
ThunderboltOutlined,
|
||||
LinkOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import stackblitzSdk from '@stackblitz/sdk';
|
||||
import type { Project } from '@stackblitz/sdk';
|
||||
import { Alert, Badge, Tooltip, Space } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import LZString from 'lz-string';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { FormattedMessage } from 'dumi';
|
||||
import ClientOnly from '../../common/ClientOnly';
|
||||
import BrowserFrame from '../../common/BrowserFrame';
|
||||
import EditButton from '../../common/EditButton';
|
||||
import CodePenIcon from '../../common/CodePenIcon';
|
||||
import CodePreview from '../../common/CodePreview';
|
||||
import CodeSandboxIcon from '../../common/CodeSandboxIcon';
|
||||
import RiddleIcon from '../../common/RiddleIcon';
|
||||
import ExternalLinkIcon from '../../common/ExternalLinkIcon';
|
||||
import fromDumiProps from './fromDumiProps';
|
||||
import type { SiteContextProps } from '../../slots/SiteContext';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import { version } from '../../../../package.json';
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
import { useTabMeta } from 'dumi';
|
||||
import CodePreviewer from './CodePreviewer';
|
||||
import DesignPreviewer from './DesignPreviewer';
|
||||
|
||||
const { ErrorBoundary } = Alert;
|
||||
const Previewer: FC<IPreviewerProps> = ({ ...props }) => {
|
||||
const tab = useTabMeta();
|
||||
|
||||
function compress(string: string): string {
|
||||
return LZString.compressToBase64(string)
|
||||
.replace(/\+/g, '-') // Convert '+' to '-'
|
||||
.replace(/\//g, '_') // Convert '/' to '_'
|
||||
.replace(/=+$/, ''); // Remove ending '='
|
||||
}
|
||||
|
||||
const track = ({ type, demo }: { type: string; demo: string }) => {
|
||||
if (!window.gtag) {
|
||||
return;
|
||||
if (tab?.frontmatter.title === 'Design') {
|
||||
return <DesignPreviewer {...props} />;
|
||||
}
|
||||
window.gtag('event', 'demo', { event_category: type, event_label: demo });
|
||||
|
||||
return <CodePreviewer {...props} />;
|
||||
};
|
||||
|
||||
interface DemoProps {
|
||||
meta: any;
|
||||
intl: any;
|
||||
utils?: any;
|
||||
src: string;
|
||||
content: string;
|
||||
highlightedCodes: Record<PropertyKey, string>;
|
||||
style: string;
|
||||
highlightedStyle: string;
|
||||
expand: boolean;
|
||||
sourceCodes: Record<'jsx' | 'tsx', string>;
|
||||
location: Location;
|
||||
showRiddleButton: boolean;
|
||||
preview: (react: typeof React, reactDOM: typeof ReactDOM) => React.ReactNode;
|
||||
}
|
||||
|
||||
const Demo: React.FC<DemoProps> = (props) => {
|
||||
const {
|
||||
location,
|
||||
sourceCodes,
|
||||
meta,
|
||||
src,
|
||||
utils,
|
||||
content,
|
||||
highlightedCodes,
|
||||
style,
|
||||
highlightedStyle,
|
||||
expand,
|
||||
intl: { locale },
|
||||
showRiddleButton,
|
||||
preview,
|
||||
} = props;
|
||||
|
||||
const liveDemo = useRef<React.ReactNode>(null);
|
||||
const anchorRef = useRef<HTMLAnchorElement>(null);
|
||||
const codeSandboxIconRef = useRef<HTMLFormElement>(null);
|
||||
const riddleIconRef = useRef<HTMLFormElement>(null);
|
||||
const codepenIconRef = useRef<HTMLFormElement>(null);
|
||||
const [codeExpand, setCodeExpand] = useState<boolean>(false);
|
||||
const [copyTooltipOpen, setCopyTooltipOpen] = useState<boolean>(false);
|
||||
const [copied, setCopied] = useState<boolean>(false);
|
||||
const [codeType, setCodeType] = useState<string>('tsx');
|
||||
const { theme } = useContext<SiteContextProps>(SiteContext);
|
||||
|
||||
const { hash, pathname, search } = location;
|
||||
const docsOnlineUrl = `https://ant.design${pathname}${search}#${meta.id}`;
|
||||
|
||||
const regexp = /preview-(\d+)-ant-design/; // matching PR preview addresses
|
||||
const showOnlineUrl =
|
||||
process.env.NODE_ENV === 'development' || regexp.test(window.location.hostname);
|
||||
|
||||
const handleCodeExpand = (demo: string) => {
|
||||
setCodeExpand((prev) => !prev);
|
||||
track({ type: 'expand', demo });
|
||||
};
|
||||
|
||||
const handleCodeCopied = (demo: string) => {
|
||||
setCopied(true);
|
||||
track({ type: 'copy', demo });
|
||||
};
|
||||
|
||||
const onCopyTooltipOpenChange = (open: boolean) => {
|
||||
setCopyTooltipOpen(open);
|
||||
if (open) {
|
||||
setCopied(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (meta.id === hash.slice(1)) {
|
||||
anchorRef.current?.click();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setCodeExpand(expand);
|
||||
}, [expand]);
|
||||
|
||||
if (!liveDemo.current) {
|
||||
liveDemo.current = meta.iframe ? (
|
||||
<BrowserFrame>
|
||||
<iframe src={src} height={meta.iframe} title="demo" className="iframe-demo" />
|
||||
</BrowserFrame>
|
||||
) : (
|
||||
preview(React, ReactDOM)
|
||||
);
|
||||
}
|
||||
|
||||
const codeBoxClass = classNames('code-box', {
|
||||
expand: codeExpand,
|
||||
'code-box-debug': meta.originDebug,
|
||||
});
|
||||
|
||||
const localizedTitle = meta?.title[locale] || meta?.title;
|
||||
const localizeIntro = content[locale] || content;
|
||||
const introChildren = <div dangerouslySetInnerHTML={{ __html: localizeIntro }} />;
|
||||
const highlightClass = classNames('highlight-wrapper', {
|
||||
'highlight-wrapper-expand': codeExpand,
|
||||
});
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" style="padding: 24px" />
|
||||
<script>const mountNode = document.getElementById('container');</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const tsconfig = `
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const suffix = codeType === 'tsx' ? 'tsx' : 'js';
|
||||
|
||||
const dependencies: Record<PropertyKey, string> = sourceCodes?.jsx.split('\n').reduce(
|
||||
(acc, line) => {
|
||||
const matches = line.match(/import .+? from '(.+)';$/);
|
||||
if (matches && matches[1] && !line.includes('antd')) {
|
||||
const paths = matches[1].split('/');
|
||||
if (paths.length) {
|
||||
const dep = paths[0].startsWith('@') ? `${paths[0]}/${paths[1]}` : paths[0];
|
||||
acc[dep] = 'latest';
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ antd: version },
|
||||
);
|
||||
|
||||
dependencies['@ant-design/icons'] = 'latest';
|
||||
|
||||
if (suffix === 'tsx') {
|
||||
dependencies['@types/react'] = '^18.0.0';
|
||||
dependencies['@types/react-dom'] = '^18.0.0';
|
||||
}
|
||||
|
||||
dependencies.react = '^18.0.0';
|
||||
dependencies['react-dom'] = '^18.0.0';
|
||||
|
||||
const codepenPrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
html,
|
||||
js: `const { createRoot } = ReactDOM;\n${sourceCodes?.jsx
|
||||
.replace(/import\s+(?:React,\s+)?{(\s+[^}]*\s+)}\s+from\s+'react'/, `const { $1 } = React;`)
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'antd';/, 'const { $1 } = antd;')
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'@ant-design\/icons';/, 'const { $1 } = icons;')
|
||||
.replace("import moment from 'moment';", '')
|
||||
.replace("import React from 'react';", '')
|
||||
.replace(/import\s+{\s+(.*)\s+}\s+from\s+'react-router';/, 'const { $1 } = ReactRouter;')
|
||||
.replace(
|
||||
/import\s+{\s+(.*)\s+}\s+from\s+'react-router-dom';/,
|
||||
'const { $1 } = ReactRouterDOM;',
|
||||
)
|
||||
.replace(/([A-Za-z]*)\s+as\s+([A-Za-z]*)/, '$1:$2')
|
||||
.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
editors: '001',
|
||||
css: '',
|
||||
js_external: [
|
||||
'react@18/umd/react.development.js',
|
||||
'react-dom@18/umd/react-dom.development.js',
|
||||
'dayjs@1/dayjs.min.js',
|
||||
`antd@${version}/dist/antd-with-locales.js`,
|
||||
`@ant-design/icons/dist/index.umd.js`,
|
||||
'react-router-dom/dist/umd/react-router-dom.production.min.js',
|
||||
'react-router/dist/umd/react-router.production.min.js',
|
||||
]
|
||||
.map((url) => `https://unpkg.com/${url}`)
|
||||
.join(';'),
|
||||
js_pre_processor: 'typescript',
|
||||
};
|
||||
|
||||
const riddlePrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
js: `${
|
||||
/import React(\D*)from 'react';/.test(sourceCodes?.jsx) ? '' : `import React from 'react';\n`
|
||||
}import { createRoot } from 'react-dom/client';\n${sourceCodes?.jsx.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
css: '',
|
||||
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
|
||||
};
|
||||
|
||||
// Reorder source code
|
||||
let parsedSourceCode = suffix === 'tsx' ? sourceCodes?.tsx : sourceCodes?.jsx;
|
||||
let importReactContent = "import React from 'react';";
|
||||
const importReactReg = /import React(\D*)from 'react';/;
|
||||
const matchImportReact = parsedSourceCode.match(importReactReg);
|
||||
if (matchImportReact) {
|
||||
[importReactContent] = matchImportReact;
|
||||
parsedSourceCode = parsedSourceCode.replace(importReactReg, '').trim();
|
||||
}
|
||||
const demoJsContent = `
|
||||
${importReactContent}
|
||||
import './index.css';
|
||||
${parsedSourceCode}
|
||||
`.trim();
|
||||
const indexCssContent = (style || '')
|
||||
.trim()
|
||||
.replace(new RegExp(`#${meta.id}\\s*`, 'g'), '')
|
||||
.replace('</style>', '')
|
||||
.replace('<style>', '');
|
||||
|
||||
const indexJsContent = `
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import Demo from './demo';
|
||||
|
||||
createRoot(document.getElementById('container')).render(<Demo />);
|
||||
`;
|
||||
|
||||
const codesandboxPackage = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
main: 'index.js',
|
||||
dependencies: {
|
||||
...dependencies,
|
||||
react: '^18.0.0',
|
||||
'react-dom': '^18.0.0',
|
||||
'react-scripts': '^4.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
typescript: '^4.0.5',
|
||||
},
|
||||
scripts: {
|
||||
start: 'react-scripts start',
|
||||
build: 'react-scripts build',
|
||||
test: 'react-scripts test --env=jsdom',
|
||||
eject: 'react-scripts eject',
|
||||
},
|
||||
browserslist: ['>0.2%', 'not dead'],
|
||||
};
|
||||
|
||||
const codesanboxPrefillConfig = {
|
||||
files: {
|
||||
'package.json': { content: codesandboxPackage },
|
||||
'index.css': { content: indexCssContent },
|
||||
[`index.${suffix}`]: { content: indexJsContent },
|
||||
[`demo.${suffix}`]: { content: demoJsContent },
|
||||
'index.html': {
|
||||
content: html,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const stackblitzPrefillConfig: Project = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
template: 'create-react-app',
|
||||
dependencies,
|
||||
description: '',
|
||||
files: {
|
||||
'index.css': indexCssContent,
|
||||
[`index.${suffix}`]: indexJsContent,
|
||||
[`demo.${suffix}`]: demoJsContent,
|
||||
'index.html': html,
|
||||
},
|
||||
};
|
||||
if (suffix === 'tsx') {
|
||||
stackblitzPrefillConfig.files['tsconfig.json'] = tsconfig;
|
||||
}
|
||||
|
||||
const backgroundGrey = theme.includes('dark') ? '#303030' : '#f0f2f5';
|
||||
|
||||
const codeBoxDemoStyle: React.CSSProperties = {
|
||||
padding: meta.iframe || meta.compact ? 0 : undefined,
|
||||
overflow: meta.iframe || meta.compact ? 'hidden' : undefined,
|
||||
backgroundColor: meta.background === 'grey' ? backgroundGrey : undefined,
|
||||
};
|
||||
|
||||
const codeBox: React.ReactNode = (
|
||||
<section className={codeBoxClass} id={meta.id}>
|
||||
<section className="code-box-demo" style={codeBoxDemoStyle}>
|
||||
<ErrorBoundary>
|
||||
<React.StrictMode>{liveDemo.current}</React.StrictMode>
|
||||
</ErrorBoundary>
|
||||
{style ? <style dangerouslySetInnerHTML={{ __html: style }} /> : null}
|
||||
</section>
|
||||
<section className="code-box-meta markdown">
|
||||
<div className="code-box-title">
|
||||
<Tooltip title={meta.originDebug ? <FormattedMessage id="app.demo.debug" /> : ''}>
|
||||
<a href={`#${meta.id}`} ref={anchorRef}>
|
||||
{localizedTitle}
|
||||
</a>
|
||||
</Tooltip>
|
||||
<EditButton
|
||||
title={<FormattedMessage id="app.content.edit-demo" />}
|
||||
filename={meta.filename}
|
||||
/>
|
||||
</div>
|
||||
<div className="code-box-description">{introChildren}</div>
|
||||
<Space wrap size="middle" className="code-box-actions">
|
||||
{showOnlineUrl && (
|
||||
<Tooltip title={<FormattedMessage id="app.demo.online" />}>
|
||||
<a
|
||||
className="code-box-code-action"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={docsOnlineUrl}
|
||||
>
|
||||
<LinkOutlined className="code-box-online" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showRiddleButton ? (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="//riddle.alibaba-inc.com/riddles/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={riddleIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'riddle', demo: meta.id });
|
||||
riddleIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
|
||||
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
|
||||
<RiddleIcon className="code-box-riddle" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
) : null}
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codesandbox.io/api/v1/sandboxes/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codeSandboxIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codesandbox', demo: meta.id });
|
||||
codeSandboxIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
name="parameters"
|
||||
value={compress(JSON.stringify(codesanboxPrefillConfig))}
|
||||
/>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
|
||||
<CodeSandboxIcon className="code-box-codesandbox" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codepen.io/pen/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codepenIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codepen', demo: meta.id });
|
||||
codepenIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<ClientOnly>
|
||||
<input type="hidden" name="data" value={JSON.stringify(codepenPrefillConfig)} />
|
||||
</ClientOnly>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codepen" />}>
|
||||
<CodePenIcon className="code-box-codepen" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.stackblitz" />}>
|
||||
<span
|
||||
className="code-box-code-action"
|
||||
onClick={() => {
|
||||
track({ type: 'stackblitz', demo: meta.id });
|
||||
stackblitzSdk.openProject(stackblitzPrefillConfig, {
|
||||
openFile: [`demo.${suffix}`],
|
||||
});
|
||||
}}
|
||||
>
|
||||
<ThunderboltOutlined className="code-box-stackblitz" />
|
||||
</span>
|
||||
</Tooltip>
|
||||
<CopyToClipboard text={sourceCodes?.tsx} onCopy={() => handleCodeCopied(meta.id)}>
|
||||
<Tooltip
|
||||
open={copyTooltipOpen as boolean}
|
||||
onOpenChange={onCopyTooltipOpenChange}
|
||||
title={<FormattedMessage id={`app.demo.${copied ? 'copied' : 'copy'}`} />}
|
||||
>
|
||||
{React.createElement(copied && copyTooltipOpen ? CheckOutlined : SnippetsOutlined, {
|
||||
className: 'code-box-code-copy code-box-code-action',
|
||||
})}
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.separate" />}>
|
||||
<a className="code-box-code-action" target="_blank" rel="noreferrer" href={src}>
|
||||
<ExternalLinkIcon className="code-box-separate" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
title={<FormattedMessage id={`app.demo.code.${codeExpand ? 'hide' : 'show'}`} />}
|
||||
>
|
||||
<div className="code-expand-icon code-box-code-action">
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/btT3qDZn1U/wSAkBuJFbdxsosKKpqyq.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/Z5c7kzvi30/expand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'}
|
||||
onClick={() => handleCodeExpand(meta.id)}
|
||||
/>
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'}
|
||||
onClick={() => handleCodeExpand(meta.id)}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</section>
|
||||
<section className={highlightClass} key="code">
|
||||
<CodePreview
|
||||
codes={highlightedCodes}
|
||||
toReactComponent={utils?.toReactComponent}
|
||||
onCodeTypeChange={(type) => setCodeType(type)}
|
||||
/>
|
||||
{highlightedStyle ? (
|
||||
<div key="style" className="highlight">
|
||||
<pre>
|
||||
<code className="css" dangerouslySetInnerHTML={{ __html: highlightedStyle }} />
|
||||
</pre>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
|
||||
if (meta.version) {
|
||||
return (
|
||||
<Badge.Ribbon text={meta.version} color={meta.version.includes('<') ? 'red' : null}>
|
||||
{codeBox}
|
||||
</Badge.Ribbon>
|
||||
);
|
||||
}
|
||||
|
||||
return codeBox;
|
||||
};
|
||||
|
||||
export default fromDumiProps(Demo);
|
||||
export default Previewer;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import * as React from 'react';
|
||||
/* eslint import/no-unresolved: 0 */
|
||||
import tokenMeta from 'antd/es/version/token-meta.json';
|
||||
import { getDesignToken } from 'antd-token-previewer';
|
||||
import { Table } from 'antd';
|
||||
import type { TableProps } from 'antd';
|
||||
import { css } from '@emotion/react';
|
||||
import type { TableProps } from 'antd';
|
||||
import { Table } from 'antd';
|
||||
import { getDesignToken } from 'antd-token-previewer';
|
||||
import tokenMeta from 'antd/es/version/token-meta.json';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import ColorChunk from '../ColorChunk';
|
||||
@@ -55,10 +55,11 @@ const useStyle = () => {
|
||||
};
|
||||
};
|
||||
|
||||
const TokenTable: FC<TokenTableProps> = ({ type }) => {
|
||||
export function useColumns(): Exclude<TableProps<TokenData>['columns'], undefined> {
|
||||
const [locale] = useLocale(locales);
|
||||
const styles = useStyle();
|
||||
const [locale, lang] = useLocale(locales);
|
||||
const columns: Exclude<TableProps<TokenData>['columns'], undefined> = [
|
||||
|
||||
return [
|
||||
{
|
||||
title: locale.token,
|
||||
key: 'name',
|
||||
@@ -89,8 +90,13 @@ const TokenTable: FC<TokenTableProps> = ({ type }) => {
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const data = useMemo<TokenData[]>(
|
||||
const TokenTable: FC<TokenTableProps> = ({ type }) => {
|
||||
const [, lang] = useLocale(locales);
|
||||
const columns = useColumns();
|
||||
|
||||
const data = React.useMemo<TokenData[]>(
|
||||
() =>
|
||||
Object.entries(tokenMeta)
|
||||
.filter(([, meta]) => meta.source === type)
|
||||
|
||||
333
.dumi/theme/common/BehaviorMap/index.tsx
Normal file
333
.dumi/theme/common/BehaviorMap/index.tsx
Normal file
@@ -0,0 +1,333 @@
|
||||
import G6 from '@antv/g6';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
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],
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
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: `
|
||||
<div style="width: 16px; height: 16px;">
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
|
||||
<g id="编组-30" transform="translate(288.000000, 354.000000)">
|
||||
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
|
||||
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
|
||||
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
|
||||
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#BFBFBF"></path>
|
||||
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#BFBFBF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
// 在 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: `
|
||||
<div style="width: 16px; height: 16px;">
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
|
||||
<g id="编组-30" transform="translate(288.000000, 354.000000)">
|
||||
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
|
||||
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
|
||||
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
|
||||
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#1677ff"></path>
|
||||
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#1677ff"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'rect',
|
||||
);
|
||||
|
||||
const dataTransform = (data: BehaviorMapItem) => {
|
||||
const changeData = (d: any, level = 0) => {
|
||||
const clonedData: any = {
|
||||
...d,
|
||||
};
|
||||
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 (d.children) {
|
||||
clonedData.children = d.children.map((child: any) => changeData(child, level + 1));
|
||||
}
|
||||
return clonedData;
|
||||
};
|
||||
return changeData(data);
|
||||
};
|
||||
|
||||
type BehaviorMapItem = {
|
||||
id: string;
|
||||
label: string;
|
||||
targetType?: 'mvp' | 'extension';
|
||||
children?: BehaviorMapItem[];
|
||||
link?: string;
|
||||
};
|
||||
|
||||
const useStyle = createStyles(() => ({
|
||||
container: css`
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
`,
|
||||
title: css`
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
font-size: 16px;
|
||||
`,
|
||||
tips: css`
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
`,
|
||||
mvp: css`
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&::before {
|
||||
display: block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 8px;
|
||||
background-color: #1677ff;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
}
|
||||
`,
|
||||
extension: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&::before {
|
||||
display: block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 8px;
|
||||
background-color: #a0a0a0;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
export type BehaviorMapProps = {
|
||||
data: BehaviorMapItem;
|
||||
};
|
||||
|
||||
const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const { styles } = useStyle();
|
||||
const meta = useRouteMeta();
|
||||
|
||||
useEffect(() => {
|
||||
const graph = 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,
|
||||
},
|
||||
});
|
||||
|
||||
graph.on('node:mouseenter', (e) => {
|
||||
graph.setItemState(e.item!, 'hover', true);
|
||||
});
|
||||
graph.on('node:mouseleave', (e) => {
|
||||
graph.setItemState(e.item!, 'hover', false);
|
||||
});
|
||||
graph.on('node:click', (e) => {
|
||||
const { link } = e.item!.getModel();
|
||||
if (link) {
|
||||
window.location.hash = link as string;
|
||||
}
|
||||
});
|
||||
|
||||
graph.data(dataTransform(data));
|
||||
graph.render();
|
||||
graph.fitCenter();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={styles.container}>
|
||||
<div className={styles.title}>{`${meta.frontmatter.title} 行为模式地图`}</div>
|
||||
<div className={styles.tips}>
|
||||
<div className={styles.mvp}>MVP 行为目的</div>
|
||||
<div className={styles.extension}>拓展行为目的</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BehaviorMap;
|
||||
@@ -1,5 +1,5 @@
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
import cls from 'classnames';
|
||||
import Palette from './Palette';
|
||||
|
||||
const colors = [
|
||||
@@ -79,11 +79,8 @@ const colors = [
|
||||
|
||||
const ColorPalettes: React.FC<{ dark?: boolean }> = (props) => {
|
||||
const { dark } = props;
|
||||
const colorCls = cls('color-palettes', {
|
||||
'color-palettes-dark': !!dark,
|
||||
});
|
||||
return (
|
||||
<div className={colorCls}>
|
||||
<div className={classnames('color-palettes', { 'color-palettes-dark': dark })}>
|
||||
{colors.map((color) => (
|
||||
<Palette key={color.name} color={color} dark={dark} showTitle />
|
||||
))}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { message } from 'antd';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { presetDarkPalettes } from '@ant-design/colors';
|
||||
import { message } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
const rgbToHex = (rgbString: string): string => {
|
||||
const rgb = rgbString.match(/\d+/g);
|
||||
@@ -21,22 +20,20 @@ interface PaletteProps {
|
||||
dark?: boolean;
|
||||
color?: {
|
||||
name: string;
|
||||
count: number;
|
||||
count?: number;
|
||||
description?: string;
|
||||
english?: string;
|
||||
chinese?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const Palette: FC<PaletteProps> = ({
|
||||
showTitle,
|
||||
direction,
|
||||
dark,
|
||||
color: { name, count = 10, description, english, chinese } = {
|
||||
name: 'gray',
|
||||
count: 13,
|
||||
},
|
||||
}) => {
|
||||
const Palette: React.FC<PaletteProps> = (props) => {
|
||||
const {
|
||||
showTitle,
|
||||
direction,
|
||||
dark,
|
||||
color: { name, count = 10, description, english, chinese } = { name: 'gray', count: 13 },
|
||||
} = props;
|
||||
const [hexColors, setHexColors] = React.useState<Record<PropertyKey, string>>({});
|
||||
const colorNodesRef = React.useRef<Record<PropertyKey, HTMLDivElement>>({});
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
PreviewImage,
|
||||
Reset,
|
||||
Responsive,
|
||||
SearchBar,
|
||||
} from './styles';
|
||||
|
||||
const GlobalStyles = () => (
|
||||
@@ -30,6 +31,7 @@ const GlobalStyles = () => (
|
||||
<PreviewImage />
|
||||
<ColorStyle />
|
||||
<HeadingAnchor />
|
||||
<SearchBar />
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
}
|
||||
|
||||
.code-box-demo {
|
||||
overflow: auto;
|
||||
background-color: ${token.colorBgContainer};
|
||||
border-radius: ${token.borderRadius}px ${token.borderRadius}px 0 0;
|
||||
}
|
||||
@@ -290,7 +291,7 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
transition: transform 0.24s;
|
||||
|
||||
&${iconCls}-check {
|
||||
color: ${token['green-6']} !important;
|
||||
color: ${token.green6} !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
@@ -342,11 +343,11 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
}
|
||||
|
||||
&-debug {
|
||||
border-color: ${token['purple-3']};
|
||||
border-color: ${token.purple3};
|
||||
}
|
||||
|
||||
&-debug &-title a {
|
||||
color: ${token['purple-6']};
|
||||
color: ${token.purple6};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ export default () => {
|
||||
|
||||
&:nth-child(3) {
|
||||
width: 22%;
|
||||
color: ${token['magenta-7']};
|
||||
color: ${token.magenta7};
|
||||
font-size: ${Math.max(token.fontSize - 1, 12)}px;
|
||||
}
|
||||
|
||||
|
||||
57
.dumi/theme/common/styles/SearchBar.tsx
Normal file
57
.dumi/theme/common/styles/SearchBar.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import { css, Global } from '@emotion/react';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
|
||||
const THEME_PREFIX = 'dumi-default-';
|
||||
|
||||
export default () => {
|
||||
const { token } = useSiteToken();
|
||||
|
||||
return (
|
||||
<Global
|
||||
styles={css`
|
||||
html {
|
||||
.${THEME_PREFIX}search-bar {
|
||||
&-input {
|
||||
color: ${token.colorText};
|
||||
background: ${token.colorBgContainer};
|
||||
&:focus {
|
||||
background: ${token.colorBgContainer};
|
||||
}
|
||||
&::placeholder {
|
||||
color: ${token.colorTextPlaceholder} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.${THEME_PREFIX}search-popover {
|
||||
background-color: ${token.colorBgElevated} !important;
|
||||
&::before {
|
||||
border-bottom-color: ${token.colorBgElevated} !important;
|
||||
}
|
||||
}
|
||||
.${THEME_PREFIX}search-result {
|
||||
dl {
|
||||
dt {
|
||||
background-color: ${token.controlItemBgActive} !important;
|
||||
}
|
||||
dd {
|
||||
a {
|
||||
&:hover {
|
||||
background-color: ${token.controlItemBgHover};
|
||||
h4,
|
||||
p {
|
||||
color: ${token.colorText} !important;
|
||||
}
|
||||
svg {
|
||||
fill: ${token.colorText} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -10,3 +10,4 @@ export { default as BrowserMockup } from './BrowserMockup';
|
||||
export { default as Responsive } from './Responsive';
|
||||
export { default as NProgress } from './NProgress';
|
||||
export { default as PreviewImage } from './PreviewImage';
|
||||
export { default as SearchBar } from './SearchBar';
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
parentSelectorLinter,
|
||||
StyleProvider,
|
||||
} from '@ant-design/cssinjs';
|
||||
import { ConfigProvider, theme as antdTheme } from 'antd';
|
||||
import { ConfigProvider, theme as antdTheme, App } from 'antd';
|
||||
import type { DirectionType } from 'antd/es/config-provider';
|
||||
import { createSearchParams, useOutlet, useSearchParams } from 'dumi';
|
||||
import React, { startTransition, useCallback, useEffect, useMemo } from 'react';
|
||||
@@ -118,13 +118,15 @@ const GlobalLayout: React.FC = () => {
|
||||
algorithm: getAlgorithm(theme),
|
||||
}}
|
||||
>
|
||||
{outlet}
|
||||
{!pathname.startsWith('/~demos') && (
|
||||
<ThemeSwitch
|
||||
value={theme}
|
||||
onChange={(nextTheme) => updateSiteConfig({ theme: nextTheme })}
|
||||
/>
|
||||
)}
|
||||
<App>
|
||||
{outlet}
|
||||
{!pathname.startsWith('/~demos') && (
|
||||
<ThemeSwitch
|
||||
value={theme}
|
||||
onChange={(nextTheme) => updateSiteConfig({ theme: nextTheme })}
|
||||
/>
|
||||
)}
|
||||
</App>
|
||||
</ConfigProvider>
|
||||
</SiteContext.Provider>
|
||||
</StyleProvider>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs';
|
||||
import type { IApi, IRoute } from 'dumi';
|
||||
import { extractStyle } from '@ant-design/cssinjs';
|
||||
import type { IApi, IRoute } from 'dumi';
|
||||
import ReactTechStack from 'dumi/dist/techStacks/react';
|
||||
import fs from 'fs';
|
||||
import sylvanas from 'sylvanas';
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import ContributorsList from '@qixian.cs/github-contributors-list';
|
||||
import { Affix, Anchor, Avatar, Col, Skeleton, Space, Tooltip, Typography } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import DayJS from 'dayjs';
|
||||
import { FormattedMessage, useIntl, useRouteMeta } from 'dumi';
|
||||
import { FormattedMessage, useIntl, useRouteMeta, useTabMeta } from 'dumi';
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import useLocation from '../../../hooks/useLocation';
|
||||
@@ -57,10 +57,10 @@ const useStyle = () => {
|
||||
box-sizing: border-box;
|
||||
|
||||
.toc-debug {
|
||||
color: ${token['purple-6']};
|
||||
color: ${token.purple6};
|
||||
|
||||
&:hover {
|
||||
color: ${token['purple-5']};
|
||||
color: ${token.purple5};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,8 +105,36 @@ type AnchorItem = {
|
||||
children?: AnchorItem[];
|
||||
};
|
||||
|
||||
const AvatarPlaceholder = ({ num = 3 }: { num?: number }) => (
|
||||
<>
|
||||
{Array.from({ length: num }).map((_, i) => (
|
||||
<Skeleton.Avatar size="small" active key={i} style={{ marginLeft: i === 0 ? 0 : -8 }} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
const AuthorAvatar = ({ name, avatar }: { name: string; avatar: string }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
useLayoutEffect(() => {
|
||||
const img = new Image();
|
||||
img.src = avatar;
|
||||
img.onload = () => setLoading(false);
|
||||
img.onerror = () => setError(true);
|
||||
}, []);
|
||||
|
||||
if (error) return null;
|
||||
if (loading) return <Skeleton.Avatar size="small" active />;
|
||||
return (
|
||||
<Avatar size="small" src={avatar} alt={name}>
|
||||
{name}
|
||||
</Avatar>
|
||||
);
|
||||
};
|
||||
|
||||
const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const meta = useRouteMeta();
|
||||
const tab = useTabMeta();
|
||||
const { pathname, hash } = useLocation();
|
||||
const { formatMessage } = useIntl();
|
||||
const styles = useStyle();
|
||||
@@ -132,7 +160,7 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
|
||||
const anchorItems = useMemo(
|
||||
() =>
|
||||
meta.toc.reduce<AnchorItem[]>((result, item) => {
|
||||
(tab?.toc || meta.toc).reduce<AnchorItem[]>((result, item) => {
|
||||
if (item.depth === 2) {
|
||||
result.push({ ...item });
|
||||
} else if (item.depth === 3) {
|
||||
@@ -144,18 +172,36 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
}
|
||||
return result;
|
||||
}, []),
|
||||
[meta.toc],
|
||||
[tab?.toc, meta.toc],
|
||||
);
|
||||
|
||||
const isRTL = direction === 'rtl';
|
||||
|
||||
const avatarPlaceholder = (
|
||||
<>
|
||||
<Skeleton.Avatar size="small" active />
|
||||
<Skeleton.Avatar size="small" active style={{ marginLeft: -8 }} />
|
||||
<Skeleton.Avatar size="small" active style={{ marginLeft: -8 }} />
|
||||
</>
|
||||
);
|
||||
// support custom author info in frontmatter
|
||||
// e.g.
|
||||
// ---
|
||||
// author:
|
||||
// - name: qixian
|
||||
// avatar: https://avatars.githubusercontent.com/u/11746742?v=4
|
||||
// - name: yutingzhao1991
|
||||
// avatar: https://avatars.githubusercontent.com/u/5378891?v=4
|
||||
// ---
|
||||
const mergedAuthorInfos = useMemo(() => {
|
||||
const { author } = meta.frontmatter;
|
||||
if (!author) {
|
||||
return [];
|
||||
}
|
||||
if (typeof author === 'string') {
|
||||
return author.split(',').map((item) => ({
|
||||
name: item,
|
||||
avatar: `https://github.com/${item}.png`,
|
||||
}));
|
||||
}
|
||||
if (Array.isArray(author)) {
|
||||
return author;
|
||||
}
|
||||
return [];
|
||||
}, [meta.frontmatter.author]);
|
||||
|
||||
return (
|
||||
<DemoContext.Provider value={contextValue}>
|
||||
@@ -187,7 +233,7 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
</section>
|
||||
</Affix>
|
||||
<article css={styles.articleWrapper} className={classNames({ rtl: isRTL })}>
|
||||
{meta.frontmatter?.title && meta.frontmatter.subtitle ? (
|
||||
{meta.frontmatter?.title ? (
|
||||
<Typography.Title style={{ fontSize: 30 }}>
|
||||
{meta.frontmatter?.title}
|
||||
{meta.frontmatter.subtitle && (
|
||||
@@ -203,32 +249,41 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
) : null}
|
||||
{/* 添加作者、时间等信息 */}
|
||||
{meta.frontmatter.date || meta.frontmatter.author ? (
|
||||
<Typography.Paragraph style={{ opacity: 0.65 }}>
|
||||
<Typography.Paragraph>
|
||||
<Space>
|
||||
{meta.frontmatter.date && (
|
||||
<span>
|
||||
<span style={{ opacity: 0.65 }}>
|
||||
<CalendarOutlined /> {DayJS(meta.frontmatter.date).format('YYYY-MM-DD')}
|
||||
</span>
|
||||
)}
|
||||
{meta.frontmatter.author &&
|
||||
(meta.frontmatter.author as string)?.split(',')?.map((author) => (
|
||||
<Typography.Link href={`https://github.com/${author}`} key={author}>
|
||||
@{author}
|
||||
</Typography.Link>
|
||||
))}
|
||||
{mergedAuthorInfos.map((info) => (
|
||||
<a
|
||||
href={`https://github.com/${info.name}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key={info.name}
|
||||
>
|
||||
<Space size={3}>
|
||||
<AuthorAvatar name={info.name} avatar={info.avatar} />
|
||||
<span style={{ opacity: 0.65 }}>@{info.name}</span>
|
||||
</Space>
|
||||
</a>
|
||||
))}
|
||||
</Space>
|
||||
</Typography.Paragraph>
|
||||
) : null}
|
||||
{!meta.frontmatter.__autoDescription && meta.frontmatter.description}
|
||||
{children}
|
||||
{meta.frontmatter.filename && (
|
||||
<ContributorsList
|
||||
repo="ant-design"
|
||||
owner="ant-design"
|
||||
css={styles.contributorsList}
|
||||
cache
|
||||
fileName={meta.frontmatter.filename}
|
||||
renderItem={(item, loading) =>
|
||||
loading || !item ? (
|
||||
avatarPlaceholder
|
||||
<AvatarPlaceholder />
|
||||
) : (
|
||||
<Tooltip
|
||||
mouseEnterDelay={0.3}
|
||||
|
||||
57
.dumi/theme/slots/ContentTabs/index.tsx
Normal file
57
.dumi/theme/slots/ContentTabs/index.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import { CodeOutlined, SkinOutlined } from '@ant-design/icons';
|
||||
import { Tabs } from 'antd';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
import type { IContentTabsProps } from 'dumi/theme-default/slots/ContentTabs';
|
||||
import type { TabsProps } from 'rc-tabs';
|
||||
|
||||
const titleMap: Record<string, string> = {
|
||||
design: '设计',
|
||||
};
|
||||
|
||||
const iconMap: Record<string, ReactNode> = {
|
||||
design: <SkinOutlined />,
|
||||
};
|
||||
|
||||
const ContentTabs: FC<IContentTabsProps> = ({ tabs, tabKey, onChange }) => {
|
||||
const meta = useRouteMeta();
|
||||
|
||||
if (!meta.tabs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
label: (
|
||||
<span>
|
||||
<CodeOutlined />
|
||||
开发
|
||||
</span>
|
||||
),
|
||||
key: 'development',
|
||||
},
|
||||
];
|
||||
tabs?.forEach((tab) => {
|
||||
items.push({
|
||||
label: (
|
||||
<span>
|
||||
{iconMap[tab.key]}
|
||||
{titleMap[tab.key]}
|
||||
</span>
|
||||
),
|
||||
key: tab.key,
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
items={items}
|
||||
activeKey={tabKey || 'development'}
|
||||
onChange={(key) => onChange(tabs.find((tab) => tab.key === key))}
|
||||
style={{ margin: '32px 0 -16px' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentTabs;
|
||||
@@ -215,7 +215,7 @@ const Footer: React.FC = () => {
|
||||
{
|
||||
icon: <ZhihuOutlined style={{ color: '#056de8' }} />,
|
||||
title: <FormattedMessage id="app.footer.zhihu.xtech" />,
|
||||
url: 'http://zhuanlan.zhihu.com/xtech',
|
||||
url: 'https://www.zhihu.com/column/c_1543658574504751104',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,10 +2,9 @@ import { GithubOutlined, MenuOutlined } from '@ant-design/icons';
|
||||
import { ClassNames, css } from '@emotion/react';
|
||||
import { Col, Modal, Popover, Row, Select } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { useLocation } from 'dumi';
|
||||
import { useLocation, useSiteData } from 'dumi';
|
||||
import DumiSearchBar from 'dumi/theme-default/slots/SearchBar';
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import packageJson from '../../../../package.json';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import * as utils from '../../utils';
|
||||
@@ -21,8 +20,6 @@ import SwitchBtn from './SwitchBtn';
|
||||
const RESPONSIVE_XS = 1120;
|
||||
const RESPONSIVE_SM = 1200;
|
||||
|
||||
const antdVersion: string = packageJson.version;
|
||||
|
||||
const useStyle = () => {
|
||||
const { token } = useSiteToken();
|
||||
const searchIconColor = '#ced4d9';
|
||||
@@ -33,7 +30,7 @@ const useStyle = () => {
|
||||
z-index: 10;
|
||||
max-width: 100%;
|
||||
background: ${token.colorBgContainer};
|
||||
box-shadow: ${token.boxShadow};
|
||||
box-shadow: ${token.boxShadowTertiary};
|
||||
|
||||
@media only screen and (max-width: ${token.mobileMaxWidth}px) {
|
||||
text-align: center;
|
||||
@@ -129,6 +126,8 @@ const Header: React.FC = () => {
|
||||
const [isClient, setIsClient] = React.useState(false);
|
||||
const [, lang] = useLocale();
|
||||
|
||||
const { pkg } = useSiteData();
|
||||
|
||||
const themeConfig = getThemeConfig();
|
||||
const [headerState, setHeaderState] = useState<HeaderState>({
|
||||
menuVisible: false,
|
||||
@@ -240,7 +239,7 @@ const Header: React.FC = () => {
|
||||
|
||||
const { menuVisible, windowWidth, searching } = headerState;
|
||||
const docVersions: Record<string, string> = {
|
||||
[antdVersion]: antdVersion,
|
||||
[pkg.version]: pkg.version,
|
||||
...themeConfig?.docVersions,
|
||||
};
|
||||
const versionOptions = Object.keys(docVersions).map((version) => ({
|
||||
@@ -287,7 +286,7 @@ const Header: React.FC = () => {
|
||||
key="version"
|
||||
className="version"
|
||||
size="small"
|
||||
defaultValue={antdVersion}
|
||||
defaultValue={pkg.version}
|
||||
onChange={handleVersionChange}
|
||||
dropdownStyle={getDropdownStyle}
|
||||
dropdownMatchSelectWidth={false}
|
||||
@@ -358,7 +357,7 @@ const Header: React.FC = () => {
|
||||
content={menu}
|
||||
trigger="click"
|
||||
open={menuVisible}
|
||||
arrowPointAtCenter
|
||||
arrow={{ arrowPointAtCenter: true }}
|
||||
onOpenChange={onMenuVisibleChange}
|
||||
>
|
||||
<MenuOutlined className="nav-phone-icon" onClick={handleShowMenu} />
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"extends": "../.dumi/tmp/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "@emotion/react",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { defineConfig } from 'dumi';
|
||||
import path from 'path';
|
||||
import rehypeAntd from './.dumi/rehypeAntd';
|
||||
import remarkAntd from './.dumi/remarkAntd';
|
||||
import { version } from './package.json';
|
||||
|
||||
export default defineConfig({
|
||||
@@ -33,6 +34,7 @@ export default defineConfig({
|
||||
antd: require.resolve('./.dumi/theme/antd.js'),
|
||||
},
|
||||
extraRehypePlugins: [rehypeAntd],
|
||||
extraRemarkPlugins: [remarkAntd],
|
||||
extraBabelPresets: ['@emotion/babel-preset-css-prop'],
|
||||
mfsu: false,
|
||||
metas: [{ name: 'theme-color', content: '#1677ff' }],
|
||||
|
||||
@@ -14,6 +14,7 @@ server
|
||||
.dumi/tmp-production
|
||||
!.dumi/
|
||||
node_modules
|
||||
.eslintcache
|
||||
_site
|
||||
dist
|
||||
coverage
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -6,7 +6,7 @@ Your pull requests will be merged after one of the collaborators approve.
|
||||
Thank you!
|
||||
-->
|
||||
|
||||
[[中文版模板 / Chinese template](https://github.com/ant-design/ant-design/blob/master/.github/PULL_REQUEST_TEMPLATE/pr_cn.md)]
|
||||
[[中文版模板 / Chinese template](https://github.com/ant-design/ant-design/blob/master/.github/PULL_REQUEST_TEMPLATE/pr_cn.md?plain=1)]
|
||||
|
||||
### 🤔 This is a ...
|
||||
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE/pr_cn.md
vendored
2
.github/PULL_REQUEST_TEMPLATE/pr_cn.md
vendored
@@ -6,7 +6,7 @@
|
||||
请确保填写以下 pull request 的信息,谢谢!~
|
||||
-->
|
||||
|
||||
[[English Template / 英文模板](https://github.com/ant-design/ant-design/blob/master/.github/PULL_REQUEST_TEMPLATE.md)]
|
||||
[[English Template / 英文模板](https://github.com/ant-design/ant-design/blob/master/.github/PULL_REQUEST_TEMPLATE.md?plain=1)]
|
||||
|
||||
### 🤔 这个变动的性质是?
|
||||
|
||||
|
||||
23
.github/workflows/chatgpt-cr.yml
vendored
Normal file
23
.github/workflows/chatgpt-cr.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: 🤖 ChatGPT Code Review
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: anc95/ChatGPT-CodeReview@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
# Optional
|
||||
LANGUAGE: Chinese
|
||||
MODEL:
|
||||
top_p: 1
|
||||
temperature: 1
|
||||
74
.github/workflows/codeql.yml
vendored
74
.github/workflows/codeql.yml
vendored
@@ -1,74 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "feature" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master", "feature" ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
29
.github/workflows/mock-project-build.yml
vendored
Normal file
29
.github/workflows/mock-project-build.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Build a cron job to create a umi project which use antd and dumi, and then build it.
|
||||
name: Mock Project Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '*/30 * * * *'
|
||||
|
||||
jobs:
|
||||
pr-check-ci:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build Project
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Run Script
|
||||
run: bash ./scripts/ci-mock-project-build.sh
|
||||
|
||||
- uses: actions-cool/ci-notice@v1
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
notice-types: 'dingding'
|
||||
dingding-token: ${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
|
||||
notice-title: 'CI Mock Project Build Failed'
|
||||
2
.github/workflows/release-helper.yml
vendored
2
.github/workflows/release-helper.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
branch: 'master, 4.x-stable'
|
||||
tag: '5*, 4*'
|
||||
latest: '5*'
|
||||
dingding-token: ${{ secrets.DINGDING_BOT_BIGFISH_TOKEN }} ${{ secrets.DINGDING_BOT_YUNFENGDIE_TOKEN }}
|
||||
dingding-token: ${{ secrets.DINGDING_BOT_BIGFISH_TOKEN }} ${{ secrets.DINGDING_BOT_BIGFISH_2_TOKEN }} ${{ secrets.DINGDING_BOT_YUNFENGDIE_TOKEN }}
|
||||
dingding-msg: 'CHANGELOG.zh-CN.md'
|
||||
dingding-delay-minute: 10
|
||||
release: false
|
||||
|
||||
4
.github/workflows/size-limit.yml
vendored
4
.github/workflows/size-limit.yml
vendored
@@ -25,6 +25,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
||||
1
.github/workflows/sync-gitee.yml
vendored
1
.github/workflows/sync-gitee.yml
vendored
@@ -10,6 +10,7 @@ on:
|
||||
- 3.x-stable
|
||||
- 4.x-stable
|
||||
create:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
33
.github/workflows/test.yml
vendored
33
.github/workflows/test.yml
vendored
@@ -19,6 +19,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -51,6 +55,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -73,6 +81,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -97,6 +109,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -136,6 +152,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -209,6 +229,11 @@ jobs:
|
||||
needs: [normal-test]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: coverage-artifacts
|
||||
@@ -231,6 +256,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -278,6 +307,10 @@ jobs:
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
# lib only run in master branch not in pull request
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
|
||||
13
.github/workflows/verify-files-modify.yml
vendored
13
.github/workflows/verify-files-modify.yml
vendored
@@ -26,16 +26,3 @@ jobs:
|
||||
Hi @${{ github.event.pull_request.user.login }}. Thanks for your contribution. The path `.github/` or `scripts/` and `CHANGELOG` is only maintained by team members. This current PR will be closed and team members will help on this.
|
||||
close: true
|
||||
set-failed: false
|
||||
|
||||
- name: verify-less
|
||||
uses: actions-cool/verify-files-modify@v1
|
||||
with:
|
||||
forbid-files: 'components/style/themes/default.less'
|
||||
skip-verify-authority: 'admin'
|
||||
comment-mark: 'less'
|
||||
comment: |
|
||||
🚨 Hi @${{ github.event.pull_request.user.login }}. Thanks for your contribution, as the `default.less` file is currently being upgraded, changes are not recommended.
|
||||
|
||||
🚨 你好,@${{ github.event.pull_request.user.login }}。感谢你的贡献,由于 `default.less` 文件近期处于升级状态,不建议进行更改。
|
||||
close: false
|
||||
set-failed: false
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -63,3 +63,4 @@ __image_snapshots__/
|
||||
/imageDiffSnapshots
|
||||
|
||||
.devcontainer*
|
||||
.husky/prepare-commit-msg
|
||||
|
||||
13
.jest.js
13
.jest.js
@@ -1,14 +1,4 @@
|
||||
const compileModules = [
|
||||
'array-move',
|
||||
'react-dnd',
|
||||
'react-dnd-html5-backend',
|
||||
'@react-dnd',
|
||||
'dnd-core',
|
||||
'react-sticky-box',
|
||||
'tween-one',
|
||||
'@babel',
|
||||
'@ant-design',
|
||||
];
|
||||
const compileModules = ['dnd-core', 'react-sticky-box', 'tween-one', '@babel', '@ant-design'];
|
||||
|
||||
const ignoreList = [];
|
||||
|
||||
@@ -62,6 +52,7 @@ module.exports = {
|
||||
'!components/*/__tests__/image.test.{ts,tsx}',
|
||||
'!components/__tests__/node.test.tsx',
|
||||
'!components/*/demo/*.tsx',
|
||||
'!components/*/design/**',
|
||||
],
|
||||
transformIgnorePatterns,
|
||||
globals: {
|
||||
|
||||
42
.stylelintrc.js
Normal file
42
.stylelintrc.js
Normal file
@@ -0,0 +1,42 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'stylelint-config-standard',
|
||||
'stylelint-prettier/recommended',
|
||||
'stylelint-config-rational-order',
|
||||
],
|
||||
// 使用 stylelint 来 lint css in js? https://github.com/emotion-js/emotion/discussions/2694
|
||||
rules: {
|
||||
'function-name-case': ['lower'],
|
||||
'function-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignoreFunctions: [
|
||||
'fade',
|
||||
'fadeout',
|
||||
'tint',
|
||||
'darken',
|
||||
'ceil',
|
||||
'fadein',
|
||||
'floor',
|
||||
'unit',
|
||||
'shade',
|
||||
'lighten',
|
||||
'percentage',
|
||||
'-',
|
||||
],
|
||||
},
|
||||
],
|
||||
'import-notation': null,
|
||||
'no-descending-specificity': null,
|
||||
'no-invalid-position-at-import-rule': null,
|
||||
'declaration-empty-line-before': null,
|
||||
'keyframes-name-pattern': null,
|
||||
'custom-property-pattern': null,
|
||||
'number-max-precision': 8,
|
||||
'alpha-value-notation': 'number',
|
||||
'color-function-notation': 'legacy',
|
||||
'selector-class-pattern': null,
|
||||
'selector-id-pattern': null,
|
||||
'selector-not-notation': null,
|
||||
},
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"stylelint-config-standard",
|
||||
"stylelint-config-rational-order",
|
||||
"stylelint-config-prettier"
|
||||
],
|
||||
"customSyntax": "postcss-less",
|
||||
"plugins": ["stylelint-declaration-block-no-ignored-properties"],
|
||||
"rules": {
|
||||
"function-name-case": ["lower"],
|
||||
"function-no-unknown": [
|
||||
true,
|
||||
{
|
||||
"ignoreFunctions": [
|
||||
"fade",
|
||||
"fadeout",
|
||||
"tint",
|
||||
"darken",
|
||||
"ceil",
|
||||
"fadein",
|
||||
"floor",
|
||||
"unit",
|
||||
"shade",
|
||||
"lighten",
|
||||
"percentage",
|
||||
"-"
|
||||
]
|
||||
}
|
||||
],
|
||||
"import-notation": null,
|
||||
"no-descending-specificity": null,
|
||||
"no-invalid-position-at-import-rule": null,
|
||||
"declaration-empty-line-before": null,
|
||||
"keyframes-name-pattern": null,
|
||||
"custom-property-pattern": null,
|
||||
"number-max-precision": 8,
|
||||
"alpha-value-notation": "number",
|
||||
"color-function-notation": "legacy",
|
||||
"selector-class-pattern": null,
|
||||
"selector-id-pattern": null,
|
||||
"selector-not-notation": null
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,139 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 5.3.2
|
||||
|
||||
`2023-03-20`
|
||||
|
||||
- Anchor
|
||||
- 💄 Fix Anchor redundant border style when it is set to horizontal direction. [#41336](https://github.com/ant-design/ant-design/pull/41336) [@gooyoung](https://github.com/gooyoung)
|
||||
- 💄 Fix Anchor ink square style in `vertical` mode. [#41317](https://github.com/ant-design/ant-design/pull/41317) [@acyza](https://github.com/acyza)
|
||||
- 🐞 Fix Grid `offset` can not be overwritten problem under different device screen sizes. [#41309](https://github.com/ant-design/ant-design/pull/41309) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix Breadcrumb `onClick` not working bug. [#41283](https://github.com/ant-design/ant-design/pull/41283) [@acyza](https://github.com/acyza)
|
||||
- 🐞 Fix Upload trigger Progress warning after upload. [#41234](https://github.com/ant-design/ant-design/pull/41234) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 Fix Table unexpected layout problem when dragging element to the right. [#41139](https://github.com/ant-design/ant-design/pull/41139) [@hoho2017](https://github.com/hoho2017)
|
||||
- 💄 Fix Tabs more icon color in dark mode. [#41313](https://github.com/ant-design/ant-design/pull/41313) [@PhosphorusP](https://github.com/PhosphorusP)
|
||||
- 💄 Fix Button focus outline style be covered by Dropdown.Button. [#41282](https://github.com/ant-design/ant-design/pull/41282) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 Fix Input.TextArea style problem when focusing. [#41228](https://github.com/ant-design/ant-design/pull/41228) [@MuxinFeng](https://github.com/MuxinFeng)
|
||||
|
||||
- RTL
|
||||
- 💄 Fix Input.TextArea RTL style when enable `showCount`. [#41319](https://github.com/ant-design/ant-design/pull/41319) [@ds1371dani](https://github.com/ds1371dani)
|
||||
- TypeScript
|
||||
- 🤖 Export `CountdownProps` for Statistic. [#41341](https://github.com/ant-design/ant-design/pull/41341) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🤖 Improve most alias token meta info. [#41297](https://github.com/ant-design/ant-design/pull/41297) [@arvinxx](https://github.com/arvinxx)
|
||||
- 🤖 Improve Badge `React.forwardRef` type definition. [#41189](https://github.com/ant-design/ant-design/pull/41189) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
|
||||
## 5.3.1
|
||||
|
||||
`2023-03-13`
|
||||
|
||||
- 🐞 Update DatePicker deps to fix laggy in Safari and support align with `transform scale`. [#41090](https://github.com/ant-design/ant-design/pull/41090)
|
||||
- 🐞 Fix Menu collapse, Tooltip sometime show with unexpected. [#41081](https://github.com/ant-design/ant-design/issues/41081)
|
||||
- 🐞 Fix Modal.confirm has additional node which makes height not correct. [#41173](https://github.com/ant-design/ant-design/pull/41173) [@Svudec](https://github.com/Svudec)
|
||||
- 🐞 Fixed InputNumber `disabled` text color not correct. [#41167](https://github.com/ant-design/ant-design/pull/41167) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix Anchor highlighting not working when dynamically updating `items`. [#40743](https://github.com/ant-design/ant-design/pull/40743) [@zqran](https://github.com/zqran)
|
||||
- 🛠 Update Mentions deps to support align with `transform scale`. [#41160](https://github.com/ant-design/ant-design/pull/41160) [@MuxinFeng](https://github.com/MuxinFeng)
|
||||
- 🐞 Fix Form with manually called `validateFields` not show success status when `hasFeedback` is on. [#41116](https://github.com/ant-design/ant-design/pull/41116) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 Fix Cascader sub panel not close when hover to leaf node. [#41134](https://github.com/ant-design/ant-design/issues/41134)
|
||||
- 🐞 Fix Popconfirm using `Promise` to close will not exist `loading` state even when open again. [#41121](https://github.com/ant-design/ant-design/pull/41121)
|
||||
- 🐞 Fix Upload `onChange` sometime not sync when in React 18. [#41082](https://github.com/ant-design/ant-design/pull/41082) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🛎 Update demo with Space.Compact instead of legacy one and patch warning info. [#41080](https://github.com/ant-design/ant-design/pull/41080) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🌐 Update ko_KR、Added Amharic Language. [#41103](https://github.com/ant-design/ant-design/pull/41103) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
|
||||
## 5.3.0
|
||||
|
||||
`2023-03-06`
|
||||
|
||||
- 🆕 Tooltip support `arrow.pointAtCenter` and deprecate `arrow.arrowPointAtCenter`. [#40989](https://github.com/ant-design/ant-design/pull/40989) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🆕 Progress support custom `size`. [#40903](https://github.com/ant-design/ant-design/pull/40903) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🆕 Tour support custom `zIndex`. [#40982](https://github.com/ant-design/ant-design/pull/40982) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🆕 Table `onHeaderCell` support customize `colSpan` and `rowSpan`. [#40885](https://github.com/ant-design/ant-design/pull/40885)
|
||||
- 🆕 Image.Group support `onChange` callback. [#40857](https://github.com/ant-design/ant-design/pull/40857) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- App
|
||||
- 🆕 App support `style` props. [#40708](https://github.com/ant-design/ant-design/pull/40708) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🆕 App support `message` and `notification` options. [#40458](https://github.com/ant-design/ant-design/pull/40458) [@luo3house](https://github.com/luo3house)
|
||||
- 🆕 ConfigProvider support `useConfig` hook to get `size` and `disabled` in context. [#40215](https://github.com/ant-design/ant-design/pull/40215) [@xliez](https://github.com/xliez)
|
||||
- 🆕 Breadcrumb support `items` prop. [#40543](https://github.com/ant-design/ant-design/pull/40543) [@heiyu4585](https://github.com/heiyu4585)
|
||||
- 🛠 Breadcrumb separators are unified into `li` elements. [#40887](https://github.com/ant-design/ant-design/pull/40887) [@heiyu4585](https://github.com/heiyu4585)
|
||||
- 🛠 Tooltip support auto arrow position & adjust position if possible. `destroyTooltipOnHide.keepParent` is deprecated since it will be always auto destroy unnecessary container now. [#40632](https://github.com/ant-design/ant-design/pull/40632)
|
||||
- 🛠 Rename preset colors in token, .e.g `blue-1` to `blue1`, and deprecate tokens before. [#41071](https://github.com/ant-design/ant-design/pull/41071)
|
||||
- 💄 Message use `colorText` in style. [#41047](https://github.com/ant-design/ant-design/pull/41047) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 Fix Select, TreeSelect, Cascader popup align position not correct when parent has `transform: scale` style. [#41013](https://github.com/ant-design/ant-design/pull/41013)
|
||||
- 💄 Optimize `rowScope` style for Table. [#40304](https://github.com/ant-design/ant-design/pull/40304) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 Provide new AliasToken `lineWidthFocus` for `outline-width` of focused component. [#40840](https://github.com/ant-design/ant-design/pull/40840) [@MadCcc](https://github.com/MadCcc)
|
||||
- 💄 WeekPicker support hover style. [#40772](https://github.com/ant-design/ant-design/pull/40772)
|
||||
- 💄 Adjust Select, TreeSelect, Cascader always show the `arrow` by default when multiple. [#41028](https://github.com/ant-design/ant-design/pull/41028)
|
||||
- 🐞 Fix Form `Form.Item.useStatus` problem with sever-side-rendering. [#40977](https://github.com/ant-design/ant-design/pull/40977) [@AndyBoat](https://github.com/AndyBoat)
|
||||
- 🐞 Fix arrow shape in some components. [#40971](https://github.com/ant-design/ant-design/pull/40971) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🐞 Fix Layout throw `React does not recognize the `suffixCls` prop on a DOM element` warning. [#40969](https://github.com/ant-design/ant-design/pull/40969)
|
||||
- 🐞 Fix Watermark that text will be displayed when the picture loads abnormally. [#40770](https://github.com/ant-design/ant-design/pull/40770) [@OriginRing](https://github.com/OriginRing)
|
||||
- 🐞 Image support flip function in preview mode. Fix Image `fallback` when used in ssr. [#40660](https://github.com/ant-design/ant-design/pull/40660)
|
||||
- 🐞 Fix Typography component is not centered in the Select component. [#40422](https://github.com/ant-design/ant-design/pull/40422) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🌐 Update locale `vi_VN` adding Vietnamese translation for Form component validation. [#40992](https://github.com/ant-design/ant-design/pull/40992) [@lamvananh](https://github.com/lamvananh)
|
||||
- RTL
|
||||
- 💄 FloatButton support `rtl` mode. [#40990](https://github.com/ant-design/ant-design/pull/40990) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- TypeScript
|
||||
- 🤖 Fix Cascader that generics should not be necessary. [#40961](https://github.com/ant-design/ant-design/pull/40961) [@crazyair](https://github.com/crazyair)
|
||||
|
||||
## 5.2.3
|
||||
|
||||
`2023-02-27`
|
||||
|
||||
- 🐞 Fix for setting `percent` and `success.percent` at the same time for `Progress`, the progress text does not change as `percent` changes. [#40922](https://github.com/ant-design/ant-design/pull/40922)
|
||||
- 🐞 Fixed Image preview icon was misaligned.[#40911](https://github.com/ant-design/ant-design/pull/40911)
|
||||
- 🐞 Fix ConfigProvider validation message template override Form configure template sometime. [#40533](https://github.com/ant-design/ant-design/pull/40533) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🐞 Fixed Confirm Modal `onOk` event could be triggered twice when close. [#40719](https://github.com/ant-design/ant-design/pull/40719) [@Rafael-Martins](https://github.com/Rafael-Martins)
|
||||
- 🛠 Rewrote the `useLocale` method and exposed `localeCode` to the public. [#40884](https://github.com/ant-design/ant-design/pull/40884) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fixed Segmented component items were unresponsive to mouse events. [#40894](https://github.com/ant-design/ant-design/pull/40894) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🛠 Refactored: replaced the LocaleReceiver component with `useLocale` and removed the LocaleReceiver component. [#40870](https://github.com/ant-design/ant-design/pull/40870) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fixed `getPopupContainer` property injected by ConfigProvider did not work. [#40871](https://github.com/ant-design/ant-design/pull/40871) [@RedJue](https://github.com/RedJue)
|
||||
- 🐞 Fixed where Descriptions did not accept `data-_` and `aria-_` attributes. [#40859](https://github.com/ant-design/ant-design/pull/40859) [@goveo](https://github.com/goveo)
|
||||
- 🛠 Changed the Separator's DOM element from `span` to `li`. [#40867](https://github.com/ant-design/ant-design/pull/40867) [@heiyu4585](https://github.com/heiyu4585)
|
||||
- 🐞 Fix token of `Layout.colorBgHeader` not work when single use Layout.Header directly. [#40933](https://github.com/ant-design/ant-design/pull/40933)
|
||||
- 💄 Changed the component's focus `outline` to the default `4px`.[#40839](https://github.com/ant-design/ant-design/pull/40839) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🐞 Fixed the Badge color was displayed abnormally. [#40848](https://github.com/ant-design/ant-design/pull/40848) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 Fixed an issue with the Timeline item's `className`. [#40835](https://github.com/ant-design/ant-design/pull/40835) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 Fixed the interaction style of the Rate component in the disabled state.[#40836](https://github.com/ant-design/ant-design/pull/40836) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🇮🇷 Added Iranian localization. [#40895](https://github.com/ant-design/ant-design/pull/40895) [@majidsadr](https://github.com/majidsadr)
|
||||
|
||||
## 5.2.2
|
||||
|
||||
`2023-02-19`
|
||||
|
||||
- DatePicker
|
||||
- 💄 Optimize DatePicker date panel style. [#40768](https://github.com/ant-design/ant-design/pull/40768)
|
||||
- 🐞 Fix RangePicker hover style on wrong date. [#40785](https://github.com/ant-design/ant-design/pull/40785) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- Form
|
||||
- 🐞 Fixed inconsistency between Checkbox and Radio in table when Form is `disabled`. [#40728](https://github.com/ant-design/ant-design/pull/40728) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix Radio/Checkbox under Form `disabled` property don't works correctly. [#40741](https://github.com/ant-design/ant-design/pull/40741) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix List extra padding when enable `grid` property. [#40806](https://github.com/ant-design/ant-design/pull/40806)
|
||||
- 🐞 Fix Upload actions icon alignment issue. [#40805](https://github.com/ant-design/ant-design/pull/40805)
|
||||
- 💄 Tweak Table filter dropdown radius style. [#40802](https://github.com/ant-design/ant-design/pull/40802)
|
||||
- 🐞 Fix Button `loading.delay` not delay at first time. [#40759](https://github.com/ant-design/ant-design/pull/40759) [@RedJue](https://github.com/RedJue)
|
||||
- 🐞 Fix Input status style when using `addonAfter` and `addonBefore`. [#40744](https://github.com/ant-design/ant-design/pull/40744) [@carla-cn](https://github.com/carla-cn)
|
||||
- 🐞 Fix Skeleton `active` flicky animation in Safari. [#40692](https://github.com/ant-design/ant-design/pull/40692) [@slotDumpling](https://github.com/slotDumpling)
|
||||
- Locales
|
||||
- 🇫🇷 Added french locale for Tour component. [#40750](https://github.com/ant-design/ant-design/pull/40750) [@RedJue](https://github.com/RedJue)
|
||||
- 🇰🇷 Update ko_KR locale. [#40716](https://github.com/ant-design/ant-design/pull/40716) [@owjs3901](https://github.com/owjs3901)
|
||||
|
||||
## 5.2.1
|
||||
|
||||
`2023-02-13`
|
||||
|
||||
- 🛠 Rewrite `panelRender` in Tour to function component。[#40670](https://github.com/ant-design/ant-design/pull/40670) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fix `className` property wrongly passed to child nodes in TimeLine。[#40700](https://github.com/ant-design/ant-design/pull/40700) [@any1024](https://github.com/any1024)
|
||||
- 🐞 Fix Slider dot to trigger click and hover correctly. [#40679](https://github.com/ant-design/ant-design/pull/40679) [@LongHaoo](https://github.com/LongHaoo)
|
||||
- 🐞 Fix Tour that should support `0` as element. [#40631](https://github.com/ant-design/ant-design/pull/40631) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 💄 Fix DataPicker.RangePicker hover range style. [#40607](https://github.com/ant-design/ant-design/pull/40607) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 Optimize Steps custom `icon` size. [#40672](https://github.com/ant-design/ant-design/pull/40672) [@MadCcc](https://github.com/MadCcc)
|
||||
- TypeScript
|
||||
- 🤖 Update Upload to support generic types. [#40634](https://github.com/ant-design/ant-design/pull/40634) [@riyadelberkawy](https://github.com/riyadelberkawy)
|
||||
- 🌐 Localization
|
||||
- 🇷🇺/🇺🇦 add missing translations for ru_RU and uk_UA. [#40656](https://github.com/ant-design/ant-design/pull/40656) [@eldarcodes](https://github.com/eldarcodes)
|
||||
|
||||
## 5.2.0
|
||||
|
||||
`2023-2-8`
|
||||
`2023-02-08`
|
||||
|
||||
- 🔥 Add `picture-circle` to Upload's `listType` prop. [#40134](https://github.com/ant-design/ant-design/pull/40134) [@ds1371dani](https://github.com/ds1371dani)
|
||||
- 🔥 Anchor component add `direction`, which supports vertical. [#39372](https://github.com/ant-design/ant-design/pull/39372) [@foryuki](https://github.com/foryuki)
|
||||
@@ -33,7 +163,7 @@ timeline: true
|
||||
- 🐞 Fix Slider missing Tooltip appear motion. [#39857](https://github.com/ant-design/ant-design/pull/39857)
|
||||
- Dropdown
|
||||
- 🆕 Dropdown support `autoAdjustOverflow` option. [#39735](https://github.com/ant-design/ant-design/pull/39735)
|
||||
- 💄 Fix Dropdown component `dange` and `disabled` style priority issue. [#39904](https://github.com/ant-design/ant-design/pull/39904) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 💄 Fix Dropdown component `danger` and `disabled` style priority issue. [#39904](https://github.com/ant-design/ant-design/pull/39904) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- Tour
|
||||
- 🆕 Tour added `indicatorsRender` to support custom indicators. [#40613](https://github.com/ant-design/ant-design/pull/40613)
|
||||
- 🆕 Tour support `scrollIntoViewOptions` to change scrollIntoView options. [#39980](https://github.com/ant-design/ant-design/pull/39980) [@kiner-tang](https://github.com/kiner-tang)
|
||||
@@ -50,7 +180,7 @@ timeline: true
|
||||
- 🐞 Fix the problem that the header filter is invalid in the case of group headers. [#40463](https://github.com/ant-design/ant-design/pull/40463) [@roman40a](https://github.com/roman40a)
|
||||
- 🐞 Fix selection column cover by other cell when fixed. [#39940](https://github.com/ant-design/ant-design/pull/39940) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 Fix Sorted/Filtered table fixed column transparent background unreadable. [#39012](https://github.com/ant-design/ant-design/pull/39012) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 💄 Fix border style problem when Table filter. [#39938](https://github.com/ant-design/ant-design/pull/39938) [@JarvisArt](https://github.com/JarvisArt)
|
||||
- 💄 Optimize Table hover style to fix problems with border. [#40469](https://github.com/ant-design/ant-design/pull/40469)
|
||||
- DatePicker
|
||||
- 🐞 Fix DatePicker that have status style when disabled. [#40608](https://github.com/ant-design/ant-design/pull/40608)
|
||||
- 💄 Optimize the DatePicker input box style. [#40549](https://github.com/ant-design/ant-design/pull/40549) [@Wxh16144](https://github.com/Wxh16144)
|
||||
@@ -79,7 +209,7 @@ timeline: true
|
||||
|
||||
## 5.1.7
|
||||
|
||||
`2023-1-31`
|
||||
`2023-01-31`
|
||||
|
||||
- Input
|
||||
- 🐞 Fix Input that unexpected cancel button is shown when `type="search"`. [#40457](https://github.com/ant-design/ant-design/pull/40457) [@MadCcc](https://github.com/MadCcc)
|
||||
@@ -98,7 +228,7 @@ timeline: true
|
||||
|
||||
## 5.1.6
|
||||
|
||||
`2023-1-20`
|
||||
`2023-01-20`
|
||||
|
||||
- 🐞 Fix DatePicker animation timing function. [#40133](https://github.com/ant-design/ant-design/pull/40133) [@MadCcc](https://github.com/MadCcc)
|
||||
- Menu
|
||||
@@ -116,7 +246,7 @@ timeline: true
|
||||
|
||||
## 5.1.5
|
||||
|
||||
`2023-1-15`
|
||||
`2023-01-15`
|
||||
|
||||
- 🐞 Fix Checkbox that label not aligned with checkbox. [#40208](https://github.com/ant-design/ant-design/pull/40208)
|
||||
- 🐞 Fix Button wave effect sometime makes layout shaking. [#40192](https://github.com/ant-design/ant-design/pull/40192)
|
||||
@@ -133,7 +263,7 @@ timeline: true
|
||||
|
||||
## 5.1.4
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- 🐞 Fix missing locale file. [#40116](https://github.com/ant-design/ant-design/pull/40116)
|
||||
- 🐞 Fix Cascader dropdown `placement` in RTL mode. [#40109](https://github.com/ant-design/ant-design/pull/40109) [@3hson](https://github.com/3hson)
|
||||
@@ -141,7 +271,7 @@ timeline: true
|
||||
|
||||
## 5.1.3
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- Table
|
||||
- 🛠 Optimize the Table `shouldCellUpdate` logic to increase the secondary rendering speed. [#40063](https://github.com/ant-design/ant-design/pull/40063)
|
||||
|
||||
@@ -15,9 +15,139 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 5.3.2
|
||||
|
||||
`2023-03-20`
|
||||
|
||||
- Anchor
|
||||
- 💄 修复 Anchor 组件设置为水平方向时多余的 border 样式。[#41336](https://github.com/ant-design/ant-design/pull/41336) [@gooyoung](https://github.com/gooyoung)
|
||||
- 💄 修复 Anchor 处于 `vertical` 方向时 ink 小方块的样式。[#41317](https://github.com/ant-design/ant-design/pull/41317) [@acyza](https://github.com/acyza)
|
||||
- 🐞 修复 Grid 在不同设备屏幕下的 `offset` 设置不会被覆盖的问题。[#41309](https://github.com/ant-design/ant-design/pull/41309) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 Breadcrumb `onClick` 不工作的问题。[#41283](https://github.com/ant-design/ant-design/pull/41283) [@acyza](https://github.com/acyza)
|
||||
- 🐞 修复 Upload 在上传完毕后 Progress 组件抛出警告的问题。[#41234](https://github.com/ant-design/ant-design/pull/41234) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 修复 Table 在拖动元素一直右移时布局错误的问题。[#41139](https://github.com/ant-design/ant-design/pull/41139) [@hoho2017](https://github.com/hoho2017)
|
||||
- 💄 修复 Tabs 在深色模式下更多图标的色值。[#41313](https://github.com/ant-design/ant-design/pull/41313) [@PhosphorusP](https://github.com/PhosphorusP)
|
||||
- 💄 修复 Button 下拉时聚焦轮廓被其他元素遮挡的问题。[#41282](https://github.com/ant-design/ant-design/pull/41282) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 修复 Input.TextArea 在 focus 状态下的样式问题。[#41228](https://github.com/ant-design/ant-design/pull/41228) [@MuxinFeng](https://github.com/MuxinFeng)
|
||||
|
||||
- RTL
|
||||
- 💄 修复 Input.TextArea 在启用 `showCount` 时 RTL 模式下位置不正确的问题。[#41319](https://github.com/ant-design/ant-design/pull/41319) [@ds1371dani](https://github.com/ds1371dani)
|
||||
- TypeScript
|
||||
- 🤖 导出 Statistic 的 `CountdownProps` 类型。[#41341](https://github.com/ant-design/ant-design/pull/41341) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🤖 优化 token 的类型提示和说明。[#41297](https://github.com/ant-design/ant-design/pull/41297) [@arvinxx](https://github.com/arvinxx)
|
||||
- 🤖 优化 Badge `React.forwardRef` 类型定义。[#41189](https://github.com/ant-design/ant-design/pull/41189) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
|
||||
## 5.3.1
|
||||
|
||||
`2023-03-13`
|
||||
|
||||
- 🐞 更新 DatePicker 底层依赖,修复 Safari 下卡顿,支持 `transform scale` 下对齐。[#41090](https://github.com/ant-design/ant-design/pull/41090)
|
||||
- 🐞 修复 Menu 收缩时,Tooltip 有时会弹出的问题。[#41081](https://github.com/ant-design/ant-design/issues/41081)
|
||||
- 🐞 修复 Modal.confirm 窗体有额外节点导致高度不正确的问题。[#41173](https://github.com/ant-design/ant-design/pull/41173) [@Svudec](https://github.com/Svudec)
|
||||
- 🐞 修复 InputNumber `disabled` 时字体高亮不正确的问题。[#41167](https://github.com/ant-design/ant-design/pull/41167) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 Anchor 动态添加 `items` 后高亮失效问题。[#40743](https://github.com/ant-design/ant-design/pull/40743) [@zqran](https://github.com/zqran)
|
||||
- 🛠 更新 Mentions 底层依赖,支持 `transform scale` 下对齐。[#41160](https://github.com/ant-design/ant-design/pull/41160) [@MuxinFeng](https://github.com/MuxinFeng)
|
||||
- 🐞 修复 Form 手工调用 `validateFields` 时,`hasFeedback` 对成功态不生效的问题。[#41116](https://github.com/ant-design/ant-design/pull/41116) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 修复 Cascader 在悬浮至叶子节点时,展开面板没有关闭的问题。[#41134](https://github.com/ant-design/ant-design/issues/41134)
|
||||
- 🐞 修复 Popconfirm 使用 `Promise` 关闭时再次打开仍然是 `loading` 状态的问题。[#41121](https://github.com/ant-design/ant-design/pull/41121)
|
||||
- 🐞 修复 Upload 在 React 18 下 `onChange` 有时数据不正确的问题。[#41082](https://github.com/ant-design/ant-design/pull/41082) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🛎 补充官网中没有切换到 Space.Compact 的遗留示例,并且添加相应警告。[#41080](https://github.com/ant-design/ant-design/pull/41080) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🌐 更新韩语国际化,添加国际化阿姆哈拉语。[#41103](https://github.com/ant-design/ant-design/pull/41103) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
|
||||
## 5.3.0
|
||||
|
||||
`2023-03-06`
|
||||
|
||||
- 🆕 Tooltip 组件新增 `arrow.pointAtCenter`, 废弃 `arrow.arrowPointAtCenter`。[#40989](https://github.com/ant-design/ant-design/pull/40989) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🆕 Progress 组件支持自定义 `size`。[#40903](https://github.com/ant-design/ant-design/pull/40903) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🆕 Tour 组件支持自定义 `zIndex`。[#40982](https://github.com/ant-design/ant-design/pull/40982) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🆕 Table `onHeaderCell` 支持自定义 `colSpan` 和 `rowSpan`。[#40885](https://github.com/ant-design/ant-design/pull/40885)
|
||||
- 🆕 Image.Group 支持 `onChange` 回调。[#40857](https://github.com/ant-design/ant-design/pull/40857) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- App
|
||||
- 🆕 App 支持自定义 `style`。[#40708](https://github.com/ant-design/ant-design/pull/40708) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🆕 App 提供预先配置 `message`、`notification` 的选项。[#40458](https://github.com/ant-design/ant-design/pull/40458) [@luo3house](https://github.com/luo3house)
|
||||
- 🆕 ConfigProvider 新增 `useConfig` 以获取上下文中的 `size` 和 `disabled`。[#40215](https://github.com/ant-design/ant-design/pull/40215) [@xliez](https://github.com/xliez)
|
||||
- 🆕 Breadcrumb 支持 `items` 数据驱动。[#40543](https://github.com/ant-design/ant-design/pull/40543) [@heiyu4585](https://github.com/heiyu4585)
|
||||
- 🛠 Breadcrumb 分隔符统一为 `li` 元素。[#40887](https://github.com/ant-design/ant-design/pull/40887) [@heiyu4585](https://github.com/heiyu4585)
|
||||
- 🛠 Tooltip 现在自动调整自身以及箭头位置以更好的展示。同时废弃 `destroyTooltipOnHide.keepParent`,现在总是会自动销毁不需要的容器。[#40632](https://github.com/ant-design/ant-design/pull/40632)
|
||||
- 🛠 重命名 token 中的预设颜色,如 `blue-1` 变为 `blue1`,废弃原有的 token。[#41071](https://github.com/ant-design/ant-design/pull/41071)
|
||||
- 💄 Message 组件使用 `colorText` 优化样式。[#41047](https://github.com/ant-design/ant-design/pull/41047) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 修复 Select, TreeSelect, Cascader 父元素存在 `transform: scale` 样式时的对齐问题。[#41013](https://github.com/ant-design/ant-design/pull/41013)
|
||||
- 💄 优化 Table 中 `rowScope` 的样式。[#40304](https://github.com/ant-design/ant-design/pull/40304) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 为组件聚焦时的 `outline` 提供新的 AliasToken `lineWidthFocus`。[#40840](https://github.com/ant-design/ant-design/pull/40840) [@MadCcc](https://github.com/MadCcc)
|
||||
- 💄 WeekPicker 支持鼠标悬浮样式。[#40772](https://github.com/ant-design/ant-design/pull/40772)
|
||||
- 💄 调整 Select, TreeSelect, Cascader 在多选时总是默认显示下拉箭头。[#41028](https://github.com/ant-design/ant-design/pull/41028)
|
||||
- 🐞 修复 Form 组件 `Form.Item.useStatus` 导致的服务端渲染问题。[#40977](https://github.com/ant-design/ant-design/pull/40977) [@AndyBoat](https://github.com/AndyBoat)
|
||||
- 🐞 修复部分组件箭头形状问题。[#40971](https://github.com/ant-design/ant-design/pull/40971) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🐞 修复 Layout 报错 `React does not recognize the `suffixCls` prop on a DOM element` 的问题。[#40969](https://github.com/ant-design/ant-design/pull/40969)
|
||||
- 🐞 修复 Watermark 组件图片加载异常时的问题,默认展示文字。[#40770](https://github.com/ant-design/ant-design/pull/40770) [@OriginRing](https://github.com/OriginRing)
|
||||
- 🐞 Image 预览新增图片翻转功能。并修复 Image `fallback` 在 ssr 下失效的问题。[#40660](https://github.com/ant-design/ant-design/pull/40660)
|
||||
- 🐞 修复 Select 中使用 Typography 不居中的问题。[#40422](https://github.com/ant-design/ant-design/pull/40422) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🌐 完善 Form 的 `vi_VN` 语言包。[#40992](https://github.com/ant-design/ant-design/pull/40992) [@lamvananh](https://github.com/lamvananh)
|
||||
- RTL
|
||||
- 💄 修复 FloatButton 不支持 `rtl` 模式的问题。[#40990](https://github.com/ant-design/ant-design/pull/40990) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- TypeScript
|
||||
- 🤖 修复 Cascader 泛型为非必传。[#40961](https://github.com/ant-design/ant-design/pull/40961) [@crazyair](https://github.com/crazyair)
|
||||
|
||||
## 5.2.3
|
||||
|
||||
`2023-02-27`
|
||||
|
||||
- 🐞 修复 Progress 同时设置 percent 和 success.percent 时,进度文本不会随着 percent 改变而改变。[#40922](https://github.com/ant-design/ant-design/pull/40922)
|
||||
- 🐞 修复 Image 预览图标不对齐的问题。[#40911](https://github.com/ant-design/ant-design/pull/40911)
|
||||
- 🐞 修复 ConfigProvider 组件表单校验消息生效顺序。[#40533](https://github.com/ant-design/ant-design/pull/40533) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🐞 修复 Confirm Modal `onOk` 可能触发两次的问题。[#40719](https://github.com/ant-design/ant-design/pull/40719) [@Rafael-Martins](https://github.com/Rafael-Martins)
|
||||
- 🛠 重写 `useLocale` 方法,对外暴露 `localeCode`。[#40884](https://github.com/ant-design/ant-design/pull/40884) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 Segemented 组件子项不响应鼠标事件的问题。[#40894](https://github.com/ant-design/ant-design/pull/40894) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🛠 重构:使用 `useLocale` 替换 LocaleReceiver 组件,并删除 LocaleReceiver 组件。[#40870](https://github.com/ant-design/ant-design/pull/40870) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 ConfigProvider 注入的 `getPopupContainer` 属性 不生效的问题。[#40871](https://github.com/ant-design/ant-design/pull/40871) [@RedJue](https://github.com/RedJue)
|
||||
- 🐞 修复 Descriptions 不接受 `data-*` 和 `aria-*` 等属性的问题。[#40859](https://github.com/ant-design/ant-design/pull/40859) [@goveo](https://github.com/goveo)
|
||||
- 🛠 修改 Separator 的 dom 由 `span` 改为 `li`。[#40867](https://github.com/ant-design/ant-design/pull/40867) [@heiyu4585](https://github.com/heiyu4585)
|
||||
- 💄 修改组件聚焦下的 `outline` 为默认 `4px`。[#40839](https://github.com/ant-design/ant-design/pull/40839) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🐞 修复 Layout.Header 单独使用时,`Layout.colorBgHeader` token 配置不生效的问题。[#40933](https://github.com/ant-design/ant-design/pull/40933)
|
||||
- 🐞 修复 Badge 颜色显示异常问题。[#40848](https://github.com/ant-design/ant-design/pull/40848) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 修复 Timeline 的子项的 `className` 错误。[#40835](https://github.com/ant-design/ant-design/pull/40835) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 修复 Rate 在禁用状态下的交互样式。[#40836](https://github.com/ant-design/ant-design/pull/40836) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🇮🇷 增加了伊朗本地化。[#40895](https://github.com/ant-design/ant-design/pull/40895) [@majidsadr](https://github.com/majidsadr)
|
||||
|
||||
## 5.2.2
|
||||
|
||||
`2023-02-19`
|
||||
|
||||
- DatePicker
|
||||
- 💄 调整 DatePicker 组件日期面板的间距样式。[#40768](https://github.com/ant-design/ant-design/pull/40768)
|
||||
- 🐞 修复 RangePicker `hover` 日期错位的问题。[#40785](https://github.com/ant-design/ant-design/pull/40785) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- Form
|
||||
- 🐞 修复 Form 下 Radio/Checkbox 的 disabled 优先级问题。[#40741](https://github.com/ant-design/ant-design/pull/40741) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 Form 为 `disabled` 时 Checkbox 和 Radio 表现不一致的问题。[#40728](https://github.com/ant-design/ant-design/pull/40728) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 List 启用 `grid` 时下额外 `padding` 样式。[#40806](https://github.com/ant-design/ant-design/pull/40806)
|
||||
- 🐞 修复 Upload 操作图标不对齐的问题。[#40805](https://github.com/ant-design/ant-design/pull/40805)
|
||||
- 💄 调整 Table 筛选菜单的底部圆角样式。[#40802](https://github.com/ant-design/ant-design/pull/40802)
|
||||
- 🐞 修复 Button 组件 `loading.delay` 第一次不生效的问题。[#40759](https://github.com/ant-design/ant-design/pull/40759) [@RedJue](https://github.com/RedJue)
|
||||
- 🐞 修复 Input `addonAfter` 和 `addonBefore` 的各种状态样式。[#40744](https://github.com/ant-design/ant-design/pull/40744) [@carla-cn](https://github.com/carla-cn)
|
||||
- 🐞 修复 Skeleton 在 Safari 下 `active` 效果闪烁的问题。[#40692](https://github.com/ant-design/ant-design/pull/40692) [@slotDumpling](https://github.com/slotDumpling)
|
||||
- 国际化
|
||||
- 🇫🇷 补充 Tour 法语本地化文案。[#40750](https://github.com/ant-design/ant-design/pull/40750) [@RedJue](https://github.com/RedJue)
|
||||
- 🇰🇷 更新韩国本地化文案。[#40716](https://github.com/ant-design/ant-design/pull/40716) [@owjs3901](https://github.com/owjs3901)
|
||||
|
||||
## 5.2.1
|
||||
|
||||
`2023-02-13`
|
||||
|
||||
- 🛠 重构 Tour 中 `panelRender` 为函数式组件。[#40670](https://github.com/ant-design/ant-design/pull/40670) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 TimeLine 中 `className` 传给子节点的问题。[#40700](https://github.com/ant-design/ant-design/pull/40700) [@any1024](https://github.com/any1024)
|
||||
- 🐞 修复 Silder 中的标记点在边缘无法点击的问题。[#40679](https://github.com/ant-design/ant-design/pull/40679) [@LongHaoo](https://github.com/LongHaoo)
|
||||
- 🐞 修复 Tour 不支持 `0` 作为节点的问题。[#40631](https://github.com/ant-design/ant-design/pull/40631) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 💄 修复 DataPicker.RangePicker 的 hover 范围样式。[#40607](https://github.com/ant-design/ant-design/pull/40607) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 💄 优化 Steps 组件自定义 `icon` 的大小。[#40672](https://github.com/ant-design/ant-design/pull/40672) [@MadCcc](https://github.com/MadCcc)
|
||||
- TypeScript
|
||||
- 🤖 Upload 组件支持泛型。[#40634](https://github.com/ant-design/ant-design/pull/40634) [@riyadelberkawy](https://github.com/riyadelberkawy)
|
||||
- 🌐 国际化
|
||||
- 🇷🇺/🇺🇦 补全 `ru_RU` 和 `uk_UA` 文案。[#40656](https://github.com/ant-design/ant-design/pull/40656) [@eldarcodes](https://github.com/eldarcodes)
|
||||
|
||||
## 5.2.0
|
||||
|
||||
`2023-2-8`
|
||||
`2023-02-08`
|
||||
|
||||
- 🔥 Upload 的 `listType` 属性添加 `picture-circle` 支持。[#40134](https://github.com/ant-design/ant-design/pull/40134) [@ds1371dani](https://github.com/ds1371dani)
|
||||
- 🔥 Anchor 组件新增 `direction` 属性,支持 vertical。[#39372](https://github.com/ant-design/ant-design/pull/39372) [@foryuki](https://github.com/foryuki)
|
||||
@@ -33,7 +163,7 @@ timeline: true
|
||||
- 🐞 修复 Slider 展示 Tooltip 时动画丢失的问题。[#39857](https://github.com/ant-design/ant-design/pull/39857)
|
||||
- Dropdown
|
||||
- 🆕 Dropdown 组件支持 `autoAdjustOverflow` 属性。[#39735](https://github.com/ant-design/ant-design/pull/39735)
|
||||
- 💄 修复 Dropdown `dange` 和 `disable` 属性同时使用样式问题。[#39904](https://github.com/ant-design/ant-design/pull/39904) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 💄 修复 Dropdown `danger` 和 `disable` 属性同时使用样式问题。[#39904](https://github.com/ant-design/ant-design/pull/39904) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- Tour
|
||||
- 🆕 Tour 新增 `indicatorsRender` 支持自定义指示器。[#40613](https://github.com/ant-design/ant-design/pull/40613)
|
||||
- 🆕 Tour 支持通过 `scrollIntoViewOptions` 改变`scrollIntoView` 的选项。[#39980](https://github.com/ant-design/ant-design/pull/39980) [@kiner-tang](https://github.com/kiner-tang)
|
||||
@@ -50,7 +180,7 @@ timeline: true
|
||||
- 🐞 修表头过滤器在分组标题情况下失效的问题。[#40463](https://github.com/ant-design/ant-design/pull/40463) [@roman40a](https://github.com/roman40a)
|
||||
- 🐞 修复选择列固定时滚动会被其他单元格遮盖的问题。[#39940](https://github.com/ant-design/ant-design/pull/39940) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 修复排序/筛选的表格的固定列背景色透明导致显示异常问题。[#39012](https://github.com/ant-design/ant-design/pull/39012) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 💄 修复 Table filter 时边框样式问题。[#39938](https://github.com/ant-design/ant-design/pull/39938) [@JarvisArt](https://github.com/JarvisArt)
|
||||
- 💄 优化 Table 组件 hover 样式,修复边框异常问题。[#40469](https://github.com/ant-design/ant-design/pull/40469)
|
||||
- DatePicker
|
||||
- 🐞 修复 DatePicker 组件禁用时状态样式生效的问题。[#40608](https://github.com/ant-design/ant-design/pull/40608)
|
||||
- 💄 优化 DatePicker 输入框样式。[#40549](https://github.com/ant-design/ant-design/pull/40549) [@Wxh16144](https://github.com/Wxh16144)
|
||||
@@ -79,7 +209,7 @@ timeline: true
|
||||
|
||||
## 5.1.7
|
||||
|
||||
`2023-1-31`
|
||||
`2023-01-31`
|
||||
|
||||
- Input
|
||||
- 🐞 修复 Input 组件 `type="search"` 时未隐藏浏览器原生取消按钮的问题。[#40457](https://github.com/ant-design/ant-design/pull/40457) [@MadCcc](https://github.com/MadCcc)
|
||||
@@ -98,7 +228,7 @@ timeline: true
|
||||
|
||||
## 5.1.6
|
||||
|
||||
`2023-1-20`
|
||||
`2023-01-20`
|
||||
|
||||
- 🐞 修复 DatePicker 等组件动画 timing function 错误的问题。[#40133](https://github.com/ant-design/ant-design/pull/40133) [@MadCcc](https://github.com/MadCcc)
|
||||
- Menu
|
||||
@@ -116,7 +246,7 @@ timeline: true
|
||||
|
||||
## 5.1.5
|
||||
|
||||
`2023-1-15`
|
||||
`2023-01-15`
|
||||
|
||||
- 🐞 修复 Checkbox 组件 label 不对齐的问题。 [#40208](https://github.com/ant-design/ant-design/pull/40208)
|
||||
- 🐞 修复 Button 水波纹效果有时会使得布局抖动的问题。[#40192](https://github.com/ant-design/ant-design/pull/40192)
|
||||
@@ -133,7 +263,7 @@ timeline: true
|
||||
|
||||
## 5.1.4
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- 🐞 修复 locale 文件丢失的问题。[#40116](https://github.com/ant-design/ant-design/pull/40116)
|
||||
- 🐞 修复 Cascader 组件 RTL 模式中下拉菜单位置问题。[#40109](https://github.com/ant-design/ant-design/pull/40109) [@3hson](https://github.com/3hson)
|
||||
@@ -141,7 +271,7 @@ timeline: true
|
||||
|
||||
## 5.1.3
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- Table
|
||||
- 🛠 优化 Table `shouldCellUpdate` 逻辑,提升二次渲染速度。[#40063](https://github.com/ant-design/ant-design/pull/40063)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url] [![Total alerts][lgtm-image]][lgtm-url] [![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![FOSSA Status][fossa-image]][fossa-url] [![Discussions][discussions-image]][discussions-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@@ -24,22 +24,22 @@
|
||||
[codecov-url]: https://codecov.io/gh/ant-design/ant-design/branch/master
|
||||
[download-image]: https://img.shields.io/npm/dm/antd.svg?style=flat-square
|
||||
[download-url]: https://npmjs.org/package/antd
|
||||
[lgtm-image]: https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design
|
||||
[lgtm-url]: https://lgtm.com/projects/g/ant-design/ant-design/alerts/
|
||||
[fossa-image]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fant-design%2Fant-design.svg?type=shield
|
||||
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
|
||||
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
|
||||
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design
|
||||
[twitter-url]: https://twitter.com/AntDesignUI
|
||||
[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue?style=flat-square
|
||||
[discussions-url]: https://github.com/ant-design/ant-design/discussions
|
||||
[bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square
|
||||
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
|
||||
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
|
||||
[bundlephobia-url]: https://bundlephobia.com/package/antd
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ Uma solução empresarial de design e biblioteca UI para React.
|
||||
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url] [![Total alerts][lgtm-image]][lgtm-url] [![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![FOSSA Status][fossa-image]][fossa-url] [![Discussions][discussions-image]][discussions-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@@ -24,22 +24,22 @@ Uma solução empresarial de design e biblioteca UI para React.
|
||||
[codecov-url]: https://codecov.io/gh/ant-design/ant-design/branch/master
|
||||
[download-image]: https://img.shields.io/npm/dm/antd.svg?style=flat-square
|
||||
[download-url]: https://npmjs.org/package/antd
|
||||
[lgtm-image]: https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design
|
||||
[lgtm-url]: https://lgtm.com/projects/g/ant-design/ant-design/alerts/
|
||||
[fossa-image]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fant-design%2Fant-design.svg?type=shield
|
||||
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
|
||||
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
|
||||
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design
|
||||
[twitter-url]: https://twitter.com/AntDesignUI
|
||||
[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue?style=flat-square
|
||||
[discussions-url]: https://github.com/ant-design/ant-design/discussions
|
||||
[bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square
|
||||
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
|
||||
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
|
||||
[bundlephobia-url]: https://bundlephobia.com/package/antd
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ Un lenguaje de diseño de interfaz de usuario de clase empresarial y una bibliot
|
||||
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url] [![Total alerts][lgtm-image]][lgtm-url] [![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![FOSSA Status][fossa-image]][fossa-url] [![Discussions][discussions-image]][discussions-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@@ -24,22 +24,22 @@ Un lenguaje de diseño de interfaz de usuario de clase empresarial y una bibliot
|
||||
[codecov-url]: https://codecov.io/gh/ant-design/ant-design/branch/master
|
||||
[download-image]: https://img.shields.io/npm/dm/antd.svg?style=flat-square
|
||||
[download-url]: https://npmjs.org/package/antd
|
||||
[lgtm-image]: https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design
|
||||
[lgtm-url]: https://lgtm.com/projects/g/ant-design/ant-design/alerts/
|
||||
[fossa-image]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fant-design%2Fant-design.svg?type=shield
|
||||
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
|
||||
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
|
||||
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design
|
||||
[twitter-url]: https://twitter.com/AntDesignUI
|
||||
[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue?style=flat-square
|
||||
[discussions-url]: https://github.com/ant-design/ant-design/discussions
|
||||
[bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square
|
||||
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
|
||||
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
|
||||
[bundlephobia-url]: https://bundlephobia.com/package/antd
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url] [![Total alerts][lgtm-image]][lgtm-url] [![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![FOSSA Status][fossa-image]][fossa-url] [![Discussions][discussions-image]][discussions-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@@ -24,22 +24,22 @@
|
||||
[codecov-url]: https://codecov.io/gh/ant-design/ant-design/branch/master
|
||||
[download-image]: https://img.shields.io/npm/dm/antd.svg?style=flat-square
|
||||
[download-url]: https://npmjs.org/package/antd
|
||||
[lgtm-image]: https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design
|
||||
[lgtm-url]: https://lgtm.com/projects/g/ant-design/ant-design/alerts/
|
||||
[fossa-image]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fant-design%2Fant-design.svg?type=shield
|
||||
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
|
||||
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
|
||||
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design
|
||||
[twitter-url]: https://twitter.com/AntDesignUI
|
||||
[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue?style=flat-square
|
||||
[discussions-url]: https://github.com/ant-design/ant-design/discussions
|
||||
[bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square
|
||||
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
|
||||
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
|
||||
[bundlephobia-url]: https://bundlephobia.com/package/antd
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url] [![Total alerts][lgtm-image]][lgtm-url] [![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![FOSSA Status][fossa-image]][fossa-url] [![Discussions][discussions-image]][discussions-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@@ -24,22 +24,22 @@
|
||||
[codecov-url]: https://codecov.io/gh/ant-design/ant-design/branch/master
|
||||
[download-image]: https://img.shields.io/npm/dm/antd.svg?style=flat-square
|
||||
[download-url]: https://npmjs.org/package/antd
|
||||
[lgtm-image]: https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design
|
||||
[lgtm-url]: https://lgtm.com/projects/g/ant-design/ant-design/alerts/
|
||||
[fossa-image]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fant-design%2Fant-design.svg?type=shield
|
||||
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
|
||||
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
|
||||
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design
|
||||
[twitter-url]: https://twitter.com/AntDesignUI
|
||||
[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue?style=flat-square
|
||||
[discussions-url]: https://github.com/ant-design/ant-design/discussions
|
||||
[bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square
|
||||
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
|
||||
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
|
||||
[bundlephobia-url]: https://bundlephobia.com/package/antd
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
|
||||
</div>
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
- 🌈 提炼自企业级中后台产品的交互语言和视觉风格。
|
||||
- 📦 开箱即用的高质量 React 组件。
|
||||
- 🛡 使用 TypeScript 开发,提供完整的类型定义文件。
|
||||
- ⚙️ 全链路开发和设计工具体系。
|
||||
- ⚙️ 应用开发框架和设计工具配套。
|
||||
- 🌍 数十个国际化语言支持。
|
||||
- 🎨 深入每个细节的主题定制能力。
|
||||
- 🎨 基于 CSS-in-JS 的主题定制能力。
|
||||
|
||||
## 🖥 兼容环境
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ An enterprise-class UI design language and React UI library.
|
||||
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@@ -28,7 +28,7 @@ An enterprise-class UI design language and React UI library.
|
||||
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
|
||||
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
|
||||
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
|
||||
[twitter-image]: https://badgen.net/twitter/follow/antdesignui?style=flat-square
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design
|
||||
[twitter-url]: https://twitter.com/AntDesignUI
|
||||
[bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square
|
||||
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
|
||||
@@ -38,6 +38,8 @@ An enterprise-class UI design language and React UI library.
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
|
||||
</div>
|
||||
|
||||
@@ -52,7 +54,7 @@ English | [Português](./README-pt_BR.md) | [简体中文](./README-zh_CN.md) |
|
||||
- 🛡 Written in TypeScript with predictable static types.
|
||||
- ⚙️ Whole package of design resources and development tools.
|
||||
- 🌍 Internationalization support for dozens of languages.
|
||||
- 🎨 Powerful theme customization in every detail.
|
||||
- 🎨 Powerful theme customization based on CSS-in-JS.
|
||||
|
||||
## 🖥 Environment Support
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@ describe('node', () => {
|
||||
});
|
||||
|
||||
// Find the component exist demo test file
|
||||
const files = glob.sync(`./components/*/__tests__/demo.test.@(j|t)s?(x)`);
|
||||
const files = glob.globSync(`./components/*/__tests__/demo.test.@(j|t)s?(x)`);
|
||||
|
||||
files.forEach((componentTestFile) => {
|
||||
const componentName = componentTestFile.match(/components\/([^/]*)\//)![1];
|
||||
|
||||
// Test for ssr
|
||||
describe(componentName, () => {
|
||||
const demoList = glob.sync(`./components/${componentName}/demo/*.tsx`);
|
||||
const demoList = glob.globSync(`./components/${componentName}/demo/*.tsx`);
|
||||
|
||||
// Use mock to get config
|
||||
require(`../../${componentTestFile}`); // eslint-disable-line global-require, import/no-dynamic-require
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import { placements } from 'rc-tooltip/lib/placements';
|
||||
import type { BuildInPlacements } from 'rc-trigger';
|
||||
|
||||
const autoAdjustOverflowEnabled = {
|
||||
adjustX: 1,
|
||||
adjustY: 1,
|
||||
};
|
||||
|
||||
const autoAdjustOverflowDisabled = {
|
||||
adjustX: 0,
|
||||
adjustY: 0,
|
||||
};
|
||||
|
||||
const targetOffset = [0, 0];
|
||||
/* eslint-disable default-case */
|
||||
import type { AlignType, BuildInPlacements } from '@rc-component/trigger';
|
||||
import { getArrowOffset } from '../style/placementArrow';
|
||||
|
||||
export interface AdjustOverflow {
|
||||
adjustX?: 0 | 1;
|
||||
@@ -20,135 +9,218 @@ export interface AdjustOverflow {
|
||||
|
||||
export interface PlacementsConfig {
|
||||
arrowWidth: number;
|
||||
horizontalArrowShift?: number;
|
||||
verticalArrowShift?: number;
|
||||
arrowPointAtCenter?: boolean;
|
||||
autoAdjustOverflow?: boolean | AdjustOverflow;
|
||||
offset: number;
|
||||
borderRadius: number;
|
||||
}
|
||||
|
||||
export function getOverflowOptions(autoAdjustOverflow?: boolean | AdjustOverflow) {
|
||||
if (typeof autoAdjustOverflow === 'boolean') {
|
||||
return autoAdjustOverflow ? autoAdjustOverflowEnabled : autoAdjustOverflowDisabled;
|
||||
export function getOverflowOptions(
|
||||
placement: string,
|
||||
arrowOffset: ReturnType<typeof getArrowOffset>,
|
||||
arrowWidth: number,
|
||||
autoAdjustOverflow?: boolean | AdjustOverflow,
|
||||
) {
|
||||
if (autoAdjustOverflow === false) {
|
||||
return {
|
||||
adjustX: false,
|
||||
adjustY: false,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...autoAdjustOverflowDisabled,
|
||||
...autoAdjustOverflow,
|
||||
|
||||
const overflow =
|
||||
autoAdjustOverflow && typeof autoAdjustOverflow === 'object' ? autoAdjustOverflow : {};
|
||||
|
||||
const baseOverflow: AlignType['overflow'] = {};
|
||||
|
||||
switch (placement) {
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
baseOverflow.shiftX = arrowOffset.dropdownArrowOffset * 2 + arrowWidth;
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
case 'right':
|
||||
baseOverflow.shiftY = arrowOffset.dropdownArrowOffsetVertical * 2 + arrowWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
const mergedOverflow = {
|
||||
...baseOverflow,
|
||||
...overflow,
|
||||
};
|
||||
|
||||
// Support auto shift
|
||||
if (!mergedOverflow.shiftX) {
|
||||
mergedOverflow.adjustX = true;
|
||||
}
|
||||
if (!mergedOverflow.shiftY) {
|
||||
mergedOverflow.adjustY = true;
|
||||
}
|
||||
|
||||
return mergedOverflow;
|
||||
}
|
||||
|
||||
type PlacementType = keyof BuildInPlacements;
|
||||
|
||||
function getArrowOffset(type: PlacementType, arrowWidth: number, offset: number): number[] {
|
||||
switch (type) {
|
||||
case 'top':
|
||||
case 'topLeft':
|
||||
case 'topRight':
|
||||
return [0, -(arrowWidth / 2 + offset)];
|
||||
case 'bottom':
|
||||
case 'bottomLeft':
|
||||
case 'bottomRight':
|
||||
return [0, arrowWidth / 2 + offset];
|
||||
case 'left':
|
||||
case 'leftTop':
|
||||
case 'leftBottom':
|
||||
return [-(arrowWidth / 2 + offset), 0];
|
||||
case 'right':
|
||||
case 'rightTop':
|
||||
case 'rightBottom':
|
||||
return [arrowWidth / 2 + offset, 0];
|
||||
/* istanbul ignore next */
|
||||
default:
|
||||
return [0, 0];
|
||||
}
|
||||
}
|
||||
const PlacementAlignMap: BuildInPlacements = {
|
||||
left: {
|
||||
points: ['cr', 'cl'],
|
||||
},
|
||||
right: {
|
||||
points: ['cl', 'cr'],
|
||||
},
|
||||
top: {
|
||||
points: ['bc', 'tc'],
|
||||
},
|
||||
bottom: {
|
||||
points: ['tc', 'bc'],
|
||||
},
|
||||
topLeft: {
|
||||
points: ['bl', 'tl'],
|
||||
},
|
||||
leftTop: {
|
||||
points: ['tr', 'tl'],
|
||||
},
|
||||
topRight: {
|
||||
points: ['br', 'tr'],
|
||||
},
|
||||
rightTop: {
|
||||
points: ['tl', 'tr'],
|
||||
},
|
||||
bottomRight: {
|
||||
points: ['tr', 'br'],
|
||||
},
|
||||
rightBottom: {
|
||||
points: ['bl', 'br'],
|
||||
},
|
||||
bottomLeft: {
|
||||
points: ['tl', 'bl'],
|
||||
},
|
||||
leftBottom: {
|
||||
points: ['br', 'bl'],
|
||||
},
|
||||
};
|
||||
|
||||
function vertexCalc(point1: number[], point2: number[]): number[] {
|
||||
return [point1[0] + point2[0], point1[1] + point2[1]];
|
||||
}
|
||||
const ArrowCenterPlacementAlignMap: BuildInPlacements = {
|
||||
topLeft: {
|
||||
points: ['bl', 'tc'],
|
||||
},
|
||||
leftTop: {
|
||||
points: ['tr', 'cl'],
|
||||
},
|
||||
topRight: {
|
||||
points: ['br', 'tc'],
|
||||
},
|
||||
rightTop: {
|
||||
points: ['tl', 'cr'],
|
||||
},
|
||||
bottomRight: {
|
||||
points: ['tr', 'bc'],
|
||||
},
|
||||
rightBottom: {
|
||||
points: ['bl', 'cr'],
|
||||
},
|
||||
bottomLeft: {
|
||||
points: ['tl', 'bc'],
|
||||
},
|
||||
leftBottom: {
|
||||
points: ['br', 'cl'],
|
||||
},
|
||||
};
|
||||
|
||||
const DisableAutoArrowList: Set<keyof BuildInPlacements> = new Set([
|
||||
'topLeft',
|
||||
'topRight',
|
||||
'bottomLeft',
|
||||
'bottomRight',
|
||||
'leftTop',
|
||||
'leftBottom',
|
||||
'rightTop',
|
||||
'rightBottom',
|
||||
]);
|
||||
|
||||
export default function getPlacements(config: PlacementsConfig) {
|
||||
const {
|
||||
arrowWidth,
|
||||
horizontalArrowShift = 16,
|
||||
verticalArrowShift = 8,
|
||||
autoAdjustOverflow,
|
||||
arrowPointAtCenter,
|
||||
offset,
|
||||
} = config;
|
||||
const { arrowWidth, autoAdjustOverflow, arrowPointAtCenter, offset, borderRadius } = config;
|
||||
const halfArrowWidth = arrowWidth / 2;
|
||||
|
||||
const placementMap: BuildInPlacements = {
|
||||
left: {
|
||||
points: ['cr', 'cl'],
|
||||
offset: [-offset, 0],
|
||||
},
|
||||
right: {
|
||||
points: ['cl', 'cr'],
|
||||
offset: [offset, 0],
|
||||
},
|
||||
top: {
|
||||
points: ['bc', 'tc'],
|
||||
offset: [0, -offset],
|
||||
},
|
||||
bottom: {
|
||||
points: ['tc', 'bc'],
|
||||
offset: [0, offset],
|
||||
},
|
||||
topLeft: {
|
||||
points: ['bl', 'tc'],
|
||||
offset: [-(horizontalArrowShift + halfArrowWidth), -offset],
|
||||
},
|
||||
leftTop: {
|
||||
points: ['tr', 'cl'],
|
||||
offset: [-offset, -(verticalArrowShift + halfArrowWidth)],
|
||||
},
|
||||
topRight: {
|
||||
points: ['br', 'tc'],
|
||||
offset: [horizontalArrowShift + halfArrowWidth, -offset],
|
||||
},
|
||||
rightTop: {
|
||||
points: ['tl', 'cr'],
|
||||
offset: [offset, -(verticalArrowShift + halfArrowWidth)],
|
||||
},
|
||||
bottomRight: {
|
||||
points: ['tr', 'bc'],
|
||||
offset: [horizontalArrowShift + halfArrowWidth, offset],
|
||||
},
|
||||
rightBottom: {
|
||||
points: ['bl', 'cr'],
|
||||
offset: [offset, verticalArrowShift + halfArrowWidth],
|
||||
},
|
||||
bottomLeft: {
|
||||
points: ['tl', 'bc'],
|
||||
offset: [-(horizontalArrowShift + halfArrowWidth), offset],
|
||||
},
|
||||
leftBottom: {
|
||||
points: ['br', 'cl'],
|
||||
offset: [-offset, verticalArrowShift + halfArrowWidth],
|
||||
},
|
||||
};
|
||||
Object.keys(placementMap).forEach((key) => {
|
||||
placementMap[key] = arrowPointAtCenter
|
||||
? {
|
||||
...placementMap[key],
|
||||
offset: vertexCalc(
|
||||
placementMap[key].offset!,
|
||||
getArrowOffset(key as PlacementType, arrowWidth, offset),
|
||||
),
|
||||
overflow: getOverflowOptions(autoAdjustOverflow),
|
||||
targetOffset,
|
||||
}
|
||||
: {
|
||||
...placements[key],
|
||||
offset: vertexCalc(
|
||||
placements[key].offset!,
|
||||
getArrowOffset(key as PlacementType, arrowWidth, offset),
|
||||
),
|
||||
overflow: getOverflowOptions(autoAdjustOverflow),
|
||||
};
|
||||
const placementMap: BuildInPlacements = {};
|
||||
|
||||
placementMap[key].ignoreShake = true;
|
||||
Object.keys(PlacementAlignMap).forEach((key: PlacementType) => {
|
||||
const template =
|
||||
(arrowPointAtCenter && ArrowCenterPlacementAlignMap[key]) || PlacementAlignMap[key];
|
||||
|
||||
const placementInfo = {
|
||||
...template,
|
||||
offset: [0, 0],
|
||||
};
|
||||
placementMap[key] = placementInfo;
|
||||
|
||||
// Disable autoArrow since design is fixed position
|
||||
if (DisableAutoArrowList.has(key)) {
|
||||
placementInfo.autoArrow = false;
|
||||
}
|
||||
|
||||
// Static offset
|
||||
switch (key) {
|
||||
case 'top':
|
||||
case 'topLeft':
|
||||
case 'topRight':
|
||||
placementInfo.offset[1] = -halfArrowWidth - offset;
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
case 'bottomLeft':
|
||||
case 'bottomRight':
|
||||
placementInfo.offset[1] = halfArrowWidth + offset;
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
case 'leftTop':
|
||||
case 'leftBottom':
|
||||
placementInfo.offset[0] = -halfArrowWidth - offset;
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
case 'rightTop':
|
||||
case 'rightBottom':
|
||||
placementInfo.offset[0] = halfArrowWidth + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
// Dynamic offset
|
||||
const arrowOffset = getArrowOffset({
|
||||
contentRadius: borderRadius,
|
||||
limitVerticalRadius: true,
|
||||
});
|
||||
|
||||
if (arrowPointAtCenter) {
|
||||
switch (key) {
|
||||
case 'topLeft':
|
||||
case 'bottomLeft':
|
||||
placementInfo.offset[0] = -arrowOffset.dropdownArrowOffset - halfArrowWidth;
|
||||
break;
|
||||
|
||||
case 'topRight':
|
||||
case 'bottomRight':
|
||||
placementInfo.offset[0] = arrowOffset.dropdownArrowOffset + halfArrowWidth;
|
||||
break;
|
||||
|
||||
case 'leftTop':
|
||||
case 'rightTop':
|
||||
placementInfo.offset[1] = -arrowOffset.dropdownArrowOffset - halfArrowWidth;
|
||||
break;
|
||||
|
||||
case 'leftBottom':
|
||||
case 'rightBottom':
|
||||
placementInfo.offset[1] = arrowOffset.dropdownArrowOffset + halfArrowWidth;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Overflow
|
||||
placementInfo.overflow = getOverflowOptions(key, arrowOffset, arrowWidth, autoAdjustOverflow);
|
||||
});
|
||||
|
||||
return placementMap;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/affix/demo/basic.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/affix/demo/basic.tsx extend context correctly 1`] = `
|
||||
Array [
|
||||
<div>
|
||||
<div
|
||||
@@ -34,9 +34,9 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/debug.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/affix/demo/debug.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
style="height:10000px"
|
||||
style="height: 10000px;"
|
||||
>
|
||||
<div>
|
||||
Top
|
||||
@@ -46,7 +46,7 @@ exports[`renders ./components/affix/demo/debug.tsx extend context correctly 1`]
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
style="background:red"
|
||||
style="background: red;"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
@@ -65,7 +65,7 @@ exports[`renders ./components/affix/demo/debug.tsx extend context correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/on-change.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/affix/demo/on-change.tsx extend context correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
@@ -82,7 +82,7 @@ exports[`renders ./components/affix/demo/on-change.tsx extend context correctly
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/target.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/affix/demo/target.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="scrollable-container"
|
||||
>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/affix/demo/basic.tsx correctly 1`] = `
|
||||
exports[`renders components/affix/demo/basic.tsx correctly 1`] = `
|
||||
Array [
|
||||
<div>
|
||||
<div
|
||||
@@ -34,7 +34,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/debug.tsx correctly 1`] = `
|
||||
exports[`renders components/affix/demo/debug.tsx correctly 1`] = `
|
||||
<div
|
||||
style="height:10000px"
|
||||
>
|
||||
@@ -65,7 +65,7 @@ exports[`renders ./components/affix/demo/debug.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/on-change.tsx correctly 1`] = `
|
||||
exports[`renders components/affix/demo/on-change.tsx correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
@@ -82,7 +82,7 @@ exports[`renders ./components/affix/demo/on-change.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/target.tsx correctly 1`] = `
|
||||
exports[`renders components/affix/demo/target.tsx correctly 1`] = `
|
||||
<div
|
||||
class="scrollable-container"
|
||||
>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
category: Components
|
||||
title: Affix
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YSm4RI3iOJ8AAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*03dxS64LxeQAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
|
||||
@@ -53,7 +53,7 @@ export interface AffixState {
|
||||
prevTarget: Window | HTMLElement | null;
|
||||
}
|
||||
|
||||
class Affix extends React.Component<InternalAffixProps, AffixState> {
|
||||
class InternalAffix extends React.Component<InternalAffixProps, AffixState> {
|
||||
static contextType = ConfigContext;
|
||||
|
||||
state: AffixState = {
|
||||
@@ -165,15 +165,15 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
|
||||
status: AffixStatus.None,
|
||||
};
|
||||
const targetRect = getTargetRect(targetNode);
|
||||
const placeholderReact = getTargetRect(this.placeholderNodeRef.current);
|
||||
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
|
||||
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
|
||||
const placeholderRect = getTargetRect(this.placeholderNodeRef.current);
|
||||
const fixedTop = getFixedTop(placeholderRect, targetRect, offsetTop);
|
||||
const fixedBottom = getFixedBottom(placeholderRect, targetRect, offsetBottom);
|
||||
|
||||
if (
|
||||
placeholderReact.top === 0 &&
|
||||
placeholderReact.left === 0 &&
|
||||
placeholderReact.width === 0 &&
|
||||
placeholderReact.height === 0
|
||||
placeholderRect.top === 0 &&
|
||||
placeholderRect.left === 0 &&
|
||||
placeholderRect.width === 0 &&
|
||||
placeholderRect.height === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -182,23 +182,23 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
|
||||
newState.affixStyle = {
|
||||
position: 'fixed',
|
||||
top: fixedTop,
|
||||
width: placeholderReact.width,
|
||||
height: placeholderReact.height,
|
||||
width: placeholderRect.width,
|
||||
height: placeholderRect.height,
|
||||
};
|
||||
newState.placeholderStyle = {
|
||||
width: placeholderReact.width,
|
||||
height: placeholderReact.height,
|
||||
width: placeholderRect.width,
|
||||
height: placeholderRect.height,
|
||||
};
|
||||
} else if (fixedBottom !== undefined) {
|
||||
newState.affixStyle = {
|
||||
position: 'fixed',
|
||||
bottom: fixedBottom,
|
||||
width: placeholderReact.width,
|
||||
height: placeholderReact.height,
|
||||
width: placeholderRect.width,
|
||||
height: placeholderRect.height,
|
||||
};
|
||||
newState.placeholderStyle = {
|
||||
width: placeholderReact.width,
|
||||
height: placeholderReact.height,
|
||||
width: placeholderRect.width,
|
||||
height: placeholderRect.height,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -241,9 +241,9 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
|
||||
const targetNode = targetFunc();
|
||||
if (targetNode && this.placeholderNodeRef.current) {
|
||||
const targetRect = getTargetRect(targetNode);
|
||||
const placeholderReact = getTargetRect(this.placeholderNodeRef.current);
|
||||
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
|
||||
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
|
||||
const placeholderRect = getTargetRect(this.placeholderNodeRef.current);
|
||||
const fixedTop = getFixedTop(placeholderRect, targetRect, offsetTop);
|
||||
const fixedBottom = getFixedBottom(placeholderRect, targetRect, offsetBottom);
|
||||
|
||||
if (
|
||||
(fixedTop !== undefined && affixStyle.top === fixedTop) ||
|
||||
@@ -293,9 +293,9 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
|
||||
}
|
||||
}
|
||||
// just use in test
|
||||
export type InternalAffixClass = Affix;
|
||||
export type InternalAffixClass = InternalAffix;
|
||||
|
||||
const AffixFC = forwardRef<Affix, AffixProps>((props, ref) => {
|
||||
const Affix = forwardRef<InternalAffix, AffixProps>((props, ref) => {
|
||||
const { prefixCls: customizePrefixCls, rootClassName } = props;
|
||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||
const affixPrefixCls = getPrefixCls('affix', customizePrefixCls);
|
||||
@@ -308,11 +308,11 @@ const AffixFC = forwardRef<Affix, AffixProps>((props, ref) => {
|
||||
rootClassName: classNames(rootClassName, hashId),
|
||||
};
|
||||
|
||||
return wrapSSR(<Affix {...AffixProps} ref={ref} />);
|
||||
return wrapSSR(<InternalAffix {...AffixProps} ref={ref} />);
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
AffixFC.displayName = 'Affix';
|
||||
Affix.displayName = 'Affix';
|
||||
}
|
||||
|
||||
export default AffixFC;
|
||||
export default Affix;
|
||||
|
||||
@@ -3,6 +3,7 @@ category: Components
|
||||
title: Affix
|
||||
subtitle: 固钉
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YSm4RI3iOJ8AAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*03dxS64LxeQAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import type { InternalAffixClass } from '.';
|
||||
|
||||
export type BindElement = HTMLElement | Window | null | undefined;
|
||||
|
||||
@@ -8,19 +9,19 @@ export function getTargetRect(target: BindElement): DOMRect {
|
||||
: ({ top: 0, bottom: window.innerHeight } as DOMRect);
|
||||
}
|
||||
|
||||
export function getFixedTop(placeholderReact: DOMRect, targetRect: DOMRect, offsetTop?: number) {
|
||||
if (offsetTop !== undefined && targetRect.top > placeholderReact.top - offsetTop) {
|
||||
export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offsetTop?: number) {
|
||||
if (offsetTop !== undefined && targetRect.top > placeholderRect.top - offsetTop) {
|
||||
return offsetTop + targetRect.top;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getFixedBottom(
|
||||
placeholderReact: DOMRect,
|
||||
placeholderRect: DOMRect,
|
||||
targetRect: DOMRect,
|
||||
offsetBottom?: number,
|
||||
) {
|
||||
if (offsetBottom !== undefined && targetRect.bottom < placeholderReact.bottom + offsetBottom) {
|
||||
if (offsetBottom !== undefined && targetRect.bottom < placeholderRect.bottom + offsetBottom) {
|
||||
const targetBottomOffset = window.innerHeight - targetRect.bottom;
|
||||
return offsetBottom + targetBottomOffset;
|
||||
}
|
||||
@@ -51,7 +52,10 @@ export function getObserverEntities() {
|
||||
return observerEntities;
|
||||
}
|
||||
|
||||
export function addObserveTarget<T>(target: HTMLElement | Window | null, affix?: T): void {
|
||||
export function addObserveTarget<T extends InternalAffixClass>(
|
||||
target: HTMLElement | Window | null,
|
||||
affix?: T,
|
||||
): void {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
@@ -79,7 +83,7 @@ export function addObserveTarget<T>(target: HTMLElement | Window | null, affix?:
|
||||
}
|
||||
}
|
||||
|
||||
export function removeObserveTarget<T>(affix: T): void {
|
||||
export function removeObserveTarget<T extends InternalAffixClass>(affix: T): void {
|
||||
const observerEntity = observerEntities.find((oriObserverEntity) => {
|
||||
const hasAffix = oriObserverEntity.affixList.some((item) => item === affix);
|
||||
if (hasAffix) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/alert/demo/action.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/action.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success"
|
||||
@@ -83,7 +83,7 @@ exports[`renders ./components/alert/demo/action.tsx extend context correctly 1`]
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-with-description"
|
||||
@@ -139,7 +139,7 @@ exports[`renders ./components/alert/demo/action.tsx extend context correctly 1`]
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon"
|
||||
@@ -232,7 +232,7 @@ exports[`renders ./components/alert/demo/action.tsx extend context correctly 1`]
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-sm"
|
||||
@@ -287,14 +287,14 @@ exports[`renders ./components/alert/demo/action.tsx extend context correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/banner.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/banner.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-banner"
|
||||
@@ -333,7 +333,7 @@ exports[`renders ./components/alert/demo/banner.tsx extend context correctly 1`]
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-banner"
|
||||
@@ -397,7 +397,7 @@ exports[`renders ./components/alert/demo/banner.tsx extend context correctly 1`]
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon ant-alert-banner"
|
||||
@@ -456,7 +456,7 @@ exports[`renders ./components/alert/demo/banner.tsx extend context correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/basic.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/basic.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
data-show="true"
|
||||
@@ -474,14 +474,14 @@ exports[`renders ./components/alert/demo/basic.tsx extend context correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/closable.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/closable.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon"
|
||||
@@ -576,7 +576,7 @@ exports[`renders ./components/alert/demo/closable.tsx extend context correctly 1
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/close-text.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/close-text.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-no-icon"
|
||||
data-show="true"
|
||||
@@ -605,14 +605,14 @@ exports[`renders ./components/alert/demo/close-text.tsx extend context correctly
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/custom-icon.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
@@ -632,7 +632,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success"
|
||||
@@ -671,7 +671,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-info"
|
||||
@@ -710,7 +710,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning"
|
||||
@@ -749,7 +749,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-error"
|
||||
@@ -788,7 +788,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-with-description"
|
||||
@@ -832,7 +832,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-with-description"
|
||||
@@ -876,7 +876,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-with-description"
|
||||
@@ -964,14 +964,14 @@ exports[`renders ./components/alert/demo/custom-icon.tsx extend context correctl
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/description.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/description.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-with-description ant-alert-no-icon"
|
||||
@@ -996,7 +996,7 @@ exports[`renders ./components/alert/demo/description.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-with-description ant-alert-no-icon"
|
||||
@@ -1021,7 +1021,7 @@ exports[`renders ./components/alert/demo/description.tsx extend context correctl
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-with-description ant-alert-no-icon"
|
||||
@@ -1071,7 +1071,7 @@ exports[`renders ./components/alert/demo/description.tsx extend context correctl
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/error-boundary.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/error-boundary.tsx extend context correctly 1`] = `
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-dangerous"
|
||||
type="button"
|
||||
@@ -1082,14 +1082,14 @@ exports[`renders ./components/alert/demo/error-boundary.tsx extend context corre
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/icon.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success"
|
||||
@@ -1128,7 +1128,7 @@ exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-info"
|
||||
@@ -1167,7 +1167,7 @@ exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning"
|
||||
@@ -1231,7 +1231,7 @@ exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-error"
|
||||
@@ -1270,7 +1270,7 @@ exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-with-description"
|
||||
@@ -1314,7 +1314,7 @@ exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-with-description"
|
||||
@@ -1358,7 +1358,7 @@ exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-with-description"
|
||||
@@ -1471,14 +1471,14 @@ exports[`renders ./components/alert/demo/icon.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/smooth-closed.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/smooth-closed.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
@@ -1523,7 +1523,7 @@ exports[`renders ./components/alert/demo/smooth-closed.tsx extend context correc
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<p>
|
||||
click the close button to see the effect
|
||||
@@ -1557,14 +1557,14 @@ exports[`renders ./components/alert/demo/smooth-closed.tsx extend context correc
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/style.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/alert/demo/style.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
@@ -1584,7 +1584,7 @@ exports[`renders ./components/alert/demo/style.tsx extend context correctly 1`]
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-no-icon"
|
||||
@@ -1604,7 +1604,7 @@ exports[`renders ./components/alert/demo/style.tsx extend context correctly 1`]
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/alert/demo/action.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/action.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -287,7 +287,7 @@ exports[`renders ./components/alert/demo/action.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/banner.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/banner.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -456,7 +456,7 @@ exports[`renders ./components/alert/demo/banner.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/basic.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/basic.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
data-show="true"
|
||||
@@ -474,7 +474,7 @@ exports[`renders ./components/alert/demo/basic.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/closable.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/closable.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -576,7 +576,7 @@ exports[`renders ./components/alert/demo/closable.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/close-text.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/close-text.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-no-icon"
|
||||
data-show="true"
|
||||
@@ -605,7 +605,7 @@ exports[`renders ./components/alert/demo/close-text.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/custom-icon.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/custom-icon.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -964,7 +964,7 @@ exports[`renders ./components/alert/demo/custom-icon.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/description.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/description.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -1071,7 +1071,7 @@ exports[`renders ./components/alert/demo/description.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/error-boundary.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/error-boundary.tsx correctly 1`] = `
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-dangerous"
|
||||
type="button"
|
||||
@@ -1082,7 +1082,7 @@ exports[`renders ./components/alert/demo/error-boundary.tsx correctly 1`] = `
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/icon.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/icon.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -1471,7 +1471,7 @@ exports[`renders ./components/alert/demo/icon.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/smooth-closed.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/smooth-closed.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -1557,7 +1557,7 @@ exports[`renders ./components/alert/demo/smooth-closed.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/style.tsx correctly 1`] = `
|
||||
exports[`renders components/alert/demo/style.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import Alert from '..';
|
||||
import accessibilityTest from '../../../tests/shared/accessibilityTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { render, act, screen } from '../../../tests/utils';
|
||||
import { act, render, screen } from '../../../tests/utils';
|
||||
import Button from '../../button';
|
||||
import Popconfirm from '../../popconfirm';
|
||||
import Tooltip from '../../tooltip';
|
||||
@@ -105,6 +105,10 @@ describe('Alert', () => {
|
||||
|
||||
await userEvent.hover(screen.getByRole('alert'));
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
expect(screen.getByRole('tooltip')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -119,6 +123,10 @@ describe('Alert', () => {
|
||||
);
|
||||
await userEvent.click(screen.getByRole('alert'));
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
expect(screen.getByRole('tooltip')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
category: Components
|
||||
title: Alert
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Ct7bT7rrTTAAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-U3XQqYN7VsAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
|
||||
@@ -3,6 +3,7 @@ category: Components
|
||||
subtitle: 警告提示
|
||||
title: Alert
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Ct7bT7rrTTAAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-U3XQqYN7VsAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import classNames from 'classnames';
|
||||
import useEvent from 'rc-util/lib/hooks/useEvent';
|
||||
import * as React from 'react';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
|
||||
@@ -43,7 +44,7 @@ function getOffsetTop(element: HTMLElement, container: AnchorContainer): number
|
||||
return rect.top;
|
||||
}
|
||||
|
||||
const sharpMatcherRegx = /#([\S ]+)$/;
|
||||
const sharpMatcherRegex = /#([\S ]+)$/;
|
||||
|
||||
interface Section {
|
||||
link: string;
|
||||
@@ -155,35 +156,30 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
|
||||
|
||||
const dependencyListItem: React.DependencyList[number] = JSON.stringify(links);
|
||||
|
||||
const registerLink = React.useCallback<AntAnchor['registerLink']>(
|
||||
(link) => {
|
||||
if (!links.includes(link)) {
|
||||
setLinks((prev) => [...prev, link]);
|
||||
}
|
||||
},
|
||||
[dependencyListItem],
|
||||
);
|
||||
const registerLink = useEvent<AntAnchor['registerLink']>((link) => {
|
||||
if (!links.includes(link)) {
|
||||
setLinks((prev) => [...prev, link]);
|
||||
}
|
||||
});
|
||||
|
||||
const unregisterLink = React.useCallback<AntAnchor['unregisterLink']>(
|
||||
(link) => {
|
||||
if (links.includes(link)) {
|
||||
setLinks((prev) => prev.filter((i) => i !== link));
|
||||
}
|
||||
},
|
||||
[dependencyListItem],
|
||||
);
|
||||
const unregisterLink = useEvent<AntAnchor['unregisterLink']>((link) => {
|
||||
if (links.includes(link)) {
|
||||
setLinks((prev) => prev.filter((i) => i !== link));
|
||||
}
|
||||
});
|
||||
|
||||
const updateInk = () => {
|
||||
const linkNode = wrapperRef.current?.querySelector<HTMLElement>(
|
||||
`.${prefixCls}-link-title-active`,
|
||||
);
|
||||
if (linkNode && spanLinkNode.current) {
|
||||
if (anchorDirection !== 'horizontal') {
|
||||
spanLinkNode.current.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2}px`;
|
||||
spanLinkNode.current.style.height = `${linkNode.clientHeight}px`;
|
||||
} else {
|
||||
spanLinkNode.current.style.left = `${linkNode.offsetLeft}px`;
|
||||
spanLinkNode.current.style.width = `${linkNode.clientWidth}px`;
|
||||
const { style: inkStyle } = spanLinkNode.current;
|
||||
const horizontalAnchor = anchorDirection === 'horizontal';
|
||||
inkStyle.top = horizontalAnchor ? '' : `${linkNode.offsetTop + linkNode.clientHeight / 2}px`;
|
||||
inkStyle.height = horizontalAnchor ? '' : `${linkNode.clientHeight}px`;
|
||||
inkStyle.left = horizontalAnchor ? `${linkNode.offsetLeft}px` : '';
|
||||
inkStyle.width = horizontalAnchor ? `${linkNode.clientWidth}px` : '';
|
||||
if (horizontalAnchor) {
|
||||
scrollIntoView(linkNode, {
|
||||
scrollMode: 'if-needed',
|
||||
block: 'nearest',
|
||||
@@ -196,7 +192,7 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
|
||||
const linkSections: Section[] = [];
|
||||
const container = getCurrentContainer();
|
||||
_links.forEach((link) => {
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link?.toString());
|
||||
const sharpLinkMatch = sharpMatcherRegex.exec(link?.toString());
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
@@ -251,7 +247,7 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
|
||||
setCurrentActiveLink(link);
|
||||
const container = getCurrentContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link);
|
||||
const sharpLinkMatch = sharpMatcherRegex.exec(link);
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import type { ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigConsumer } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import warning from '../_util/warning';
|
||||
import type { AntAnchor } from './Anchor';
|
||||
import AnchorContext from './context';
|
||||
@@ -30,7 +29,7 @@ const AnchorLink: React.FC<AnchorLinkProps> = (props) => {
|
||||
return () => {
|
||||
unregisterLink?.(href);
|
||||
};
|
||||
}, [href, registerLink, unregisterLink]);
|
||||
}, [href]);
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
||||
onClick?.(e, { title, href });
|
||||
@@ -46,33 +45,33 @@ const AnchorLink: React.FC<AnchorLinkProps> = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
|
||||
const active = activeLink === href;
|
||||
|
||||
const wrapperClassName = classNames(`${prefixCls}-link`, className, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
});
|
||||
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
[`${prefixCls}-link-title-active`]: active,
|
||||
});
|
||||
|
||||
return (
|
||||
<ConfigConsumer>
|
||||
{({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
const active = activeLink === href;
|
||||
const wrapperClassName = classNames(`${prefixCls}-link`, className, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
});
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
[`${prefixCls}-link-title-active`]: active,
|
||||
});
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<a
|
||||
className={titleClassName}
|
||||
href={href}
|
||||
title={typeof title === 'string' ? title : ''}
|
||||
target={target}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
{direction !== 'horizontal' ? children : null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</ConfigConsumer>
|
||||
<div className={wrapperClassName}>
|
||||
<a
|
||||
className={titleClassName}
|
||||
href={href}
|
||||
title={typeof title === 'string' ? title : ''}
|
||||
target={target}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
{direction !== 'horizontal' ? children : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { resetWarned } from 'rc-util/lib/warning';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
|
||||
import Anchor from '..';
|
||||
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||
import type { AnchorDirection } from '../Anchor';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
@@ -374,10 +375,10 @@ describe('Anchor Render', () => {
|
||||
|
||||
it('handles invalid hash correctly', () => {
|
||||
const { container } = render(
|
||||
<Anchor items={[{ key: 'title', href: 'notexsited', title: 'title' }]} />,
|
||||
<Anchor items={[{ key: 'title', href: 'nonexistent', title: 'title' }]} />,
|
||||
);
|
||||
|
||||
const link = container.querySelector(`a[href="notexsited"]`)!;
|
||||
const link = container.querySelector(`a[href="nonexistent"]`)!;
|
||||
fireEvent.click(link);
|
||||
expect(container.querySelector(`.ant-anchor-link-title-active`)?.textContent).toBe('title');
|
||||
});
|
||||
@@ -791,11 +792,11 @@ describe('Anchor Render', () => {
|
||||
it('handles invalid hash correctly', () => {
|
||||
const { container } = render(
|
||||
<Anchor>
|
||||
<Link href="notexsited" title="title" />
|
||||
<Link href="nonexistent" title="title" />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
const link = container.querySelector(`a[href="notexsited"]`)!;
|
||||
const link = container.querySelector(`a[href="nonexistent"]`)!;
|
||||
fireEvent.click(link);
|
||||
expect(container.querySelector(`.ant-anchor-link-title-active`)?.textContent).toBe('title');
|
||||
});
|
||||
@@ -886,5 +887,54 @@ describe('Anchor Render', () => {
|
||||
'Warning: [antd: Anchor.Link] `Anchor.Link children` is not supported when `Anchor` direction is horizontal',
|
||||
);
|
||||
});
|
||||
it('switch direction', async () => {
|
||||
const Foo: React.FC = () => {
|
||||
const [direction, setDirection] = useState<AnchorDirection>('vertical');
|
||||
const toggle = () => {
|
||||
setDirection(direction === 'vertical' ? 'horizontal' : 'vertical');
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<button onClick={toggle} type="button">
|
||||
toggle
|
||||
</button>
|
||||
<Anchor
|
||||
direction={direction}
|
||||
items={[
|
||||
{
|
||||
title: 'part-1',
|
||||
href: 'part-1',
|
||||
key: 'part-1',
|
||||
},
|
||||
{
|
||||
title: 'part-2',
|
||||
href: 'part-2',
|
||||
key: 'part-2',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const wrapper = await render(<Foo />);
|
||||
(await wrapper.findByText('part-1')).click();
|
||||
await waitFakeTimer();
|
||||
const ink = wrapper.container.querySelector<HTMLSpanElement>('.ant-anchor-ink')!;
|
||||
const toggleButton = wrapper.container.querySelector('button')!;
|
||||
|
||||
fireEvent.click(toggleButton);
|
||||
act(() => jest.runAllTimers());
|
||||
expect(!!ink.style.left).toBe(true);
|
||||
expect(!!ink.style.width).toBe(true);
|
||||
expect(ink.style.top).toBe('');
|
||||
expect(ink.style.height).toBe('');
|
||||
|
||||
fireEvent.click(toggleButton);
|
||||
act(() => jest.runAllTimers());
|
||||
expect(!!ink.style.top).toBe(true);
|
||||
expect(!!ink.style.height).toBe(true);
|
||||
expect(ink.style.left).toBe('');
|
||||
expect(ink.style.width).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/anchor/demo/basic.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/basic.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-row"
|
||||
>
|
||||
@@ -9,15 +9,15 @@ exports[`renders ./components/anchor/demo/basic.tsx extend context correctly 1`]
|
||||
>
|
||||
<div
|
||||
id="part-1"
|
||||
style="height:100vh;background:rgba(255,0,0,0.02)"
|
||||
style="height: 100vh; background: rgba(255, 0, 0, 0.02);"
|
||||
/>
|
||||
<div
|
||||
id="part-2"
|
||||
style="height:100vh;background:rgba(0,255,0,0.02)"
|
||||
style="height: 100vh; background: rgba(0, 255, 0, 0.02);"
|
||||
/>
|
||||
<div
|
||||
id="part-3"
|
||||
style="height:100vh;background:rgba(0,0,255,0.02)"
|
||||
style="height: 100vh; background: rgba(0, 0, 255, 0.02);"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@@ -29,19 +29,20 @@ exports[`renders ./components/anchor/demo/basic.tsx extend context correctly 1`]
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink"
|
||||
class="ant-anchor-ink ant-anchor-ink-visible"
|
||||
style="top: 0px; height: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
class="ant-anchor-link ant-anchor-link-active"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
class="ant-anchor-link-title ant-anchor-link-title-active"
|
||||
href="#part-1"
|
||||
title="Part 1"
|
||||
>
|
||||
@@ -78,16 +79,17 @@ exports[`renders ./components/anchor/demo/basic.tsx extend context correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/customizeHighlight.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/customizeHighlight.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor ant-anchor-fixed"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink"
|
||||
class="ant-anchor-ink ant-anchor-ink-visible"
|
||||
style="top: 0px; height: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
@@ -101,10 +103,10 @@ exports[`renders ./components/anchor/demo/customizeHighlight.tsx extend context
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
class="ant-anchor-link ant-anchor-link-active"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
class="ant-anchor-link-title ant-anchor-link-title-active"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
>
|
||||
@@ -148,10 +150,10 @@ exports[`renders ./components/anchor/demo/customizeHighlight.tsx extend context
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/horizontal.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/horizontal.tsx extend context correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
style="padding:20px"
|
||||
style="padding: 20px;"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -159,19 +161,20 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper ant-anchor-wrapper-horizontal"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink"
|
||||
class="ant-anchor-ink ant-anchor-ink-visible"
|
||||
style="left: 0px; width: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
class="ant-anchor-link ant-anchor-link-active"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
class="ant-anchor-link-title ant-anchor-link-title-active"
|
||||
href="#part-1"
|
||||
title="Part 1"
|
||||
>
|
||||
@@ -241,36 +244,36 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
id="part-1"
|
||||
style="width:100vw;height:100vh;text-align:center;background:rgba(0,255,0,0.02)"
|
||||
style="width: 100vw; height: 100vh; text-align: center; background: rgba(0, 255, 0, 0.02);"
|
||||
/>
|
||||
<div
|
||||
id="part-2"
|
||||
style="width:100vw;height:100vh;text-align:center;background:rgba(0,0,255,0.02)"
|
||||
style="width: 100vw; height: 100vh; text-align: center; background: rgba(0, 0, 255, 0.02);"
|
||||
/>
|
||||
<div
|
||||
id="part-3"
|
||||
style="width:100vw;height:100vh;text-align:center;background:#FFFBE9"
|
||||
style="width: 100vw; height: 100vh; text-align: center; background: rgb(255, 251, 233);"
|
||||
/>
|
||||
<div
|
||||
id="part-4"
|
||||
style="width:100vw;height:100vh;text-align:center;background:#F4EAD5"
|
||||
style="width: 100vw; height: 100vh; text-align: center; background: rgb(244, 234, 213);"
|
||||
/>
|
||||
<div
|
||||
id="part-5"
|
||||
style="width:100vw;height:100vh;text-align:center;background:#DAE2B6"
|
||||
style="width: 100vw; height: 100vh; text-align: center; background: rgb(218, 226, 182);"
|
||||
/>
|
||||
<div
|
||||
id="part-6"
|
||||
style="width:100vw;height:100vh;text-align:center;background:#CCD6A6"
|
||||
style="width: 100vw; height: 100vh; text-align: center; background: rgb(204, 214, 166);"
|
||||
/>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/legacy-anchor.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/legacy-anchor.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor ant-anchor-fixed"
|
||||
@@ -337,10 +340,10 @@ exports[`renders ./components/anchor/demo/legacy-anchor.tsx extend context corre
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onChange.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/onChange.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor ant-anchor-fixed"
|
||||
@@ -407,10 +410,10 @@ exports[`renders ./components/anchor/demo/onChange.tsx extend context correctly
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onClick.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/onClick.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor ant-anchor-fixed"
|
||||
@@ -477,10 +480,10 @@ exports[`renders ./components/anchor/demo/onClick.tsx extend context correctly 1
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/static.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/static.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor ant-anchor-fixed"
|
||||
@@ -547,7 +550,7 @@ exports[`renders ./components/anchor/demo/static.tsx extend context correctly 1`
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/targetOffset.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/targetOffset.tsx extend context correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-row"
|
||||
@@ -557,19 +560,19 @@ exports[`renders ./components/anchor/demo/targetOffset.tsx extend context correc
|
||||
>
|
||||
<div
|
||||
id="part-1"
|
||||
style="height:100vh;background:rgba(255,0,0,0.02);margin-top:30vh"
|
||||
style="height: 100vh; background: rgba(255, 0, 0, 0.02); margin-top: 30vh;"
|
||||
>
|
||||
Part 1
|
||||
</div>
|
||||
<div
|
||||
id="part-2"
|
||||
style="height:100vh;background:rgba(0,255,0,0.02)"
|
||||
style="height: 100vh; background: rgba(0, 255, 0, 0.02);"
|
||||
>
|
||||
Part 2
|
||||
</div>
|
||||
<div
|
||||
id="part-3"
|
||||
style="height:100vh;background:rgba(0,0,255,0.02)"
|
||||
style="height: 100vh; background: rgba(0, 0, 255, 0.02);"
|
||||
>
|
||||
Part 3
|
||||
</div>
|
||||
@@ -583,19 +586,20 @@ exports[`renders ./components/anchor/demo/targetOffset.tsx extend context correc
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink"
|
||||
class="ant-anchor-ink ant-anchor-ink-visible"
|
||||
style="top: 0px; height: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
class="ant-anchor-link ant-anchor-link-active"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
class="ant-anchor-link-title ant-anchor-link-title-active"
|
||||
href="#part-1"
|
||||
title="Part 1"
|
||||
>
|
||||
@@ -631,7 +635,7 @@ exports[`renders ./components/anchor/demo/targetOffset.tsx extend context correc
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="height:30vh;background:rgba(0,0,0,0.85);position:fixed;top:0;left:0;width:75%;color:#FFF"
|
||||
style="height: 30vh; background: rgba(0, 0, 0, 0.85); position: fixed; top: 0px; left: 0px; width: 75%; color: rgb(255, 255, 255);"
|
||||
>
|
||||
<div>
|
||||
Fixed Top Block
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/anchor/demo/basic.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/basic.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-row"
|
||||
>
|
||||
@@ -78,7 +78,7 @@ exports[`renders ./components/anchor/demo/basic.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/customizeHighlight.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/customizeHighlight.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
@@ -148,7 +148,7 @@ exports[`renders ./components/anchor/demo/customizeHighlight.tsx correctly 1`] =
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/horizontal.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/horizontal.tsx correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
style="padding:20px"
|
||||
@@ -267,7 +267,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/legacy-anchor.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/legacy-anchor.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
@@ -337,7 +337,7 @@ exports[`renders ./components/anchor/demo/legacy-anchor.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onChange.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/onChange.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
@@ -407,7 +407,7 @@ exports[`renders ./components/anchor/demo/onChange.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onClick.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/onClick.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
@@ -477,7 +477,7 @@ exports[`renders ./components/anchor/demo/onClick.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/static.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/static.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
@@ -547,7 +547,7 @@ exports[`renders ./components/anchor/demo/static.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/targetOffset.tsx correctly 1`] = `
|
||||
exports[`renders components/anchor/demo/targetOffset.tsx correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-row"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
category: Components
|
||||
title: Anchor
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
group:
|
||||
title: Navigation
|
||||
|
||||
@@ -3,6 +3,7 @@ category: Components
|
||||
title: Anchor
|
||||
subtitle: 锚点
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
group:
|
||||
title: 导航
|
||||
|
||||
@@ -69,7 +69,7 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
||||
},
|
||||
},
|
||||
|
||||
[`&:not(${componentCls}-horizontal)`]: {
|
||||
[`&:not(${componentCls}-wrapper-horizontal)`]: {
|
||||
[componentCls]: {
|
||||
'&::before': {
|
||||
position: 'absolute',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/app/demo/basic.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/app/demo/basic.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-app"
|
||||
>
|
||||
@@ -9,7 +9,7 @@ exports[`renders ./components/app/demo/basic.tsx extend context correctly 1`] =
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
@@ -22,7 +22,7 @@ exports[`renders ./components/app/demo/basic.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/app/demo/basic.tsx correctly 1`] = `
|
||||
exports[`renders components/app/demo/basic.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-app"
|
||||
>
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import App from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { render } from '../../../tests/utils';
|
||||
import { render, waitFakeTimer } from '../../../tests/utils';
|
||||
import type { AppConfig } from '../context';
|
||||
import { AppConfigContext } from '../context';
|
||||
|
||||
describe('App', () => {
|
||||
mountTest(App);
|
||||
rtlTest(App);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('single', () => {
|
||||
// Sub page
|
||||
const MyPage = () => {
|
||||
const MyPage: React.FC = () => {
|
||||
const { message } = App.useApp();
|
||||
React.useEffect(() => {
|
||||
message.success('Good!');
|
||||
@@ -20,7 +31,7 @@ describe('App', () => {
|
||||
};
|
||||
|
||||
// Entry component
|
||||
const MyApp = () => (
|
||||
const MyApp: React.FC = () => (
|
||||
<App>
|
||||
<MyPage />
|
||||
</App>
|
||||
@@ -30,4 +41,103 @@ describe('App', () => {
|
||||
expect(getByText('Hello World')).toBeTruthy();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should work as message and notification config configured in app', async () => {
|
||||
let consumedConfig: AppConfig | undefined;
|
||||
const Consumer = () => {
|
||||
const { message, notification } = App.useApp();
|
||||
consumedConfig = React.useContext(AppConfigContext);
|
||||
|
||||
useEffect(() => {
|
||||
message.success('Message 1');
|
||||
message.success('Message 2');
|
||||
notification.success({ message: 'Notification 1' });
|
||||
notification.success({ message: 'Notification 2' });
|
||||
notification.success({ message: 'Notification 3' });
|
||||
}, [message, notification]);
|
||||
|
||||
return <div />;
|
||||
};
|
||||
const Wrapper = () => (
|
||||
<App message={{ maxCount: 1 }} notification={{ maxCount: 2 }}>
|
||||
<Consumer />
|
||||
</App>
|
||||
);
|
||||
|
||||
render(<Wrapper />);
|
||||
|
||||
await waitFakeTimer();
|
||||
|
||||
expect(consumedConfig?.message).toStrictEqual({ maxCount: 1 });
|
||||
expect(consumedConfig?.notification).toStrictEqual({ maxCount: 2 });
|
||||
|
||||
expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1);
|
||||
expect(document.querySelectorAll('.ant-notification-notice')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should be a merged config configured in nested app', async () => {
|
||||
let offsetConsumedConfig: AppConfig | undefined;
|
||||
let maxCountConsumedConfig: AppConfig | undefined;
|
||||
const OffsetConsumer = () => {
|
||||
offsetConsumedConfig = React.useContext(AppConfigContext);
|
||||
return <div />;
|
||||
};
|
||||
const MaxCountConsumer = () => {
|
||||
maxCountConsumedConfig = React.useContext(AppConfigContext);
|
||||
return <div />;
|
||||
};
|
||||
const Wrapper = () => (
|
||||
<App message={{ maxCount: 1 }} notification={{ maxCount: 2 }}>
|
||||
<App message={{ top: 32 }} notification={{ top: 96 }}>
|
||||
<OffsetConsumer />
|
||||
</App>
|
||||
<MaxCountConsumer />
|
||||
</App>
|
||||
);
|
||||
|
||||
render(<Wrapper />);
|
||||
|
||||
expect(offsetConsumedConfig?.message).toStrictEqual({ maxCount: 1, top: 32 });
|
||||
expect(offsetConsumedConfig?.notification).toStrictEqual({ maxCount: 2, top: 96 });
|
||||
expect(maxCountConsumedConfig?.message).toStrictEqual({ maxCount: 1 });
|
||||
expect(maxCountConsumedConfig?.notification).toStrictEqual({ maxCount: 2 });
|
||||
});
|
||||
|
||||
it('should respect config from props in priority', async () => {
|
||||
let config: AppConfig | undefined;
|
||||
const Consumer = () => {
|
||||
config = React.useContext(AppConfigContext);
|
||||
return <div />;
|
||||
};
|
||||
const Wrapper = () => (
|
||||
<App message={{ maxCount: 10, top: 20 }} notification={{ maxCount: 30, bottom: 40 }}>
|
||||
<App message={{ maxCount: 11 }} notification={{ bottom: 41 }}>
|
||||
<Consumer />
|
||||
</App>
|
||||
</App>
|
||||
);
|
||||
|
||||
render(<Wrapper />);
|
||||
|
||||
expect(config?.message).toStrictEqual({ maxCount: 11, top: 20 });
|
||||
expect(config?.notification).toStrictEqual({ maxCount: 30, bottom: 41 });
|
||||
});
|
||||
|
||||
it('support className', () => {
|
||||
const { container } = render(
|
||||
<App className="test-class">
|
||||
<div>test</div>
|
||||
</App>,
|
||||
);
|
||||
expect(container.querySelector<HTMLDivElement>('.ant-app')).toHaveClass('test-class');
|
||||
});
|
||||
|
||||
it('support style', () => {
|
||||
const { container } = render(
|
||||
<App style={{ color: 'blue' }}>
|
||||
<div>test</div>
|
||||
</App>,
|
||||
);
|
||||
expect(container.querySelector<HTMLDivElement>('.ant-app')).toHaveStyle('color: blue;');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import React from 'react';
|
||||
import type { MessageInstance } from '../message/interface';
|
||||
import type { NotificationInstance } from '../notification/interface';
|
||||
import type { MessageInstance, ConfigOptions as MessageConfig } from '../message/interface';
|
||||
import type { NotificationInstance, NotificationConfig } from '../notification/interface';
|
||||
import type { ModalStaticFunctions } from '../modal/confirm';
|
||||
|
||||
export type AppConfig = {
|
||||
message?: MessageConfig;
|
||||
notification?: NotificationConfig;
|
||||
};
|
||||
|
||||
export const AppConfigContext = React.createContext<AppConfig>({});
|
||||
|
||||
type ModalType = Omit<ModalStaticFunctions, 'warn'>;
|
||||
export interface useAppProps {
|
||||
message: MessageInstance;
|
||||
|
||||
@@ -3,6 +3,7 @@ category: Components
|
||||
group: Other
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HJz8SZos2wgAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*oC92TK44Ex8AAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
---
|
||||
@@ -25,8 +26,8 @@ Static function in React 18 concurrent mode will not well support. In v5, we rec
|
||||
App provides upstream and downstream method calls through `Context`, because useApp needs to be used as a subcomponent, we recommend encapsulating App at the top level in the application.
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { App } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const MyPage: React.FC = () => {
|
||||
const { message, notification, modal } = App.useApp();
|
||||
@@ -76,11 +77,10 @@ The App component can only use the token in the `ConfigProvider`, if you need to
|
||||
|
||||
```tsx
|
||||
// Entry component
|
||||
import React, { useEffect } from 'react';
|
||||
import { App } from 'antd';
|
||||
import type { MessageInstance } from 'antd/es/message/interface';
|
||||
import type { NotificationInstance } from 'antd/es/notification/interface';
|
||||
import type { ModalStaticFunctions } from 'antd/es/modal/confirm';
|
||||
import type { NotificationInstance } from 'antd/es/notification/interface';
|
||||
|
||||
let message: MessageInstance;
|
||||
let notification: NotificationInstance;
|
||||
@@ -99,9 +99,9 @@ export { message, notification, modal };
|
||||
|
||||
```tsx
|
||||
// sub page
|
||||
import React from 'react';
|
||||
import { Button, Space } from 'antd';
|
||||
import { message, modal, notification } from './store';
|
||||
import React from 'react';
|
||||
import { message } from './store';
|
||||
|
||||
export default () => {
|
||||
const showMessage = () => {
|
||||
@@ -117,3 +117,12 @@ export default () => {
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### App
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| message | Global config for Message | [MessageConfig](/components/message/#messageconfig) | - | 5.3.0 |
|
||||
| notification | Global config for Notification | [NotificationConfig](/components/notification/#notificationconfig) | - | 5.3.0 |
|
||||
|
||||
@@ -6,28 +6,49 @@ import { ConfigContext } from '../config-provider';
|
||||
import useMessage from '../message/useMessage';
|
||||
import useModal from '../modal/useModal';
|
||||
import useNotification from '../notification/useNotification';
|
||||
import type { useAppProps } from './context';
|
||||
import AppContext from './context';
|
||||
import type { AppConfig, useAppProps } from './context';
|
||||
import AppContext, { AppConfigContext } from './context';
|
||||
import useStyle from './style';
|
||||
|
||||
export type AppProps = {
|
||||
export interface AppProps extends AppConfig {
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
rootClassName?: string;
|
||||
prefixCls?: string;
|
||||
children?: ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
const useApp = () => React.useContext<useAppProps>(AppContext);
|
||||
|
||||
const App: React.FC<AppProps> & { useApp: () => useAppProps } = (props) => {
|
||||
const { prefixCls: customizePrefixCls, children, className, rootClassName } = props;
|
||||
const App: React.FC<AppProps> & { useApp: typeof useApp } = (props) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
children,
|
||||
className,
|
||||
rootClassName,
|
||||
message,
|
||||
notification,
|
||||
style,
|
||||
} = props;
|
||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||
const prefixCls = getPrefixCls('app', customizePrefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const customClassName = classNames(hashId, prefixCls, className, rootClassName);
|
||||
|
||||
const [messageApi, messageContextHolder] = useMessage();
|
||||
const [notificationApi, notificationContextHolder] = useNotification();
|
||||
const appConfig = useContext<AppConfig>(AppConfigContext);
|
||||
|
||||
const mergedAppConfig = React.useMemo<AppConfig>(
|
||||
() => ({
|
||||
message: { ...appConfig.message, ...message },
|
||||
notification: { ...appConfig.notification, ...notification },
|
||||
}),
|
||||
[message, notification, appConfig.message, appConfig.message],
|
||||
);
|
||||
|
||||
const [messageApi, messageContextHolder] = useMessage(mergedAppConfig.message);
|
||||
const [notificationApi, notificationContextHolder] = useNotification(
|
||||
mergedAppConfig.notification,
|
||||
);
|
||||
const [ModalApi, ModalContextHolder] = useModal();
|
||||
|
||||
const memoizedContextValue = React.useMemo<useAppProps>(
|
||||
@@ -41,12 +62,14 @@ const App: React.FC<AppProps> & { useApp: () => useAppProps } = (props) => {
|
||||
|
||||
return wrapSSR(
|
||||
<AppContext.Provider value={memoizedContextValue}>
|
||||
<div className={customClassName}>
|
||||
{ModalContextHolder}
|
||||
{messageContextHolder}
|
||||
{notificationContextHolder}
|
||||
{children}
|
||||
</div>
|
||||
<AppConfigContext.Provider value={mergedAppConfig}>
|
||||
<div className={customClassName} style={style}>
|
||||
{ModalContextHolder}
|
||||
{messageContextHolder}
|
||||
{notificationContextHolder}
|
||||
{children}
|
||||
</div>
|
||||
</AppConfigContext.Provider>
|
||||
</AppContext.Provider>,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ subtitle: 包裹组件
|
||||
group: 其他
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HJz8SZos2wgAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*oC92TK44Ex8AAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
---
|
||||
@@ -118,3 +119,12 @@ export default () => {
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### App
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 5.3.0 |
|
||||
| notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 5.3.0 |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/basic.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/basic.tsx correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
|
||||
@@ -67,7 +67,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/certain-category.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
style="width:250px"
|
||||
@@ -135,7 +135,7 @@ exports[`renders ./components/auto-complete/demo/certain-category.tsx correctly
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/custom.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/custom.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
style="width:200px"
|
||||
@@ -167,7 +167,7 @@ exports[`renders ./components/auto-complete/demo/custom.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
<form
|
||||
class="ant-form ant-form-horizontal"
|
||||
style="margin:0 auto"
|
||||
@@ -995,7 +995,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.tsx correctly 1`] =
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/non-case-sensitive.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/non-case-sensitive.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
|
||||
style="width:200px"
|
||||
@@ -1028,7 +1028,7 @@ exports[`renders ./components/auto-complete/demo/non-case-sensitive.tsx correctl
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/options.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/options.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
|
||||
style="width:200px"
|
||||
@@ -1061,7 +1061,7 @@ exports[`renders ./components/auto-complete/demo/options.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/render-panel.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/render-panel.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="display:flex"
|
||||
@@ -1128,7 +1128,7 @@ exports[`renders ./components/auto-complete/demo/render-panel.tsx correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/status.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/status.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
@@ -1201,7 +1201,7 @@ exports[`renders ./components/auto-complete/demo/status.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/uncertain-category.tsx correctly 1`] = `
|
||||
exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
style="width:300px"
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('AutoComplete children could be focus', () => {
|
||||
expect(mockRef).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('child.ref instance should support be focused and blured', () => {
|
||||
it('child.ref instance should support be focused and blurred', () => {
|
||||
const inputRef = React.createRef<HTMLInputElement>();
|
||||
render(
|
||||
<AutoComplete dataSource={[]}>
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('AutoComplete', () => {
|
||||
expect(screen.getByTitle(/reactnode/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('legacy AutoComplete.Option should be compatiable', async () => {
|
||||
it('legacy AutoComplete.Option should be compatible', async () => {
|
||||
render(
|
||||
<AutoComplete>
|
||||
<AutoComplete.Option value="111">111</AutoComplete.Option>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { AutoComplete } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const mockVal = (str: string, repeat = 1) => ({
|
||||
value: str.repeat(repeat),
|
||||
@@ -8,12 +8,10 @@ const mockVal = (str: string, repeat = 1) => ({
|
||||
const App: React.FC = () => {
|
||||
const [value, setValue] = useState('');
|
||||
const [options, setOptions] = useState<{ value: string }[]>([]);
|
||||
const [anotherOptions, setAnotherOptions] = useState<{ value: string }[]>([]);
|
||||
|
||||
const onSearch = (searchText: string) => {
|
||||
setOptions(
|
||||
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)],
|
||||
);
|
||||
};
|
||||
const getPanelValue = (searchText: string) =>
|
||||
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
|
||||
|
||||
const onSelect = (data: string) => {
|
||||
console.log('onSelect', data);
|
||||
@@ -29,17 +27,17 @@ const App: React.FC = () => {
|
||||
options={options}
|
||||
style={{ width: 200 }}
|
||||
onSelect={onSelect}
|
||||
onSearch={onSearch}
|
||||
onSearch={(text) => setOptions(getPanelValue(text))}
|
||||
placeholder="input here"
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<AutoComplete
|
||||
value={value}
|
||||
options={options}
|
||||
options={anotherOptions}
|
||||
style={{ width: 200 }}
|
||||
onSelect={onSelect}
|
||||
onSearch={onSearch}
|
||||
onSearch={(text) => setAnotherOptions(getPanelValue(text))}
|
||||
onChange={onChange}
|
||||
placeholder="control mode"
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { AutoComplete, Space } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const mockVal = (str: string, repeat = 1) => ({
|
||||
value: str.repeat(repeat),
|
||||
@@ -7,17 +7,25 @@ const mockVal = (str: string, repeat = 1) => ({
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [options, setOptions] = useState<{ value: string }[]>([]);
|
||||
const [anotherOptions, setAnotherOptions] = useState<{ value: string }[]>([]);
|
||||
|
||||
const onSearch = (searchText: string) => {
|
||||
setOptions(
|
||||
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)],
|
||||
);
|
||||
};
|
||||
const getPanelValue = (searchText: string) =>
|
||||
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
|
||||
|
||||
return (
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<AutoComplete options={options} onSearch={onSearch} status="error" style={{ width: 200 }} />
|
||||
<AutoComplete options={options} onSearch={onSearch} status="warning" style={{ width: 200 }} />
|
||||
<AutoComplete
|
||||
options={options}
|
||||
onSearch={(text) => setOptions(getPanelValue(text))}
|
||||
status="error"
|
||||
style={{ width: 200 }}
|
||||
/>
|
||||
<AutoComplete
|
||||
options={anotherOptions}
|
||||
onSearch={(text) => setAnotherOptions(getPanelValue(text))}
|
||||
status="warning"
|
||||
style={{ width: 200 }}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
category: Components
|
||||
title: AutoComplete
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*g8THS4NpV6sAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*WERTQ6qvgEYAAAAAAAAAAAAADrJ8AQ/original
|
||||
group:
|
||||
title: Data Entry
|
||||
order: 4
|
||||
|
||||
@@ -144,6 +144,7 @@ const AutoComplete: React.ForwardRefRenderFunction<RefSelectProps, AutoCompleteP
|
||||
return (
|
||||
<Select
|
||||
ref={ref}
|
||||
showArrow={false}
|
||||
{...omit(props, ['dataSource', 'dropdownClassName'])}
|
||||
prefixCls={prefixCls}
|
||||
popupClassName={popupClassName || dropdownClassName}
|
||||
|
||||
@@ -3,6 +3,7 @@ category: Components
|
||||
subtitle: 自动完成
|
||||
title: AutoComplete
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*g8THS4NpV6sAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*WERTQ6qvgEYAAAAAAAAAAAAADrJ8AQ/original
|
||||
group:
|
||||
title: 数据录入
|
||||
order: 4
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('Avatar Render', () => {
|
||||
|
||||
it('should handle onError correctly', () => {
|
||||
const LOAD_FAILURE_SRC = 'http://error.url/';
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
const Foo: React.FC = () => {
|
||||
const [avatarSrc, setAvatarSrc] = useState<typeof LOAD_FAILURE_SRC | typeof LOAD_SUCCESS_SRC>(
|
||||
LOAD_FAILURE_SRC,
|
||||
@@ -75,7 +75,7 @@ describe('Avatar Render', () => {
|
||||
|
||||
it('should show image on success after a failure state', () => {
|
||||
const LOAD_FAILURE_SRC = 'http://error.url';
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
|
||||
const div = global.document.createElement('div');
|
||||
global.document.body.appendChild(div);
|
||||
@@ -172,7 +172,7 @@ describe('Avatar Render', () => {
|
||||
});
|
||||
|
||||
it('should exist crossorigin attribute', () => {
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
const crossOrigin = 'anonymous';
|
||||
const { container } = render(
|
||||
<Avatar src={LOAD_SUCCESS_SRC} crossOrigin={crossOrigin}>
|
||||
@@ -184,7 +184,7 @@ describe('Avatar Render', () => {
|
||||
});
|
||||
|
||||
it('should not exist crossorigin attribute', () => {
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
const { container } = render(<Avatar src={LOAD_SUCCESS_SRC}>crossorigin</Avatar>);
|
||||
expect(container.querySelector('img')?.crossOrigin).toBeFalsy();
|
||||
expect(container.querySelector('img')?.crossOrigin).toEqual('');
|
||||
|
||||
@@ -140,7 +140,7 @@ exports[`Avatar Render should handle onError correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
`;
|
||||
@@ -163,7 +163,7 @@ exports[`Avatar Render should show image on success after a failure state 2`] =
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
`;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/avatar/demo/badge.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/badge.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
@@ -90,7 +90,7 @@ exports[`renders ./components/avatar/demo/badge.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/basic.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/basic.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
@@ -342,7 +342,7 @@ exports[`renders ./components/avatar/demo/basic.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/dynamic.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/dynamic.tsx correctly 1`] = `
|
||||
Array [
|
||||
<span
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle"
|
||||
@@ -376,7 +376,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/fallback.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/fallback.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
@@ -406,7 +406,7 @@ exports[`renders ./components/avatar/demo/fallback.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/group.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/group.tsx correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-avatar-group"
|
||||
@@ -415,7 +415,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
<a
|
||||
@@ -493,7 +493,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
@@ -530,7 +530,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
@@ -596,7 +596,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/responsive.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/responsive.tsx correctly 1`] = `
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
@@ -622,7 +622,7 @@ exports[`renders ./components/avatar/demo/responsive.tsx correctly 1`] = `
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/toggle-debug.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/toggle-debug.tsx correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
@@ -717,7 +717,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/type.tsx correctly 1`] = `
|
||||
exports[`renders components/avatar/demo/type.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
style="flex-wrap:wrap;margin-bottom:-16px"
|
||||
|
||||
@@ -24,7 +24,7 @@ export interface AvatarProps {
|
||||
src?: React.ReactNode;
|
||||
/** Srcset of image avatar */
|
||||
srcSet?: string;
|
||||
draggable?: boolean;
|
||||
draggable?: boolean | 'true' | 'false';
|
||||
/** Icon to be used in avatar */
|
||||
icon?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { AntDesignOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Divider, Tooltip } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<Avatar.Group>
|
||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<Avatar src="https://joesch.moe/api/v1/random?key=1" />
|
||||
<a href="https://ant.design">
|
||||
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
|
||||
</a>
|
||||
@@ -16,7 +16,7 @@ const App: React.FC = () => (
|
||||
</Avatar.Group>
|
||||
<Divider />
|
||||
<Avatar.Group maxCount={2} maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>
|
||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<Avatar src="https://joesch.moe/api/v1/random?key=2" />
|
||||
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
|
||||
<Tooltip title="Ant User" placement="top">
|
||||
<Avatar style={{ backgroundColor: '#87d068' }} icon={<UserOutlined />} />
|
||||
@@ -29,7 +29,7 @@ const App: React.FC = () => (
|
||||
size="large"
|
||||
maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf' }}
|
||||
>
|
||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<Avatar src="https://joesch.moe/api/v1/random?key=3" />
|
||||
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
|
||||
<Tooltip title="Ant User" placement="top">
|
||||
<Avatar style={{ backgroundColor: '#87d068' }} icon={<UserOutlined />} />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
category: Components
|
||||
title: Avatar
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JJBSS5lBG4IAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YbgyQaRGz-UAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
@@ -36,7 +37,7 @@ Avatars can be used to represent people or objects. It supports images, `Icon`s,
|
||||
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.7.0 |
|
||||
| src | The address of the image for an image avatar or image element | string \| ReactNode | - | ReactNode: 4.8.0 |
|
||||
| srcSet | A list of sources to use for different screen resolutions | string | - | |
|
||||
| draggable | Whether the picture is allowed to be dragged | boolean \| `'true'` \| `'false'` | - | |
|
||||
| draggable | Whether the picture is allowed to be dragged | boolean \| `'true'` \| `'false'` | true | |
|
||||
| crossOrigin | CORS settings attributes | `'anonymous'` \| `'use-credentials'` \| `''` | - | 4.17.0 |
|
||||
| onError | Handler when img load error, return false to prevent default fallback behavior | () => boolean | - | |
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ category: Components
|
||||
subtitle: 头像
|
||||
title: Avatar
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JJBSS5lBG4IAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YbgyQaRGz-UAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
@@ -41,7 +42,7 @@ group:
|
||||
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.7.0 |
|
||||
| src | 图片类头像的资源地址或者图片元素 | string \| ReactNode | - | ReactNode: 4.8.0 |
|
||||
| srcSet | 设置图片类头像响应式资源地址 | string | - | |
|
||||
| draggable | 图片是否允许拖动 | boolean \| `'true'` \| `'false'` | - | |
|
||||
| draggable | 图片是否允许拖动 | boolean \| `'true'` \| `'false'` | true | |
|
||||
| crossOrigin | CORS 属性设置 | `'anonymous'` \| `'use-credentials'` \| `''` | - | 4.17.0 |
|
||||
| onError | 图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为 | () => boolean | - | |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/back-top/demo/basic.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/back-top/demo/basic.tsx extend context correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-back-top"
|
||||
@@ -15,9 +15,9 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/back-top/demo/custom.tsx extend context correctly 1`] = `
|
||||
exports[`renders components/back-top/demo/custom.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
style="height:600vh;padding:8px"
|
||||
style="height: 600vh; padding: 8px;"
|
||||
>
|
||||
<div>
|
||||
Scroll to bottom
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/back-top/demo/basic.tsx correctly 1`] = `
|
||||
exports[`renders components/back-top/demo/basic.tsx correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-back-top"
|
||||
@@ -15,7 +15,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/back-top/demo/custom.tsx correctly 1`] = `
|
||||
exports[`renders components/back-top/demo/custom.tsx correctly 1`] = `
|
||||
<div
|
||||
style="height:600vh;padding:8px"
|
||||
>
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
|
||||
You can customize the style of the button, just note the size limit: no more than `40px * 40px`.
|
||||
|
||||
> Note: `BackTop` expects a element could accept `onClick` propety as children. If you put a text directly as children the component will not function properly.
|
||||
> Note: `BackTop` expects a element could accept `onClick` property as children. If you put a text directly as children the component will not function properly.
|
||||
|
||||
@@ -21,7 +21,7 @@ export interface ScrollNumberState {
|
||||
count?: string | number | null;
|
||||
}
|
||||
|
||||
const ScrollNumber = React.forwardRef<React.Ref<HTMLDivElement>, ScrollNumberProps>(
|
||||
const ScrollNumber = React.forwardRef<HTMLElement, ScrollNumberProps>(
|
||||
(
|
||||
{
|
||||
prefixCls: customizePrefixCls,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user