mirror of
https://github.com/ant-design/ant-design.git
synced 2025-08-06 16:06:28 +08:00
commit
59c9119be1
@ -2,6 +2,7 @@ import type { ReactNode } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { useFullSidebarData, useSidebarData } from 'dumi';
|
||||
import { Tag, theme } from 'antd';
|
||||
import useLocation from './useLocation';
|
||||
import Link from '../theme/common/Link';
|
||||
|
||||
@ -15,6 +16,7 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
const { pathname, search } = useLocation();
|
||||
const sidebarData = useSidebarData();
|
||||
const { before, after } = options;
|
||||
const { token } = theme.useToken();
|
||||
|
||||
const menuItems = useMemo<MenuProps['items']>(() => {
|
||||
const sidebarItems = [...(sidebarData ?? [])];
|
||||
@ -108,6 +110,11 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
<span className="chinese" key="chinese">
|
||||
{(item.frontmatter as any).subtitle}
|
||||
</span>
|
||||
{(item.frontmatter as any).tag && (
|
||||
<Tag color="warning" style={{ marginLeft: token.marginXS }}>
|
||||
{(item.frontmatter as any).tag}
|
||||
</Tag>
|
||||
)}
|
||||
{after}
|
||||
</Link>
|
||||
),
|
||||
|
50
.dumi/theme/builtins/InlinePopover/index.tsx
Normal file
50
.dumi/theme/builtins/InlinePopover/index.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import { PictureOutlined } from '@ant-design/icons';
|
||||
import { Image, Tooltip, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
tip: '预览',
|
||||
},
|
||||
en: {
|
||||
tip: 'Preview',
|
||||
},
|
||||
};
|
||||
|
||||
export interface InlinePopoverProps {
|
||||
previewURL?: string;
|
||||
}
|
||||
|
||||
// 鼠标悬浮弹出 Popover 组件,用于帮助用户更快看到一些属性对应的预览效果
|
||||
const InlinePopover: React.FC = (props: InlinePopoverProps) => {
|
||||
const { previewURL } = props;
|
||||
|
||||
const [locale] = useLocale(locales);
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={locale.tip}>
|
||||
<Typography.Link onClick={() => setVisible(true)}>
|
||||
<PictureOutlined />
|
||||
</Typography.Link>
|
||||
</Tooltip>
|
||||
|
||||
<Image
|
||||
width={10}
|
||||
style={{ display: 'none' }}
|
||||
src={previewURL}
|
||||
preview={{
|
||||
visible,
|
||||
src: previewURL,
|
||||
onVisibleChange: (value) => {
|
||||
setVisible(value);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InlinePopover;
|
@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import { FloatButton } from 'antd';
|
||||
import { FormattedMessage, Link, useLocation } from 'dumi';
|
||||
import { DarkTheme, CompactTheme } from 'antd-token-previewer/es/icons';
|
||||
import { BgColorsOutlined } from '@ant-design/icons';
|
||||
import { FloatButton } from 'antd';
|
||||
import { CompactTheme, DarkTheme, Motion } from 'antd-token-previewer/es/icons';
|
||||
import { FormattedMessage, Link, useLocation } from 'dumi';
|
||||
import React from 'react';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import { getLocalizedPathname, isZhCN } from '../../utils';
|
||||
import ThemeIcon from './ThemeIcon';
|
||||
|
||||
export type ThemeName = 'light' | 'dark' | 'compact';
|
||||
export type ThemeName = 'light' | 'dark' | 'compact' | 'motion-off';
|
||||
|
||||
export type ThemeSwitchProps = {
|
||||
value?: ThemeName[];
|
||||
@ -18,6 +18,9 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = (props: ThemeSwitchProps) => {
|
||||
const { value = ['light'], onChange } = props;
|
||||
const { token } = useSiteToken();
|
||||
const { pathname, search } = useLocation();
|
||||
|
||||
const isMotionOff = value.includes('motion-off');
|
||||
|
||||
return (
|
||||
<FloatButton.Group trigger="click" icon={<ThemeIcon />}>
|
||||
<Link
|
||||
@ -53,6 +56,22 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = (props: ThemeSwitchProps) => {
|
||||
}}
|
||||
tooltip={<FormattedMessage id="app.theme.switch.compact" />}
|
||||
/>
|
||||
<FloatButton
|
||||
icon={<Motion />}
|
||||
type={!isMotionOff ? 'primary' : 'default'}
|
||||
onClick={() => {
|
||||
if (isMotionOff) {
|
||||
onChange(value.filter((theme) => theme !== 'motion-off'));
|
||||
} else {
|
||||
onChange([...value, 'motion-off']);
|
||||
}
|
||||
}}
|
||||
tooltip={
|
||||
<FormattedMessage
|
||||
id={isMotionOff ? 'app.theme.switch.motion.off' : 'app.theme.switch.motion.on'}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</FloatButton.Group>
|
||||
);
|
||||
};
|
||||
|
@ -9,13 +9,13 @@ import { App, theme as antdTheme } from 'antd';
|
||||
import type { DirectionType } from 'antd/es/config-provider';
|
||||
import { createSearchParams, useOutlet, useSearchParams } from 'dumi';
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import useLayoutState from '../../hooks/useLayoutState';
|
||||
import SiteThemeProvider from '../SiteThemeProvider';
|
||||
import useLocation from '../../hooks/useLocation';
|
||||
import type { ThemeName } from '../common/ThemeSwitch';
|
||||
import ThemeSwitch from '../common/ThemeSwitch';
|
||||
import type { SiteContextProps } from '../slots/SiteContext';
|
||||
import SiteContext from '../slots/SiteContext';
|
||||
import useLayoutState from '../../hooks/useLayoutState';
|
||||
|
||||
type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
|
||||
type SiteState = Partial<Omit<SiteContextProps, 'updateSiteContext'>>;
|
||||
@ -42,10 +42,10 @@ const GlobalLayout: React.FC = () => {
|
||||
const outlet = useOutlet();
|
||||
const { pathname } = useLocation();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [{ theme, direction, isMobile }, setSiteState] = useLayoutState<SiteState>({
|
||||
const [{ theme = [], direction, isMobile }, setSiteState] = useLayoutState<SiteState>({
|
||||
isMobile: false,
|
||||
direction: 'ltr',
|
||||
theme: ['light'],
|
||||
theme: ['light', 'motion-off'],
|
||||
});
|
||||
|
||||
const updateSiteConfig = useCallback(
|
||||
@ -116,6 +116,9 @@ const GlobalLayout: React.FC = () => {
|
||||
<SiteThemeProvider
|
||||
theme={{
|
||||
algorithm: getAlgorithm(theme),
|
||||
token: {
|
||||
motion: !theme.includes('motion-off'),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<App>
|
||||
|
@ -3,6 +3,8 @@
|
||||
"app.theme.switch.default": "Default theme",
|
||||
"app.theme.switch.dark": "Dark theme",
|
||||
"app.theme.switch.compact": "Compact theme",
|
||||
"app.theme.switch.motion.on": "Motion On",
|
||||
"app.theme.switch.motion.off": "Motion Off",
|
||||
"app.header.search": "Search...",
|
||||
"app.header.menu.documentation": "Docs",
|
||||
"app.header.menu.more": "More",
|
||||
|
@ -3,6 +3,8 @@
|
||||
"app.theme.switch.default": "默认主题",
|
||||
"app.theme.switch.dark": "暗黑主题",
|
||||
"app.theme.switch.compact": "紧凑主题",
|
||||
"app.theme.switch.motion.on": "动画开启",
|
||||
"app.theme.switch.motion.off": "动画关闭",
|
||||
"app.header.search": "全文本搜索...",
|
||||
"app.header.menu.documentation": "文档",
|
||||
"app.header.menu.more": "更多",
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -64,3 +64,5 @@ __image_snapshots__/
|
||||
|
||||
.devcontainer*
|
||||
.husky/prepare-commit-msg
|
||||
|
||||
.eslintcache
|
||||
|
@ -19,6 +19,7 @@ exports[`antd exports modules correctly 1`] = `
|
||||
"Checkbox",
|
||||
"Col",
|
||||
"Collapse",
|
||||
"ColorPicker",
|
||||
"ConfigProvider",
|
||||
"DatePicker",
|
||||
"Descriptions",
|
||||
|
@ -78,9 +78,7 @@ export default function genPurePanel<ComponentProps extends BaseProps>(
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
motionDurationFast: '0.01s',
|
||||
motionDurationMid: '0.01s',
|
||||
motionDurationSlow: '0.01s',
|
||||
motion: false,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@ -89,7 +87,6 @@ export default function genPurePanel<ComponentProps extends BaseProps>(
|
||||
style={{
|
||||
paddingBottom: popupHeight,
|
||||
position: 'relative',
|
||||
width: 'fit-content',
|
||||
minWidth: popupWidth,
|
||||
}}
|
||||
>
|
||||
|
@ -135,23 +135,27 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -1406,23 +1410,27 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -1632,23 +1640,27 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -1677,23 +1689,27 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
Search
|
||||
@ -2193,23 +2209,27 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx extend con
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
|
@ -108,23 +108,27 @@ exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -791,23 +795,27 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -946,23 +954,27 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
@ -979,23 +991,27 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
Search
|
||||
@ -1112,7 +1128,7 @@ exports[`renders components/auto-complete/demo/render-panel.tsx correctly 1`] =
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
style="padding-bottom:0;position:relative;width:fit-content;min-width:0"
|
||||
style="padding-bottom:0;position:relative;min-width:0"
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
|
||||
@ -1259,23 +1275,27 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
|
@ -11,6 +11,10 @@ import type { BaseSelectRef } from 'rc-select';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import * as React from 'react';
|
||||
import genPurePanel from '../_util/PurePanel';
|
||||
import { isValidElement } from '../_util/reactNode';
|
||||
import type { InputStatus } from '../_util/statusUtils';
|
||||
import warning from '../_util/warning';
|
||||
import type { ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import type {
|
||||
@ -20,10 +24,6 @@ import type {
|
||||
RefSelectProps,
|
||||
} from '../select';
|
||||
import Select from '../select';
|
||||
import genPurePanel from '../_util/PurePanel';
|
||||
import { isValidElement } from '../_util/reactNode';
|
||||
import type { InputStatus } from '../_util/statusUtils';
|
||||
import warning from '../_util/warning';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
@ -45,6 +45,9 @@ export interface AutoCompleteProps<
|
||||
popupClassName?: string;
|
||||
/** @deprecated Please use `popupClassName` instead */
|
||||
dropdownClassName?: string;
|
||||
/** @deprecated Please use `popupMatchSelectWidth` instead */
|
||||
dropdownMatchSelectWidth?: boolean | number;
|
||||
popupMatchSelectWidth?: boolean | number;
|
||||
}
|
||||
|
||||
function isSelectOptionOrSelectOptGroup(child: any): Boolean {
|
||||
|
@ -114,7 +114,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
|
||||
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].includes(key),
|
||||
);
|
||||
const screens = useBreakpoint(needResponsive);
|
||||
const responsiveSizeStyle: React.CSSProperties = React.useMemo(() => {
|
||||
const responsiveSizeStyle = React.useMemo<React.CSSProperties>(() => {
|
||||
if (typeof size !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
@ -158,23 +158,27 @@ exports[`renders components/badge/demo/change.tsx extend context correctly 1`] =
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="minus"
|
||||
class="anticon anticon-minus"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="minus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="minus"
|
||||
class="anticon anticon-minus"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M872 474H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h720c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="minus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M872 474H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h720c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
@ -182,29 +186,33 @@ exports[`renders components/badge/demo/change.tsx extend context correctly 1`] =
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
@ -212,23 +220,27 @@ exports[`renders components/badge/demo/change.tsx extend context correctly 1`] =
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="question"
|
||||
class="anticon anticon-question"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="question"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="question"
|
||||
class="anticon anticon-question"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M764 280.9c-14-30.6-33.9-58.1-59.3-81.6C653.1 151.4 584.6 125 512 125s-141.1 26.4-192.7 74.2c-25.4 23.6-45.3 51-59.3 81.7-14.6 32-22 65.9-22 100.9v27c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-27c0-99.5 88.6-180.4 197.6-180.4s197.6 80.9 197.6 180.4c0 40.8-14.5 79.2-42 111.2-27.2 31.7-65.6 54.4-108.1 64-24.3 5.5-46.2 19.2-61.7 38.8a110.85 110.85 0 00-23.9 68.6v31.4c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-31.4c0-15.7 10.9-29.5 26-32.9 58.4-13.2 111.4-44.7 149.3-88.7 19.1-22.3 34-47.1 44.3-74 10.7-27.9 16.1-57.2 16.1-87 0-35-7.4-69-22-100.9zM512 787c-30.9 0-56 25.1-56 56s25.1 56 56 56 56-25.1 56-56-25.1-56-56-56z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="question"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M764 280.9c-14-30.6-33.9-58.1-59.3-81.6C653.1 151.4 584.6 125 512 125s-141.1 26.4-192.7 74.2c-25.4 23.6-45.3 51-59.3 81.7-14.6 32-22 65.9-22 100.9v27c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-27c0-99.5 88.6-180.4 197.6-180.4s197.6 80.9 197.6 180.4c0 40.8-14.5 79.2-42 111.2-27.2 31.7-65.6 54.4-108.1 64-24.3 5.5-46.2 19.2-61.7 38.8a110.85 110.85 0 00-23.9 68.6v31.4c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-31.4c0-15.7 10.9-29.5 26-32.9 58.4-13.2 111.4-44.7 149.3-88.7 19.1-22.3 34-47.1 44.3-74 10.7-27.9 16.1-57.2 16.1-87 0-35-7.4-69-22-100.9zM512 787c-30.9 0-56 25.1-56 56s25.1 56 56 56 56-25.1 56-56-25.1-56-56-56z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -158,23 +158,27 @@ exports[`renders components/badge/demo/change.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="minus"
|
||||
class="anticon anticon-minus"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="minus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="minus"
|
||||
class="anticon anticon-minus"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M872 474H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h720c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="minus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M872 474H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h720c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
@ -182,29 +186,33 @@ exports[`renders components/badge/demo/change.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
@ -212,23 +220,27 @@ exports[`renders components/badge/demo/change.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="question"
|
||||
class="anticon anticon-question"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="question"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="question"
|
||||
class="anticon anticon-question"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M764 280.9c-14-30.6-33.9-58.1-59.3-81.6C653.1 151.4 584.6 125 512 125s-141.1 26.4-192.7 74.2c-25.4 23.6-45.3 51-59.3 81.7-14.6 32-22 65.9-22 100.9v27c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-27c0-99.5 88.6-180.4 197.6-180.4s197.6 80.9 197.6 180.4c0 40.8-14.5 79.2-42 111.2-27.2 31.7-65.6 54.4-108.1 64-24.3 5.5-46.2 19.2-61.7 38.8a110.85 110.85 0 00-23.9 68.6v31.4c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-31.4c0-15.7 10.9-29.5 26-32.9 58.4-13.2 111.4-44.7 149.3-88.7 19.1-22.3 34-47.1 44.3-74 10.7-27.9 16.1-57.2 16.1-87 0-35-7.4-69-22-100.9zM512 787c-30.9 0-56 25.1-56 56s25.1 56 56 56 56-25.1 56-56-25.1-56-56-56z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="question"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M764 280.9c-14-30.6-33.9-58.1-59.3-81.6C653.1 151.4 584.6 125 512 125s-141.1 26.4-192.7 74.2c-25.4 23.6-45.3 51-59.3 81.7-14.6 32-22 65.9-22 100.9v27c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-27c0-99.5 88.6-180.4 197.6-180.4s197.6 80.9 197.6 180.4c0 40.8-14.5 79.2-42 111.2-27.2 31.7-65.6 54.4-108.1 64-24.3 5.5-46.2 19.2-61.7 38.8a110.85 110.85 0 00-23.9 68.6v31.4c0 6.2 5 11.2 11.2 11.2h54c6.2 0 11.2-5 11.2-11.2v-31.4c0-15.7 10.9-29.5 26-32.9 58.4-13.2 111.4-44.7 149.3-88.7 19.1-22.3 34-47.1 44.3-74 10.7-27.9 16.1-57.2 16.1-87 0-35-7.4-69-22-100.9zM512 787c-30.9 0-56 25.1-56 56s25.1 56 56 56 56-25.1 56-56-25.1-56-56-56z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -112,121 +112,119 @@ exports[`renders components/breadcrumb/demo/debug-routes.tsx extend context corr
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
|
||||
style="opacity: 0;"
|
||||
<div
|
||||
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-dropdown-placement-bottom"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<ul
|
||||
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
<ul
|
||||
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-0"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-0"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
<a
|
||||
href="#/home/user/user1"
|
||||
>
|
||||
<a
|
||||
href="#/home/user/user1"
|
||||
>
|
||||
User1
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-1"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<a
|
||||
href="#/home/user/user2"
|
||||
>
|
||||
User2
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
User1
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-1"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<a
|
||||
href="#/home/user/user2"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
User2
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -304,177 +302,175 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
|
||||
style="opacity: 0;"
|
||||
<div
|
||||
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-dropdown-placement-bottom"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<ul
|
||||
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
<ul
|
||||
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-1"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-1"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
<a
|
||||
href="http://www.alipay.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<a
|
||||
href="http://www.alipay.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
General
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-2"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<a
|
||||
href="http://www.taobao.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Layout
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-3"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<a
|
||||
href="http://www.tmall.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Navigation
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
General
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-2"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<a
|
||||
href="http://www.taobao.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Layout
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-3"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
<a
|
||||
href="http://www.tmall.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
Navigation
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-dropdown-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
23
components/button/IconWrapper.tsx
Normal file
23
components/button/IconWrapper.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export type IconWrapperProps = {
|
||||
prefixCls: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const IconWrapper = forwardRef<HTMLSpanElement, IconWrapperProps>((props, ref) => {
|
||||
const { className, style, children, prefixCls } = props;
|
||||
|
||||
const iconWrapperCls = classNames(`${prefixCls}-icon`, className);
|
||||
|
||||
return (
|
||||
<span ref={ref} className={iconWrapperCls} style={style}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
export default IconWrapper;
|
@ -1,11 +1,34 @@
|
||||
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
|
||||
import CSSMotion from 'rc-motion';
|
||||
import React from 'react';
|
||||
import React, { forwardRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import IconWrapper from './IconWrapper';
|
||||
|
||||
type InnerLoadingIconProps = {
|
||||
prefixCls: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
iconClassName?: string;
|
||||
};
|
||||
|
||||
const InnerLoadingIcon = forwardRef<HTMLSpanElement, InnerLoadingIconProps>(
|
||||
({ prefixCls, className, style, iconClassName }, ref) => {
|
||||
const mergedIconCls = classNames(`${prefixCls}-loading-icon`, className);
|
||||
|
||||
return (
|
||||
<IconWrapper prefixCls={prefixCls} className={mergedIconCls} style={style} ref={ref}>
|
||||
<LoadingOutlined className={iconClassName} />
|
||||
</IconWrapper>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export interface LoadingIconProps {
|
||||
prefixCls: string;
|
||||
existIcon: boolean;
|
||||
loading?: boolean | object;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const getCollapsedWidth = (): React.CSSProperties => ({
|
||||
@ -20,15 +43,17 @@ const getRealWidth = (node: HTMLElement): React.CSSProperties => ({
|
||||
transform: 'scale(1)',
|
||||
});
|
||||
|
||||
const LoadingIcon: React.FC<LoadingIconProps> = ({ prefixCls, loading, existIcon }) => {
|
||||
const LoadingIcon: React.FC<LoadingIconProps> = ({
|
||||
prefixCls,
|
||||
loading,
|
||||
existIcon,
|
||||
className,
|
||||
style,
|
||||
}) => {
|
||||
const visible = !!loading;
|
||||
|
||||
if (existIcon) {
|
||||
return (
|
||||
<span className={`${prefixCls}-loading-icon`}>
|
||||
<LoadingOutlined />
|
||||
</span>
|
||||
);
|
||||
return <InnerLoadingIcon prefixCls={prefixCls} className={className} style={style} />;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -44,10 +69,20 @@ const LoadingIcon: React.FC<LoadingIconProps> = ({ prefixCls, loading, existIcon
|
||||
onLeaveStart={getRealWidth}
|
||||
onLeaveActive={getCollapsedWidth}
|
||||
>
|
||||
{({ className, style }: { className?: string; style?: React.CSSProperties }, ref: any) => (
|
||||
<span className={`${prefixCls}-loading-icon`} style={style} ref={ref}>
|
||||
<LoadingOutlined className={className} />
|
||||
</span>
|
||||
{(
|
||||
{
|
||||
className: motionCls,
|
||||
style: motionStyle,
|
||||
}: { className?: string; style?: React.CSSProperties },
|
||||
ref: any,
|
||||
) => (
|
||||
<InnerLoadingIcon
|
||||
prefixCls={prefixCls}
|
||||
className={className}
|
||||
style={{ ...style, ...motionStyle }}
|
||||
ref={ref}
|
||||
iconClassName={motionCls}
|
||||
/>
|
||||
)}
|
||||
</CSSMotion>
|
||||
);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -44,23 +44,27 @@ exports[`Button renders Chinese characters correctly 2`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
按钮
|
||||
@ -104,23 +108,27 @@ exports[`Button renders Chinese characters correctly 4`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
按钮
|
||||
@ -134,7 +142,7 @@ exports[`Button renders Chinese characters correctly 5`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-loading-icon"
|
||||
class="ant-btn-icon ant-btn-loading-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="loading"
|
||||
@ -168,7 +176,7 @@ exports[`Button renders Chinese characters correctly 6`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-loading-icon"
|
||||
class="ant-btn-icon ant-btn-loading-icon"
|
||||
style="width: 0px; opacity: 0; transform: scale(0);"
|
||||
>
|
||||
<span
|
||||
@ -304,6 +312,73 @@ exports[`Button should render empty button without errors 1`] = `
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Button should support custom icon className 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon custom-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Button should support custom icon styles 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
style="color: red;"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Button should support link button 1`] = `
|
||||
<a
|
||||
class="ant-btn ant-btn-default"
|
||||
|
@ -161,6 +161,21 @@ describe('Button', () => {
|
||||
expect(wrapper.container.firstChild).not.toHaveClass('ant-btn-loading');
|
||||
});
|
||||
|
||||
it('should support custom icon className', () => {
|
||||
const { container } = render(
|
||||
<Button type="primary" icon={<SearchOutlined />} classNames={{ icon: 'custom-icon' }} />,
|
||||
);
|
||||
expect(container.querySelectorAll('.custom-icon').length).toBe(1);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support custom icon styles', () => {
|
||||
const { container } = render(
|
||||
<Button type="primary" icon={<SearchOutlined />} styles={{ icon: { color: 'red' } }} />,
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('reset when loading back of delay', () => {
|
||||
jest.useFakeTimers();
|
||||
const { rerender, container } = render(<Button loading={{ delay: 1000 }} />);
|
||||
|
@ -23,6 +23,7 @@ import Group, { GroupSizeContext } from './button-group';
|
||||
import type { ButtonHTMLType, ButtonShape, ButtonType } from './buttonHelpers';
|
||||
import { isTwoCNChar, isUnBorderedButtonType, spaceChildren } from './buttonHelpers';
|
||||
import useStyle from './style';
|
||||
import IconWrapper from './IconWrapper';
|
||||
|
||||
export type LegacyButtonType = ButtonType | 'danger';
|
||||
|
||||
@ -48,6 +49,8 @@ export interface BaseButtonProps {
|
||||
block?: boolean;
|
||||
children?: React.ReactNode;
|
||||
[key: `data-${string}`]: string;
|
||||
classNames?: { icon: string };
|
||||
styles?: { icon: React.CSSProperties };
|
||||
}
|
||||
|
||||
export type AnchorButtonProps = {
|
||||
@ -107,6 +110,7 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
danger,
|
||||
shape = 'default',
|
||||
size: customizeSize,
|
||||
styles,
|
||||
disabled: customDisabled,
|
||||
className,
|
||||
rootClassName,
|
||||
@ -116,6 +120,7 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
block = false,
|
||||
// React does not recognize the `htmlType` prop on a DOM element. Here we pick it out of `rest`.
|
||||
htmlType = 'button',
|
||||
classNames: customClassNames,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
@ -237,7 +242,9 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
|
||||
const iconNode =
|
||||
icon && !innerLoading ? (
|
||||
icon
|
||||
<IconWrapper prefixCls={prefixCls} className={customClassNames?.icon} style={styles?.icon}>
|
||||
{icon}
|
||||
</IconWrapper>
|
||||
) : (
|
||||
<LoadingIcon existIcon={!!icon} prefixCls={prefixCls} loading={!!innerLoading} />
|
||||
);
|
||||
|
@ -55,6 +55,7 @@ Different button styles can be generated by setting Button properties. The recom
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| block | Option to fit button width to its parent width | boolean | false | |
|
||||
| classNames | Semantic DOM class | Record<SemanticDOM, string> | - | 5.4.0 |
|
||||
| danger | Set the danger status of button | boolean | false | |
|
||||
| disabled | Disabled state of button | boolean | false | |
|
||||
| ghost | Make background transparent and invert text and border colors | boolean | false | |
|
||||
@ -64,12 +65,19 @@ Different button styles can be generated by setting Button properties. The recom
|
||||
| loading | Set the loading status of button | boolean \| { delay: number } | false | |
|
||||
| shape | Can be set button shape | `default` \| `circle` \| `round` | `default` | |
|
||||
| size | Set the size of button | `large` \| `middle` \| `small` | `middle` | |
|
||||
| styles | Semantic DOM style | Record<SemanticDOM, CSSProperties> | - | 5.4.0 |
|
||||
| target | Same as target attribute of a, works when href is specified | string | - | |
|
||||
| type | Can be set to `primary` `ghost` `dashed` `link` `text` `default` | string | `default` | |
|
||||
| onClick | Set the handler to handle `click` event | (event: MouseEvent) => void | - | |
|
||||
|
||||
It accepts all props which native buttons support.
|
||||
|
||||
### `styles` and `classNames` attribute
|
||||
|
||||
| Property | Description | Version |
|
||||
| -------- | ----------------- | ------- |
|
||||
| icon | set `icon`element | 5.5.0 |
|
||||
|
||||
## Design Token
|
||||
|
||||
<ComponentTokenTable component="Button"></ComponentTokenTable>
|
||||
|
@ -60,6 +60,7 @@ group:
|
||||
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| block | 将按钮宽度调整为其父宽度的选项 | boolean | false | |
|
||||
| classNames | 语义化结构 class | Record<SemanticDOM, string> | - | 5.4.0 |
|
||||
| danger | 设置危险按钮 | boolean | false | |
|
||||
| disabled | 设置按钮失效状态 | boolean | false | |
|
||||
| ghost | 幽灵属性,使按钮背景透明 | boolean | false | |
|
||||
@ -69,12 +70,19 @@ group:
|
||||
| loading | 设置按钮载入状态 | boolean \| { delay: number } | false | |
|
||||
| shape | 设置按钮形状 | `default` \| `circle` \| `round` | `default` | |
|
||||
| size | 设置按钮大小 | `large` \| `middle` \| `small` | `middle` | |
|
||||
| styles | 语义化结构 style | Record<SemanticDOM, CSSProperties> | - | 5.4.0 |
|
||||
| target | 相当于 a 链接的 target 属性,href 存在时生效 | string | - | |
|
||||
| type | 设置按钮类型 | `primary` \| `ghost` \| `dashed` \| `link` \| `text` \| `default` | `default` | |
|
||||
| onClick | 点击按钮时的回调 | (event: MouseEvent) => void | - | |
|
||||
|
||||
支持原生 button 的其他所有属性。
|
||||
|
||||
### `styles` 和 `classNames` 属性
|
||||
|
||||
| 名称 | 说明 | 版本 |
|
||||
| ---- | ------------ | ----- |
|
||||
| icon | 设置图标元素 | 5.5.0 |
|
||||
|
||||
## Design Token
|
||||
|
||||
<ComponentTokenTable component="Button"></ComponentTokenTable>
|
||||
|
@ -1,30 +1,31 @@
|
||||
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import genGroupStyle from './group';
|
||||
import { genFocusStyle } from '../../style';
|
||||
import { genCompactItemStyle } from '../../style/compact-item';
|
||||
import { genCompactItemVerticalStyle } from '../../style/compact-item-vertical';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import genGroupStyle from './group';
|
||||
|
||||
/** Component only token. Which will handle additional calculation of alias token */
|
||||
export interface ComponentToken {}
|
||||
|
||||
export interface ButtonToken extends FullToken<'Button'> {
|
||||
// FIXME: should be removed
|
||||
colorOutlineDefault: string;
|
||||
buttonPaddingHorizontal: number;
|
||||
buttonIconOnlyFontSize: number;
|
||||
buttonFontWeight: number;
|
||||
}
|
||||
|
||||
// ============================== Shared ==============================
|
||||
const genSharedButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token): CSSObject => {
|
||||
const { componentCls, iconCls } = token;
|
||||
const { componentCls, iconCls, buttonFontWeight } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
outline: 'none',
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
fontWeight: 400,
|
||||
fontWeight: buttonFontWeight,
|
||||
whiteSpace: 'nowrap',
|
||||
textAlign: 'center',
|
||||
backgroundImage: 'none',
|
||||
@ -41,8 +42,19 @@ const genSharedButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token): CSS
|
||||
display: 'inline-block',
|
||||
},
|
||||
|
||||
[`${componentCls}-icon`]: {
|
||||
lineHeight: 0,
|
||||
},
|
||||
|
||||
// Leave a space between icon and text.
|
||||
[`> ${iconCls} + span, > span + ${iconCls}`]: {
|
||||
[`&:not(${componentCls}-icon-only) > ${componentCls}-icon`]: {
|
||||
[`&${componentCls}-loading-icon, &:not(:last-child)`]: {
|
||||
marginInlineEnd: token.marginXS,
|
||||
},
|
||||
},
|
||||
|
||||
// Special case for anticon after children
|
||||
[`> span + ${iconCls}`]: {
|
||||
marginInlineStart: token.marginXS,
|
||||
},
|
||||
|
||||
@ -397,13 +409,13 @@ const genTypeButtonStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = ''): CSSInterpolation => {
|
||||
const {
|
||||
componentCls,
|
||||
iconCls,
|
||||
controlHeight,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
lineWidth,
|
||||
borderRadius,
|
||||
buttonPaddingHorizontal,
|
||||
iconCls,
|
||||
} = token;
|
||||
|
||||
const paddingVertical = Math.max(0, (controlHeight - fontSize * lineHeight) / 2 - lineWidth);
|
||||
@ -427,8 +439,8 @@ const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = ''): CSS
|
||||
[`&${componentCls}-round`]: {
|
||||
width: 'auto',
|
||||
},
|
||||
'> span': {
|
||||
transform: 'scale(1.143)', // 14px -> 16px
|
||||
[iconCls]: {
|
||||
fontSize: token.buttonIconOnlyFontSize,
|
||||
},
|
||||
},
|
||||
|
||||
@ -441,10 +453,6 @@ const genSizeButtonStyle = (token: ButtonToken, sizePrefixCls: string = ''): CSS
|
||||
[`${componentCls}-loading-icon`]: {
|
||||
transition: `width ${token.motionDurationSlow} ${token.motionEaseInOut}, opacity ${token.motionDurationSlow} ${token.motionEaseInOut}`,
|
||||
},
|
||||
|
||||
[`&:not(${iconOnlyCls}) ${componentCls}-loading-icon > ${iconCls}`]: {
|
||||
marginInlineEnd: token.marginXS,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -466,6 +474,7 @@ const genSizeSmallButtonStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
padding: token.paddingXS,
|
||||
buttonPaddingHorizontal: 8, // Fixed padding
|
||||
borderRadius: token.borderRadiusSM,
|
||||
buttonIconOnlyFontSize: token.fontSizeLG - 2,
|
||||
});
|
||||
|
||||
return genSizeButtonStyle(smallToken, `${token.componentCls}-sm`);
|
||||
@ -476,6 +485,7 @@ const genSizeLargeButtonStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
controlHeight: token.controlHeightLG,
|
||||
fontSize: token.fontSizeLG,
|
||||
borderRadius: token.borderRadiusLG,
|
||||
buttonIconOnlyFontSize: token.fontSizeLG + 2,
|
||||
});
|
||||
|
||||
return genSizeButtonStyle(largeToken, `${token.componentCls}-lg`);
|
||||
@ -499,6 +509,8 @@ export default genComponentStyleHook('Button', (token) => {
|
||||
const buttonToken = mergeToken<ButtonToken>(token, {
|
||||
colorOutlineDefault: controlTmpOutline,
|
||||
buttonPaddingHorizontal: paddingContentHorizontal,
|
||||
buttonIconOnlyFontSize: token.fontSizeLG,
|
||||
buttonFontWeight: 400,
|
||||
});
|
||||
|
||||
return [
|
||||
|
@ -2837,3 +2837,949 @@ exports[`Calendar rtl render component should be rendered correctly in RTL direc
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Calendar support Calendar.generateCalendar 1`] = `
|
||||
<div
|
||||
class="ant-picker-calendar ant-picker-calendar-full"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-header"
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-picker-calendar-year-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-item"
|
||||
title="2000"
|
||||
>
|
||||
2000
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-picker-calendar-month-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-item"
|
||||
title="Jan"
|
||||
>
|
||||
Jan
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-radio-group ant-radio-group-outline ant-picker-calendar-mode-switch"
|
||||
>
|
||||
<label
|
||||
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
|
||||
>
|
||||
<span
|
||||
class="ant-radio-button ant-radio-button-checked"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="ant-radio-button-input"
|
||||
type="radio"
|
||||
value="month"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
Month
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-button-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-radio-button"
|
||||
>
|
||||
<input
|
||||
class="ant-radio-button-input"
|
||||
type="radio"
|
||||
value="year"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
Year
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-panel"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-date-panel"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-body"
|
||||
>
|
||||
<table
|
||||
class="ant-picker-content"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Su
|
||||
</th>
|
||||
<th>
|
||||
Mo
|
||||
</th>
|
||||
<th>
|
||||
Tu
|
||||
</th>
|
||||
<th>
|
||||
We
|
||||
</th>
|
||||
<th>
|
||||
Th
|
||||
</th>
|
||||
<th>
|
||||
Fr
|
||||
</th>
|
||||
<th>
|
||||
Sa
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="1999-12-26"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
26
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="1999-12-27"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
27
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="1999-12-28"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
28
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="1999-12-29"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
29
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="1999-12-30"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
30
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-end"
|
||||
title="1999-12-31"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
31
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-start ant-picker-cell-in-view ant-picker-cell-today ant-picker-cell-selected"
|
||||
title="2000-01-01"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date ant-picker-calendar-date-today"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
01
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-02"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
02
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-03"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
03
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-04"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
04
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-05"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
05
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-06"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
06
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-07"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
07
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-08"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
08
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-09"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
09
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-10"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
10
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-11"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
11
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-12"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
12
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-13"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
13
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-14"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
14
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-15"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
15
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-16"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
16
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-17"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
17
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-18"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
18
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-19"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
19
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-20"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
20
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-21"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
21
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-22"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
22
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-23"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
23
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-24"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
24
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-25"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
25
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-26"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
26
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-27"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
27
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-28"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
28
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-29"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
29
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-in-view"
|
||||
title="2000-01-30"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
30
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-end ant-picker-cell-in-view"
|
||||
title="2000-01-31"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
31
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell ant-picker-cell-start"
|
||||
title="2000-02-01"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
01
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="2000-02-02"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
02
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="2000-02-03"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
03
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="2000-02-04"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
04
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="ant-picker-cell"
|
||||
title="2000-02-05"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-cell-inner ant-picker-calendar-date"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-calendar-date-value"
|
||||
>
|
||||
05
|
||||
</div>
|
||||
<div
|
||||
class="ant-picker-calendar-date-content"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -538,4 +538,14 @@ describe('Calendar', () => {
|
||||
expect(container.querySelector('.bar')).toBeTruthy();
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('support Calendar.generateCalendar', () => {
|
||||
jest.useFakeTimers().setSystemTime(new Date('2000-01-01'));
|
||||
|
||||
const MyCalendar = Calendar.generateCalendar(dayjsGenerateConfig);
|
||||
const { container } = render(<MyCalendar />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
@ -5,5 +5,11 @@ import generateCalendar from './generateCalendar';
|
||||
|
||||
const Calendar = generateCalendar<Dayjs>(dayjsGenerateConfig);
|
||||
|
||||
export type CalendarType = typeof Calendar & {
|
||||
generateCalendar: typeof generateCalendar;
|
||||
};
|
||||
|
||||
(Calendar as CalendarType).generateCalendar = generateCalendar;
|
||||
|
||||
export type { CalendarProps };
|
||||
export default Calendar;
|
||||
export default Calendar as CalendarType;
|
||||
|
@ -836,24 +836,22 @@ Array [
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tabs-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-tabs-dropdown-placement-bottomLeft"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<ul
|
||||
aria-label="expanded dropdown"
|
||||
class="ant-tabs-dropdown-menu ant-tabs-dropdown-menu-root ant-tabs-dropdown-menu-vertical"
|
||||
data-menu-list="true"
|
||||
id="rc-tabs-test-more-popup"
|
||||
role="listbox"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<div
|
||||
class="ant-tabs-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
|
||||
style="opacity: 0;"
|
||||
>
|
||||
<ul
|
||||
aria-label="expanded dropdown"
|
||||
class="ant-tabs-dropdown-menu ant-tabs-dropdown-menu-root ant-tabs-dropdown-menu-vertical"
|
||||
data-menu-list="true"
|
||||
id="rc-tabs-test-more-popup"
|
||||
role="listbox"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -996,24 +994,22 @@ Array [
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tabs-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-tabs-dropdown-placement-bottomLeft"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<ul
|
||||
aria-label="expanded dropdown"
|
||||
class="ant-tabs-dropdown-menu ant-tabs-dropdown-menu-root ant-tabs-dropdown-menu-vertical"
|
||||
data-menu-list="true"
|
||||
id="rc-tabs-test-more-popup"
|
||||
role="listbox"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<div
|
||||
class="ant-tabs-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
|
||||
style="opacity: 0;"
|
||||
>
|
||||
<ul
|
||||
aria-label="expanded dropdown"
|
||||
class="ant-tabs-dropdown-menu ant-tabs-dropdown-menu-root ant-tabs-dropdown-menu-vertical"
|
||||
data-menu-list="true"
|
||||
id="rc-tabs-test-more-popup"
|
||||
role="listbox"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -848,7 +848,7 @@ Array [
|
||||
|
||||
exports[`renders components/cascader/demo/render-panel.tsx correctly 1`] = `
|
||||
<div
|
||||
style="padding-bottom:0;position:relative;width:fit-content;min-width:0"
|
||||
style="padding-bottom:0;position:relative;min-width:0"
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
|
@ -681,4 +681,38 @@ describe('Cascader', () => {
|
||||
expect(selectedValue!.join(',')).toBe('zhejiang');
|
||||
});
|
||||
});
|
||||
|
||||
it('should be correct expression with disableCheckbox', () => {
|
||||
const { container } = render(
|
||||
<Cascader
|
||||
multiple
|
||||
options={[
|
||||
{
|
||||
label: '台湾',
|
||||
value: 'tw',
|
||||
children: [
|
||||
{
|
||||
label: '福建',
|
||||
value: 'fj',
|
||||
disableCheckbox: true,
|
||||
},
|
||||
{
|
||||
label: '兰州',
|
||||
value: 'lz',
|
||||
},
|
||||
{ label: '北京', value: 'bj' },
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
fireEvent.mouseDown(container.querySelector('.ant-select-selector')!);
|
||||
// disabled className
|
||||
fireEvent.click(container.querySelector('.ant-cascader-menu-item')!);
|
||||
expect(container.querySelectorAll('.ant-cascader-checkbox-disabled')).toHaveLength(1);
|
||||
// Check all children except disableCheckbox When the parent checkbox is checked
|
||||
expect(container.querySelectorAll('.ant-cascader-checkbox')).toHaveLength(4);
|
||||
fireEvent.click(container.querySelector('.ant-cascader-checkbox')!);
|
||||
expect(container.querySelectorAll('.ant-cascader-checkbox-checked')).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
一次性选择多个选项。
|
||||
一次性选择多个选项。通过添加 `disableCheckbox` 属性,选择具体某一个`checkbox`禁用 。可以通过类名修改禁用的样式。
|
||||
|
||||
## en-US
|
||||
|
||||
Select multiple options
|
||||
Select multiple options. Disable the `checkbox` by adding the `disableCheckbox` property and selecting a specific item. The style of the disable can be modified by the className.
|
||||
|
@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import { Cascader } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
interface Option {
|
||||
value: string | number;
|
||||
label: string;
|
||||
children?: Option[];
|
||||
disableCheckbox?: boolean;
|
||||
}
|
||||
|
||||
const options: Option[] = [
|
||||
@ -26,6 +27,7 @@ const options: Option[] = [
|
||||
{
|
||||
label: 'Toy Fish',
|
||||
value: 'fish',
|
||||
disableCheckbox: true,
|
||||
},
|
||||
{
|
||||
label: 'Toy Cards',
|
||||
|
@ -159,8 +159,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
|
||||
getPrefixCls,
|
||||
renderEmpty,
|
||||
direction: rootDirection,
|
||||
// virtual,
|
||||
// dropdownMatchSelectWidth,
|
||||
popupOverflow,
|
||||
} = React.useContext(ConfigContext);
|
||||
|
||||
const mergedDirection = direction || rootDirection;
|
||||
@ -273,7 +272,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
|
||||
return isRtl ? 'bottomRight' : 'bottomLeft';
|
||||
}, [placement, isRtl]);
|
||||
|
||||
const mergedBuiltinPlacements = useBuiltinPlacements(builtinPlacements);
|
||||
const mergedBuiltinPlacements = useBuiltinPlacements(builtinPlacements, popupOverflow);
|
||||
|
||||
// ==================== Render =====================
|
||||
const renderNode = (
|
||||
|
168
components/color-picker/ColorPicker.tsx
Normal file
168
components/color-picker/ColorPicker.tsx
Normal file
@ -0,0 +1,168 @@
|
||||
import type {
|
||||
ColorPickerPanelProps as RcColorPickerPanelProps,
|
||||
TriggerPlacement,
|
||||
TriggerType,
|
||||
} from '@rc-component/color-picker';
|
||||
import classNames from 'classnames';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import type { CSSProperties } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import type { ConfigConsumerProps } from '../config-provider/context';
|
||||
import { ConfigContext } from '../config-provider/context';
|
||||
import type { PopoverProps } from '../popover';
|
||||
import Popover from '../popover';
|
||||
import theme from '../theme';
|
||||
import ColorPickerPanel from './ColorPickerPanel';
|
||||
import type { Color } from './color';
|
||||
import ColorTrigger from './components/ColorTrigger';
|
||||
import useColorState from './hooks/useColorState';
|
||||
import type { ColorFormat, ColorPickerBaseProps, PresetsItem } from './interface';
|
||||
import useStyle from './style/index';
|
||||
import { customizePrefixCls, generateColor } from './util';
|
||||
import genPurePanel from '../_util/PurePanel';
|
||||
|
||||
export interface ColorPickerProps
|
||||
extends Omit<
|
||||
RcColorPickerPanelProps,
|
||||
'onChange' | 'arrow' | 'value' | 'defaultValue' | 'children' | 'panelRender'
|
||||
> {
|
||||
value?: Color | string;
|
||||
defaultValue?: Color | string;
|
||||
children?: React.ReactElement;
|
||||
open?: boolean;
|
||||
disabled?: boolean;
|
||||
placement?: TriggerPlacement;
|
||||
trigger?: TriggerType;
|
||||
format?: keyof typeof ColorFormat;
|
||||
allowClear?: boolean;
|
||||
presets?: PresetsItem[];
|
||||
arrow?: boolean | { pointAtCenter: boolean };
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
styles?: { popup?: CSSProperties };
|
||||
rootClassName?: string;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
onFormatChange?: (format: ColorFormat) => void;
|
||||
onChange?: (value: Color, hex: string) => void;
|
||||
getPopupContainer?: PopoverProps['getPopupContainer'];
|
||||
}
|
||||
|
||||
type CompoundedComponent = React.FC<ColorPickerProps> & {
|
||||
_InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel;
|
||||
};
|
||||
|
||||
const ColorPicker: CompoundedComponent = (props) => {
|
||||
const {
|
||||
value,
|
||||
defaultValue,
|
||||
format,
|
||||
allowClear = false,
|
||||
presets,
|
||||
children,
|
||||
trigger = 'click',
|
||||
open,
|
||||
disabled,
|
||||
placement = 'bottomLeft',
|
||||
arrow = true,
|
||||
style,
|
||||
className,
|
||||
rootClassName,
|
||||
styles,
|
||||
onFormatChange,
|
||||
onChange,
|
||||
onOpenChange,
|
||||
getPopupContainer,
|
||||
} = props;
|
||||
|
||||
const { getPrefixCls, direction } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||
const { token } = theme.useToken();
|
||||
|
||||
const [colorValue, setColorValue] = useColorState(token.colorPrimary, {
|
||||
value,
|
||||
defaultValue,
|
||||
});
|
||||
const [popupOpen, setPopupOpen] = useMergedState(false, {
|
||||
value: open,
|
||||
postState: (openData) => !disabled && openData,
|
||||
onChange: onOpenChange,
|
||||
});
|
||||
const [clearColor, setClearColor] = useState(false);
|
||||
|
||||
const prefixCls = getPrefixCls('color-picker', customizePrefixCls);
|
||||
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const mergeRootCls = classNames(rootClassName, {
|
||||
[`${prefixCls}-rtl`]: direction,
|
||||
});
|
||||
const mergeCls = classNames(mergeRootCls, className, hashId);
|
||||
|
||||
const handleChange = (data: Color) => {
|
||||
const color: Color = generateColor(data);
|
||||
if (clearColor && color.toHsb().a > 0) {
|
||||
setClearColor(false);
|
||||
}
|
||||
if (!value) {
|
||||
setColorValue(color);
|
||||
}
|
||||
onChange?.(color, color.toHexString());
|
||||
};
|
||||
|
||||
const handleClear = (clear: boolean) => {
|
||||
setClearColor(clear);
|
||||
};
|
||||
|
||||
const popoverProps: PopoverProps = {
|
||||
open: popupOpen,
|
||||
trigger,
|
||||
placement,
|
||||
arrow,
|
||||
rootClassName,
|
||||
getPopupContainer,
|
||||
};
|
||||
|
||||
const colorBaseProps: ColorPickerBaseProps = {
|
||||
prefixCls,
|
||||
color: colorValue,
|
||||
allowClear,
|
||||
clearColor,
|
||||
disabled,
|
||||
presets,
|
||||
format,
|
||||
onFormatChange,
|
||||
};
|
||||
|
||||
return wrapSSR(
|
||||
<Popover
|
||||
style={styles?.popup}
|
||||
onOpenChange={setPopupOpen}
|
||||
content={
|
||||
<ColorPickerPanel {...colorBaseProps} onChange={handleChange} onClear={handleClear} />
|
||||
}
|
||||
overlayClassName={prefixCls}
|
||||
{...popoverProps}
|
||||
>
|
||||
{children || (
|
||||
<ColorTrigger
|
||||
open={popupOpen}
|
||||
className={mergeCls}
|
||||
style={style}
|
||||
color={colorValue}
|
||||
prefixCls={prefixCls}
|
||||
clearColor={clearColor}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
</Popover>,
|
||||
);
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
ColorPicker.displayName = 'ColorPicker';
|
||||
}
|
||||
|
||||
const PurePanel = genPurePanel(ColorPicker, 'color-picker', (prefixCls) => prefixCls);
|
||||
|
||||
ColorPicker._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
||||
|
||||
export default ColorPicker;
|
63
components/color-picker/ColorPickerPanel.tsx
Normal file
63
components/color-picker/ColorPickerPanel.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { ColorPickerPanel as RcColorPickerPanel } from '@rc-component/color-picker';
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import Divider from '../divider';
|
||||
import type { Color } from './color';
|
||||
import ColorClear from './components/ColorClear';
|
||||
import ColorInput from './components/ColorInput';
|
||||
import ColorPresets from './components/ColorPresets';
|
||||
import type { ColorPickerBaseProps } from './interface';
|
||||
|
||||
interface ColorPickerPanelProps extends ColorPickerBaseProps {
|
||||
onChange?: (value?: Color) => void;
|
||||
onClear?: (clear?: boolean) => void;
|
||||
}
|
||||
|
||||
const ColorPickerPanel: FC<ColorPickerPanelProps> = (props) => {
|
||||
const { prefixCls, allowClear, presets, onChange, onClear, color, ...injectProps } = props;
|
||||
const colorPickerPanelPrefixCls = `${prefixCls}-inner-panel`;
|
||||
|
||||
const extraPanelRender = (panel: React.ReactElement) => (
|
||||
<div className={colorPickerPanelPrefixCls}>
|
||||
{allowClear && (
|
||||
<ColorClear
|
||||
prefixCls={prefixCls}
|
||||
value={color}
|
||||
onChange={(clearColor) => {
|
||||
onChange?.(clearColor);
|
||||
onClear?.(true);
|
||||
}}
|
||||
{...injectProps}
|
||||
/>
|
||||
)}
|
||||
{panel}
|
||||
<ColorInput
|
||||
value={color}
|
||||
onChange={(value) => onChange?.(value)}
|
||||
prefixCls={prefixCls}
|
||||
{...injectProps}
|
||||
/>
|
||||
|
||||
{Array.isArray(presets) && (
|
||||
<>
|
||||
<Divider className={`${colorPickerPanelPrefixCls}-divider`} />
|
||||
<ColorPresets
|
||||
value={color}
|
||||
presets={presets}
|
||||
onChange={(value) => onChange?.(value)}
|
||||
prefixCls={prefixCls}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<RcColorPickerPanel
|
||||
prefixCls={prefixCls}
|
||||
value={color?.toHsb()}
|
||||
onChange={onChange}
|
||||
panelRender={extraPanelRender}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default ColorPickerPanel;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,248 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders components/color-picker/demo/allowClear.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-color-picker-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(22, 119, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/color-picker/demo/base.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-color-picker-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(22, 119, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/color-picker/demo/disabled.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-color-picker-trigger ant-color-picker-trigger-disabled"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(22, 119, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/color-picker/demo/format.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="display:flex"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:16px"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-row-middle"
|
||||
>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-col"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(22, 119, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col"
|
||||
>
|
||||
HEX:
|
||||
<span>
|
||||
#1677ff
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:16px"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-row-middle"
|
||||
>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-col"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(23, 120, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col"
|
||||
>
|
||||
HSB:
|
||||
<span>
|
||||
hsb(215,91%,100%)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-row-middle"
|
||||
>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-col"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(22, 119, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col"
|
||||
>
|
||||
RGB:
|
||||
<span>
|
||||
rgb(22,119,255)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/color-picker/demo/presets.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-color-picker-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(22, 119, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/color-picker/demo/pure-panel.tsx correctly 1`] = `
|
||||
<div
|
||||
style="padding-bottom:0;position:relative;min-width:0"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-trigger"
|
||||
style="margin:0"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background:rgb(22, 119, 255)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/color-picker/demo/trigger.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<div
|
||||
style="width:20px;height:20px;border-radius:4px;background:#1677ff"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span>
|
||||
#1677ff
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -0,0 +1,41 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ColorPicker Should disabled work 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-color-picker-trigger ant-color-picker-trigger-disabled"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background: rgb(22, 119, 255);"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ColorPicker Should render trigger work 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="trigger"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ColorPicker rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<div
|
||||
class="ant-color-picker-trigger ant-color-picker-rtl"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block"
|
||||
>
|
||||
<div
|
||||
class="ant-color-picker-color-block-inner"
|
||||
style="background: rgb(22, 119, 255);"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
96
components/color-picker/__tests__/components.test.tsx
Normal file
96
components/color-picker/__tests__/components.test.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import ColorAlphaInput from '../components/ColorAlphaInput';
|
||||
import ColorHexInput from '../components/ColorHexInput';
|
||||
import ColorHsbInput from '../components/ColorHsbInput';
|
||||
import ColorRgbInput from '../components/ColorRgbInput';
|
||||
import ColorSteppers from '../components/ColorSteppers';
|
||||
|
||||
describe('ColorPicker Components test', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('Should ColorSteppers work correct', () => {
|
||||
const handleAlphaChange = jest.fn();
|
||||
const { container } = render(<ColorSteppers prefixCls="test" onChange={handleAlphaChange} />);
|
||||
expect(container.querySelector('.test-steppers')).toBeTruthy();
|
||||
fireEvent.change(container.querySelector('.test-steppers input')!, {
|
||||
target: { value: 1 },
|
||||
});
|
||||
expect(container.querySelector('.test-steppers input')?.getAttribute('value')).toEqual('1');
|
||||
expect(handleAlphaChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Should ColorAlphaInput work correct', () => {
|
||||
const handleAlphaChange = jest.fn();
|
||||
const { container } = render(<ColorAlphaInput prefixCls="test" onChange={handleAlphaChange} />);
|
||||
expect(container.querySelector('.test-alpha-input')).toBeTruthy();
|
||||
fireEvent.change(container.querySelector('.test-alpha-input input')!, {
|
||||
target: { value: 1 },
|
||||
});
|
||||
expect(container.querySelector('.test-alpha-input input')?.getAttribute('value')).toEqual('1%');
|
||||
expect(handleAlphaChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Should ColorHexInput work correct', () => {
|
||||
const handleAlphaChange = jest.fn();
|
||||
const { container } = render(<ColorHexInput prefixCls="test" onChange={handleAlphaChange} />);
|
||||
expect(container.querySelector('.test-hex-input')).toBeTruthy();
|
||||
fireEvent.change(container.querySelector('.test-hex-input input')!, {
|
||||
target: { value: 631515 },
|
||||
});
|
||||
expect(container.querySelector('.test-hex-input input')?.getAttribute('value')).toEqual(
|
||||
'631515',
|
||||
);
|
||||
expect(handleAlphaChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Should ColorHsbInput work correct', () => {
|
||||
const handleAlphaChange = jest.fn();
|
||||
const { container } = render(<ColorHsbInput prefixCls="test" onChange={handleAlphaChange} />);
|
||||
expect(container.querySelector('.test-hsb-input')).toBeTruthy();
|
||||
const hsbInputEls = container.querySelectorAll('.test-hsb-input input');
|
||||
fireEvent.change(hsbInputEls[0], {
|
||||
target: { value: 139 },
|
||||
});
|
||||
expect(hsbInputEls[0]?.getAttribute('value')).toEqual('139');
|
||||
|
||||
fireEvent.change(hsbInputEls[1], {
|
||||
target: { value: 78 },
|
||||
});
|
||||
expect(hsbInputEls[1]?.getAttribute('value')).toEqual('78%');
|
||||
|
||||
fireEvent.change(hsbInputEls[2], {
|
||||
target: { value: 39 },
|
||||
});
|
||||
expect(hsbInputEls[2]?.getAttribute('value')).toEqual('39%');
|
||||
expect(handleAlphaChange).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('Should ColorRgbInput work correct', () => {
|
||||
const handleAlphaChange = jest.fn();
|
||||
const { container } = render(<ColorRgbInput prefixCls="test" onChange={handleAlphaChange} />);
|
||||
expect(container.querySelector('.test-rgb-input')).toBeTruthy();
|
||||
const rgbInputEls = container.querySelectorAll('.test-rgb-input input');
|
||||
fireEvent.change(rgbInputEls[0], {
|
||||
target: { value: 99 },
|
||||
});
|
||||
expect(rgbInputEls[0]?.getAttribute('value')).toEqual('99');
|
||||
|
||||
fireEvent.change(rgbInputEls[1], {
|
||||
target: { value: 21 },
|
||||
});
|
||||
expect(rgbInputEls[1]?.getAttribute('value')).toEqual('21');
|
||||
|
||||
fireEvent.change(rgbInputEls[2], {
|
||||
target: { value: 21 },
|
||||
});
|
||||
expect(rgbInputEls[2]?.getAttribute('value')).toEqual('21');
|
||||
expect(handleAlphaChange).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
3
components/color-picker/__tests__/demo-extend.test.ts
Normal file
3
components/color-picker/__tests__/demo-extend.test.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { extendTest } from '../../../tests/shared/demoTest';
|
||||
|
||||
extendTest('color-picker');
|
3
components/color-picker/__tests__/demo.test.ts
Normal file
3
components/color-picker/__tests__/demo.test.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('color-picker');
|
5
components/color-picker/__tests__/image.test.ts
Normal file
5
components/color-picker/__tests__/image.test.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||
|
||||
describe('ColorPicker image', () => {
|
||||
imageDemoTest('color-picker');
|
||||
});
|
249
components/color-picker/__tests__/index.test.tsx
Normal file
249
components/color-picker/__tests__/index.test.tsx
Normal file
@ -0,0 +1,249 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { waitFakeTimer } from '../../../tests/utils';
|
||||
import ColorPicker from '../ColorPicker';
|
||||
import type { Color } from '../color';
|
||||
|
||||
describe('ColorPicker', () => {
|
||||
mountTest(ColorPicker);
|
||||
rtlTest(ColorPicker);
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('Should component render correct', () => {
|
||||
const { container } = render(<ColorPicker />);
|
||||
expect(container.querySelector('.ant-color-picker-trigger')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Should component defaultValue work', () => {
|
||||
const { container } = render(<ColorPicker defaultValue="#000000" />);
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-color-block-inner')?.getAttribute('style'),
|
||||
).toEqual('background: rgb(0, 0, 0);');
|
||||
});
|
||||
|
||||
it('Should component custom trigger work', async () => {
|
||||
const App = () => {
|
||||
const [color, setColor] = useState<Color | string>('hsb(215, 91%, 100%)');
|
||||
const colorString = useMemo(
|
||||
() => (typeof color === 'string' ? color : color.toHsbString()),
|
||||
[color],
|
||||
);
|
||||
return (
|
||||
<ColorPicker value={color} onChange={setColor} format="hsb">
|
||||
<span className="custom-trigger">{colorString}</span>
|
||||
</ColorPicker>
|
||||
);
|
||||
};
|
||||
const { container } = render(<App />);
|
||||
expect(container.querySelector('.custom-trigger')).toBeTruthy();
|
||||
fireEvent.click(container.querySelector('.custom-trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker')).toBeTruthy();
|
||||
const hsbInputEls = container.querySelectorAll('.ant-color-picker-hsb-input input');
|
||||
fireEvent.change(hsbInputEls[0], {
|
||||
target: { value: 0 },
|
||||
});
|
||||
fireEvent.change(hsbInputEls[1], {
|
||||
target: { value: 78 },
|
||||
});
|
||||
fireEvent.change(hsbInputEls[2], {
|
||||
target: { value: 39 },
|
||||
});
|
||||
expect(container.querySelector('.custom-trigger')?.innerHTML).toEqual('hsb(0, 78%, 39%)');
|
||||
});
|
||||
|
||||
it('Should popup open work', async () => {
|
||||
const { container } = render(<ColorPicker />);
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker')).toBeTruthy();
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-popover-hidden')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Should disabled work', async () => {
|
||||
const { container } = render(<ColorPicker disabled />);
|
||||
expect(container.querySelector('.ant-color-picker-trigger-disabled')).toBeTruthy();
|
||||
expect(container).toMatchSnapshot();
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Should allowClear work', async () => {
|
||||
const { container } = render(<ColorPicker allowClear />);
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker-clear')).toBeTruthy();
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-clear')!);
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-alpha-input input')?.getAttribute('value'),
|
||||
).toEqual('0%');
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-trigger .ant-color-picker-clear'),
|
||||
).toBeTruthy();
|
||||
fireEvent.change(container.querySelector('.ant-color-picker-alpha-input input')!, {
|
||||
target: { value: 1 },
|
||||
});
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-trigger .ant-color-picker-clear'),
|
||||
).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Should render trigger work', async () => {
|
||||
const { container } = render(
|
||||
<ColorPicker>
|
||||
<div className="trigger" />
|
||||
</ColorPicker>,
|
||||
);
|
||||
expect(container.querySelector('.trigger')).toBeTruthy();
|
||||
expect(container).toMatchSnapshot();
|
||||
fireEvent.click(container.querySelector('.trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker')).toBeTruthy();
|
||||
fireEvent.click(container.querySelector('.trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-popover-hidden')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Should preset color work', async () => {
|
||||
const handleColorChange = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<ColorPicker
|
||||
onChange={handleColorChange}
|
||||
presets={[
|
||||
{
|
||||
label: 'Recommended',
|
||||
colors: [
|
||||
'#000000',
|
||||
'#000000E0',
|
||||
'#000000A6',
|
||||
'#00000073',
|
||||
'#00000040',
|
||||
'#00000026',
|
||||
'#0000001A',
|
||||
'#00000012',
|
||||
'#0000000A',
|
||||
'#00000005',
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Recent',
|
||||
colors: [],
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
const presetsColors = container
|
||||
.querySelector('.ant-collapse-content')
|
||||
?.querySelectorAll('.ant-color-picker-presets-color')!;
|
||||
|
||||
expect(container.querySelector('.ant-color-picker-presets')).toBeTruthy();
|
||||
expect(presetsColors.length).toBe(10);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-collapse-content')[1]
|
||||
.querySelector('.ant-color-picker-presets-empty'),
|
||||
).toBeTruthy();
|
||||
|
||||
fireEvent.click(presetsColors[0]);
|
||||
expect(
|
||||
presetsColors[0].classList.contains('ant-color-picker-presets-color-bright'),
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-hex-input input')?.getAttribute('value'),
|
||||
).toEqual('000000');
|
||||
|
||||
fireEvent.click(presetsColors[9]);
|
||||
expect(
|
||||
presetsColors[9].classList.contains('ant-color-picker-presets-color-bright'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-hex-input input')?.getAttribute('value'),
|
||||
).toEqual('000000');
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-alpha-input input')?.getAttribute('value'),
|
||||
).toEqual('2%');
|
||||
|
||||
expect(handleColorChange).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('Should format change work', async () => {
|
||||
const { container } = render(<ColorPicker />);
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker-hex-input')).toBeTruthy();
|
||||
fireEvent.mouseDown(
|
||||
container.querySelector('.ant-color-picker-format-select .ant-select-selector')!,
|
||||
);
|
||||
await waitFakeTimer();
|
||||
fireEvent.click(container.querySelector('.ant-select-item[title="HSB"]')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker-hsb-input')).toBeTruthy();
|
||||
|
||||
fireEvent.mouseDown(
|
||||
container.querySelector('.ant-color-picker-format-select .ant-select-selector')!,
|
||||
);
|
||||
await waitFakeTimer();
|
||||
fireEvent.click(container.querySelector('.ant-select-item[title="RGB"]')!);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-color-picker-rgb-input')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Should hex input work', async () => {
|
||||
const { container } = render(<ColorPicker open format="hex" />);
|
||||
fireEvent.change(container.querySelector('.ant-color-picker-hex-input input')!, {
|
||||
target: { value: 631515 },
|
||||
});
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-color-block-inner')?.getAttribute('style'),
|
||||
).toEqual('background: rgb(99, 21, 21);');
|
||||
});
|
||||
|
||||
it('Should rgb input work', async () => {
|
||||
const { container } = render(<ColorPicker open format="rgb" />);
|
||||
const rgbInputEls = container.querySelectorAll('.ant-color-picker-rgb-input input');
|
||||
fireEvent.change(rgbInputEls[0], {
|
||||
target: { value: 99 },
|
||||
});
|
||||
fireEvent.change(rgbInputEls[1], {
|
||||
target: { value: 21 },
|
||||
});
|
||||
fireEvent.change(rgbInputEls[2], {
|
||||
target: { value: 21 },
|
||||
});
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-color-block-inner')?.getAttribute('style'),
|
||||
).toEqual('background: rgb(99, 21, 21);');
|
||||
});
|
||||
|
||||
it('Should hsb input work', async () => {
|
||||
const { container } = render(<ColorPicker open format="hsb" />);
|
||||
const hsbInputEls = container.querySelectorAll('.ant-color-picker-hsb-input input');
|
||||
fireEvent.change(hsbInputEls[0], {
|
||||
target: { value: 0 },
|
||||
});
|
||||
fireEvent.change(hsbInputEls[1], {
|
||||
target: { value: 78 },
|
||||
});
|
||||
fireEvent.change(hsbInputEls[2], {
|
||||
target: { value: 39 },
|
||||
});
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-color-block-inner')?.getAttribute('style'),
|
||||
).toEqual('background: rgb(99, 22, 22);');
|
||||
});
|
||||
});
|
45
components/color-picker/color.ts
Normal file
45
components/color-picker/color.ts
Normal file
@ -0,0 +1,45 @@
|
||||
/* eslint-disable class-methods-use-this */
|
||||
import type { ColorGenInput } from '@rc-component/color-picker';
|
||||
import { Color as RcColor } from '@rc-component/color-picker';
|
||||
import { getHex } from './util';
|
||||
|
||||
export interface Color
|
||||
extends Pick<
|
||||
RcColor,
|
||||
'toHsb' | 'toHsbString' | 'toHex' | 'toHexString' | 'toRgb' | 'toRgbString'
|
||||
> {}
|
||||
|
||||
export class ColorFactory {
|
||||
/** Original Color object */
|
||||
private metaColor: RcColor;
|
||||
|
||||
constructor(color: ColorGenInput<Color>) {
|
||||
this.metaColor = new RcColor(color as ColorGenInput);
|
||||
}
|
||||
|
||||
toHsb() {
|
||||
return this.metaColor.toHsb();
|
||||
}
|
||||
|
||||
toHsbString() {
|
||||
return this.metaColor.toHsbString();
|
||||
}
|
||||
|
||||
toHex() {
|
||||
return getHex(this.toHexString(), this.metaColor.getAlpha() < 1);
|
||||
}
|
||||
|
||||
toHexString() {
|
||||
return this.metaColor.getAlpha() === 1
|
||||
? this.metaColor.toHexString()
|
||||
: this.metaColor.toHex8String();
|
||||
}
|
||||
|
||||
toRgb() {
|
||||
return this.metaColor.toRgb();
|
||||
}
|
||||
|
||||
toRgbString() {
|
||||
return this.metaColor.toRgbString();
|
||||
}
|
||||
}
|
45
components/color-picker/components/ColorAlphaInput.tsx
Normal file
45
components/color-picker/components/ColorAlphaInput.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { Color } from '../color';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
import { generateColor, getAlphaColor } from '../util';
|
||||
import ColorSteppers from './ColorSteppers';
|
||||
|
||||
interface ColorAlphaInputProps extends Pick<ColorPickerBaseProps, 'prefixCls'> {
|
||||
value?: Color;
|
||||
onChange?: (value: Color) => void;
|
||||
}
|
||||
|
||||
const ColorAlphaInput: FC<ColorAlphaInputProps> = ({ prefixCls, value, onChange }) => {
|
||||
const colorAlphaInputPrefixCls = `${prefixCls}-alpha-input`;
|
||||
const [alphaValue, setAlphaValue] = useState(generateColor(value || '#000'));
|
||||
|
||||
// Update step value
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setAlphaValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleAlphaChange = (step: number) => {
|
||||
const hsba = alphaValue.toHsb();
|
||||
hsba.a = (step || 0) / 100;
|
||||
const genColor = generateColor(hsba);
|
||||
if (!value) {
|
||||
setAlphaValue(genColor);
|
||||
}
|
||||
onChange?.(genColor);
|
||||
};
|
||||
|
||||
return (
|
||||
<ColorSteppers
|
||||
value={getAlphaColor(alphaValue)}
|
||||
prefixCls={prefixCls}
|
||||
formatter={(step) => `${step}%`}
|
||||
className={colorAlphaInputPrefixCls}
|
||||
onChange={handleAlphaChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorAlphaInput;
|
24
components/color-picker/components/ColorClear.tsx
Normal file
24
components/color-picker/components/ColorClear.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import type { Color } from '../color';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
import { generateColor } from '../util';
|
||||
|
||||
interface ColorClearProps extends Pick<ColorPickerBaseProps, 'prefixCls'> {
|
||||
value?: Color;
|
||||
onChange?: (value: Color) => void;
|
||||
}
|
||||
|
||||
const ColorClear: FC<ColorClearProps> = ({ prefixCls, value, onChange }) => {
|
||||
const handleClick = () => {
|
||||
if (value) {
|
||||
const hsba = value.toHsb();
|
||||
hsba.a = 0;
|
||||
const genColor = generateColor(hsba);
|
||||
onChange?.(genColor);
|
||||
}
|
||||
};
|
||||
|
||||
return <div className={`${prefixCls}-clear`} onClick={handleClick} />;
|
||||
};
|
||||
export default ColorClear;
|
47
components/color-picker/components/ColorHexInput.tsx
Normal file
47
components/color-picker/components/ColorHexInput.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Input from '../../input';
|
||||
import type { Color } from '../color';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
import { generateColor, toHexFormat } from '../util';
|
||||
|
||||
interface ColorHexInputProps extends Pick<ColorPickerBaseProps, 'prefixCls'> {
|
||||
value?: Color;
|
||||
onChange?: (value: Color) => void;
|
||||
}
|
||||
|
||||
const hexReg = /(^#[\da-f]{6}$)|(^#[\da-f]{8}$)/i;
|
||||
const isHexString = (hex?: string) => hexReg.test(`#${hex}`);
|
||||
|
||||
const ColorHexInput: FC<ColorHexInputProps> = ({ prefixCls, value, onChange }) => {
|
||||
const colorHexInputPrefixCls = `${prefixCls}-hex-input`;
|
||||
const [hexValue, setHexValue] = useState(value?.toHex());
|
||||
|
||||
// Update step value
|
||||
useEffect(() => {
|
||||
const hex = value?.toHex();
|
||||
if (isHexString(hex) && value) {
|
||||
setHexValue(toHexFormat(hex));
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleHexChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const originValue = e.target.value;
|
||||
setHexValue(toHexFormat(originValue));
|
||||
if (isHexString(toHexFormat(originValue, true))) {
|
||||
onChange?.(generateColor(originValue));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Input
|
||||
className={colorHexInputPrefixCls}
|
||||
value={hexValue?.toUpperCase()}
|
||||
prefix="#"
|
||||
onChange={handleHexChange}
|
||||
size="small"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorHexInput;
|
69
components/color-picker/components/ColorHsbInput.tsx
Normal file
69
components/color-picker/components/ColorHsbInput.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import type { HSB } from '@rc-component/color-picker';
|
||||
import { getRoundNumber } from '@rc-component/color-picker/lib/util';
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { Color } from '../color';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
import { generateColor } from '../util';
|
||||
import ColorSteppers from './ColorSteppers';
|
||||
|
||||
interface ColorHsbInputProps extends Pick<ColorPickerBaseProps, 'prefixCls'> {
|
||||
value?: Color;
|
||||
onChange?: (value: Color) => void;
|
||||
}
|
||||
|
||||
const ColorHsbInput: FC<ColorHsbInputProps> = ({ prefixCls, value, onChange }) => {
|
||||
const colorHsbInputPrefixCls = `${prefixCls}-hsb-input`;
|
||||
const [hsbValue, setHsbValue] = useState(generateColor(value || '#000'));
|
||||
|
||||
// Update step value
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setHsbValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleHsbChange = (step: number, type: keyof HSB) => {
|
||||
const hsb = hsbValue.toHsb();
|
||||
hsb[type] = type === 'h' ? step : (step || 0) / 100;
|
||||
const genColor = generateColor(hsb);
|
||||
if (!value) {
|
||||
setHsbValue(genColor);
|
||||
}
|
||||
onChange?.(genColor);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={colorHsbInputPrefixCls}>
|
||||
<ColorSteppers
|
||||
max={360}
|
||||
min={0}
|
||||
value={Number(hsbValue.toHsb().h)}
|
||||
prefixCls={prefixCls}
|
||||
className={colorHsbInputPrefixCls}
|
||||
formatter={(step) => getRoundNumber(step || 0).toString()}
|
||||
onChange={(step) => handleHsbChange(Number(step), 'h')}
|
||||
/>
|
||||
<ColorSteppers
|
||||
max={100}
|
||||
min={0}
|
||||
value={Number(hsbValue.toHsb().s) * 100}
|
||||
prefixCls={prefixCls}
|
||||
className={colorHsbInputPrefixCls}
|
||||
formatter={(step) => `${getRoundNumber(step || 0)}%`}
|
||||
onChange={(step) => handleHsbChange(Number(step), 's')}
|
||||
/>
|
||||
<ColorSteppers
|
||||
max={100}
|
||||
min={0}
|
||||
value={Number(hsbValue.toHsb().b) * 100}
|
||||
prefixCls={prefixCls}
|
||||
className={colorHsbInputPrefixCls}
|
||||
formatter={(step) => `${getRoundNumber(step || 0)}%`}
|
||||
onChange={(step) => handleHsbChange(Number(step), 'b')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorHsbInput;
|
75
components/color-picker/components/ColorInput.tsx
Normal file
75
components/color-picker/components/ColorInput.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import Select from '../../select';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
import { ColorFormat } from '../interface';
|
||||
import type { Color } from '../color';
|
||||
import ColorAlphaInput from './ColorAlphaInput';
|
||||
import ColorHexInput from './ColorHexInput';
|
||||
import ColorHsbInput from './ColorHsbInput';
|
||||
import ColorRgbInput from './ColorRgbInput';
|
||||
|
||||
interface ColorInputProps
|
||||
extends Pick<ColorPickerBaseProps, 'prefixCls' | 'format' | 'onFormatChange'> {
|
||||
value?: Color;
|
||||
onChange?: (value: Color) => void;
|
||||
}
|
||||
|
||||
const ColorInput: FC<ColorInputProps> = (props) => {
|
||||
const { prefixCls, format, onFormatChange, value, onChange } = props;
|
||||
const [colorFormat, setColorFormat] = useMergedState('hex', {
|
||||
value: format,
|
||||
onChange: onFormatChange,
|
||||
});
|
||||
|
||||
const colorInputPrefixCls = `${prefixCls}-input`;
|
||||
|
||||
const handleFormatChange = (newFormat: ColorFormat) => {
|
||||
setColorFormat(newFormat);
|
||||
};
|
||||
|
||||
const steppersRender = () => {
|
||||
switch (colorFormat) {
|
||||
case ColorFormat.hsb:
|
||||
return <ColorHsbInput value={value} onChange={onChange} prefixCls={prefixCls} />;
|
||||
case ColorFormat.rgb:
|
||||
return <ColorRgbInput value={value} onChange={onChange} prefixCls={prefixCls} />;
|
||||
case ColorFormat.hex:
|
||||
default:
|
||||
return <ColorHexInput value={value} onChange={onChange} prefixCls={prefixCls} />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${colorInputPrefixCls}-container`}>
|
||||
<Select
|
||||
value={colorFormat}
|
||||
bordered={false}
|
||||
getPopupContainer={(current) => current}
|
||||
popupMatchSelectWidth={68}
|
||||
placement="bottomRight"
|
||||
onChange={handleFormatChange}
|
||||
className={`${prefixCls}-format-select`}
|
||||
size="small"
|
||||
options={[
|
||||
{
|
||||
label: ColorFormat.hex.toLocaleUpperCase(),
|
||||
value: ColorFormat.hex,
|
||||
},
|
||||
{
|
||||
label: ColorFormat.hsb.toLocaleUpperCase(),
|
||||
value: ColorFormat.hsb,
|
||||
},
|
||||
{
|
||||
label: ColorFormat.rgb.toLocaleUpperCase(),
|
||||
value: ColorFormat.rgb,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div className={colorInputPrefixCls}>{steppersRender()}</div>
|
||||
<ColorAlphaInput prefixCls={prefixCls} value={value} onChange={onChange} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ColorInput;
|
84
components/color-picker/components/ColorPresets.tsx
Normal file
84
components/color-picker/components/ColorPresets.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import classNames from 'classnames';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import type { FC } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { ColorBlock } from '@rc-component/color-picker';
|
||||
import Collapse from '../../collapse';
|
||||
import { useLocale } from '../../locale';
|
||||
import type { Color } from '../color';
|
||||
import type { ColorPickerBaseProps, PresetsItem } from '../interface';
|
||||
import { generateColor } from '../util';
|
||||
|
||||
const { Panel } = Collapse;
|
||||
|
||||
interface ColorPresetsProps extends Pick<ColorPickerBaseProps, 'prefixCls'> {
|
||||
presets: PresetsItem[];
|
||||
value?: Color;
|
||||
onChange?: (value: Color) => void;
|
||||
}
|
||||
|
||||
const genPresetColor = (list: PresetsItem[]) =>
|
||||
list.map((value) => {
|
||||
value.colors = value.colors.map((color) => generateColor(color));
|
||||
return value;
|
||||
});
|
||||
|
||||
const isBright = (value: Color) => {
|
||||
const { r, g, b, a } = value.toRgb();
|
||||
if (a <= 0.5) {
|
||||
return true;
|
||||
}
|
||||
return r * 0.299 + g * 0.587 + b * 0.114 > 192;
|
||||
};
|
||||
|
||||
const ColorPresets: FC<ColorPresetsProps> = ({ prefixCls, presets, value: color, onChange }) => {
|
||||
const [locale] = useLocale('ColorPicker');
|
||||
const [presetsValue] = useMergedState(genPresetColor(presets), {
|
||||
value: genPresetColor(presets),
|
||||
postState: (item) => genPresetColor(item),
|
||||
});
|
||||
const colorPresetsPrefixCls = `${prefixCls}-presets`;
|
||||
|
||||
const activeKey = useMemo(
|
||||
() => presetsValue.map((preset) => `panel-${preset.label}`),
|
||||
[presetsValue],
|
||||
);
|
||||
|
||||
const handleClick = (colorValue: Color) => {
|
||||
onChange?.(colorValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={colorPresetsPrefixCls}>
|
||||
<Collapse defaultActiveKey={activeKey} ghost>
|
||||
{presetsValue.map((preset) => (
|
||||
<Panel
|
||||
header={<div className={`${colorPresetsPrefixCls}-label`}>{preset?.label}</div>}
|
||||
key={`panel-${preset?.label}`}
|
||||
>
|
||||
<div className={`${colorPresetsPrefixCls}-items`}>
|
||||
{Array.isArray(preset?.colors) && preset?.colors.length > 0 ? (
|
||||
preset.colors.map((presetColor: Color) => (
|
||||
<ColorBlock
|
||||
key={`preset-${presetColor.toHexString()}`}
|
||||
color={generateColor(presetColor).toRgbString()}
|
||||
prefixCls={prefixCls}
|
||||
className={classNames(`${colorPresetsPrefixCls}-color`, {
|
||||
[`${colorPresetsPrefixCls}-color-checked`]:
|
||||
presetColor.toHexString() === color?.toHexString(),
|
||||
[`${colorPresetsPrefixCls}-color-bright`]: isBright(presetColor),
|
||||
})}
|
||||
onClick={() => handleClick(presetColor)}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<span className={`${colorPresetsPrefixCls}-empty`}>{locale.presetEmpty}</span>
|
||||
)}
|
||||
</div>
|
||||
</Panel>
|
||||
))}
|
||||
</Collapse>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ColorPresets;
|
65
components/color-picker/components/ColorRgbInput.tsx
Normal file
65
components/color-picker/components/ColorRgbInput.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import type { RGB } from '@rc-component/color-picker';
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { Color } from '../color';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
import { generateColor } from '../util';
|
||||
import ColorSteppers from './ColorSteppers';
|
||||
|
||||
interface ColorRgbInputProps extends Pick<ColorPickerBaseProps, 'prefixCls'> {
|
||||
value?: Color;
|
||||
onChange?: (value: Color) => void;
|
||||
}
|
||||
|
||||
const ColorRgbInput: FC<ColorRgbInputProps> = ({ prefixCls, value, onChange }) => {
|
||||
const colorRgbInputPrefixCls = `${prefixCls}-rgb-input`;
|
||||
const [rgbValue, setRgbValue] = useState(generateColor(value || '#000'));
|
||||
|
||||
// Update step value
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setRgbValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleRgbChange = (step: number | null, type: keyof RGB) => {
|
||||
const rgb = rgbValue.toRgb();
|
||||
rgb[type] = step || 0;
|
||||
const genColor = generateColor(rgb);
|
||||
if (!value) {
|
||||
setRgbValue(genColor);
|
||||
}
|
||||
onChange?.(genColor);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={colorRgbInputPrefixCls}>
|
||||
<ColorSteppers
|
||||
max={255}
|
||||
min={0}
|
||||
value={Number(rgbValue.toRgb().r)}
|
||||
prefixCls={prefixCls}
|
||||
className={colorRgbInputPrefixCls}
|
||||
onChange={(step) => handleRgbChange(Number(step), 'r')}
|
||||
/>
|
||||
<ColorSteppers
|
||||
max={255}
|
||||
min={0}
|
||||
value={Number(rgbValue.toRgb().g)}
|
||||
prefixCls={prefixCls}
|
||||
className={colorRgbInputPrefixCls}
|
||||
onChange={(step) => handleRgbChange(Number(step), 'g')}
|
||||
/>
|
||||
<ColorSteppers
|
||||
max={255}
|
||||
min={0}
|
||||
value={Number(rgbValue.toRgb().b)}
|
||||
prefixCls={prefixCls}
|
||||
className={colorRgbInputPrefixCls}
|
||||
onChange={(step) => handleRgbChange(Number(step), 'b')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorRgbInput;
|
55
components/color-picker/components/ColorSteppers.tsx
Normal file
55
components/color-picker/components/ColorSteppers.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import classNames from 'classnames';
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { InputNumberProps } from '../../input-number';
|
||||
import InputNumber from '../../input-number';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
|
||||
interface ColorSteppersProps extends Pick<ColorPickerBaseProps, 'prefixCls'> {
|
||||
value?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
onChange?: (value: number | null) => void;
|
||||
className?: string;
|
||||
prefix?: (prefixCls: string) => React.ReactNode;
|
||||
formatter?: InputNumberProps<number>['formatter'];
|
||||
}
|
||||
|
||||
const ColorSteppers: FC<ColorSteppersProps> = ({
|
||||
prefixCls,
|
||||
min = 0,
|
||||
max = 100,
|
||||
value,
|
||||
onChange,
|
||||
className,
|
||||
formatter,
|
||||
}) => {
|
||||
const colorSteppersPrefixCls = `${prefixCls}-steppers`;
|
||||
const [stepValue, setStepValue] = useState(value);
|
||||
|
||||
// Update step value
|
||||
useEffect(() => {
|
||||
if (!Number.isNaN(value)) {
|
||||
setStepValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<InputNumber
|
||||
className={classNames(colorSteppersPrefixCls, className)}
|
||||
min={min}
|
||||
max={max}
|
||||
value={stepValue}
|
||||
formatter={formatter}
|
||||
size="small"
|
||||
onChange={(step) => {
|
||||
if (!value) {
|
||||
setStepValue(step || 0);
|
||||
}
|
||||
onChange?.(step);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorSteppers;
|
46
components/color-picker/components/ColorTrigger.tsx
Normal file
46
components/color-picker/components/ColorTrigger.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import classNames from 'classnames';
|
||||
import type { CSSProperties, MouseEventHandler } from 'react';
|
||||
import React, { forwardRef, useMemo } from 'react';
|
||||
import { ColorBlock } from '@rc-component/color-picker';
|
||||
import type { ColorPickerBaseProps } from '../interface';
|
||||
import ColorClear from './ColorClear';
|
||||
|
||||
interface colorTriggerProps
|
||||
extends Pick<ColorPickerBaseProps, 'prefixCls' | 'clearColor' | 'disabled'> {
|
||||
color: Exclude<ColorPickerBaseProps['color'], undefined>;
|
||||
open?: boolean;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||
onMouseEnter?: MouseEventHandler<HTMLDivElement>;
|
||||
onMouseLeave?: MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const ColorTrigger = forwardRef<HTMLDivElement, colorTriggerProps>((props, ref) => {
|
||||
const { color, prefixCls, open, clearColor, disabled, className, ...rest } = props;
|
||||
const colorTriggerPrefixCls = `${prefixCls}-trigger`;
|
||||
|
||||
const containerRender = useMemo(
|
||||
() =>
|
||||
clearColor ? (
|
||||
<ColorClear prefixCls={prefixCls} />
|
||||
) : (
|
||||
<ColorBlock color={color.toRgbString()} prefixCls={prefixCls} />
|
||||
),
|
||||
[color, clearColor],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={classNames(colorTriggerPrefixCls, className, {
|
||||
[`${colorTriggerPrefixCls}-active`]: open,
|
||||
[`${colorTriggerPrefixCls}-disabled`]: disabled,
|
||||
})}
|
||||
{...rest}
|
||||
>
|
||||
{containerRender}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
export default ColorTrigger;
|
7
components/color-picker/demo/allowClear.md
Normal file
7
components/color-picker/demo/allowClear.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
清除已选择的颜色。
|
||||
|
||||
## en-US
|
||||
|
||||
Clear Color.
|
4
components/color-picker/demo/allowClear.tsx
Normal file
4
components/color-picker/demo/allowClear.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
import { ColorPicker } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export default () => <ColorPicker allowClear />;
|
7
components/color-picker/demo/base.md
Normal file
7
components/color-picker/demo/base.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
最简单的使用方法。
|
||||
|
||||
## en-US
|
||||
|
||||
Basic Usage.
|
10
components/color-picker/demo/base.tsx
Normal file
10
components/color-picker/demo/base.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { ColorPicker, theme } from 'antd';
|
||||
import type { Color } from 'antd/lib/color-picker';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export default () => {
|
||||
const { token } = theme.useToken();
|
||||
const [color, setColor] = useState<Color | string>(token.colorPrimary);
|
||||
|
||||
return <ColorPicker value={color} onChange={setColor} />;
|
||||
};
|
7
components/color-picker/demo/disabled.md
Normal file
7
components/color-picker/demo/disabled.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
设置为禁用状态。
|
||||
|
||||
## en-US
|
||||
|
||||
Set to disabled state.
|
4
components/color-picker/demo/disabled.tsx
Normal file
4
components/color-picker/demo/disabled.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
import { ColorPicker } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export default () => <ColorPicker disabled />;
|
7
components/color-picker/demo/format.md
Normal file
7
components/color-picker/demo/format.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
编码格式,支持`HEX`、`HSB`、`RGB`。
|
||||
|
||||
## en-US
|
||||
|
||||
Encoding formats, support `HEX`, `HSB`, `RGB`.
|
57
components/color-picker/demo/format.tsx
Normal file
57
components/color-picker/demo/format.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import { Col, ColorPicker, Row, Space } from 'antd';
|
||||
import type { Color } from 'antd/lib/color-picker';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
export default () => {
|
||||
const [colorHex, setColorHex] = useState<Color | string>('#1677ff');
|
||||
const [colorHsb, setColorHsb] = useState<Color | string>('hsb(215,91%,100%)');
|
||||
const [colorRgb, setColorRgb] = useState<Color | string>('rgb(22,119,255)');
|
||||
|
||||
const hexString = useMemo(
|
||||
() => (typeof colorHex === 'string' ? colorHex : colorHex.toHexString()),
|
||||
[colorHex],
|
||||
);
|
||||
const hsbString = useMemo(
|
||||
() => (typeof colorHsb === 'string' ? colorHsb : colorHsb.toHsbString()),
|
||||
[colorHsb],
|
||||
);
|
||||
const rgbString = useMemo(
|
||||
() => (typeof colorRgb === 'string' ? colorRgb : colorRgb.toRgbString()),
|
||||
[colorRgb],
|
||||
);
|
||||
|
||||
return (
|
||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||
<Row align="middle">
|
||||
<Space>
|
||||
<Col>
|
||||
<ColorPicker format="hex" value={colorHex} onChange={setColorHex} />
|
||||
</Col>
|
||||
<Col>
|
||||
HEX: <span>{hexString}</span>
|
||||
</Col>
|
||||
</Space>
|
||||
</Row>
|
||||
<Row align="middle">
|
||||
<Space>
|
||||
<Col>
|
||||
<ColorPicker format="hsb" value={colorHsb} onChange={setColorHsb} />
|
||||
</Col>
|
||||
<Col>
|
||||
HSB: <span>{hsbString}</span>
|
||||
</Col>
|
||||
</Space>
|
||||
</Row>
|
||||
<Row align="middle">
|
||||
<Space>
|
||||
<Col>
|
||||
<ColorPicker format="rgb" value={colorRgb} onChange={setColorRgb} />
|
||||
</Col>
|
||||
<Col>
|
||||
RGB: <span>{rgbString}</span>
|
||||
</Col>
|
||||
</Space>
|
||||
</Row>
|
||||
</Space>
|
||||
);
|
||||
};
|
7
components/color-picker/demo/presets.md
Normal file
7
components/color-picker/demo/presets.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
设置颜色选择器的预设颜色。
|
||||
|
||||
## en-US
|
||||
|
||||
Set the presets color of the color picker.
|
48
components/color-picker/demo/presets.tsx
Normal file
48
components/color-picker/demo/presets.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import { ColorPicker } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export default () => (
|
||||
<ColorPicker
|
||||
presets={[
|
||||
{
|
||||
label: 'Recommended',
|
||||
colors: [
|
||||
'#000000',
|
||||
'#000000E0',
|
||||
'#000000A6',
|
||||
'#00000073',
|
||||
'#00000040',
|
||||
'#00000026',
|
||||
'#0000001A',
|
||||
'#00000012',
|
||||
'#0000000A',
|
||||
'#00000005',
|
||||
'#F5222D',
|
||||
'#FA8C16',
|
||||
'#FADB14',
|
||||
'#8BBB11',
|
||||
'#52C41A',
|
||||
'#13A8A8',
|
||||
'#1677FF',
|
||||
'#2F54EB',
|
||||
'#722ED1',
|
||||
'#EB2F96',
|
||||
'#F5222D4D',
|
||||
'#FA8C164D',
|
||||
'#FADB144D',
|
||||
'#8BBB114D',
|
||||
'#52C41A4D',
|
||||
'#13A8A84D',
|
||||
'#1677FF4D',
|
||||
'#2F54EB4D',
|
||||
'#722ED14D',
|
||||
'#EB2F964D',
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Recent',
|
||||
colors: [],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
7
components/color-picker/demo/pure-panel.md
Normal file
7
components/color-picker/demo/pure-panel.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
Pure Panel
|
||||
|
||||
## en-US
|
||||
|
||||
Pure Panel
|
12
components/color-picker/demo/pure-panel.tsx
Normal file
12
components/color-picker/demo/pure-panel.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { ColorPicker, theme } from 'antd';
|
||||
import type { Color } from 'antd/lib/color-picker';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const PureRenderColorPicker = ColorPicker._InternalPanelDoNotUseOrYouWillBeFired;
|
||||
|
||||
export default () => {
|
||||
const { token } = theme.useToken();
|
||||
const [color, setColor] = useState<Color | string>(token.colorPrimary);
|
||||
|
||||
return <PureRenderColorPicker value={color} onChange={setColor} />;
|
||||
};
|
7
components/color-picker/demo/trigger.md
Normal file
7
components/color-picker/demo/trigger.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
自定义颜色面板的触发器。
|
||||
|
||||
## en-US
|
||||
|
||||
Triggers for customizing color panels.
|
28
components/color-picker/demo/trigger.tsx
Normal file
28
components/color-picker/demo/trigger.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { ColorPicker, Space, theme } from 'antd';
|
||||
import type { Color } from 'antd/lib/color-picker';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
export default () => {
|
||||
const { token } = theme.useToken();
|
||||
const [color, setColor] = useState<Color | string>(token.colorPrimary);
|
||||
const genColor = useMemo(
|
||||
() => (typeof color === 'string' ? color : color.toHexString()),
|
||||
[color],
|
||||
);
|
||||
|
||||
return (
|
||||
<ColorPicker value={color} onChange={setColor}>
|
||||
<Space>
|
||||
<div
|
||||
style={{
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 4,
|
||||
background: genColor,
|
||||
}}
|
||||
/>
|
||||
<span>{genColor}</span>
|
||||
</Space>
|
||||
</ColorPicker>
|
||||
);
|
||||
};
|
39
components/color-picker/hooks/useColorState.ts
Normal file
39
components/color-picker/hooks/useColorState.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { Color } from '../color';
|
||||
import { generateColor } from '../util';
|
||||
|
||||
function hasValue(value: Color | string | undefined) {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
const useColorState = (
|
||||
defaultStateValue: Color | string,
|
||||
option: {
|
||||
defaultValue?: Color | string;
|
||||
value?: Color | string;
|
||||
},
|
||||
): [Color, React.Dispatch<React.SetStateAction<Color>>] => {
|
||||
const { defaultValue, value } = option;
|
||||
const [colorValue, setColorValue] = useState(() => {
|
||||
let mergeState;
|
||||
if (hasValue(value)) {
|
||||
mergeState = value;
|
||||
} else if (hasValue(defaultValue)) {
|
||||
mergeState = defaultValue;
|
||||
} else {
|
||||
mergeState = defaultStateValue;
|
||||
}
|
||||
const genColor = generateColor(mergeState || '');
|
||||
return genColor;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setColorValue(generateColor(value));
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
return [colorValue, setColorValue];
|
||||
};
|
||||
|
||||
export default useColorState;
|
68
components/color-picker/index.en-US.md
Normal file
68
components/color-picker/index.en-US.md
Normal file
@ -0,0 +1,68 @@
|
||||
---
|
||||
category: Components
|
||||
title: ColorPicker
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*PpY4RYNM8UcAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*EHL-QYJofZsAAAAAAAAAAAAADrJ8AQ/original
|
||||
tag: New
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
title: Data Entry
|
||||
---
|
||||
|
||||
Components providing color selection
|
||||
|
||||
## When To Use
|
||||
|
||||
Used when the user needs to customize the color selection
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/base.tsx">Basic Usage</code>
|
||||
<code src="./demo/disabled.tsx" debug>Disable</code>
|
||||
<code src="./demo/allowClear.tsx">Clear Color</code>
|
||||
<code src="./demo/trigger.tsx">Custom Trigger</code>
|
||||
<code src="./demo/format.tsx">Color Format</code>
|
||||
<code src="./demo/presets.tsx">Preset Colors</code>
|
||||
<code src="./demo/pure-panel.tsx" debug>Pure Render</code>
|
||||
|
||||
## API
|
||||
|
||||
> This component is available since antd@5.5.0
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| Property | Description | Type | Default |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| format | Format of color | `rgb` \| `hex` \| `hsb` | `hex` |
|
||||
| onFormatChange | Callback when `format` is changed | `(format: 'hex' \| 'rgb' \| 'hsb') => void` | - |
|
||||
| value | Value of color | string \| `Color` | - |
|
||||
| defaultValue | Default value of color | string \| `Color` | - |
|
||||
| onChange | Callback when `value` is changed | `(value: Color, hex: string) => void` | - |
|
||||
| allowClear | Allow clearing color selected | boolean | false |
|
||||
| presets | Preset colors | `{ label: ReactNode, colors: Array<string \| Color> }[]` | - |
|
||||
| children | Trigger of ColorPicker | ReactElement | - |
|
||||
| trigger | ColorPicker trigger mode | `hover` \| `click` | `click` |
|
||||
| open | Whether to show popup | boolean | - |
|
||||
| onOpenChange | Callback when `open` is changed | `(open: boolean) => void` | - |
|
||||
| disabled | Disable ColorPicker | boolean | - |
|
||||
| placement | Placement of popup | `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | `bottomLeft` |
|
||||
| arrow | Configuration for popup arrow | boolean | `{ pointAtCenter: boolean }` | - |
|
||||
|
||||
### Color
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| Property | Description | Type | Default |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| toHex | Convert to `hex` format characters | `() => string` | - |
|
||||
| toHexString | Convert to `hex` format color string | `() => string` | - |
|
||||
| toHsb | Convert to `hsb` object | `() => ({ h: number, s: number, b: number, a number })` | - |
|
||||
| toHsbString | Convert to `hsb` format color string | `() => string` | - |
|
||||
| toRgb | Convert to `rgb` object | `() => ({ r: number, g: number, b: number, a number })` | - |
|
||||
| toRgbString | Convert to `rgb` format color string | `() => string` | - |
|
||||
|
||||
## FAQ
|
||||
|
||||
### Questions about color assignment
|
||||
|
||||
The value of the color selector supports both string color values and selector-generated `Color` objects. However, since there is a precision error when converting color strings of different formats to each other, it is recommended to use selector-generated `Color` objects for assignment operations in controlled scenarios, so that the precision problem can be avoided and the values are guaranteed to be accurate and the selector can work as expected.
|
6
components/color-picker/index.tsx
Normal file
6
components/color-picker/index.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import ColorPicker from './ColorPicker';
|
||||
|
||||
export type { Color } from './color';
|
||||
export type { ColorPickerProps } from './ColorPicker';
|
||||
|
||||
export default ColorPicker;
|
69
components/color-picker/index.zh-CN.md
Normal file
69
components/color-picker/index.zh-CN.md
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 颜色选择器
|
||||
title: ColorPicker
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*PpY4RYNM8UcAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*EHL-QYJofZsAAAAAAAAAAAAADrJ8AQ/original
|
||||
tag: 新
|
||||
demo:
|
||||
cols: 2
|
||||
group:
|
||||
title: 数据录入
|
||||
---
|
||||
|
||||
提供颜色选取的组件
|
||||
|
||||
## 何时使用
|
||||
|
||||
当用户需要自定义颜色选择的时候使用。
|
||||
|
||||
## 代码演示
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/base.tsx">基本使用</code>
|
||||
<code src="./demo/disabled.tsx" debug>禁用</code>
|
||||
<code src="./demo/allowClear.tsx">清除颜色</code>
|
||||
<code src="./demo/trigger.tsx">自定义触发器</code>
|
||||
<code src="./demo/format.tsx">颜色编码</code>
|
||||
<code src="./demo/presets.tsx">预设颜色</code>
|
||||
<code src="./demo/pure-panel.tsx" debug>Pure Render</code>
|
||||
|
||||
## API
|
||||
|
||||
> 自 `antd@5.5.0` 版本开始提供该组件。
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| format | 颜色格式 | `rgb` \| `hex` \| `hsb` | `hex` |
|
||||
| onFormatChange | 颜色格式变化的回调 | `(format: 'hex' \| 'rgb' \| 'hsb') => void` | - |
|
||||
| value | 颜色的值 | string \| `Color` | - |
|
||||
| defaultValue | 颜色默认的值 | string \| `Color` | - |
|
||||
| onChange | 颜色变化的回调 | `(value: Color, hex: string) => void` | - |
|
||||
| allowClear | 允许清除选择的颜色 | boolean | false |
|
||||
| presets | 预设的颜色 | `{ label: ReactNode, colors: Array<string \| Color> }[]` | - |
|
||||
| children | 颜色选择器的触发器 | ReactElement | - |
|
||||
| trigger | 颜色选择器的触发模式 | `hover` \| `click` | `click` |
|
||||
| open | 是否显示弹出窗口 | boolean | - |
|
||||
| onOpenChange | 当 `open` 被改变时的回调 | `(open: boolean) => void` | - |
|
||||
| disabled | 禁用颜色选择器 | boolean | - |
|
||||
| placement | 弹出窗口的位置 | `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | `bottomLeft` |
|
||||
| arrow | 配置弹出的箭头 | boolean | `{ pointAtCenter: boolean }` | - |
|
||||
|
||||
### Color
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| toHex | 转换成 `hex` 格式字符 | `() => string` | - |
|
||||
| toHexString | 转换成 `hex` 格式颜色字符串 | `() => string` | - |
|
||||
| toHsb | 转换成 `hsb` 对象 | `() => ({ h: number, s: number, b: number, a number })` | - |
|
||||
| toHsbString | 转换成 `hsb` 格式颜色字符串 | `() => string` | - |
|
||||
| toRgb | 转换成 `rgb` 对象 | `() => ({ r: number, g: number, b: number, a number })` | - |
|
||||
| toRgbString | 转换成 `rgb` 格式颜色字符串 | `() => string` | - |
|
||||
|
||||
## FAQ
|
||||
|
||||
### 关于颜色赋值的问题
|
||||
|
||||
颜色选择器的值同时支持字符串色值和选择器生成的 `Color` 对象,但由于不同格式的颜色字符串互相转换会有精度误差问题,所以受控场景推荐使用选择器生成的 `Color` 对象来进行赋值操作,这样可以避免精度问题,保证取值是精准的,选择器也可以按照预期工作。
|
22
components/color-picker/interface.ts
Normal file
22
components/color-picker/interface.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ColorPickerProps } from './ColorPicker';
|
||||
import type { Color } from './color';
|
||||
|
||||
export enum ColorFormat {
|
||||
hex = 'hex',
|
||||
rgb = 'rgb',
|
||||
hsb = 'hsb',
|
||||
}
|
||||
|
||||
export type PresetsItem = { label: ReactNode; colors: Array<string | Color> };
|
||||
|
||||
export interface ColorPickerBaseProps {
|
||||
color?: Color;
|
||||
prefixCls: string;
|
||||
format?: keyof typeof ColorFormat;
|
||||
allowClear?: boolean;
|
||||
clearColor?: boolean;
|
||||
disabled?: boolean;
|
||||
presets?: PresetsItem[];
|
||||
onFormatChange?: ColorPickerProps['onFormatChange'];
|
||||
}
|
27
components/color-picker/style/color-block.ts
Normal file
27
components/color-picker/style/color-block.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import type { ColorPickerToken } from './index';
|
||||
|
||||
const genColorBlockStyle = (token: ColorPickerToken, size: number): CSSObject => {
|
||||
const { componentCls, borderRadiusSM, colorPickerInsetShadow, lineWidth, colorFillSecondary } =
|
||||
token;
|
||||
return {
|
||||
[`${componentCls}-color-block`]: {
|
||||
position: 'relative',
|
||||
borderRadius: borderRadiusSM,
|
||||
width: size,
|
||||
height: size,
|
||||
boxShadow: colorPickerInsetShadow,
|
||||
backgroundSize: '100%',
|
||||
backgroundImage:
|
||||
'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAFpJREFUWAntljEKADAIA23p6v//qQ+wfUEcCu1yriEgp0FHRJSJcnehmmWm1Dv/lO4HIg1AAAKjTqm03ea88zMCCEDgO4HV5bS757f+7wRoAAIQ4B9gByAAgQ3pfiDmXmAeEwAAAABJRU5ErkJggg==")',
|
||||
[`${componentCls}-color-block-inner`]: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
border: `${lineWidth}px solid ${colorFillSecondary}`,
|
||||
borderRadius: 'inherit',
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genColorBlockStyle;
|
153
components/color-picker/style/index.ts
Normal file
153
components/color-picker/style/index.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import genPickerStyle from './picker';
|
||||
import genInputStyle from './input';
|
||||
import genPresetsStyle from './presets';
|
||||
import genColorBlockStyle from './color-block';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
export interface ColorPickerToken extends FullToken<'ColorPicker'> {
|
||||
colorPickerWidth: number;
|
||||
colorPickerInsetShadow: string;
|
||||
colorPickerHandlerSize: number;
|
||||
colorPickerHandlerSizeSM: number;
|
||||
colorPickerSliderHeight: number;
|
||||
colorPickerPreviewSize: number;
|
||||
colorPickerAlphaInputWidth: number;
|
||||
colorPickerInputNumberHandleWidth: number;
|
||||
colorPickerPresetColorSize: number;
|
||||
}
|
||||
|
||||
export const genActiveStyle = (token: ColorPickerToken) => ({
|
||||
boxShadow: `0 0 0 ${token.controlOutlineWidth}px ${token.controlOutline}`,
|
||||
borderInlineEndWidth: token.lineWidth,
|
||||
outline: 0,
|
||||
});
|
||||
|
||||
const genClearStyle = (token: ColorPickerToken, size: number): CSSObject => {
|
||||
const { componentCls, borderRadiusSM, lineWidth, colorSplit, red6 } = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-clear`]: {
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius: borderRadiusSM,
|
||||
border: `${lineWidth}px solid ${colorSplit}`,
|
||||
position: 'relative',
|
||||
cursor: 'pointer',
|
||||
overflow: 'hidden',
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
insetInlineEnd: lineWidth,
|
||||
top: 0,
|
||||
display: 'block',
|
||||
width: 40, // maximum
|
||||
height: 2, // fixed
|
||||
transformOrigin: 'right',
|
||||
transform: 'rotate(-45deg)',
|
||||
backgroundColor: red6,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const genColorPickerStyle: GenerateStyle<ColorPickerToken> = (token) => {
|
||||
const {
|
||||
componentCls,
|
||||
colorPickerWidth,
|
||||
colorPrimary,
|
||||
motionDurationMid,
|
||||
colorBgElevated,
|
||||
colorTextDisabled,
|
||||
colorBgContainerDisabled,
|
||||
borderRadius,
|
||||
marginXS,
|
||||
marginSM,
|
||||
controlHeight,
|
||||
controlHeightSM,
|
||||
colorBgTextActive,
|
||||
colorPickerPresetColorSize,
|
||||
lineWidth,
|
||||
colorBorder,
|
||||
} = token;
|
||||
|
||||
return [
|
||||
{
|
||||
[componentCls]: {
|
||||
[`${componentCls}-panel`]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: colorPickerWidth,
|
||||
|
||||
[`${componentCls}-inner-panel`]: {
|
||||
[`${componentCls}-clear`]: {
|
||||
marginInlineStart: 'auto',
|
||||
marginBottom: marginXS,
|
||||
},
|
||||
'&-divider': {
|
||||
margin: `${marginSM}px 0 ${marginXS}px`,
|
||||
},
|
||||
},
|
||||
|
||||
...genPickerStyle(token),
|
||||
...genInputStyle(token),
|
||||
...genPresetsStyle(token),
|
||||
...genClearStyle(token, colorPickerPresetColorSize),
|
||||
},
|
||||
|
||||
'&-trigger': {
|
||||
width: controlHeight,
|
||||
height: controlHeight,
|
||||
borderRadius,
|
||||
border: `${lineWidth}px solid ${colorBorder}`,
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
transition: `all ${motionDurationMid}`,
|
||||
background: colorBgElevated,
|
||||
'&-active': {
|
||||
...genActiveStyle(token),
|
||||
borderColor: colorPrimary,
|
||||
},
|
||||
'&:hover': {
|
||||
borderColor: colorPrimary,
|
||||
},
|
||||
'&-disabled': {
|
||||
color: colorTextDisabled,
|
||||
background: colorBgContainerDisabled,
|
||||
cursor: 'not-allowed',
|
||||
'&:hover': {
|
||||
borderColor: colorBgTextActive,
|
||||
},
|
||||
},
|
||||
...genClearStyle(token, controlHeightSM),
|
||||
...genColorBlockStyle(token, controlHeightSM),
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export default genComponentStyleHook('ColorPicker', (token) => {
|
||||
const { colorTextQuaternary, marginSM } = token;
|
||||
|
||||
const colorPickerSliderHeight = 8;
|
||||
|
||||
const ColorPickerToken = mergeToken<ColorPickerToken>(token, {
|
||||
colorPickerWidth: 234,
|
||||
colorPickerHandlerSize: 16,
|
||||
colorPickerHandlerSizeSM: 12,
|
||||
colorPickerAlphaInputWidth: 44,
|
||||
colorPickerInputNumberHandleWidth: 16,
|
||||
colorPickerPresetColorSize: 18,
|
||||
colorPickerInsetShadow: `inset 0 0 1px 0 ${colorTextQuaternary}`,
|
||||
colorPickerSliderHeight,
|
||||
colorPickerPreviewSize: colorPickerSliderHeight * 2 + marginSM,
|
||||
});
|
||||
|
||||
return [genColorPickerStyle(ColorPickerToken)];
|
||||
});
|
99
components/color-picker/style/input.ts
Normal file
99
components/color-picker/style/input.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
import type { ColorPickerToken } from './index';
|
||||
|
||||
const genInputStyle: GenerateStyle<ColorPickerToken, CSSObject> = (token) => {
|
||||
const {
|
||||
componentCls,
|
||||
antCls,
|
||||
fontSizeSM,
|
||||
lineHeightSM,
|
||||
colorPickerAlphaInputWidth,
|
||||
marginXXS,
|
||||
paddingXXS,
|
||||
controlHeightSM,
|
||||
marginXS,
|
||||
fontSizeIcon,
|
||||
paddingXS,
|
||||
colorTextPlaceholder,
|
||||
colorPickerInputNumberHandleWidth,
|
||||
lineWidth,
|
||||
} = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-input-container`]: {
|
||||
display: 'flex',
|
||||
[`${componentCls}-steppers${antCls}-input-number`]: {
|
||||
fontSize: fontSizeSM,
|
||||
lineHeight: lineHeightSM,
|
||||
[`${antCls}-input-number-input`]: {
|
||||
paddingInlineStart: paddingXXS,
|
||||
paddingInlineEnd: 0,
|
||||
},
|
||||
[`${antCls}-input-number-handler-wrap`]: {
|
||||
width: colorPickerInputNumberHandleWidth,
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-steppers${componentCls}-alpha-input`]: {
|
||||
flex: `0 0 ${colorPickerAlphaInputWidth}px`,
|
||||
marginInlineStart: marginXXS,
|
||||
},
|
||||
|
||||
[`${componentCls}-format-select${antCls}-select`]: {
|
||||
marginInlineEnd: marginXS,
|
||||
'&-single': {
|
||||
[`${antCls}-select-selector`]: {
|
||||
padding: 0,
|
||||
border: 0,
|
||||
},
|
||||
[`${antCls}-select-arrow`]: {
|
||||
insetInlineEnd: 0,
|
||||
},
|
||||
[`${antCls}-select-selection-item`]: {
|
||||
paddingInlineEnd: fontSizeIcon + marginXXS,
|
||||
fontSize: fontSizeSM,
|
||||
lineHeight: `${controlHeightSM}px`,
|
||||
},
|
||||
[`${antCls}-select-item-option-content`]: {
|
||||
fontSize: fontSizeSM,
|
||||
lineHeight: lineHeightSM,
|
||||
},
|
||||
[`${antCls}-select-dropdown`]: {
|
||||
[`${antCls}-select-item`]: {
|
||||
minHeight: 'auto',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-input`]: {
|
||||
gap: marginXXS,
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
width: 0,
|
||||
[`${componentCls}-hsb-input,${componentCls}-rgb-input`]: {
|
||||
display: 'flex',
|
||||
gap: marginXXS,
|
||||
alignItems: 'center',
|
||||
},
|
||||
[`${componentCls}-steppers`]: {
|
||||
flex: 1,
|
||||
},
|
||||
[`${componentCls}-hex-input${antCls}-input-affix-wrapper`]: {
|
||||
flex: 1,
|
||||
padding: `0 ${paddingXS}px`,
|
||||
[`${antCls}-input`]: {
|
||||
fontSize: fontSizeSM,
|
||||
lineHeight: `${controlHeightSM - 2 * lineWidth}px`,
|
||||
},
|
||||
[`${antCls}-input-prefix`]: {
|
||||
color: colorTextPlaceholder,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genInputStyle;
|
80
components/color-picker/style/picker.ts
Normal file
80
components/color-picker/style/picker.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
import type { ColorPickerToken } from './index';
|
||||
import genColorBlockStyle from './color-block';
|
||||
|
||||
const genPickerStyle: GenerateStyle<ColorPickerToken, CSSObject> = (token) => {
|
||||
const {
|
||||
componentCls,
|
||||
controlHeightLG,
|
||||
borderRadiusSM,
|
||||
colorPickerInsetShadow,
|
||||
marginSM,
|
||||
colorBgElevated,
|
||||
colorFillSecondary,
|
||||
lineWidthBold,
|
||||
colorPickerHandlerSize,
|
||||
colorPickerHandlerSizeSM,
|
||||
colorPickerSliderHeight,
|
||||
colorPickerPreviewSize,
|
||||
} = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-select`]: {
|
||||
[`${componentCls}-palette`]: {
|
||||
minHeight: controlHeightLG * 4,
|
||||
overflow: 'hidden',
|
||||
borderRadius: borderRadiusSM,
|
||||
},
|
||||
[`${componentCls}-saturation`]: {
|
||||
position: 'absolute',
|
||||
borderRadius: 'inherit',
|
||||
boxShadow: colorPickerInsetShadow,
|
||||
inset: 0,
|
||||
},
|
||||
marginBottom: marginSM,
|
||||
},
|
||||
|
||||
[`${componentCls}-handler`]: {
|
||||
width: colorPickerHandlerSize,
|
||||
height: colorPickerHandlerSize,
|
||||
border: `${lineWidthBold}px solid ${colorBgElevated}`,
|
||||
position: 'relative',
|
||||
borderRadius: '50%',
|
||||
boxShadow: `${colorPickerInsetShadow}, 0 0 0 1px ${colorFillSecondary}`,
|
||||
'&-sm': {
|
||||
width: colorPickerHandlerSizeSM,
|
||||
height: colorPickerHandlerSizeSM,
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-slider`]: {
|
||||
borderRadius: colorPickerSliderHeight / 2,
|
||||
[`${componentCls}-palette`]: {
|
||||
height: colorPickerSliderHeight,
|
||||
},
|
||||
[`${componentCls}-gradient`]: {
|
||||
borderRadius: colorPickerSliderHeight / 2,
|
||||
boxShadow: colorPickerInsetShadow,
|
||||
},
|
||||
'&-alpha': {
|
||||
backgroundSize: colorPickerSliderHeight * 2,
|
||||
backgroundImage:
|
||||
'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAFpJREFUWAntljEKADAIA23p6v//qQ+wfUEcCu1yriEgp0FHRJSJcnehmmWm1Dv/lO4HIg1AAAKjTqm03ea88zMCCEDgO4HV5bS757f+7wRoAAIQ4B9gByAAgQ3pfiDmXmAeEwAAAABJRU5ErkJggg==")',
|
||||
},
|
||||
marginBottom: marginSM,
|
||||
},
|
||||
|
||||
[`${componentCls}-slider-container`]: {
|
||||
display: 'flex',
|
||||
gap: marginSM,
|
||||
[`${componentCls}-slider-group`]: {
|
||||
flex: 1,
|
||||
},
|
||||
},
|
||||
|
||||
...genColorBlockStyle(token, colorPickerPreviewSize),
|
||||
};
|
||||
};
|
||||
|
||||
export default genPickerStyle;
|
113
components/color-picker/style/presets.ts
Normal file
113
components/color-picker/style/presets.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
import type { ColorPickerToken } from './index';
|
||||
|
||||
const genPresetsStyle: GenerateStyle<ColorPickerToken, CSSObject> = (token) => {
|
||||
const {
|
||||
componentCls,
|
||||
antCls,
|
||||
colorTextQuaternary,
|
||||
paddingXXS,
|
||||
colorPickerPresetColorSize,
|
||||
fontSizeSM,
|
||||
colorText,
|
||||
lineHeightSM,
|
||||
lineWidth,
|
||||
borderRadius,
|
||||
colorFill,
|
||||
colorWhite,
|
||||
colorTextTertiary,
|
||||
marginXXS,
|
||||
paddingXS,
|
||||
} = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-presets`]: {
|
||||
[`${antCls}-collapse-item > ${antCls}-collapse-header`]: {
|
||||
padding: 0,
|
||||
[`${antCls}-collapse-expand-icon`]: {
|
||||
height: fontSizeSM * lineHeightSM,
|
||||
color: colorTextQuaternary,
|
||||
paddingInlineEnd: paddingXXS,
|
||||
},
|
||||
},
|
||||
[`${antCls}-collapse`]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: marginXXS,
|
||||
},
|
||||
[`${antCls}-collapse-item > ${antCls}-collapse-content > ${antCls}-collapse-content-box`]: {
|
||||
padding: `${paddingXS}px 0`,
|
||||
},
|
||||
'&-label': {
|
||||
fontSize: fontSizeSM,
|
||||
color: colorText,
|
||||
lineHeight: lineHeightSM,
|
||||
},
|
||||
'&-items': {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: marginXXS * 1.5,
|
||||
[`${componentCls}-presets-color`]: {
|
||||
position: 'relative',
|
||||
cursor: 'pointer',
|
||||
width: colorPickerPresetColorSize,
|
||||
height: colorPickerPresetColorSize,
|
||||
|
||||
'&::before': {
|
||||
content: '""',
|
||||
pointerEvents: 'none',
|
||||
width: colorPickerPresetColorSize + 4 * lineWidth,
|
||||
height: colorPickerPresetColorSize + 4 * lineWidth,
|
||||
position: 'absolute',
|
||||
top: -2 * lineWidth,
|
||||
insetInlineStart: -2 * lineWidth,
|
||||
borderRadius,
|
||||
border: `${lineWidth}px solid transparent`,
|
||||
transition: `border-color ${token.motionDurationMid} ${token.motionEaseInBack}`,
|
||||
},
|
||||
'&:hover::before': {
|
||||
borderColor: colorFill,
|
||||
},
|
||||
|
||||
'&::after': {
|
||||
boxSizing: 'border-box',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
insetInlineStart: '21.5%',
|
||||
display: 'table',
|
||||
width: (colorPickerPresetColorSize / 13) * 5,
|
||||
height: (colorPickerPresetColorSize / 13) * 8,
|
||||
border: `${token.lineWidthBold}px solid ${token.colorWhite}`,
|
||||
borderTop: 0,
|
||||
borderInlineStart: 0,
|
||||
transform: 'rotate(45deg) scale(0) translate(-50%,-50%)',
|
||||
opacity: 0,
|
||||
content: '""',
|
||||
transition: `all ${token.motionDurationFast} ${token.motionEaseInBack}, opacity ${token.motionDurationFast}`,
|
||||
},
|
||||
|
||||
[`&${componentCls}-presets-color-checked`]: {
|
||||
'&::after': {
|
||||
opacity: 1,
|
||||
borderColor: colorWhite,
|
||||
transform: 'rotate(45deg) scale(1) translate(-50%,-50%)',
|
||||
transition: `transform ${token.motionDurationMid} ${token.motionEaseOutBack} ${token.motionDurationFast}`,
|
||||
},
|
||||
[`&${componentCls}-presets-color-bright`]: {
|
||||
'&::after': {
|
||||
borderColor: colorTextTertiary,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'&-empty': {
|
||||
fontSize: fontSizeSM,
|
||||
color: colorTextQuaternary,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genPresetsStyle;
|
20
components/color-picker/util.ts
Normal file
20
components/color-picker/util.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import type { ColorGenInput } from '@rc-component/color-picker';
|
||||
import { getRoundNumber } from '@rc-component/color-picker/lib/util';
|
||||
import type { Color } from './color';
|
||||
import { ColorFactory } from './color';
|
||||
|
||||
export const customizePrefixCls = 'ant-color-picker';
|
||||
|
||||
export const generateColor = (color: ColorGenInput<Color>): Color => {
|
||||
if (color instanceof ColorFactory) {
|
||||
return color;
|
||||
}
|
||||
return new ColorFactory(color);
|
||||
};
|
||||
|
||||
export const getAlphaColor = (color: Color) => getRoundNumber(color.toHsb().a * 100);
|
||||
|
||||
export const toHexFormat = (value?: string, alpha?: boolean) =>
|
||||
value?.replace(/[^\w/]/gi, '').slice(0, alpha ? 8 : 6) || '';
|
||||
|
||||
export const getHex = (value?: string, alpha?: boolean) => (value ? toHexFormat(value, alpha) : '');
|
22
components/config-provider/MotionWrapper.tsx
Normal file
22
components/config-provider/MotionWrapper.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Provider as MotionProvider } from 'rc-motion';
|
||||
import * as React from 'react';
|
||||
import { useToken } from '../theme/internal';
|
||||
|
||||
export interface MotionWrapperProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function MotionWrapper(props: MotionWrapperProps): React.ReactElement {
|
||||
const { children } = props;
|
||||
const [, token] = useToken();
|
||||
const { motion } = token;
|
||||
|
||||
const needWrapMotionProviderRef = React.useRef(false);
|
||||
needWrapMotionProviderRef.current = needWrapMotionProviderRef.current || motion === false;
|
||||
|
||||
if (needWrapMotionProviderRef.current) {
|
||||
return <MotionProvider motion={motion}>{children}</MotionProvider>;
|
||||
}
|
||||
|
||||
return children as React.ReactElement;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,532 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ConfigProvider.Popup disable virtual if dropdownMatchSelectWidth is false 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider.Popup disable virtual if is false 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider.Popup disable virtual if popupMatchSelectWidth is false 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow ant-select-open"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_TEST_OR_SSR_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_TEST_OR_SSR"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -122,15 +122,6 @@ describe('ConfigProvider', () => {
|
||||
);
|
||||
expect(isArray ? container.children : container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('configProvider virtual and dropdownMatchSelectWidth', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider virtual={false} dropdownMatchSelectWidth={false}>
|
||||
{renderComponent({})}
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(isArray ? container.children : container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
111
components/config-provider/__tests__/popup.test.tsx
Normal file
111
components/config-provider/__tests__/popup.test.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import type { TriggerProps } from '@rc-component/trigger';
|
||||
import dayjs from 'dayjs';
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
import React from 'react';
|
||||
import ConfigProvider from '..';
|
||||
import { render } from '../../../tests/utils';
|
||||
import Cascader from '../../cascader';
|
||||
import Select from '../../select';
|
||||
import TreeSelect from '../../tree-select';
|
||||
|
||||
dayjs.extend(customParseFormat);
|
||||
jest.mock('rc-util/lib/Portal');
|
||||
|
||||
function triggerProps(): TriggerProps {
|
||||
return (global as any).triggerProps;
|
||||
}
|
||||
|
||||
jest.mock('@rc-component/trigger', () => {
|
||||
const R = jest.requireActual('react');
|
||||
const Trigger = jest.requireActual('@rc-component/trigger').default;
|
||||
return R.forwardRef((props: any, ref: any) => {
|
||||
(global as any).triggerProps = props;
|
||||
return <Trigger {...props} ref={ref} />;
|
||||
});
|
||||
});
|
||||
|
||||
describe('ConfigProvider.Popup', () => {
|
||||
beforeEach(() => {
|
||||
(global as any).triggerProps = null;
|
||||
});
|
||||
|
||||
const selectLikeNodes = (
|
||||
<>
|
||||
<Select
|
||||
open
|
||||
options={new Array(20).fill(null).map((_, index) => ({ value: index, label: index }))}
|
||||
/>
|
||||
<TreeSelect
|
||||
open
|
||||
treeData={new Array(20).fill(null).map((_, index) => ({ value: index, title: index }))}
|
||||
/>
|
||||
<Cascader
|
||||
open
|
||||
options={new Array(20).fill(null).map((_, index) => ({ value: index, label: index }))}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
it('disable virtual if is false', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider virtual={false}>{selectLikeNodes}</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('disable virtual if dropdownMatchSelectWidth is false', () => {
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const { container } = render(
|
||||
<ConfigProvider dropdownMatchSelectWidth={false}>{selectLikeNodes}</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: ConfigProvider] `dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
|
||||
);
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('disable virtual if popupMatchSelectWidth is false', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider popupMatchSelectWidth={false}>{selectLikeNodes}</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('config popupOverflow', () => {
|
||||
it('Select', () => {
|
||||
render(
|
||||
<ConfigProvider popupOverflow="scroll">
|
||||
<Select open />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(triggerProps().builtinPlacements!.topLeft!.htmlRegion).toBe('scroll');
|
||||
});
|
||||
|
||||
it('TreeSelect', () => {
|
||||
render(
|
||||
<ConfigProvider popupOverflow="scroll">
|
||||
<TreeSelect open />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(triggerProps().builtinPlacements!.topLeft!.htmlRegion).toBe('scroll');
|
||||
});
|
||||
|
||||
it('Cascader', () => {
|
||||
render(
|
||||
<ConfigProvider popupOverflow="scroll">
|
||||
<Cascader open />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(triggerProps().builtinPlacements!.topLeft!.htmlRegion).toBe('scroll');
|
||||
});
|
||||
});
|
||||
});
|
@ -34,6 +34,8 @@ export interface ThemeConfig {
|
||||
inherit?: boolean;
|
||||
}
|
||||
|
||||
export type PopupOverflow = 'viewport' | 'scroll';
|
||||
|
||||
export interface ConfigConsumerProps {
|
||||
getTargetContainer?: () => HTMLElement;
|
||||
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
|
||||
@ -58,7 +60,8 @@ export interface ConfigConsumerProps {
|
||||
size?: SizeType | number;
|
||||
};
|
||||
virtual?: boolean;
|
||||
dropdownMatchSelectWidth?: boolean;
|
||||
popupMatchSelectWidth?: boolean;
|
||||
popupOverflow?: PopupOverflow;
|
||||
form?: {
|
||||
requiredMark?: RequiredMark;
|
||||
colon?: boolean;
|
||||
|
@ -55,7 +55,8 @@ Some components use dynamic style to support wave effect. You can config `csp` p
|
||||
| componentSize | Config antd component size | `small` \| `middle` \| `large` | - | |
|
||||
| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | |
|
||||
| direction | Set direction of layout. See [demo](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
|
||||
| dropdownMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 4.3.0 |
|
||||
| popupMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 5.5.0 |
|
||||
| popupOverflow | Select like component popup logic. Can set to show in viewport or follow window scroll | 'viewport' \| 'scroll' <InlinePopover previewURL="https://user-images.githubusercontent.com/5378891/230344474-5b9f7e09-0a5d-49e8-bae8-7d2abed6c837.png"></InlinePopover> | 'viewport' | 5.5.0 |
|
||||
| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) } | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0 |
|
||||
| getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | function(triggerNode) | () => document.body | |
|
||||
| getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 |
|
||||
|
@ -7,6 +7,7 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
|
||||
import type { ReactElement } from 'react';
|
||||
import * as React from 'react';
|
||||
import type { Options } from 'scroll-into-view-if-needed';
|
||||
import warning from '../_util/warning';
|
||||
import type { RequiredMark } from '../form/Form';
|
||||
import type { Locale } from '../locale';
|
||||
import LocaleProvider, { ANT_MARK } from '../locale';
|
||||
@ -15,14 +16,21 @@ import LocaleContext from '../locale/context';
|
||||
import defaultLocale from '../locale/en_US';
|
||||
import { DesignTokenContext } from '../theme/internal';
|
||||
import defaultSeedToken from '../theme/themes/seed';
|
||||
import warning from '../_util/warning';
|
||||
import type { ConfigConsumerProps, CSPConfig, DirectionType, Theme, ThemeConfig } from './context';
|
||||
import type {
|
||||
ConfigConsumerProps,
|
||||
CSPConfig,
|
||||
DirectionType,
|
||||
PopupOverflow,
|
||||
Theme,
|
||||
ThemeConfig,
|
||||
} from './context';
|
||||
import { ConfigConsumer, ConfigContext, defaultIconPrefixCls } from './context';
|
||||
import { registerTheme } from './cssVariables';
|
||||
import type { RenderEmptyHandler } from './defaultRenderEmpty';
|
||||
import { DisabledContextProvider } from './DisabledContext';
|
||||
import useConfig from './hooks/useConfig';
|
||||
import useTheme from './hooks/useTheme';
|
||||
import MotionWrapper from './MotionWrapper';
|
||||
import type { SizeType } from './SizeContext';
|
||||
import SizeContext, { SizeContextProvider } from './SizeContext';
|
||||
import useStyle from './style';
|
||||
@ -115,7 +123,10 @@ export interface ConfigProviderProps {
|
||||
size?: SizeType | number;
|
||||
};
|
||||
virtual?: boolean;
|
||||
/** @deprecated Please use `popupMatchSelectWidth` instead */
|
||||
dropdownMatchSelectWidth?: boolean;
|
||||
popupMatchSelectWidth?: boolean;
|
||||
popupOverflow?: PopupOverflow;
|
||||
theme?: ThemeConfig;
|
||||
}
|
||||
|
||||
@ -182,6 +193,8 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
|
||||
space,
|
||||
virtual,
|
||||
dropdownMatchSelectWidth,
|
||||
popupMatchSelectWidth,
|
||||
popupOverflow,
|
||||
legacyLocale,
|
||||
parentContext,
|
||||
iconPrefixCls: customIconPrefixCls,
|
||||
@ -189,6 +202,16 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
|
||||
componentDisabled,
|
||||
} = props;
|
||||
|
||||
// =================================== Warning ===================================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(
|
||||
dropdownMatchSelectWidth === undefined,
|
||||
'ConfigProvider',
|
||||
'`dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
|
||||
);
|
||||
}
|
||||
|
||||
// =================================== Context ===================================
|
||||
const getPrefixCls = React.useCallback(
|
||||
(suffixCls: string, customizePrefixCls?: string) => {
|
||||
const { prefixCls } = props;
|
||||
@ -221,7 +244,8 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
|
||||
direction,
|
||||
space,
|
||||
virtual,
|
||||
dropdownMatchSelectWidth,
|
||||
popupMatchSelectWidth: popupMatchSelectWidth ?? dropdownMatchSelectWidth,
|
||||
popupOverflow,
|
||||
getPrefixCls,
|
||||
iconPrefixCls,
|
||||
theme: mergedTheme,
|
||||
@ -300,6 +324,9 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
|
||||
childNode = <SizeContextProvider size={componentSize}>{childNode}</SizeContextProvider>;
|
||||
}
|
||||
|
||||
// =================================== Motion ===================================
|
||||
childNode = <MotionWrapper>{childNode}</MotionWrapper>;
|
||||
|
||||
// ================================ Dynamic theme ================================
|
||||
const memoTheme = React.useMemo(() => {
|
||||
const { algorithm, token, ...rest } = mergedTheme || {};
|
||||
|
@ -56,7 +56,8 @@ export default Demo;
|
||||
| componentSize | 设置 antd 组件大小 | `small` \| `middle` \| `large` | - | |
|
||||
| csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | |
|
||||
| direction | 设置文本展示方向。 [示例](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
|
||||
| dropdownMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 4.3.0 |
|
||||
| popupMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 5.5.0 |
|
||||
| popupOverflow | Select 类组件弹层展示逻辑,默认为可视区域滚动,可配置成滚动区域滚动 | 'viewport' \| 'scroll' <InlinePopover previewURL="https://user-images.githubusercontent.com/5378891/230344474-5b9f7e09-0a5d-49e8-bae8-7d2abed6c837.png"></InlinePopover> | 'viewport' | 5.5.0 |
|
||||
| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form-cn#validatemessages), requiredMark?: boolean \| `optional`, colon?: boolean, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)} | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0 |
|
||||
| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | |
|
||||
| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 |
|
||||
|
@ -2,13 +2,14 @@ import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/mk'; // to test local in 'prop locale should works' test case
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
import MockDate from 'mockdate';
|
||||
import React from 'react';
|
||||
import dayJsGenerateConfig from 'rc-picker/lib/generate/dayjs';
|
||||
import type { TriggerProps } from 'rc-trigger';
|
||||
import { fireEvent, render } from '../../../tests/utils';
|
||||
import React from 'react';
|
||||
import DatePicker from '..';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
import type { PickerLocale } from '../generatePicker';
|
||||
import { fireEvent, render } from '../../../tests/utils';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
import type { PickerLocale } from '../generatePicker';
|
||||
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
@ -288,4 +289,10 @@ describe('DatePicker', () => {
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('support DatePicker.generatePicker', () => {
|
||||
const MyDatePicker = DatePicker.generatePicker(dayJsGenerateConfig);
|
||||
const { container } = render(<MyDatePicker />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -1224,3 +1224,45 @@ Array [
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`DatePicker support DatePicker.generatePicker 1`] = `
|
||||
<div
|
||||
class="ant-picker"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder="Select date"
|
||||
readonly=""
|
||||
size="12"
|
||||
title=""
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-picker-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="calendar"
|
||||
class="anticon anticon-calendar"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="calendar"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -3305,7 +3305,7 @@ exports[`renders components/date-picker/demo/range-picker.tsx correctly 1`] = `
|
||||
|
||||
exports[`renders components/date-picker/demo/render-panel.tsx correctly 1`] = `
|
||||
<div
|
||||
style="padding-bottom:0;position:relative;width:fit-content;min-width:0"
|
||||
style="padding-bottom:0;position:relative;min-width:0"
|
||||
>
|
||||
<div
|
||||
class="ant-picker"
|
||||
|
@ -1,7 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
这里举例如何用 `onCalendarChange` 和 `disabledDate` 来限制动态的日期区间选择。
|
||||
使用 `changeOnBlur` 配合 `onCalendarChange` 和 `disabledDate` 来限制动态的日期区间选择。
|
||||
|
||||
## en-US
|
||||
|
||||
A example shows how to select a dynamic range by using `onCalendarChange` and `disabledDate`.
|
||||
Using `changeOnBlur` work with `onCalendarChange` and `disabledDate` to limit date selection.
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
@ -31,9 +31,14 @@ const App: React.FC = () => {
|
||||
<RangePicker
|
||||
value={dates || value}
|
||||
disabledDate={disabledDate}
|
||||
onCalendarChange={(val) => setDates(val)}
|
||||
onChange={(val) => setValue(val)}
|
||||
onCalendarChange={(val) => {
|
||||
setDates(val);
|
||||
}}
|
||||
onChange={(val) => {
|
||||
setValue(val);
|
||||
}}
|
||||
onOpenChange={onOpenChange}
|
||||
changeOnBlur
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -82,6 +82,7 @@ The following APIs are shared by DatePicker, RangePicker.
|
||||
| bordered | Whether has border style | boolean | true | |
|
||||
| className | The picker className | string | - | |
|
||||
| dateRender | Custom rendering function for date cells, >= 5.4.0 use `cellRender` instead. | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 |
|
||||
| changeOnBlur | Trigger `change` when blur. e.g. datetime picker no need click confirm button | boolean | false | 5.5.0 |
|
||||
| cellRender | Custom rendering function for picker cells | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| disabled | Determine whether the DatePicker is disabled | boolean | false | |
|
||||
| disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | |
|
||||
|
@ -16,6 +16,12 @@ export type RangePickerProps = BaseRangePickerProps<Dayjs>;
|
||||
|
||||
const DatePicker = generatePicker<Dayjs>(dayjsGenerateConfig);
|
||||
|
||||
export type DatePickerType = typeof DatePicker & {
|
||||
_InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel;
|
||||
_InternalRangePanelDoNotUseOrYouWillBeFired: typeof PureRangePanel;
|
||||
generatePicker: typeof generatePicker;
|
||||
};
|
||||
|
||||
function postPureProps(props: DatePickerProps) {
|
||||
const dropdownAlign = transPlacement2DropdownAlign(props.direction, props.placement);
|
||||
|
||||
@ -31,11 +37,9 @@ function postPureProps(props: DatePickerProps) {
|
||||
// We don't care debug panel
|
||||
/* istanbul ignore next */
|
||||
const PurePanel = genPurePanel(DatePicker, 'picker', null, postPureProps);
|
||||
(DatePicker as any)._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
||||
(DatePicker as DatePickerType)._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
||||
const PureRangePanel = genPurePanel(DatePicker.RangePicker, 'picker', null, postPureProps);
|
||||
(DatePicker as any)._InternalRangePanelDoNotUseOrYouWillBeFired = PureRangePanel;
|
||||
(DatePicker as DatePickerType)._InternalRangePanelDoNotUseOrYouWillBeFired = PureRangePanel;
|
||||
(DatePicker as DatePickerType).generatePicker = generatePicker;
|
||||
|
||||
export default DatePicker as typeof DatePicker & {
|
||||
_InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel;
|
||||
_InternalRangePanelDoNotUseOrYouWillBeFired: typeof PureRangePanel;
|
||||
};
|
||||
export default DatePicker as DatePickerType;
|
||||
|
@ -83,6 +83,7 @@ import locale from 'antd/locale/zh_CN';
|
||||
| bordered | 是否有边框 | boolean | true | |
|
||||
| className | 选择器 className | string | - | |
|
||||
| dateRender | 自定义日期单元格的内容,5.4.0 起用 `cellRender` 代替 | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 |
|
||||
| changeOnBlur | 失去焦点时触发 `change` 事件,例如 datetime 下不再需要点击确认按钮 | boolean | false | 5.5.0 |
|
||||
| cellRender | 自定义单元格的内容 | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| disabled | 禁用 | boolean | false | |
|
||||
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | |
|
||||
|
@ -99,6 +99,70 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/drawer/demo/component-token.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
style="padding: 32px; background: rgb(230, 230, 230);"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-pure ant-drawer-right"
|
||||
style="height: 300px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="ant-drawer-title"
|
||||
>
|
||||
Hello Title
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
>
|
||||
Hello Content
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-footer"
|
||||
>
|
||||
Footer!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/drawer/demo/config-provider.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="site-drawer-render-in-current-wrapper"
|
||||
@ -434,29 +498,33 @@ Array [
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
New account
|
||||
|
@ -11,6 +11,70 @@ exports[`renders components/drawer/demo/basic-right.tsx correctly 1`] = `
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`renders components/drawer/demo/component-token.tsx correctly 1`] = `
|
||||
<div
|
||||
style="padding:32px;background:#e6e6e6"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-pure ant-drawer-right"
|
||||
style="height:300px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="ant-drawer-title"
|
||||
>
|
||||
Hello Title
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
>
|
||||
Hello Content
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-footer"
|
||||
>
|
||||
Footer!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/drawer/demo/config-provider.tsx correctly 1`] = `
|
||||
<div
|
||||
class="site-drawer-render-in-current-wrapper"
|
||||
@ -137,29 +201,33 @@ exports[`renders components/drawer/demo/form-in-drawer.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="plus"
|
||||
class="anticon anticon-plus"
|
||||
role="img"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<defs>
|
||||
<style />
|
||||
</defs>
|
||||
<path
|
||||
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
|
||||
/>
|
||||
<path
|
||||
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
New account
|
||||
|
7
components/drawer/demo/component-token.md
Normal file
7
components/drawer/demo/component-token.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
Component Token Debug.
|
||||
|
||||
## en-US
|
||||
|
||||
Component Token Debug.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user