Merge pull request #40195 from ant-design/master

chore: feature merge master
This commit is contained in:
二货爱吃白萝卜 2023-01-13 00:01:15 +08:00 committed by GitHub
commit 92203acc33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 600 additions and 473 deletions

View File

@ -24,7 +24,7 @@ const useStyle = () => {
width: 6px;
height: 6px;
border-radius: ${token.borderRadiusSM}px;
margin-right: 4px;
margin-inline-end: 4px;
border: 1px solid ${token.colorSplit};
`,
};

View File

@ -1,8 +1,9 @@
import React, { memo, useMemo, useState } from 'react';
import React, { memo, useMemo, useRef, useState } from 'react';
import type { CSSProperties } from 'react';
import { Link, useIntl, useSidebarData, useLocation } from 'dumi';
import { css } from '@emotion/react';
import debounce from 'lodash/debounce';
import { Card, Col, Divider, Input, Row, Space, Tag, Typography } from 'antd';
import { Card, Col, Divider, Input, Row, Space, Tag, Typography, Affix } from 'antd';
import { SearchOutlined } from '@ant-design/icons';
import type { Component } from './ProComponentsList';
import proComponentsList from './ProComponentsList';
@ -10,7 +11,6 @@ import useSiteToken from '../../../hooks/useSiteToken';
const useStyle = () => {
const { token } = useSiteToken();
return {
componentsOverviewGroupTitle: css`
margin-bottom: 24px !important;
@ -33,22 +33,25 @@ const useStyle = () => {
box-shadow: 0 6px 16px -8px #00000014, 0 9px 28px #0000000d, 0 12px 48px 16px #00000008;
}
`,
componentsOverviewAffix: css`
display: flex;
transition: all 0.3s;
justify-content: space-between;
`,
componentsOverviewSearch: css`
font-size: ${token.fontSizeXL}px;
padding: 0;
.anticon-search {
color: ${token.colorTextDisabled};
}
`,
componentsOverviewContent: css`
&:empty:after {
content: 'Not Found';
text-align: center;
padding: 16px 0 40px;
display: block;
padding: 16px 0 40px;
color: ${token.colorTextDisabled};
text-align: center;
border-bottom: 1px solid ${token.colorSplit};
content: 'Not Found';
}
`,
};
@ -76,13 +79,27 @@ const { Title } = Typography;
const Overview: React.FC = () => {
const style = useStyle();
const data = useSidebarData();
const [searchBarAffixed, setSearchBarAffixed] = useState<boolean>(false);
const { token } = useSiteToken();
const { borderRadius, colorBgContainer, fontSizeXL } = token;
const affixedStyle: CSSProperties = {
boxShadow: 'rgba(50, 50, 93, 0.25) 0 6px 12px -2px, rgba(0, 0, 0, 0.3) 0 3px 7px -3px',
padding: 8,
margin: -8,
borderRadius,
backgroundColor: colorBgContainer,
};
const { search: urlSearch } = useLocation();
const { locale, formatMessage } = useIntl();
const [search, setSearch] = useState<string>('');
const sectionRef = React.useRef<HTMLElement>(null);
const sectionRef = useRef<HTMLElement>(null);
const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {
if (event.keyCode === 13 && search.trim().length) {
@ -114,23 +131,27 @@ const Overview: React.FC = () => {
]),
[data, locale],
);
return (
<section className="markdown" ref={sectionRef}>
<Divider />
<Input
value={search}
placeholder={formatMessage({ id: 'app.components.overview.search' })}
css={style.componentsOverviewSearch}
onChange={(e) => {
setSearch(e.target.value);
reportSearch(e.target.value);
}}
onKeyDown={onKeyDown}
bordered={false}
autoFocus
suffix={<SearchOutlined />}
/>
<Affix offsetTop={24} onChange={setSearchBarAffixed}>
<div css={style.componentsOverviewAffix} style={searchBarAffixed ? affixedStyle : {}}>
<Input
autoFocus
value={search}
placeholder={formatMessage({ id: 'app.components.overview.search' })}
css={style.componentsOverviewSearch}
onChange={(e) => {
setSearch(e.target.value);
reportSearch(e.target.value);
}}
onKeyDown={onKeyDown}
bordered={false}
suffix={<SearchOutlined />}
style={{ fontSize: searchBarAffixed ? fontSizeXL - 2 : fontSizeXL }}
/>
</div>
</Affix>
<Divider />
<div css={style.componentsOverviewContent}>
{groups

View File

@ -1,6 +1,10 @@
import * as React from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import type { CSSProperties } from 'react';
import Icon, * as AntdIcons from '@ant-design/icons';
import type { SegmentedProps } from 'antd';
import type { IntlShape } from 'react-intl';
import { Segmented, Input, Empty, Affix } from 'antd';
import { css } from '@emotion/react';
import { useIntl } from 'dumi';
import debounce from 'lodash/debounce';
import Category from './Category';
@ -17,6 +21,32 @@ export enum ThemeType {
const allIcons: { [key: string]: any } = AntdIcons;
const useStyle = () => ({
iconSearchAffix: css`
display: flex;
transition: all 0.3s;
justify-content: space-between;
`,
});
const options = (intl: IntlShape): SegmentedProps['options'] => [
{
value: ThemeType.Outlined,
icon: <Icon component={OutlinedIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.outlined' }),
},
{
value: ThemeType.Filled,
icon: <Icon component={FilledIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.filled' }),
},
{
value: ThemeType.TwoTone,
icon: <Icon component={TwoToneIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.two-tone' }),
},
];
interface IconSearchState {
theme: ThemeType;
searchKey: string;
@ -24,25 +54,23 @@ interface IconSearchState {
const IconSearch: React.FC = () => {
const intl = useIntl();
const [displayState, setDisplayState] = React.useState<IconSearchState>({
theme: ThemeType.Outlined,
const { iconSearchAffix } = useStyle();
const [displayState, setDisplayState] = useState<IconSearchState>({
searchKey: '',
theme: ThemeType.Outlined,
});
const newIconNames: string[] = [];
const handleSearchIcon = React.useCallback(
debounce((searchKey: string) => {
setDisplayState((prevState) => ({ ...prevState, searchKey }));
}),
[],
);
const handleSearchIcon = debounce((e: React.ChangeEvent<HTMLInputElement>) => {
setDisplayState((prevState) => ({ ...prevState, searchKey: e.target.value }));
}, 300);
const handleChangeTheme = React.useCallback((value) => {
const handleChangeTheme = useCallback((value) => {
setDisplayState((prevState) => ({ ...prevState, theme: value as ThemeType }));
}, []);
const renderCategories = React.useMemo<React.ReactNode | React.ReactNode[]>(() => {
const renderCategories = useMemo<React.ReactNode | React.ReactNode[]>(() => {
const { searchKey = '', theme } = displayState;
const categoriesResult = Object.keys(categories)
@ -77,62 +105,38 @@ const IconSearch: React.FC = () => {
newIcons={newIconNames}
/>
));
return categoriesResult.length === 0 ? <Empty style={{ margin: '2em 0' }} /> : categoriesResult;
return categoriesResult.length ? categoriesResult : <Empty style={{ margin: '2em 0' }} />;
}, [displayState.searchKey, displayState.theme]);
const [searchBarAffixed, setSearchBarAffixed] = React.useState(false);
const [searchBarAffixed, setSearchBarAffixed] = useState<boolean>(false);
const { token } = useSiteToken();
const { borderRadius, colorBgContainer } = token;
const affixedStyle = searchBarAffixed
? {
boxShadow: 'rgba(50, 50, 93, 0.25) 0px 6px 12px -2px, rgba(0, 0, 0, 0.3) 0px 3px 7px -3px',
padding: 8,
margin: -8,
borderRadius,
background: colorBgContainer,
}
: {};
const affixedStyle: CSSProperties = {
boxShadow: 'rgba(50, 50, 93, 0.25) 0 6px 12px -2px, rgba(0, 0, 0, 0.3) 0 3px 7px -3px',
padding: 8,
margin: -8,
borderRadius,
backgroundColor: colorBgContainer,
};
return (
<div className="markdown">
<Affix offsetTop={24} onChange={(affixed) => setSearchBarAffixed(affixed)}>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
transition: 'all .3s',
...affixedStyle,
}}
>
<Affix offsetTop={24} onChange={setSearchBarAffixed}>
<div css={iconSearchAffix} style={searchBarAffixed ? affixedStyle : {}}>
<Segmented
value={displayState.theme}
onChange={handleChangeTheme}
size="large"
options={[
{
icon: <Icon component={OutlinedIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.outlined' }),
value: ThemeType.Outlined,
},
{
icon: <Icon component={FilledIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.filled' }),
value: ThemeType.Filled,
},
{
icon: <Icon component={TwoToneIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.two-tone' }),
value: ThemeType.TwoTone,
},
]}
value={displayState.theme}
options={options(intl)}
onChange={handleChangeTheme}
/>
<Input.Search
placeholder={intl.formatMessage({ id: 'app.docs.components.icon.search.placeholder' })}
style={{ flex: 1, marginInlineStart: 16 }}
allowClear
onChange={(e) => handleSearchIcon(e.currentTarget.value)}
size="large"
autoFocus
size="large"
onChange={handleSearchIcon}
/>
</div>
</Affix>

View File

@ -1,4 +1,9 @@
import { CheckOutlined, SnippetsOutlined, ThunderboltOutlined } from '@ant-design/icons';
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';
@ -78,9 +83,12 @@ const Demo: React.FC<DemoProps> = (props) => {
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 isDev = process.env.NODE_ENV === 'development';
const docsOnlineUrl = `https://ant.design${pathname}${search}#${meta.id}`;
const handleCodeExpand = (demo: string) => {
setCodeExpand(!codeExpand);
track({ type: 'expand', demo });
@ -99,7 +107,7 @@ const Demo: React.FC<DemoProps> = (props) => {
};
useEffect(() => {
if (meta.id === location.hash.slice(1)) {
if (meta.id === hash.slice(1)) {
anchorRef.current?.click();
}
}, []);
@ -334,6 +342,18 @@ const Demo: React.FC<DemoProps> = (props) => {
</div>
<div className="code-box-description">{introChildren}</div>
<Space wrap size="middle" className="code-box-actions">
{isDev && (
<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"

View File

@ -1,7 +1,9 @@
import React from 'react';
import { Col, Row } from 'antd';
import { Col, Row, Tooltip } from 'antd';
import { css } from '@emotion/react';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import useSiteToken from '../../../hooks/useSiteToken';
import useLocale from '../../../hooks/useLocale';
const useStyle = () => {
const { token } = useSiteToken();
@ -42,6 +44,8 @@ const useStyle = () => {
background: rgba(0, 0, 0, 0.65);
border-radius: 1px;
box-shadow: 0 0 2px rgba(255, 255, 255, 0.2);
display: inline-flex;
column-gap: 4px;
`,
title: css`
margin: 16px 20px 8px;
@ -66,12 +70,26 @@ export type Resource = {
official?: boolean;
};
const locales = {
cn: {
official: '官方',
thirdPart: '非官方',
thirdPartDesc: '非官方产品,请自行确认可用性',
},
en: {
official: 'Official',
thirdPart: 'Third Part',
thirdPartDesc: 'Unofficial product, please take care confirm availability',
},
};
export type ResourceCardProps = {
resource: Resource;
};
const ResourceCard: React.FC<ResourceCardProps> = ({ resource }) => {
const styles = useStyle();
const [locale] = useLocale(locales);
const { title: titleStr, description, cover, src, official } = resource;
@ -93,7 +111,16 @@ const ResourceCard: React.FC<ResourceCardProps> = ({ resource }) => {
alt={title}
style={coverColor ? { backgroundColor: coverColor } : {}}
/>
{official && <div css={styles.badge}>Official</div>}
{official ? (
<div css={styles.badge}>{locale.official}</div>
) : (
<Tooltip title={locale.thirdPartDesc}>
<div css={styles.badge}>
<ExclamationCircleOutlined />
{locale.thirdPart}
</div>
</Tooltip>
)}
<p css={styles?.title}>{title}</p>
<p css={styles.description}>{description}</p>
</a>

View File

@ -32,6 +32,7 @@
"app.demo.stackblitz": "Open in Stackblitz",
"app.demo.riddle": "Open in Riddle",
"app.demo.separate": "Open in a new window",
"app.demo.online": "Online Address",
"app.home.introduce": "A design system for enterprise-level products. Create an efficient and enjoyable work experience.",
"app.home.pr-welcome": "💡 It is an alpha version and still in progress. Contribution from community is welcome!",
"app.home.recommend": "Recommended",

View File

@ -32,6 +32,7 @@
"app.demo.stackblitz": "在 Stackblitz 中打开",
"app.demo.riddle": "在 Riddle 中打开",
"app.demo.separate": "在新窗口打开",
"app.demo.online": "线上地址",
"app.home.introduce": "企业级产品设计体系,创造高效愉悦的工作体验",
"app.home.pr-welcome": "💡 当前为 alpha 版本,仍在开发中。欢迎社区一起共建,让 Ant Design 变得更好!",
"app.home.recommend": "精彩推荐",

View File

@ -61,15 +61,15 @@ export function getEcosystemGroup(): Exclude<MenuProps['items'], undefined> {
}
export default (props: SharedProps) => {
const downstyle = props.isRTL ? '-1px 2px 0 0' : '-1px 0 0 2px';
const downStyle = props.isRTL ? '-1px 2px 0 0' : '-1px 0 0 2px';
return (
<Dropdown menu={{ items: getEcosystemGroup() }} placement="bottomRight">
<Button size="small" className="header-button">
<Button size="small">
<FormattedMessage id="app.header.menu.more" />
<DownOutlined
style={{
fontSize: '9px',
margin: downstyle,
margin: downStyle,
verticalAlign: 'middle',
}}
/>

View File

@ -20,8 +20,6 @@ import SwitchBtn from './SwitchBtn';
const RESPONSIVE_XS = 1120;
const RESPONSIVE_SM = 1200;
const { Option } = Select;
const antdVersion: string = packageJson.version;
const useStyle = () => {
@ -244,14 +242,12 @@ const Header: React.FC = () => {
[antdVersion]: antdVersion,
...themeConfig?.docVersions,
};
const versionOptions = Object.keys(docVersions).map((version) => (
<Option value={docVersions[version]} key={version}>
{version}
</Option>
));
const versionOptions = Object.keys(docVersions).map((version) => ({
value: docVersions[version],
label: version,
}));
const isHome = ['', 'index', 'index-cn'].includes(pathname);
const isZhCN = lang === 'cn';
const isRTL = direction === 'rtl';
let responsive: null | 'narrow' | 'crowded' = null;
@ -284,7 +280,7 @@ const Header: React.FC = () => {
/>
);
let menu: React.ReactNode[] = [
let menu = [
navigationNode,
<Select
key="version"
@ -295,9 +291,8 @@ const Header: React.FC = () => {
dropdownStyle={getDropdownStyle}
dropdownMatchSelectWidth={false}
getPopupContainer={(trigger) => trigger.parentNode}
>
{versionOptions}
</Select>,
options={versionOptions}
/>,
<More key="more" {...sharedProps} />,
<SwitchBtn
key="lang"

View File

@ -1,6 +1,6 @@
import React, { useContext } from 'react';
import { useSidebarData } from 'dumi';
import { Affix, Col, ConfigProvider, Menu } from 'antd';
import { Col, ConfigProvider, Menu } from 'antd';
import MobileMenu from 'rc-drawer';
import { css } from '@emotion/react';
import SiteContext from '../SiteContext';
@ -107,6 +107,9 @@ const useStyle = () => {
z-index: 1;
.main-menu-inner {
position: sticky;
top: 0;
width: 100%;
height: 100%;
max-height: 100vh;
overflow: hidden;
@ -115,11 +118,6 @@ const useStyle = () => {
&:hover .main-menu-inner {
overflow-y: auto;
}
> div,
> div > div {
height: 100%;
}
`,
};
};
@ -153,11 +151,7 @@ const Sidebar: React.FC = () => {
<MobileMenu key="Mobile-menu">{menuChild}</MobileMenu>
) : (
<Col xxl={4} xl={5} lg={6} md={6} sm={24} xs={24} css={styles.mainMenu}>
<Affix>
<section style={{ width: '100%' }} className="main-menu-inner">
{menuChild}
</section>
</Affix>
<section className="main-menu-inner">{menuChild}</section>
</Col>
);
};

View File

@ -10,6 +10,7 @@ export default defineConfig({
},
ssr: process.env.NODE_ENV === 'production' ? {} : false,
hash: true,
crossorigin: {},
outputPath: '_site',
favicons: ['https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png'],
resolve: {

View File

@ -79,10 +79,3 @@ jobs:
Hello @${{ github.event.issue.user.login }}, your issue has been closed because it does not conform to our issue requirements. Please use the [Issue Helper](http://new-issue.ant.design) to create an issue, thank you!
你好 @${{ github.event.issue.user.login }},为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为不符合要求而被自动关闭。你可以通过 [issue 助手](http://new-issue.ant.design) 来创建 issue 以方便我们定位错误。谢谢配合!
- name: rtl
if: github.event.label.name == 'rtl'
uses: actions-cool/issues-helper@v3
with:
actions: 'add-assignees'
assignees: 'xrkffgg'

View File

@ -21,6 +21,13 @@ jobs:
require: 'write'
check-bot: true
- name: add unconfirmed label
uses: actions-cool/issues-helper@v3
with:
actions: 'add-labels'
issue-number: ${{ github.event.issue.number }}
labels: 'unconfirmed'
- name: check invalid
if: (contains(github.event.issue.body, 'ant-design-issue-helper') == false) && (steps.checkUser.outputs.require-result == 'false')
uses: actions-cool/issues-helper@v3

View File

@ -171,12 +171,12 @@ jobs:
if: ${{ matrix.module == 'dist' }}
run: node ./tests/dekko/dist.test.js
# 17 only
- name: bundlesize
if: ${{ matrix.module == 'dist' && matrix.react == '17' }}
if: ${{ matrix.module == 'dist' && matrix.react == '18' }}
run: npm run bundlesize
env:
BUNDLESIZE_GITHUB_TOKEN: ${{ secrets.BUNDLESIZE_GITHUB_TOKEN }}
INTERNAL_SKIP_CACHE: true
# dom test
- name: dom test

View File

@ -79,6 +79,7 @@ yarn add antd
## 🔨 使い方
```jsx
import React from 'react';
import { Button, DatePicker } from 'antd';
const App = () => (

View File

@ -79,6 +79,7 @@ yarn add antd
## 🔨 Uso
```jsx
import React from 'react';
import { Button, DatePicker } from 'antd';
const App = () => (

View File

@ -79,6 +79,7 @@ yarn add antd
## 🔨 Uso
```jsx
import React from 'react';
import { Button, DatePicker } from 'antd';
const App = () => (

View File

@ -79,6 +79,7 @@ yarn add antd
## 🔨 Використання
```jsx
import React from 'react';
import { Button, DatePicker } from 'antd';
const App = () => (

View File

@ -79,6 +79,7 @@ yarn add antd
## 🔨 示例
```jsx
import React from 'react';
import { Button, DatePicker } from 'antd';
const App = () => (

View File

@ -77,6 +77,7 @@ yarn add antd
## 🔨 Usage
```jsx
import React from 'react';
import { Button, DatePicker } from 'antd';
const App = () => (

View File

@ -46,9 +46,12 @@ const WaveEffect: React.FC<WaveEffectProps> = (props) => {
// Get wave color from target
setWaveColor(getTargetWaveColor(target));
const isStatic = nodeStyle.position === 'static';
// Rect
setLeft(target.offsetLeft);
setTop(target.offsetTop);
const { borderLeftWidth, borderTopWidth } = nodeStyle;
setLeft(isStatic ? target.offsetLeft : -parseFloat(borderLeftWidth));
setTop(isStatic ? target.offsetTop : -parseFloat(borderTopWidth));
setWidth(target.offsetWidth);
setHeight(target.offsetHeight);
@ -128,7 +131,7 @@ export default function showWaveEffect(node: HTMLElement, className: string) {
holder.style.position = 'absolute';
holder.style.left = `0px`;
holder.style.top = `0px`;
node.parentElement?.appendChild(holder);
node?.insertBefore(holder, node?.firstChild);
render(<WaveEffect target={node} className={className} />, holder);
}

View File

@ -253,7 +253,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
},
[`${numberPrefixCls}`]: {
overflow: 'hidden',
direction: 'ltr',
[`${numberPrefixCls}-only`]: {
position: 'relative',
display: 'inline-block',
@ -276,7 +275,7 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
direction: 'rtl',
[`${componentCls}-count, ${componentCls}-dot, ${numberPrefixCls}-custom-component`]: {
insetInlineEnd: 'auto',
transform: 'translate(-50%, -50%)',
},
},
},

View File

@ -52,8 +52,12 @@ const genBreadcrumbStyle: GenerateStyle<BreadcrumbToken, CSSObject> = (token) =>
...genFocusStyle(token),
},
[`li:last-child > ${componentCls}-separator`]: {
display: 'none',
[`li:last-child`]: {
color: token.breadcrumbLastItemColor,
[`& > ${componentCls}-separator`]: {
display: 'none',
},
},
[`${componentCls}-separator`]: {

View File

@ -7,8 +7,14 @@ export interface LoadingIconProps {
existIcon: boolean;
loading?: boolean | object;
}
const getCollapsedWidth = () => ({ width: 0, opacity: 0, transform: 'scale(0)' });
const getRealWidth = (node: HTMLElement) => ({
const getCollapsedWidth = (): React.CSSProperties => ({
width: 0,
opacity: 0,
transform: 'scale(0)',
});
const getRealWidth = (node: HTMLElement): React.CSSProperties => ({
width: node.scrollWidth,
opacity: 1,
transform: 'scale(1)',

View File

@ -21,12 +21,10 @@ const ButtonGroup: React.FC<ButtonGroupProps> = (props) => {
const { prefixCls: customizePrefixCls, size, className, ...others } = props;
const prefixCls = getPrefixCls('btn-group', customizePrefixCls);
// Here we only need hashId
const [, , hashId] = useToken();
// large => lg
// small => sm
let sizeCls = '';
switch (size) {
case 'large':
sizeCls = 'lg';

View File

@ -2,90 +2,22 @@
import classNames from 'classnames';
import omit from 'rc-util/lib/omit';
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import { useCompactItemContext } from '../space/Compact';
import { cloneElement, isFragment } from '../_util/reactNode';
import warning from '../_util/warning';
import Wave from '../_util/wave';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import SizeContext from '../config-provider/SizeContext';
import { useCompactItemContext } from '../space/Compact';
import Group, { GroupSizeContext } from './button-group';
import { isTwoCNChar, isUnBorderedButtonType, spaceChildren } from './buttonHelpers';
import LoadingIcon from './LoadingIcon';
// CSSINJS
import useStyle from './style';
const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/;
const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar);
function isString(str: any) {
return typeof str === 'string';
}
function isUnBorderedButtonType(type: ButtonType | undefined) {
return type === 'text' || type === 'link';
}
// Insert one space between two chinese characters automatically.
function insertSpace(child: React.ReactElement | string | number, needInserted: boolean) {
// Check the child if is undefined or null.
if (child === null || child === undefined) {
return;
}
const SPACE = needInserted ? ' ' : '';
// strictNullChecks oops.
if (
typeof child !== 'string' &&
typeof child !== 'number' &&
isString(child.type) &&
isTwoCNChar(child.props.children)
) {
return cloneElement(child, {
children: child.props.children.split('').join(SPACE),
});
}
if (typeof child === 'string') {
return isTwoCNChar(child) ? <span>{child.split('').join(SPACE)}</span> : <span>{child}</span>;
}
if (isFragment(child)) {
return <span>{child}</span>;
}
return child;
}
function spaceChildren(children: React.ReactNode, needInserted: boolean) {
let isPrevChildPure: boolean = false;
const childList: React.ReactNode[] = [];
React.Children.forEach(children, (child) => {
const type = typeof child;
const isCurrentChildPure = type === 'string' || type === 'number';
if (isPrevChildPure && isCurrentChildPure) {
const lastIndex = childList.length - 1;
const lastChild = childList[lastIndex];
childList[lastIndex] = `${lastChild}${child}`;
} else {
childList.push(child);
}
isPrevChildPure = isCurrentChildPure;
});
// Pass to React.Children.map to auto fill key
return React.Children.map(childList, (child) =>
insertSpace(child as React.ReactElement | string | number, needInserted),
);
}
const ButtonTypes = ['default', 'primary', 'ghost', 'dashed', 'link', 'text'] as const;
export type ButtonType = typeof ButtonTypes[number];
const ButtonShapes = ['default', 'circle', 'round'] as const;
export type ButtonShape = typeof ButtonShapes[number];
const ButtonHTMLTypes = ['submit', 'button', 'reset'] as const;
export type ButtonHTMLType = typeof ButtonHTMLTypes[number];
import type { ButtonType, ButtonHTMLType, ButtonShape } from './buttonHelpers';
import type { SizeType } from '../config-provider/SizeContext';
export type LegacyButtonType = ButtonType | 'danger';
export function convertLegacyProps(type?: LegacyButtonType): ButtonProps {
if (type === 'danger') {
return { danger: true };
@ -96,11 +28,6 @@ export function convertLegacyProps(type?: LegacyButtonType): ButtonProps {
export interface BaseButtonProps {
type?: ButtonType;
icon?: React.ReactNode;
/**
* Shape of Button
*
* @default default
*/
shape?: ButtonShape;
size?: SizeType;
disabled?: boolean;
@ -113,21 +40,18 @@ export interface BaseButtonProps {
children?: React.ReactNode;
}
// Typescript will make optional not optional if use Pick with union.
// Should change to `AnchorButtonProps | NativeButtonProps` and `any` to `HTMLAnchorElement | HTMLButtonElement` if it fixed.
// ref: https://github.com/ant-design/ant-design/issues/15930
export type AnchorButtonProps = {
href: string;
target?: string;
onClick?: React.MouseEventHandler<HTMLAnchorElement>;
} & BaseButtonProps &
Omit<React.AnchorHTMLAttributes<any>, 'type' | 'onClick'>;
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement | HTMLButtonElement>, 'type' | 'onClick'>;
export type NativeButtonProps = {
htmlType?: ButtonHTMLType;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
} & BaseButtonProps &
Omit<React.ButtonHTMLAttributes<any>, 'type' | 'onClick'>;
Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type' | 'onClick'>;
export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>;
@ -158,7 +82,6 @@ const InternalButton: React.ForwardRefRenderFunction<
icon,
ghost = false,
block = false,
/** If we extract items here, we don't need use omit.js */
// React does not recognize the `htmlType` prop on a DOM element. Here we pick it out of `rest`.
htmlType = 'button',
...rest
@ -167,11 +90,9 @@ const InternalButton: React.ForwardRefRenderFunction<
const { getPrefixCls, autoInsertSpaceInButton, direction } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('btn', customizePrefixCls);
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
const size = React.useContext(SizeContext);
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
@ -179,11 +100,12 @@ const InternalButton: React.ForwardRefRenderFunction<
const [innerLoading, setLoading] = React.useState<Loading>(!!loading);
const [hasTwoCNChar, setHasTwoCNChar] = React.useState(false);
const buttonRef = (ref as any) || React.createRef<HTMLAnchorElement | HTMLButtonElement>();
const isNeedInserted = () =>
React.Children.count(children) === 1 && !icon && !isUnBorderedButtonType(type);
const fixTwoCNChar = () => {
// Fix for HOC usage like <FormatMessage />
// FIXME: for HOC usage like <FormatMessage />
if (!buttonRef || !buttonRef.current || autoInsertSpaceInButton === false) {
return;
}
@ -197,7 +119,6 @@ const InternalButton: React.ForwardRefRenderFunction<
}
};
// =============== Update Loading ===============
const loadingOrDelay: Loading = typeof loading === 'boolean' ? loading : loading?.delay || true;
React.useEffect(() => {
@ -212,21 +133,21 @@ const InternalButton: React.ForwardRefRenderFunction<
setLoading(loadingOrDelay);
}
return () => {
function cleanupTimer() {
if (delayTimer) {
// in order to not perform a React state update on an unmounted component
// and clear timer after 'loadingOrDelay' updated.
window.clearTimeout(delayTimer);
delayTimer = null;
}
};
}
return cleanupTimer;
}, [loadingOrDelay]);
React.useEffect(fixTwoCNChar, [buttonRef]);
const handleClick = (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => {
const { onClick } = props;
// https://github.com/ant-design/ant-design/issues/30207
// FIXME: https://github.com/ant-design/ant-design/issues/30207
if (innerLoading || mergedDisabled) {
e.preventDefault();
return;
@ -263,7 +184,7 @@ const InternalButton: React.ForwardRefRenderFunction<
prefixCls,
hashId,
{
[`${prefixCls}-${shape}`]: shape !== 'default' && shape, // Note: Shape also has `default`
[`${prefixCls}-${shape}`]: shape !== 'default' && shape,
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-${sizeCls}`]: sizeCls,
[`${prefixCls}-icon-only`]: !children && children !== 0 && !!iconType,

View File

@ -0,0 +1,74 @@
import React from 'react';
import { cloneElement, isFragment } from '../_util/reactNode';
const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/;
export const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar);
export function isString(str: any) {
return typeof str === 'string';
}
export function isUnBorderedButtonType(type: ButtonType | undefined) {
return type === 'text' || type === 'link';
}
function splitCNCharsBySpace(child: React.ReactElement | string | number, needInserted: boolean) {
if (child === null || child === undefined) {
return;
}
const SPACE = needInserted ? ' ' : '';
if (
typeof child !== 'string' &&
typeof child !== 'number' &&
isString(child.type) &&
isTwoCNChar(child.props.children)
) {
return cloneElement(child, {
children: child.props.children.split('').join(SPACE),
});
}
if (typeof child === 'string') {
return isTwoCNChar(child) ? <span>{child.split('').join(SPACE)}</span> : <span>{child}</span>;
}
if (isFragment(child)) {
return <span>{child}</span>;
}
return child;
}
export function spaceChildren(children: React.ReactNode, needInserted: boolean) {
let isPrevChildPure: boolean = false;
const childList: React.ReactNode[] = [];
React.Children.forEach(children, (child) => {
const type = typeof child;
const isCurrentChildPure = type === 'string' || type === 'number';
if (isPrevChildPure && isCurrentChildPure) {
const lastIndex = childList.length - 1;
const lastChild = childList[lastIndex];
childList[lastIndex] = `${lastChild}${child}`;
} else {
childList.push(child);
}
isPrevChildPure = isCurrentChildPure;
});
return React.Children.map(childList, (child) =>
splitCNCharsBySpace(child as React.ReactElement | string | number, needInserted),
);
}
const ButtonTypes = ['default', 'primary', 'ghost', 'dashed', 'link', 'text'] as const;
export type ButtonType = typeof ButtonTypes[number];
const ButtonShapes = ['default', 'circle', 'round'] as const;
export type ButtonShape = typeof ButtonShapes[number];
const ButtonHTMLTypes = ['submit', 'button', 'reset'] as const;
export type ButtonHTMLType = typeof ButtonHTMLTypes[number];

View File

@ -1,7 +1,9 @@
import Button from './button';
export type { SizeType as ButtonSize } from '../config-provider/SizeContext';
export type { ButtonProps, ButtonShape, ButtonType } from './button';
export type { ButtonProps } from './button';
export type { ButtonGroupProps } from './button-group';
export * from './buttonHelpers';
export default Button;

View File

@ -589,10 +589,12 @@ exports[`renders ./components/collapse/demo/collapsible.tsx extend context corre
exports[`renders ./components/collapse/demo/custom.tsx extend context correctly 1`] = `
<div
class="ant-collapse ant-collapse-icon-position-start ant-collapse-borderless site-collapse-custom-collapse"
class="ant-collapse ant-collapse-icon-position-start ant-collapse-borderless"
style="background:#ffffff"
>
<div
class="ant-collapse-item ant-collapse-item-active site-collapse-custom-panel"
class="ant-collapse-item ant-collapse-item-active"
style="margin-bottom:24px;background:rgba(0, 0, 0, 0.02);border-radius:8px;border:none"
>
<div
aria-disabled="false"
@ -646,7 +648,8 @@ exports[`renders ./components/collapse/demo/custom.tsx extend context correctly
</div>
</div>
<div
class="ant-collapse-item site-collapse-custom-panel"
class="ant-collapse-item"
style="margin-bottom:24px;background:rgba(0, 0, 0, 0.02);border-radius:8px;border:none"
>
<div
aria-disabled="false"
@ -686,7 +689,8 @@ exports[`renders ./components/collapse/demo/custom.tsx extend context correctly
</div>
</div>
<div
class="ant-collapse-item site-collapse-custom-panel"
class="ant-collapse-item"
style="margin-bottom:24px;background:rgba(0, 0, 0, 0.02);border-radius:8px;border:none"
>
<div
aria-disabled="false"

View File

@ -589,10 +589,12 @@ exports[`renders ./components/collapse/demo/collapsible.tsx correctly 1`] = `
exports[`renders ./components/collapse/demo/custom.tsx correctly 1`] = `
<div
class="ant-collapse ant-collapse-icon-position-start ant-collapse-borderless site-collapse-custom-collapse"
class="ant-collapse ant-collapse-icon-position-start ant-collapse-borderless"
style="background:#ffffff"
>
<div
class="ant-collapse-item ant-collapse-item-active site-collapse-custom-panel"
class="ant-collapse-item ant-collapse-item-active"
style="margin-bottom:24px;background:rgba(0, 0, 0, 0.02);border-radius:8px;border:none"
>
<div
aria-disabled="false"
@ -646,7 +648,8 @@ exports[`renders ./components/collapse/demo/custom.tsx correctly 1`] = `
</div>
</div>
<div
class="ant-collapse-item site-collapse-custom-panel"
class="ant-collapse-item"
style="margin-bottom:24px;background:rgba(0, 0, 0, 0.02);border-radius:8px;border:none"
>
<div
aria-disabled="false"
@ -686,7 +689,8 @@ exports[`renders ./components/collapse/demo/custom.tsx correctly 1`] = `
</div>
</div>
<div
class="ant-collapse-item site-collapse-custom-panel"
class="ant-collapse-item"
style="margin-bottom:24px;background:rgba(0, 0, 0, 0.02);border-radius:8px;border:none"
>
<div
aria-disabled="false"

View File

@ -5,21 +5,3 @@
## en-US
Customize the background, border, margin styles and icon for each panel.
```css
[data-theme='compact'] .site-collapse-custom-collapse .site-collapse-custom-panel,
.site-collapse-custom-collapse .site-collapse-custom-panel {
margin-bottom: 24px;
overflow: hidden;
background: #f7f7f7;
border: 0px !important;
border-radius: 2px;
}
```
<style>
[data-theme="dark"] .site-collapse-custom-collapse .site-collapse-custom-panel {
background: rgba(255,255,255,0.04);
border: 0px;
}
</style>

View File

@ -1,6 +1,6 @@
import React from 'react';
import { CaretRightOutlined } from '@ant-design/icons';
import { Collapse } from 'antd';
import { Collapse, theme } from 'antd';
const { Panel } = Collapse;
@ -10,23 +10,34 @@ const text = `
it can be found as a welcome guest in many households across the world.
`;
const App: React.FC = () => (
<Collapse
bordered={false}
defaultActiveKey={['1']}
expandIcon={({ isActive }) => <CaretRightOutlined rotate={isActive ? 90 : 0} />}
className="site-collapse-custom-collapse"
>
<Panel header="This is panel header 1" key="1" className="site-collapse-custom-panel">
<p>{text}</p>
</Panel>
<Panel header="This is panel header 2" key="2" className="site-collapse-custom-panel">
<p>{text}</p>
</Panel>
<Panel header="This is panel header 3" key="3" className="site-collapse-custom-panel">
<p>{text}</p>
</Panel>
</Collapse>
);
const App: React.FC = () => {
const { token } = theme.useToken();
const panelStyle = {
marginBottom: 24,
background: token.colorFillAlter,
borderRadius: token.borderRadiusLG,
border: 'none',
};
return (
<Collapse
bordered={false}
defaultActiveKey={['1']}
expandIcon={({ isActive }) => <CaretRightOutlined rotate={isActive ? 90 : 0} />}
style={{ background: token.colorBgContainer }}
>
<Panel header="This is panel header 1" key="1" style={panelStyle}>
<p>{text}</p>
</Panel>
<Panel header="This is panel header 2" key="2" style={panelStyle}>
<p>{text}</p>
</Panel>
<Panel header="This is panel header 3" key="3" style={panelStyle}>
<p>{text}</p>
</Panel>
</Collapse>
);
};
export default App;

View File

@ -2902,7 +2902,7 @@ Array [
exports[`renders ./components/drawer/demo/render-in-current.tsx extend context correctly 1`] = `
<div
class="site-drawer-render-in-current-wrapper"
style="position:relative;height:200px;padding:48px;overflow:hidden;text-align:center;background:rgba(0, 0, 0, 0.02);border:1px solid #f0f0f0;border-radius:8px"
>
Render in this
<div

View File

@ -296,7 +296,7 @@ exports[`renders ./components/drawer/demo/placement.tsx correctly 1`] = `
exports[`renders ./components/drawer/demo/render-in-current.tsx correctly 1`] = `
<div
class="site-drawer-render-in-current-wrapper"
style="position:relative;height:200px;padding:48px;overflow:hidden;text-align:center;background:rgba(0, 0, 0, 0.02);border:1px solid #f0f0f0;border-radius:8px"
>
Render in this
<div

View File

@ -9,23 +9,3 @@
Render in current dom. custom container, check `getContainer`.
> Note: `style` and `className` props are moved to Drawer panel in v5 which is aligned with Modal component. Original `style` and `className` props are replaced by `rootStyle` and `rootClassName`.
```css
.site-drawer-render-in-current-wrapper {
position: relative;
height: 200px;
padding: 48px;
overflow: hidden;
text-align: center;
background: #fafafa;
border: 1px solid #ebedf0;
border-radius: 2px;
}
```
<style>
[data-theme="dark"] .site-drawer-render-in-current-wrapper {
background: #000;
border: 1px solid #303030;
}
</style>

View File

@ -1,7 +1,8 @@
import React, { useState } from 'react';
import { Button, Drawer } from 'antd';
import { Button, Drawer, theme } from 'antd';
const App: React.FC = () => {
const { token } = theme.useToken();
const [open, setOpen] = useState(false);
const showDrawer = () => {
@ -12,8 +13,19 @@ const App: React.FC = () => {
setOpen(false);
};
const containerStyle: React.CSSProperties = {
position: 'relative',
height: 200,
padding: 48,
overflow: 'hidden',
textAlign: 'center',
background: token.colorFillAlter,
border: `1px solid ${token.colorBorderSecondary}`,
borderRadius: token.borderRadiusLG,
};
return (
<div className="site-drawer-render-in-current-wrapper">
<div style={containerStyle}>
Render in this
<div style={{ marginTop: 16 }}>
<Button type="primary" onClick={showDrawer}>

View File

@ -1,17 +1,17 @@
import EllipsisOutlined from '@ant-design/icons/EllipsisOutlined';
import classNames from 'classnames';
import * as React from 'react';
import type { ButtonProps } from '../button';
import EllipsisOutlined from '@ant-design/icons/EllipsisOutlined';
import Button from '../button';
import type { ButtonHTMLType } from '../button/button';
import type { ButtonGroupProps } from '../button/button-group';
import { ConfigContext } from '../config-provider';
import { useCompactItemContext } from '../space/Compact';
import type { DropdownProps } from './dropdown';
import Dropdown from './dropdown';
import Space from '../space';
import { useCompactItemContext } from '../space/Compact';
import Dropdown from './dropdown';
import useStyle from './style';
import type { ButtonProps, ButtonHTMLType } from '../button';
import type { ButtonGroupProps } from '../button/button-group';
import type { DropdownProps } from './dropdown';
export type DropdownButtonType = 'default' | 'primary' | 'ghost' | 'dashed' | 'link' | 'text';
export interface DropdownButtonProps extends ButtonGroupProps, DropdownProps {

View File

@ -3,8 +3,9 @@
exports[`renders ./components/form/demo/advanced-search.tsx extend context correctly 1`] = `
<div>
<form
class="ant-form ant-form-horizontal ant-advanced-search-form"
class="ant-form ant-form-horizontal"
id="advanced_search"
style="max-width:none;background:rgba(0, 0, 0, 0.02);border-radius:8px;padding:24px"
>
<div
class="ant-row"
@ -599,7 +600,7 @@ exports[`renders ./components/form/demo/advanced-search.tsx extend context corre
</div>
</form>
<div
class="search-result-list"
style="line-height:200px;text-align:center;background:rgba(0, 0, 0, 0.02);border-radius:8px;margin-top:16px"
>
Search Result List
</div>
@ -6752,10 +6753,14 @@ Array [
</div>
</div>
</form>,
<pre
class="language-bash"
<div
class="ant-typography"
style="max-width:440px;margin-top:24px"
>
[
<pre
style="border:none"
>
[
{
"name": [
"username"
@ -6763,7 +6768,8 @@ Array [
"value": "Ant Design"
}
]
</pre>,
</pre>
</div>,
]
`;

View File

@ -3,8 +3,9 @@
exports[`renders ./components/form/demo/advanced-search.tsx correctly 1`] = `
<div>
<form
class="ant-form ant-form-horizontal ant-advanced-search-form"
class="ant-form ant-form-horizontal"
id="advanced_search"
style="max-width:none;background:rgba(0, 0, 0, 0.02);border-radius:8px;padding:24px"
>
<div
class="ant-row"
@ -435,7 +436,7 @@ exports[`renders ./components/form/demo/advanced-search.tsx correctly 1`] = `
</div>
</form>
<div
class="search-result-list"
style="line-height:200px;text-align:center;background:rgba(0, 0, 0, 0.02);border-radius:8px;margin-top:16px"
>
Search Result List
</div>
@ -4143,10 +4144,14 @@ Array [
</div>
</div>
</form>,
<pre
class="language-bash"
<div
class="ant-typography"
style="max-width:440px;margin-top:24px"
>
[
<pre
style="border:none"
>
[
{
"name": [
"username"
@ -4154,7 +4159,8 @@ Array [
"value": "Ant Design"
}
]
</pre>,
</pre>
</div>,
]
`;

View File

@ -11,48 +11,3 @@
Three columns layout is often used for advanced searching of data table.
Because the width of label is not fixed, you may need to adjust it by customizing its style.
```css
[data-theme='compact'] .ant-advanced-search-form,
.ant-advanced-search-form {
padding: 24px !important;
background: #fbfbfb;
border: 1px solid #d9d9d9;
border-radius: 2px;
}
[data-theme='compact'] .ant-advanced-search-form .ant-form-item,
.ant-advanced-search-form .ant-form-item {
display: flex;
}
[data-theme='compact'] .ant-advanced-search-form .ant-form-item-control-wrapper,
.ant-advanced-search-form .ant-form-item-control-wrapper {
flex: 1;
}
```
<style>
#components-form-demo-advanced-search .ant-form {
max-width: none;
}
#components-form-demo-advanced-search .search-result-list {
margin-top: 16px;
border: 1px dashed #e9e9e9;
border-radius: 2px;
background-color: #fafafa;
min-height: 200px;
text-align: center;
padding-top: 80px;
}
[data-theme="dark"] .ant-advanced-search-form {
background: rgba(255,255,255,0.04);
border: 1px solid #434343;
padding: 24px;
border-radius: 2px;
}
[data-theme="dark"] #components-form-demo-advanced-search .search-result-list {
border: 1px dashed #434343;
background: rgba(255,255,255,0.04);
}
</style>

View File

@ -1,12 +1,20 @@
import React, { useState } from 'react';
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import { Button, Col, Form, Input, Row, Select } from 'antd';
import { Button, Col, Form, Input, Row, Select, theme } from 'antd';
const { Option } = Select;
const AdvancedSearchForm = () => {
const [expand, setExpand] = useState(false);
const { token } = theme.useToken();
const [form] = Form.useForm();
const [expand, setExpand] = useState(false);
const formStyle = {
maxWidth: 'none',
background: token.colorFillAlter,
borderRadius: token.borderRadiusLG,
padding: 24,
};
const getFields = () => {
const count = expand ? 10 : 6;
@ -46,12 +54,7 @@ const AdvancedSearchForm = () => {
};
return (
<Form
form={form}
name="advanced_search"
className="ant-advanced-search-form"
onFinish={onFinish}
>
<Form form={form} name="advanced_search" style={formStyle} onFinish={onFinish}>
<Row gutter={24}>{getFields()}</Row>
<Row>
<Col span={24} style={{ textAlign: 'right' }}>
@ -80,11 +83,23 @@ const AdvancedSearchForm = () => {
);
};
const App: React.FC = () => (
<div>
<AdvancedSearchForm />
<div className="search-result-list">Search Result List</div>
</div>
);
const App: React.FC = () => {
const { token } = theme.useToken();
const listStyle: React.CSSProperties = {
lineHeight: '200px',
textAlign: 'center',
background: token.colorFillAlter,
borderRadius: token.borderRadiusLG,
marginTop: 16,
};
return (
<div>
<AdvancedSearchForm />
<div style={listStyle}>Search Result List</div>
</div>
);
};
export default App;

View File

@ -9,11 +9,3 @@
We can store form data into upper component or [Redux](https://github.com/reactjs/redux) or [dva](https://github.com/dvajs/dva) by using `onFieldsChange` and `fields`, see more at this [rc-field-form demo](https://rc-field-form.react-component.now.sh/?selectedKind=rc-field-form&selectedStory=StateForm-redux&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel).
**Note:** Save Form data globally [is not a good practice](https://github.com/reduxjs/redux/issues/1287#issuecomment-175351978). You should avoid this if not necessary.
<style>
#components-form-demo-global-state .language-bash {
max-width: 400px;
border-radius: 6px;
margin-top: 24px;
}
</style>

View File

@ -1,5 +1,7 @@
import React, { useState } from 'react';
import { Form, Input } from 'antd';
import { Form, Input, Typography } from 'antd';
const { Paragraph } = Typography;
interface FieldData {
name: string | number | (string | number)[];
@ -44,7 +46,9 @@ const App: React.FC = () => {
setFields(newFields);
}}
/>
<pre className="language-bash">{JSON.stringify(fields, null, 2)}</pre>
<Paragraph style={{ maxWidth: 440, marginTop: 24 }}>
<pre style={{ border: 'none' }}>{JSON.stringify(fields, null, 2)}</pre>
</Paragraph>
</>
);
};

View File

@ -3,8 +3,8 @@ import DoubleRightOutlined from '@ant-design/icons/DoubleRightOutlined';
import LeftOutlined from '@ant-design/icons/LeftOutlined';
import RightOutlined from '@ant-design/icons/RightOutlined';
import classNames from 'classnames';
import type { PaginationProps as RcPaginationProps } from 'rc-pagination';
import RcPagination, { type PaginationLocale } from 'rc-pagination';
import type { PaginationProps as RcPaginationProps, PaginationLocale } from 'rc-pagination';
import RcPagination from 'rc-pagination';
import enUS from 'rc-pagination/lib/locale/en_US';
import * as React from 'react';
import { ConfigContext } from '../config-provider';

View File

@ -139,7 +139,7 @@ describe('Progress', () => {
expect(handleGradient({ from: 'test', to: 'test' }).backgroundImage).toBe(
'linear-gradient(to right, test, test)',
);
expect(handleGradient({}).backgroundImage).toBe('linear-gradient(to right, #1890FF, #1890FF)');
expect(handleGradient({}).backgroundImage).toBe('linear-gradient(to right, #1677FF, #1677FF)');
expect(handleGradient({ from: 'test', to: 'test', '0%': 'test' }).backgroundImage).toBe(
'linear-gradient(to right, test 0%)',
);

View File

@ -17,7 +17,7 @@ interface SegmentedToken extends FullToken<'Segmented'> {
}
// ============================== Mixins ==============================
function segmentedDisabledItem(cls: string, token: SegmentedToken): CSSObject {
function getItemDisabledStyle(cls: string, token: SegmentedToken): CSSObject {
return {
[`${cls}, ${cls}:hover, ${cls}:focus`]: {
color: token.colorTextDisabled,
@ -26,7 +26,7 @@ function segmentedDisabledItem(cls: string, token: SegmentedToken): CSSObject {
};
}
function getSegmentedItemSelectedStyle(token: SegmentedToken): CSSObject {
function getItemSelectedStyle(token: SegmentedToken): CSSObject {
return {
backgroundColor: token.bgColorSelected,
boxShadow: token.boxShadow,
@ -86,7 +86,7 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
borderRadius: token.borderRadiusSM,
'&-selected': {
...getSegmentedItemSelectedStyle(token),
...getItemSelectedStyle(token),
color: token.labelColorHover,
},
@ -97,7 +97,7 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
height: '100%',
top: 0,
insetInlineStart: 0,
borderRadius: token.borderRadiusSM,
borderRadius: 'inherit',
transition: `background-color ${token.motionDurationMid}`,
},
@ -132,39 +132,9 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
},
},
// size styles
'&&-lg': {
borderRadius: token.borderRadiusLG,
[`${componentCls}-item-label`]: {
minHeight: token.controlHeightLG - token.segmentedContainerPadding * 2,
lineHeight: `${token.controlHeightLG - token.segmentedContainerPadding * 2}px`,
padding: `0 ${token.segmentedPaddingHorizontal}px`,
fontSize: token.fontSizeLG,
},
[`${componentCls}-item-selected`]: {
borderRadius: token.borderRadius,
},
},
'&&-sm': {
borderRadius: token.borderRadiusSM,
[`${componentCls}-item-label`]: {
minHeight: token.controlHeightSM - token.segmentedContainerPadding * 2,
lineHeight: `${token.controlHeightSM - token.segmentedContainerPadding * 2}px`,
padding: `0 ${token.segmentedPaddingHorizontalSM}px`,
},
[`${componentCls}-item-selected`]: {
borderRadius: token.borderRadiusXS,
},
},
// disabled styles
...segmentedDisabledItem(`&-disabled ${componentCls}-item`, token),
...segmentedDisabledItem(`${componentCls}-item-disabled`, token),
// thumb styles
[`${componentCls}-thumb`]: {
...getSegmentedItemSelectedStyle(token),
...getItemSelectedStyle(token),
position: 'absolute',
insetBlockStart: 0,
@ -180,6 +150,36 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
},
},
// size styles
'&&-lg': {
borderRadius: token.borderRadiusLG,
[`${componentCls}-item-label`]: {
minHeight: token.controlHeightLG - token.segmentedContainerPadding * 2,
lineHeight: `${token.controlHeightLG - token.segmentedContainerPadding * 2}px`,
padding: `0 ${token.segmentedPaddingHorizontal}px`,
fontSize: token.fontSizeLG,
},
[`${componentCls}-item, ${componentCls}-thumb`]: {
borderRadius: token.borderRadius,
},
},
'&&-sm': {
borderRadius: token.borderRadiusSM,
[`${componentCls}-item-label`]: {
minHeight: token.controlHeightSM - token.segmentedContainerPadding * 2,
lineHeight: `${token.controlHeightSM - token.segmentedContainerPadding * 2}px`,
padding: `0 ${token.segmentedPaddingHorizontalSM}px`,
},
[`${componentCls}-item, ${componentCls}-thumb`]: {
borderRadius: token.borderRadiusXS,
},
},
// disabled styles
...getItemDisabledStyle(`&-disabled ${componentCls}-item`, token),
...getItemDisabledStyle(`${componentCls}-item-disabled`, token),
// transition effect when `appear-active`
[`${componentCls}-thumb-motion-appear-active`]: {
transition: `transform ${token.motionDurationSlow} ${token.motionEaseInOut}, width ${token.motionDurationSlow} ${token.motionEaseInOut}`,

View File

@ -1,8 +1,7 @@
// TODO: 4.0 - codemod should help to change `filterOption` to support node props.
import classNames from 'classnames';
import type { SelectProps as RcSelectProps } from 'rc-select';
import RcSelect, { type BaseSelectRef, OptGroup, Option } from 'rc-select';
import RcSelect, { OptGroup, Option } from 'rc-select';
import type { SelectProps as RcSelectProps, BaseSelectRef } from 'rc-select';
import type { OptionProps } from 'rc-select/lib/Option';
import type { BaseOptionType, DefaultOptionType } from 'rc-select/lib/Select';
import omit from 'rc-util/lib/omit';

View File

@ -3,8 +3,15 @@ import type { GenerateStyle } from '../../theme/internal';
import type { TableToken } from './index';
const genFixedStyle: GenerateStyle<TableToken, CSSObject> = (token) => {
const { componentCls, lineWidth, colorSplit, motionDurationSlow, zIndexTableFixed, tableBg } =
token;
const {
componentCls,
lineWidth,
colorSplit,
motionDurationSlow,
zIndexTableFixed,
tableBg,
zIndexTableSticky,
} = token;
const shadowColor = colorSplit;
@ -65,7 +72,7 @@ const genFixedStyle: GenerateStyle<TableToken, CSSObject> = (token) => {
position: 'absolute',
top: 0,
bottom: 0,
zIndex: zIndexTableFixed,
zIndex: zIndexTableSticky + 1,
width: 30,
transition: `box-shadow ${motionDurationSlow}`,
content: '""',

View File

@ -1,11 +1,14 @@
import classNames from 'classnames';
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import type { LiteralUnion } from '../_util/type';
type Color = 'blue' | 'red' | 'green' | 'gray';
export interface TimelineItemProps {
prefixCls?: string;
className?: string;
color?: string;
color?: LiteralUnion<Color>;
dot?: React.ReactNode;
pending?: boolean;
position?: string;
@ -42,14 +45,14 @@ const TimelineItem: React.FC<TimelineItemProps> = ({
className,
);
const customColor = /blue|red|green|gray/.test(color || '') ? undefined : color;
const dotClassName = classNames({
[`${prefixCls}-item-head`]: true,
[`${prefixCls}-item-head-custom`]: !!dot,
[`${prefixCls}-item-head-${color}`]: true,
[`${prefixCls}-item-head-${color}`]: !customColor,
});
const customColor = /blue|red|green|gray/.test(color || '') ? undefined : color;
return (
<li {...restProps} className={itemClassName}>
{label && <div className={`${prefixCls}-item-label`}>{label}</div>}

View File

@ -345,7 +345,7 @@ exports[`renders ./components/timeline/demo/color.tsx extend context correctly 1
class="ant-timeline-item-tail"
/>
<div
class="ant-timeline-item-head ant-timeline-item-head-custom ant-timeline-item-head-#00CCFF"
class="ant-timeline-item-head ant-timeline-item-head-custom"
style="border-color:#00CCFF;color:#00CCFF"
>
<span

View File

@ -345,7 +345,7 @@ exports[`renders ./components/timeline/demo/color.tsx correctly 1`] = `
class="ant-timeline-item-tail"
/>
<div
class="ant-timeline-item-head ant-timeline-item-head-custom ant-timeline-item-head-#00CCFF"
class="ant-timeline-item-head ant-timeline-item-head-custom"
style="border-color:#00CCFF;color:#00CCFF"
>
<span

View File

@ -141,4 +141,40 @@ describe('TimeLine', () => {
expect(container.querySelectorAll('.ant-timeline-label')).toHaveLength(1);
expect(container.querySelector('.ant-timeline-item-label')).toHaveTextContent(label);
});
describe('prop: color', () => {
const presetColors = ['blue', 'red', 'green', 'gray'];
presetColors.forEach((color) => {
it(`className should have a preset color ${color}`, () => {
const { container } = render(
<TimeLine>
<Item color={color}>foo</Item>
</TimeLine>,
);
expect(container.querySelector('.ant-timeline-item-head')).toHaveClass(
`ant-timeline-item-head-${color}`,
);
});
});
// other non-preset colors
const nonPresetColors = ['rgb(255, 0, 0)', 'rgba(255, 0, 0, 0.5)', '#ff0000', '#f00'].filter(
(color) => !presetColors.includes(color),
);
// https://github.com/ant-design/ant-design/issues/39386
nonPresetColors.forEach((color) => {
it(`className should not have a non-preset color ${color}`, () => {
const { container } = render(
<TimeLine>
<Item color={color}>foo</Item>
</TimeLine>,
);
expect(container.querySelector('.ant-timeline-item-head')).not.toHaveClass(
`ant-timeline-item-head-${color}`,
);
});
});
});
});

View File

@ -154,7 +154,9 @@ const genTimelineStyle: GenerateStyle<TimelineToken, CSSObject> = (token) => {
[`${componentCls}-item-tail,
${componentCls}-item-head,
${componentCls}-item-head-custom`]: {
insetInlineStart: `calc(100% - ${token.timeLinePaddingInlineEnd}px)`,
insetInlineStart: `calc(100% - ${
(token.timeLineItemHeadSize + token.timeLineItemTailWidth) / 2
}px)`,
},
[`${componentCls}-item-content`]: {
@ -207,6 +209,15 @@ const genTimelineStyle: GenerateStyle<TimelineToken, CSSObject> = (token) => {
},
},
},
// ====================== RTL =======================
'&-rtl': {
direction: 'rtl',
[`${componentCls}-item-head-custom`]: {
transform: `translate(50%, -50%)`,
},
},
},
};
};

View File

@ -203,14 +203,15 @@ const mapToken = defaultAlgorithm(defaultSeed);
const v4Token = convertLegacyToken(mapToken);
// Webpack Config
{
loader: "less-loader",
module.exports = {
// ... other config
loader: 'less-loader',
options: {
lessOptions: {
modifyVars: v4Token,
},
},
}
};
```
Ant then remove antd less reference in your less file:

View File

@ -195,14 +195,15 @@ const mapToken = defaultAlgorithm(defaultSeed);
const v4Token = convertLegacyToken(mapToken);
// Webpack Config
{
loader: "less-loader",
module.exports = {
// ... other config
loader: 'less-loader',
options: {
lessOptions: {
modifyVars: v4Token,
},
},
}
};
```
同时移除对 antd less 文件的直接引用:

View File

@ -69,6 +69,7 @@ Let's create a `ProductList` component that we can use in multiple places to sho
Create `src/components/ProductList.tsx` by typing:
```tsx
import React from 'react';
import { Table, Popconfirm, Button } from 'antd';
const ProductList: React.FC<{ products: { name: string }[]; onDelete: (id: string) => void }> = ({
@ -82,7 +83,7 @@ const ProductList: React.FC<{ products: { name: string }[]; onDelete: (id: strin
},
{
title: 'Actions',
render: (text, record) => {
render(text, record) {
return (
<Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
<Button>Delete</Button>
@ -112,8 +113,8 @@ export function queryProductList() {
}
*/
// mock request service by setTimeout
export function queryProductList() {
return new Promise(resolve => {
export default function queryProductList() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: [
@ -129,6 +130,7 @@ export function queryProductList() {
Then you need to create a new file `src/models/useProductList.ts`.
```tsx
import { message } from 'antd';
import { useRequest } from 'umi';
import { queryProductList } from '@/services/product';
@ -157,6 +159,7 @@ export default function useProductList(params: { pageSize: number; current: numb
Edit `src/pages/products.tsx` and replace with the following:
```tsx
import React from 'react';
import { useModel } from 'umi';
import ProductList from '@/components/ProductList';
@ -164,7 +167,7 @@ const Products = () => {
const { dataSource, reload, deleteProducts } = useModel('useProductList');
return (
<div>
<a onClick={() => reload()}>reload</a>
<a onClick={reload}>reload</a>
<ProductList onDelete={deleteProducts} products={dataSource} />
</div>
);
@ -188,6 +191,7 @@ And supports three modes of `side`, `mix`, and `top`, and it also has built-in m
The method of use is also extremely simple, requiring only a few simple settings.
```tsx
import React from 'react';
import { Button } from 'antd';
import ProLayout, { PageContainer } from '@ant-design/pro-layout';
@ -201,7 +205,12 @@ export default (
Main Operating
</Button>,
]}
footer={[<Button>reset</Button>, <Button type="primary">submit</Button>]}
footer={[
<Button key={1}>reset</Button>,
<Button key={2} type="primary">
submit
</Button>,
]}
>
{children}
</PageContainer>
@ -216,8 +225,9 @@ Click here [Quick Start](https://procomponents.ant.design/en-US/components/layou
Many data in an admin page does not need to be shared across pages, and models are sometimes not needed.
```tsx
import React, { useRef } from 'react';
import ProTable from '@ant-design/pro-table';
import { Popconfirm, Button } from 'antd';
import { Popconfirm, Button, message } from 'antd';
import { queryProductList } from '@/services/product';
const Products = () => {
@ -240,7 +250,7 @@ const Products = () => {
},
{
title: 'Actions',
render: (text, record) => {
render(text, record) {
return (
<Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
<Button>Delete</Button>

View File

@ -63,6 +63,7 @@ export default defineConfig({
然后新建 `src/components/ProductList.tsx` 文件:
```tsx
import React from 'react';
import { Table, Popconfirm, Button } from 'antd';
const ProductList: React.FC<{ products: { name: string }[]; onDelete: (id: string) => void }> = ({
@ -76,7 +77,7 @@ const ProductList: React.FC<{ products: { name: string }[]; onDelete: (id: strin
},
{
title: 'Actions',
render: (text, record) => {
render(text, record) {
return (
<Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
<Button>Delete</Button>
@ -106,8 +107,8 @@ export function queryProductList() {
}
*/
// 先用 setTimeout 模拟一个请求,正常的写法如上所示
export function queryProductList() {
return new Promise(resolve => {
export default function queryProductList() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: [
@ -123,6 +124,7 @@ export function queryProductList() {
然后新建文件 `src/models/useProductList.ts`
```tsx
import { message } from 'antd';
import { useRequest } from 'umi';
import { queryProductList } from '@/services/product';
@ -151,6 +153,7 @@ export default function useProductList(params: { pageSize: number; current: numb
编辑 `src/pages/products.tsx`,替换为以下内容:
```tsx
import React from 'react';
import { useModel } from 'umi';
import ProductList from '@/components/ProductList';
@ -158,7 +161,7 @@ const Products = () => {
const { dataSource, reload, deleteProducts } = useModel('useProductList');
return (
<div>
<a onClick={() => reload()}>reload</a>
<a onClick={reload}>reload</a>
<ProductList onDelete={deleteProducts} products={dataSource} />
</div>
);
@ -188,6 +191,7 @@ $ yarn start
使用方式也是极为简单,只需要进行几个简单的设置。
```tsx
import React from 'react';
import { Button } from 'antd';
import ProLayout, { PageContainer } from '@ant-design/pro-layout';
@ -201,7 +205,12 @@ export default (
Main Operating
</Button>,
]}
footer={[<Button>reset</Button>, <Button type="primary">submit</Button>]}
footer={[
<Button key={1}>reset</Button>,
<Button key={2} type="primary">
submit
</Button>,
]}
>
{children}
</PageContainer>
@ -216,8 +225,9 @@ export default (
一个中后台页面中很多数据都不需要跨页面共享models 在一些时候也是不需要的。
```tsx
import React, { useRef } from 'react';
import ProTable from '@ant-design/pro-table';
import { Popconfirm, Button } from 'antd';
import { Popconfirm, Button, message } from 'antd';
import { queryProductList } from '@/services/product';
const Products = () => {
@ -240,7 +250,7 @@ const Products = () => {
},
{
title: 'Actions',
render: (text, record) => {
render(text, record) {
return (
<Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
<Button>Delete</Button>

View File

@ -58,7 +58,6 @@ There are some products to recommend for developer/designer/product manager.
.markdown table td:first-child {
width: 20%;
font-weight: 500;
background: #fcfcfc;
}
.markdown table td > a:not(:last-child) {
margin-right: 18px;

View File

@ -13,7 +13,7 @@ title: 社区精选组件
| 路由 | [react-router](https://github.com/ReactTraining/react-router) |
| 布局 | [react-grid-layout](https://github.com/react-grid-layout/react-grid-layout) [react-grid-system](https://github.com/sealninja/react-grid-system) [rc-dock](https://github.com/ticlo/rc-dock) |
| 拖拽 | [dnd-kit](https://github.com/clauderic/dnd-kit) [react-beautiful-dnd](https://github.com/atlassian/react-beautiful-dnd/) [react-dnd](https://github.com/gaearon/react-dnd) |
| 代码编辑器 | [@uiw/react-codemirror](https://github.com/uiwjs/react-codemirror) [react-monaco-editor]([https://github.com/superRaytin/react-monaco-editor](https://github.com/react-monaco-editor/react-monaco-editor)) |
| 代码编辑器 | [@uiw/react-codemirror](https://github.com/uiwjs/react-codemirror) [react-monaco-editor](https://github.com/react-monaco-editor/react-monaco-editor) |
| 富文本编辑器 | [react-quill](https://github.com/zenoamaro/react-quill) |
| JSON 编辑器 | [vanilla-jsoneditor](https://github.com/josdejong/svelte-jsoneditor) |
| JSON 显示器 | [react-json-view](https://github.com/mac-s-g/react-json-view) |
@ -59,7 +59,6 @@ title: 社区精选组件
.markdown table td:first-child {
width: 20%;
font-weight: 500;
background: #fcfcfc;
}
.markdown table td > a:not(:last-child) {
margin-right: 18px;

View File

@ -98,7 +98,7 @@ We also provide another implementation, which we provide with `@ant-design/momen
```js
// webpack-config.js
import AntdMomentWebpackPlugin from '@ant-design/moment-webpack-plugin';
const AntdMomentWebpackPlugin = require('@ant-design/moment-webpack-plugin');
module.exports = {
// ...

View File

@ -18,7 +18,7 @@ Ant Design 默认使用 [Day.js](https://day.js.org) 来处理时间日期问题
编写如下代码:
```tsx
import { Moment } from 'moment';
import type { Moment } from 'moment';
import momentGenerateConfig from 'rc-picker/es/generate/moment';
import generatePicker from 'antd/es/date-picker/generatePicker';
@ -34,16 +34,16 @@ export default DatePicker;
编写如下代码:
```tsx
import { Moment } from 'moment';
import type { Moment } from 'moment';
import * as React from 'react';
import type { PickerTimeProps } from 'antd/es/date-picker/generatePicker';
import DatePicker from './DatePicker';
import { PickerTimeProps } from 'antd/es/date-picker/generatePicker';
export interface TimePickerProps extends Omit<PickerTimeProps<Moment>, 'picker'> {}
const TimePicker = React.forwardRef<any, TimePickerProps>((props, ref) => {
return <DatePicker {...props} picker="time" mode={undefined} ref={ref} />;
});
const TimePicker = React.forwardRef<any, TimePickerProps>((props, ref) => (
<DatePicker {...props} picker="time" mode={undefined} ref={ref} />
));
TimePicker.displayName = 'TimePicker';
@ -57,7 +57,7 @@ export default TimePicker;
编写如下代码:
```tsx
import { Moment } from 'moment';
import type { Moment } from 'moment';
import momentGenerateConfig from 'rc-picker/es/generate/moment';
import generateCalendar from 'antd/es/calendar/generateCalendar';
@ -96,7 +96,7 @@ export { default as TimePicker } from './TimePicker';
```js
// webpack-config.js
import AntdMomentWebpackPlugin from '@ant-design/moment-webpack-plugin';
const AntdMomentWebpackPlugin = require('@ant-design/moment-webpack-plugin');
module.exports = {
// ...

View File

@ -43,7 +43,8 @@ $ yarn add antd
Modify `src/App.tsx`, import Button component from `antd`.
```tsx
import React, { FC } from 'react';
import React from 'react';
import type { FC } from 'react';
import { Button } from 'antd';
import 'antd/dist/reset.css';
import './App.css';

View File

@ -43,7 +43,8 @@ $ yarn add antd
修改 `src/App.tsx`,引入 antd 的按钮组件。
```tsx
import React, { FC } from 'react';
import React from 'react';
import type { FC } from 'react';
import { Button } from 'antd';
import 'antd/dist/reset.css';
import './App.css';

View File

@ -70,7 +70,7 @@ We provide JavaScript usage for developers.
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1c74TKxuEW4AAAAAAAAAAABkARQnAQ">
</ImagePreview>
The brand color is one of the most intuitive visual elements used that is used to embody product characteristics and communicate ideas. When selecting colors, it is important to understand how the brand color is used in the user interface. In the basic color palette to choose the main color, we recommend choosing the color plate from the shallow depth of the sixth color as the main color. Ant Design's brand color comes from blue of the base color palette, it's Hex value is 1890FF, application scenarios include: key action point, the operation status, important information highlighting, graphics and other scenes.
The brand color is one of the most intuitive visual elements used that is used to embody product characteristics and communicate ideas. When selecting colors, it is important to understand how the brand color is used in the user interface. In the basic color palette to choose the main color, we recommend choosing the color plate from the shallow depth of the sixth color as the main color. Ant Design's brand color comes from blue of the base color palette, it's Hex value is <ColorChunk color="#1890ff" /></ColorChunk>, application scenarios include: key action point, the operation status, important information highlighting, graphics and other scenes.
### Functional Color

View File

@ -78,7 +78,7 @@ Ant Design 的色板还具备进一步拓展的能力。经过设计师和程序
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1c74TKxuEW4AAAAAAAAAAABkARQnAQ">
</ImagePreview>
品牌色是体现产品特性和传播理念最直观的视觉元素之一。在色彩选取时,需要先明确品牌色在界面中的使用场景及范围。在基础色板中选择主色,我们建议选择色板从浅至深的第六个颜色作为主色。 Ant Design 的品牌色取自基础色板的蓝色Hex 值为 `#1890FF`,应用场景包括:关键行动点,操作状态、重要信息高亮,图形化等场景。
品牌色是体现产品特性和传播理念最直观的视觉元素之一。在色彩选取时,需要先明确品牌色在界面中的使用场景及范围。在基础色板中选择主色,我们建议选择色板从浅至深的第六个颜色作为主色。 Ant Design 的品牌色取自基础色板的蓝色Hex 值为 <ColorChunk color="#1890ff" /></ColorChunk>,应用场景包括:关键行动点,操作状态、重要信息高亮,图形化等场景。
### 功能色

View File

@ -107,9 +107,9 @@
"not dead"
],
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/colors": "^7.0.0",
"@ant-design/cssinjs": "^1.4.0",
"@ant-design/icons": "^4.7.0",
"@ant-design/icons": "^5.0.0",
"@ant-design/react-slick": "~1.0.0",
"@babel/runtime": "^7.18.3",
"@ctrl/tinycolor": "^3.4.0",
@ -149,7 +149,7 @@
"rc-tooltip": "~5.2.0",
"rc-tree": "~5.7.0",
"rc-tree-select": "~5.6.0",
"rc-trigger": "^5.2.10",
"rc-trigger": "^5.3.4",
"rc-upload": "~4.3.0",
"rc-util": "^5.27.0",
"scroll-into-view-if-needed": "^3.0.3",

View File

@ -28,6 +28,7 @@ const DEPRECIATED_VERSION = {
'5.1.0': ['https://github.com/react-component/drawer/pull/370'],
'5.1.2': ['https://github.com/ant-design/ant-design/issues/39949'],
'5.1.3': ['https://github.com/ant-design/ant-design/issues/40113'],
'5.1.4': ['https://github.com/ant-design/ant-design/issues/40186'],
};
function matchDeprecated(version) {