mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-30 02:59:04 +08:00
Merge pull request #40195 from ant-design/master
chore: feature merge master
This commit is contained in:
commit
92203acc33
@ -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};
|
||||
`,
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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",
|
||||
|
@ -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": "精彩推荐",
|
||||
|
@ -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',
|
||||
}}
|
||||
/>
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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: {
|
||||
|
7
.github/workflows/issue-labeled.yml
vendored
7
.github/workflows/issue-labeled.yml
vendored
@ -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'
|
||||
|
7
.github/workflows/issue-open-check.yml
vendored
7
.github/workflows/issue-open-check.yml
vendored
@ -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
|
||||
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -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
|
||||
|
@ -79,6 +79,7 @@ yarn add antd
|
||||
## 🔨 使い方
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import { Button, DatePicker } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
|
@ -79,6 +79,7 @@ yarn add antd
|
||||
## 🔨 Uso
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import { Button, DatePicker } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
|
@ -79,6 +79,7 @@ yarn add antd
|
||||
## 🔨 Uso
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import { Button, DatePicker } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
|
@ -79,6 +79,7 @@ yarn add antd
|
||||
## 🔨 Використання
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import { Button, DatePicker } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
|
@ -79,6 +79,7 @@ yarn add antd
|
||||
## 🔨 示例
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import { Button, DatePicker } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
|
@ -77,6 +77,7 @@ yarn add antd
|
||||
## 🔨 Usage
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import { Button, DatePicker } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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`]: {
|
||||
|
@ -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)',
|
||||
|
@ -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';
|
||||
|
@ -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,
|
||||
|
74
components/button/buttonHelpers.tsx
Normal file
74
components/button/buttonHelpers.tsx
Normal 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];
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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}>
|
||||
|
@ -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 {
|
||||
|
@ -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>,
|
||||
]
|
||||
`;
|
||||
|
||||
|
@ -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>,
|
||||
]
|
||||
`;
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -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';
|
||||
|
@ -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%)',
|
||||
);
|
||||
|
@ -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}`,
|
||||
|
@ -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';
|
||||
|
@ -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: '""',
|
||||
|
@ -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>}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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%)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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 文件的直接引用:
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
// ...
|
||||
|
@ -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 = {
|
||||
// ...
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>,应用场景包括:关键行动点,操作状态、重要信息高亮,图形化等场景。
|
||||
|
||||
### 功能色
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user