Compare commits

...

11 Commits
6.2.3 ... theme

Author SHA1 Message Date
遇见同学
c1cc97c90e chore: adjust 2026-01-15 10:24:42 +08:00
遇见同学
06a4287d73 Update .dumi/pages/index/components/PreviewBanner/ComponentsBlock.tsx
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: 遇见同学 <1875694521@qq.com>
2026-01-15 10:24:41 +08:00
遇见同学
37a3ef15d8 Update .dumi/pages/index/index.tsx
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: 遇见同学 <1875694521@qq.com>
2026-01-15 10:24:41 +08:00
遇见同学
b22a7108cf Update .dumi/pages/index/components/BannerRecommends.tsx
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: 遇见同学 <1875694521@qq.com>
2026-01-15 10:24:40 +08:00
遇见同学
67305c0ace site: Homepage style redesign, theme switching 2026-01-15 10:24:39 +08:00
github-actions[bot]
4ab542e7c3 chore: auto merge branches (#56614)
chore: sync master into feature
2026-01-15 02:22:27 +00:00
二货爱吃白萝卜
3e0b56dacf feat: ColorPicker semantic support ColorBlock customize (#56607)
* feat: ColorPicker missing semantic

* chore: fix lint

* test: update snapshot

* chore: fix lint
2026-01-14 17:53:23 +08:00
Guo Yunhe
7d35e112ae feat(ConfigProvider,Form): support tooltip prop and config (#56372)
* feat(ConfigProvider,Form): support tooltipIcon and tooltipProps

* feat(ConfigProvider,Form): support tooltipIcon and tooltipProps

* feat(ConfigProvider,Form): support tooltipIcon and tooltipProps

* feat(Form): support tooltip config

* feat(Form): support tooltip config

* fix(Form): remove unnecessary type assertion in tooltip prop

* refactor(Form): enhance tooltip prop handling by merging context with tooltip properties

---------

Co-authored-by: thinkasany <480968828@qq.com>
2026-01-14 16:23:30 +08:00
Guo Yunhe
6e55573b5c feat(Avatar): size default to 'medium' instead of 'default' for consistancy (#56440)
Co-authored-by: 遇见同学 <1875694521@qq.com>
2026-01-14 13:18:27 +08:00
github-actions[bot]
0e4f60dd01 chore: auto merge branches (#56601)
chore: sync master into feature
2026-01-14 02:16:19 +00:00
github-actions[bot]
98614197cb chore: auto merge branches (#56596)
chore: sync master into feature
2026-01-13 12:57:25 +00:00
35 changed files with 1141 additions and 334 deletions

View File

@@ -49,7 +49,8 @@ const useStyle = createStyles(({ cssVar, css, cx }) => {
max-width: 100%;
margin-inline: auto;
box-sizing: border-box;
column-gap: calc(${cssVar.paddingMD} * 2);
column-gap: ${cssVar.paddingMD};
padding: 0 ${cssVar.padding};
align-items: stretch;
text-align: start;
min-height: 178px;

View File

@@ -5,6 +5,7 @@ import {
Button,
Checkbox,
ColorPicker,
ConfigProvider,
Dropdown,
Input,
message,
@@ -18,8 +19,10 @@ import {
Tooltip,
} from 'antd';
import { createStaticStyles } from 'antd-style';
import type { ConfigProviderProps } from 'antd';
import useLocale from '../../../../hooks/useLocale';
import Tilt from './Tilt';
const { _InternalPanelDoNotUseOrYouWillBeFired: ModalPanel } = Modal;
@@ -103,117 +106,123 @@ const styles = createStaticStyles(({ cssVar, css }) => {
`,
};
});
interface ComponentsBlockProps {
config: ConfigProviderProps;
}
const ComponentsBlock: React.FC = () => {
const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
const [locale] = useLocale(locales);
const { config } = props;
return (
<Tilt options={{ max: 4, glare: false, scale: 0.98 }} className={styles.holder}>
<ModalPanel title="Ant Design" width="100%">
{locale.text}
</ModalPanel>
<Alert title={locale.infoText} type="info" />
{/* Line */}
<div className={styles.flex}>
<ColorPicker style={{ flex: 'none' }} />
<div style={{ flex: 'none' }}>
<Space.Compact>
<Button>{locale.dropdown}</Button>
<Dropdown
menu={{
items: Array.from({ length: 5 }).map((_, index) => ({
key: `opt${index}`,
label: `${locale.option} ${index}`,
})),
}}
>
<Button icon={<DownOutlined />} />
</Dropdown>
</Space.Compact>
<ConfigProvider {...config}>
<Tilt options={{ max: 4, glare: false, scale: 0.98 }} className={styles.holder}>
<ModalPanel title="Ant Design" width="100%">
{locale.text}
</ModalPanel>
<Alert title={locale.infoText} type="info" />
{/* Line */}
<div className={styles.flex}>
<ColorPicker style={{ flex: 'none' }} />
<div style={{ flex: 'none' }}>
<Space.Compact>
<Button>{locale.dropdown}</Button>
<Dropdown
menu={{
items: Array.from({ length: 5 }).map((_, index) => ({
key: `opt${index}`,
label: `${locale.option} ${index}`,
})),
}}
>
<Button icon={<DownOutlined />} />
</Dropdown>
</Space.Compact>
</div>
<Select
style={{ flex: 'auto' }}
mode="multiple"
maxTagCount="responsive"
defaultValue={[{ value: 'apple' }, { value: 'banana' }]}
options={[
{ value: 'apple', label: locale.apple },
{ value: 'banana', label: locale.banana },
{ value: 'orange', label: locale.orange },
{ value: 'watermelon', label: locale.watermelon },
]}
/>
<Input style={{ flex: 'none', width: 120 }} />
</div>
<Select
style={{ flex: 'auto' }}
mode="multiple"
maxTagCount="responsive"
defaultValue={[{ value: 'apple' }, { value: 'banana' }]}
options={[
{ value: 'apple', label: locale.apple },
{ value: 'banana', label: locale.banana },
{ value: 'orange', label: locale.orange },
{ value: 'watermelon', label: locale.watermelon },
<Progress
style={{ margin: 0 }}
percent={100}
strokeColor={{ '0%': '#108ee9', '100%': '#87d068' }}
/>
<Progress style={{ margin: 0 }} percent={33} status="exception" />
<Steps
current={1}
items={[
{ title: locale.finished },
{ title: locale.inProgress },
{ title: locale.waiting },
]}
/>
<Input style={{ flex: 'none', width: 120 }} />
</div>
<Progress
style={{ margin: 0 }}
percent={100}
strokeColor={{ '0%': '#108ee9', '100%': '#87d068' }}
/>
<Progress style={{ margin: 0 }} percent={33} status="exception" />
<Steps
current={1}
items={[
{ title: locale.finished },
{ title: locale.inProgress },
{ title: locale.waiting },
]}
/>
{/* Line */}
<div className={styles.block}>
<Slider
style={{ marginInline: 20 }}
range
marks={{
0: '0°C',
26: '26°C',
37: '37°C',
100: {
style: { color: '#f50' },
label: <strong>100°C</strong>,
},
}}
defaultValue={[26, 37]}
/>
</div>
{/* Line */}
<div className={styles.flex}>
<Button className={styles.ptg_20} type="primary">
{locale.primary}
</Button>
<Button className={styles.ptg_20} type="primary" danger>
{locale.danger}
</Button>
<Button className={styles.ptg_20}>{locale.default}</Button>
<Button className={styles.ptg_20} type="dashed">
{locale.dashed}
</Button>
<Button className={styles.ptg_20} icon={<AntDesignOutlined />}>
{locale.icon}
</Button>
</div>
{/* Line */}
<div className={styles.block}>
<div className={styles.flex}>
<Switch
className={styles.ptg_none}
defaultChecked
checkedChildren={<CheckOutlined />}
unCheckedChildren={<CloseOutlined />}
/>
<Checkbox.Group
className={styles.ptg_none}
options={[locale.apple, locale.banana, locale.orange]}
defaultValue={[locale.apple]}
{/* Line */}
<div className={styles.block}>
<Slider
style={{ marginInline: 20 }}
range
marks={{
0: '0°C',
26: '26°C',
37: '37°C',
100: {
style: { color: '#f50' },
label: <strong>100°C</strong>,
},
}}
defaultValue={[26, 37]}
/>
</div>
</div>
<div>
<InternalMessage content={locale.release} type="success" />
</div>
<InternalTooltip title={locale.hello} placement="topLeft" className={styles.noMargin} />
<Alert title="Ant Design love you!" type="success" />
</Tilt>
{/* Line */}
<div className={styles.flex}>
<Button className={styles.ptg_20} type="primary">
{locale.primary}
</Button>
<Button className={styles.ptg_20} type="primary" danger>
{locale.danger}
</Button>
<Button className={styles.ptg_20}>{locale.default}</Button>
<Button className={styles.ptg_20} type="dashed">
{locale.dashed}
</Button>
<Button className={styles.ptg_20} icon={<AntDesignOutlined />}>
{locale.icon}
</Button>
</div>
{/* Line */}
<div className={styles.block}>
<div className={styles.flex}>
<Switch
className={styles.ptg_none}
defaultChecked
checkedChildren={<CheckOutlined />}
unCheckedChildren={<CloseOutlined />}
/>
<Checkbox.Group
className={styles.ptg_none}
options={[locale.apple, locale.banana, locale.orange]}
defaultValue={[locale.apple]}
/>
</div>
</div>
<div>
<InternalMessage content={locale.release} type="success" />
</div>
<InternalTooltip title={locale.hello} placement="topLeft" className={styles.noMargin} />
<Alert title="Ant Design love you!" type="success" />
</Tilt>
</ConfigProvider>
);
};

View File

@@ -1,15 +1,21 @@
import React, { Suspense, use } from 'react';
import { Flex, Typography } from 'antd';
import React, { Suspense, use, useState } from 'react';
import { Button, Flex, Typography } from 'antd';
import type { ConfigProviderProps, ThemeConfig } from 'antd';
import { createStyles } from 'antd-style';
import { clsx } from 'clsx';
import { useLocation } from 'dumi';
import { DarkContext } from '../../../../hooks/useDark';
import useLocale from '../../../../hooks/useLocale';
import LinkButton from '../../../../theme/common/LinkButton';
import PromptDrawer from '../../../../theme/common/ThemeSwitch/PromptDrawer';
import ThemeIcon from '../../../../theme/common/ThemeSwitch/ThemeIcon';
import SiteContext from '../../../../theme/slots/SiteContext';
import type { SiteContextProps } from '../../../../theme/slots/SiteContext';
import * as utils from '../../../../theme/utils';
import GroupMaskLayer from '../GroupMaskLayer';
import { muiComponentConfig, muiDark, muiLight } from './themes/mui';
import { shadcnComponentConfig, shadcnDark, shadcnLight } from './themes/shadcn';
import '../SiteContext';
@@ -119,64 +125,251 @@ const useStyle = createStyles(({ cssVar, css, cx }, siteConfig: SiteContextProps
bottom: 120px;
inset-inline-end: ${siteConfig.isMobile ? 0 : '40%'};
`,
themeBar: css`
display: flex;
gap: 12px;
margin: 24px 0;
align-items: center;
justify-content: center;
`,
themeLabel: css`
background: ${cssVar.colorBgElevated};
padding: 6px 12px;
border-radius: 20px;
box-shadow: ${cssVar.boxShadowSecondary};
color: ${cssVar.colorText};
font-weight: 600;
font-size: ${cssVar.fontSizeSM};
`,
presets: css`
display: flex;
gap: 8px;
align-items: center;
`,
presetButton: cx(css`
display: inline-flex;
align-items: center;
gap: 8px;
border-radius: 14px;
background: ${cssVar.colorBgElevated};
color: ${cssVar.colorText};
cursor: pointer;
border: 1px solid transparent;
box-shadow: ${cssVar.boxShadowSecondary};
transition: all 0.2s ease;
font-size: ${cssVar.fontSizeSM};
padding: 7px 18px;
line-height: 18px;
border-radius: 6px;
font-size: 14px;
&:hover {
transform: translateY(-2px);
}
`),
swatches: css`
display: inline-flex;
align-items: center;
gap: 6px;
`,
swatch: css`
width: 10px;
height: 10px;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
`,
name: css`
margin-left: 10px;
text-transform: capitalize;
`,
};
});
type THEME_MAP = 'antd' | 'shadcn' | 'mui';
interface Theme {
name: THEME_MAP;
theme: ThemeConfig;
componentsConfig: Partial<ConfigProviderProps>;
style?: React.CSSProperties;
activeStyle: React.CSSProperties;
swatches: string[];
}
const PreviewBanner: React.FC<Readonly<React.PropsWithChildren>> = (props) => {
const { updateSiteConfig } = use<SiteContextProps>(SiteContext);
const [isMarketDrawerOpen, setIsMarketDrawerOpen] = useState(false);
const { children } = props;
const [locale] = useLocale(locales);
const siteConfig = use(SiteContext);
const { styles } = useStyle(siteConfig);
const { pathname, search } = useLocation();
const isZhCN = utils.isZhCN(pathname);
const [theme, setTheme] = useState<THEME_MAP>('antd');
const isDark = React.use(DarkContext);
const themeMap: Record<THEME_MAP, Theme> = {
antd: {
name: 'antd',
theme: {},
componentsConfig: {},
activeStyle: {
border: '1px solid #1677ff',
},
swatches: ['#1677ff', '#91d5ff', '#f0f5ff'],
},
shadcn: {
name: 'shadcn',
theme: isDark ? shadcnDark : shadcnLight,
style: {
backgroundColor: 'rgba(0, 0, 0, 0.1)',
},
activeStyle: {
border: '1px solid oklch(0.205 0 0)',
},
componentsConfig: shadcnComponentConfig,
swatches: ['oklch(0.205 0 0)', 'oklch(0.556 0 0)', 'rgba(0, 0, 0, 0.05)'],
},
mui: {
name: 'mui',
theme: isDark ? muiDark : muiLight,
componentsConfig: muiComponentConfig,
style: {
color: '#fff',
backgroundColor: 'rgb(2, 136, 209, 0.5)',
},
activeStyle: {
border: '1px solid rgb(25, 118, 210)',
},
swatches: ['#1677ff', '#91d5ff', '#f0f5ff'],
},
};
const config: ConfigProviderProps = {
theme: themeMap[theme].theme,
...themeMap[theme].componentsConfig,
};
return (
<GroupMaskLayer>
{/* Image Left Top */}
<img
alt="bg"
src="https://gw.alipayobjects.com/zos/bmw-prod/49f963db-b2a8-4f15-857a-270d771a1204.svg"
draggable={false}
className={clsx(styles.bgImg, styles.bgImgTop)}
/>
{/* Image Right Top */}
<img
alt="bg"
src="https://gw.alipayobjects.com/zos/bmw-prod/e152223c-bcae-4913-8938-54fda9efe330.svg"
draggable={false}
className={clsx(styles.bgImg, styles.bgImgBottom)}
/>
<div
className={styles.holder}
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'stretch',
justifyContent: 'center',
height: 640,
position: 'relative',
overflow: 'hidden',
perspective: 800,
}}
>
<div
style={{
flex: 1,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
position: 'relative',
zIndex: 1,
}}
>
<img
alt="bg"
src="https://gw.alipayobjects.com/zos/bmw-prod/49f963db-b2a8-4f15-857a-270d771a1204.svg"
draggable={false}
className={clsx(styles.bgImg, styles.bgImgTop)}
style={{ position: 'absolute', left: 0, top: 0, zIndex: 0 }}
/>
<div className={styles.mask} />
<div className={styles.holder}>
{/* Mobile not show the component preview */}
<Suspense fallback={null}>
{siteConfig.isMobile ? null : (
<div className={styles.block}>
<ComponentsBlock />
<Typography className={styles.typography}>
<h1>Ant Design</h1>
<p>{locale.slogan}</p>
</Typography>
<div className={styles.themeBar}>
<div className={styles.presets}>
{Object.keys(themeMap).map((v, i) => {
const key = v as THEME_MAP;
return (
<div
key={i}
role="button"
tabIndex={0}
onClick={() => setTheme(themeMap[key].name)}
className={clsx(styles.presetButton)}
style={{
...themeMap[key].style,
...(theme === themeMap[key].name ? themeMap[key].activeStyle : {}),
}}
>
<div className={styles.swatches}>
{themeMap[key].swatches?.map((s: any) => (
<span key={s} className={styles.swatch} style={{ background: s }} />
))}
</div>
<span className={styles.name}>{themeMap[key].name}</span>
</div>
);
})}
<Button
variant="solid"
icon={<ThemeIcon />}
onClick={() => setIsMarketDrawerOpen(true)}
style={{ fontSize: 16 }}
/>
</div>
)}
</Suspense>
<div className={styles.mask} />
<Typography className={styles.typography}>
<h1>Ant Design</h1>
<p>{locale.slogan}</p>
</Typography>
<Flex gap="middle" className={styles.btnWrap}>
<LinkButton
size="large"
type="primary"
to={utils.getLocalizedPathname('/components/overview/', isZhCN, search)}
>
{locale.start}
</LinkButton>
<LinkButton
size="large"
to={utils.getLocalizedPathname('/docs/spec/introduce/', isZhCN, search)}
>
{locale.designLanguage}
</LinkButton>
</Flex>
<div className={styles.child}>{children}</div>
</div>
<Flex gap="middle" className={styles.btnWrap}>
<LinkButton
size="large"
type="primary"
to={utils.getLocalizedPathname('/components/overview/', isZhCN, search)}
>
{locale.start}
</LinkButton>
<LinkButton
size="large"
to={utils.getLocalizedPathname('/docs/spec/introduce/', isZhCN, search)}
>
{locale.designLanguage}
</LinkButton>
</Flex>
<div className={styles.child}>{children}</div>
</div>
<PromptDrawer
open={isMarketDrawerOpen}
onClose={() => setIsMarketDrawerOpen(false)}
onThemeChange={(nextTheme) => {
updateSiteConfig({
dynamicTheme: nextTheme,
});
}}
/>
<div
style={{
width: '40%',
display: 'flex',
alignItems: 'center',
position: 'relative',
backgroundColor: isDark ? '#393F4A' : '#f4f8ff',
borderRadius: '0 0px 0px 12px',
}}
>
<img
alt="bg"
src="https://gw.alipayobjects.com/zos/bmw-prod/e152223c-bcae-4913-8938-54fda9efe330.svg"
draggable={false}
className={clsx(styles.bgImg, styles.bgImgBottom)}
style={{ position: 'absolute', right: 0, top: 0, zIndex: 0 }}
/>
<Suspense fallback={null}>
{siteConfig.isMobile ? null : (
<div className={styles.block} style={{ position: 'relative', zIndex: 1 }}>
<ComponentsBlock config={config} />
</div>
)}
</Suspense>
</div>
</div>
</GroupMaskLayer>
);

View File

@@ -0,0 +1,244 @@
import type { ConfigProviderProps, ThemeConfig } from 'antd';
import { theme } from 'antd';
const { darkAlgorithm, defaultAlgorithm } = theme;
export const mui: ThemeConfig = {
token: {
colorPrimary: '#1976d2',
colorSuccess: '#2e7d32',
colorWarning: '#ed6c02',
colorError: '#d32f2f',
colorInfo: '#0288d1',
colorTextBase: '#212121',
colorBgBase: '#fafafa',
colorPrimaryBg: '#e3f2fd',
colorPrimaryBgHover: '#bbdefb',
colorPrimaryBorder: '#90caf9',
colorPrimaryBorderHover: '#64b5f6',
colorPrimaryHover: '#42a5f5',
colorPrimaryActive: '#1565c0',
colorPrimaryText: '#1976d2',
colorPrimaryTextHover: '#42a5f5',
colorPrimaryTextActive: '#1565c0',
colorSuccessBg: '#e8f5e9',
colorSuccessBgHover: '#c8e6c9',
colorSuccessBorder: '#a5d6a7',
colorSuccessBorderHover: '#81c784',
colorSuccessHover: '#4caf50',
colorSuccessActive: '#1b5e20',
colorSuccessText: '#2e7d32',
colorSuccessTextHover: '#4caf50',
colorSuccessTextActive: '#1b5e20',
colorWarningBg: '#fff3e0',
colorWarningBgHover: '#ffe0b2',
colorWarningBorder: '#ffcc02',
colorWarningBorderHover: '#ffb74d',
colorWarningHover: '#ff9800',
colorWarningActive: '#e65100',
colorWarningText: '#ed6c02',
colorWarningTextHover: '#ff9800',
colorWarningTextActive: '#e65100',
colorErrorBg: '#ffebee',
colorErrorBgHover: '#ffcdd2',
colorErrorBorder: '#ef9a9a',
colorErrorBorderHover: '#e57373',
colorErrorHover: '#ef5350',
colorErrorActive: '#c62828',
colorErrorText: '#d32f2f',
colorErrorTextHover: '#ef5350',
colorErrorTextActive: '#c62828',
colorInfoBg: '#e1f5fe',
colorInfoBgHover: '#b3e5fc',
colorInfoBorder: '#81d4fa',
colorInfoBorderHover: '#4fc3f7',
colorInfoHover: '#03a9f4',
colorInfoActive: '#01579b',
colorInfoText: '#0288d1',
colorInfoTextHover: '#03a9f4',
colorInfoTextActive: '#01579b',
colorText: 'rgba(33, 33, 33, 0.87)',
colorTextSecondary: 'rgba(33, 33, 33, 0.6)',
colorTextTertiary: 'rgba(33, 33, 33, 0.38)',
colorTextQuaternary: 'rgba(33, 33, 33, 0.26)',
colorTextDisabled: 'rgba(33, 33, 33, 0.38)',
colorBgContainer: '#ffffff',
colorBgElevated: '#ffffff',
colorBgLayout: '#f5f5f5',
colorBgSpotlight: 'rgba(33, 33, 33, 0.85)',
colorBgMask: 'rgba(33, 33, 33, 0.5)',
colorBorder: '#e0e0e0',
colorBorderSecondary: '#eeeeee',
borderRadius: 4,
borderRadiusXS: 1,
borderRadiusSM: 2,
borderRadiusLG: 6,
padding: 16,
paddingSM: 8,
paddingLG: 24,
margin: 16,
marginSM: 8,
marginLG: 24,
boxShadow:
'0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)',
boxShadowSecondary:
'0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)',
},
components: {
Button: {
primaryShadow:
'0px 3px 1px -2px rgba(0,0,0,0.2), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12)',
defaultShadow:
'0px 3px 1px -2px rgba(0,0,0,0.2), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12)',
dangerShadow:
'0px 3px 1px -2px rgba(0,0,0,0.2), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12)',
fontWeight: 500,
defaultBorderColor: 'rgba(0, 0, 0, 0.23)',
defaultColor: 'rgba(0, 0, 0, 0.87)',
defaultBg: '#ffffff',
defaultHoverBg: 'rgba(25, 118, 210, 0.04)',
defaultHoverBorderColor: 'rgba(0, 0, 0, 0.23)',
paddingInline: 16,
paddingBlock: 6,
contentFontSize: 14,
borderRadius: 4,
},
Alert: {
borderRadiusLG: 4,
},
Modal: {
borderRadiusLG: 4,
},
Progress: {
defaultColor: '#1976d2',
remainingColor: 'rgba(25, 118, 210, 0.12)',
},
Steps: {
iconSize: 24,
},
Checkbox: {
borderRadiusSM: 2,
},
Slider: {
trackBg: 'rgba(25, 118, 210, 0.26)',
trackHoverBg: 'rgba(25, 118, 210, 0.38)',
handleSize: 20,
handleSizeHover: 20,
railSize: 4,
},
ColorPicker: {
borderRadius: 4,
},
},
};
export const muiLight: ThemeConfig = {
algorithm: defaultAlgorithm,
token: mui.token,
components: mui.components,
};
export const muiDark: ThemeConfig = {
algorithm: darkAlgorithm,
token: {
...mui.token,
},
components: {
...mui.components,
Message: {
contentBg: '#212121',
contentPadding: '8px 16px',
zIndexPopup: 1010,
},
},
};
export const muiComponentConfig: Partial<ConfigProviderProps> = {
button: {
styles: (info) => {
const { props } = info;
if (props.type === 'primary') {
return {
root: {
backgroundColor: '#1976d2',
color: '#ffffff',
border: 'none',
fontWeight: 500,
textTransform: 'uppercase' as const,
letterSpacing: '0.02857em',
boxShadow:
'0px 3px 1px -2px rgba(0,0,0,0.2), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12)',
transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
},
};
}
if (props.type === 'default') {
return {
root: {
backgroundColor: '#ffffff',
color: 'rgba(0, 0, 0, 0.87)',
border: '1px solid rgba(0, 0, 0, 0.23)',
fontWeight: 500,
textTransform: 'uppercase' as const,
letterSpacing: '0.02857em',
transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
},
};
}
if (props.danger) {
return {
root: {
backgroundColor: '#d32f2f',
color: '#ffffff',
border: 'none',
fontWeight: 500,
textTransform: 'uppercase' as const,
letterSpacing: '0.02857em',
boxShadow:
'0px 3px 1px -2px rgba(0,0,0,0.2), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12)',
},
};
}
return {};
},
},
input: {
styles: (info) => {
const { props } = info;
const baseStyle = {
root: {
borderColor: 'rgba(0, 0, 0, 0.23)',
transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
},
input: {
color: 'rgba(0, 0, 0, 0.87)',
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
},
};
if (props.status === 'error') {
return {
...baseStyle,
root: {
...baseStyle.root,
borderColor: '#d32f2f',
},
};
}
return baseStyle;
},
},
select: {
styles: {
root: {
borderColor: 'rgba(0, 0, 0, 0.23)',
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
},
popup: {
root: {
borderRadius: 4,
boxShadow:
'0px 5px 5px -3px rgba(0,0,0,0.2), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12)',
},
},
},
},
};

View File

@@ -0,0 +1,243 @@
import type { ConfigProviderProps, ThemeConfig } from 'antd';
import { theme } from 'antd';
const { darkAlgorithm, defaultAlgorithm } = theme;
export const shadcn: ThemeConfig = {
algorithm: defaultAlgorithm,
token: {
colorPrimary: '#262626',
colorSuccess: '#22c55e',
colorWarning: '#f97316',
colorError: '#ef4444',
colorInfo: '#262626',
colorTextBase: '#262626',
colorBgBase: '#ffffff',
colorPrimaryBg: '#f5f5f5',
colorPrimaryBgHover: '#e5e5e5',
colorPrimaryBorder: '#d4d4d4',
colorPrimaryBorderHover: '#a3a3a3',
colorPrimaryHover: '#404040',
colorPrimaryActive: '#171717',
colorPrimaryText: '#262626',
colorPrimaryTextHover: '#404040',
colorPrimaryTextActive: '#171717',
colorSuccessBg: '#f0fdf4',
colorSuccessBgHover: '#dcfce7',
colorSuccessBorder: '#bbf7d0',
colorSuccessBorderHover: '#86efac',
colorSuccessHover: '#16a34a',
colorSuccessActive: '#15803d',
colorSuccessText: '#16a34a',
colorSuccessTextHover: '#16a34a',
colorSuccessTextActive: '#15803d',
colorWarningBg: '#fff7ed',
colorWarningBgHover: '#fed7aa',
colorWarningBorder: '#fdba74',
colorWarningBorderHover: '#fb923c',
colorWarningHover: '#ea580c',
colorWarningActive: '#c2410c',
colorWarningText: '#ea580c',
colorWarningTextHover: '#ea580c',
colorWarningTextActive: '#c2410c',
colorErrorBg: '#fef2f2',
colorErrorBgHover: '#fecaca',
colorErrorBorder: '#fca5a5',
colorErrorBorderHover: '#f87171',
colorErrorHover: '#dc2626',
colorErrorActive: '#b91c1c',
colorErrorText: '#dc2626',
colorErrorTextHover: '#dc2626',
colorErrorTextActive: '#b91c1c',
colorInfoBg: '#f5f5f5',
colorInfoBgHover: '#e5e5e5',
colorInfoBorder: '#d4d4d4',
colorInfoBorderHover: '#a3a3a3',
colorInfoHover: '#404040',
colorInfoActive: '#171717',
colorInfoText: '#262626',
colorInfoTextHover: '#404040',
colorInfoTextActive: '#171717',
colorText: '#262626',
colorTextSecondary: '#525252',
colorTextTertiary: '#737373',
colorTextQuaternary: '#a3a3a3',
colorTextDisabled: '#a3a3a3',
colorBgContainer: '#ffffff',
colorBgElevated: '#ffffff',
colorBgLayout: '#fafafa',
colorBgSpotlight: 'rgba(38, 38, 38, 0.85)',
colorBgMask: 'rgba(38, 38, 38, 0.45)',
colorBorder: '#e5e5e5',
colorBorderSecondary: '#f5f5f5',
borderRadius: 10,
borderRadiusXS: 2,
borderRadiusSM: 6,
borderRadiusLG: 14,
padding: 16,
paddingSM: 12,
paddingLG: 24,
margin: 16,
marginSM: 12,
marginLG: 24,
boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)',
boxShadowSecondary: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
},
components: {
Button: {
primaryShadow: 'none',
defaultShadow: 'none',
dangerShadow: 'none',
defaultBorderColor: '#e4e4e7',
defaultColor: '#18181b',
defaultBg: '#ffffff',
defaultHoverBg: '#f4f4f5',
defaultHoverBorderColor: '#d4d4d8',
defaultHoverColor: '#18181b',
defaultActiveBg: '#e4e4e7',
defaultActiveBorderColor: '#d4d4d8',
borderRadius: 6,
},
Input: {
activeShadow: 'none',
hoverBorderColor: '#a1a1aa',
activeBorderColor: '#18181b',
borderRadius: 6,
},
Select: {
optionSelectedBg: '#f4f4f5',
optionActiveBg: '#fafafa',
optionSelectedFontWeight: 500,
borderRadius: 6,
},
Alert: {
borderRadiusLG: 8,
},
Modal: {
borderRadiusLG: 12,
},
Progress: {
defaultColor: '#18181b',
remainingColor: '#f4f4f5',
},
Steps: {
iconSize: 32,
},
Switch: {
trackHeight: 24,
trackMinWidth: 44,
innerMinMargin: 4,
innerMaxMargin: 24,
},
Checkbox: {
borderRadiusSM: 4,
},
Slider: {
trackBg: '#f4f4f5',
trackHoverBg: '#e4e4e7',
handleSize: 18,
handleSizeHover: 20,
railSize: 6,
},
ColorPicker: {
borderRadius: 6,
},
},
};
export const shadcnLight: ThemeConfig = {
algorithm: defaultAlgorithm,
token: shadcn.token,
components: shadcn.components,
};
export const shadcnDark: ThemeConfig = {
algorithm: darkAlgorithm,
token: {
...shadcn.token,
},
components: {
...shadcn.components,
Message: {
contentBg: '#212121',
},
},
};
export const shadcnComponentConfig: Partial<ConfigProviderProps> = {
button: {
styles: (info) => {
const { props } = info;
if (props.type === 'primary') {
return {
root: {
backgroundColor: '#18181b',
color: '#ffffff',
border: '1px solid #18181b',
fontWeight: 500,
transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
},
};
}
if (props.type === 'default') {
return {
root: {
backgroundColor: '#ffffff',
color: '#18181b',
border: '1px solid #e4e4e7',
fontWeight: 500,
transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
},
};
}
if (props.danger) {
return {
root: {
backgroundColor: '#dc2626',
color: '#ffffff',
border: '1px solid #dc2626',
fontWeight: 500,
},
};
}
return {};
},
},
input: {
styles: (info) => {
const { props } = info;
const baseStyle = {
root: {
borderColor: '#e4e4e7',
transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
},
input: {
color: '#18181b',
},
};
if (props.status === 'error') {
return {
...baseStyle,
root: {
...baseStyle.root,
borderColor: '#dc2626',
},
};
}
return baseStyle;
},
},
select: {
styles: {
root: {
borderColor: '#e4e4e7',
},
popup: {
root: {
borderRadius: 8,
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
},
},
},
},
};

View File

@@ -49,13 +49,6 @@ const Homepage: React.FC = () => {
</PreviewBanner>
<div>
{/* 定制主题 */}
<ConfigProvider theme={{ algorithm: theme.defaultAlgorithm }}>
<Suspense fallback={null}>
<Theme />
</Suspense>
</ConfigProvider>
{/* 组件列表 */}
<Group
background={token.colorBgElevated}
@@ -69,11 +62,18 @@ const Homepage: React.FC = () => {
</Suspense>
</Group>
{/* 定制主题 */}
<ConfigProvider theme={{ algorithm: theme.defaultAlgorithm }}>
<Suspense fallback={null}>
<Theme />
</Suspense>
</ConfigProvider>
{/* 设计语言 */}
<Group
title={locale.designTitle}
description={locale.designDesc}
background={isDark ? '#393F4A' : '#F5F8FF'}
background={isDark ? '#393F4A' : token.colorBgContainer}
decoration={
<img
draggable={false}

View File

@@ -4,16 +4,16 @@ import { isValidElement } from 'react';
import type { TooltipProps } from '../tooltip';
import isNonNullable from './isNonNullable';
const convertToTooltipProps = <P extends TooltipProps>(tooltip: P | ReactNode) => {
const convertToTooltipProps = <P extends TooltipProps>(tooltip: P | ReactNode, context?: P) => {
if (!isNonNullable(tooltip)) {
return null;
}
if (typeof tooltip === 'object' && !isValidElement(tooltip)) {
return tooltip as P;
return { ...context, ...tooltip } as P;
}
return { title: tooltip } as P;
return { ...context, title: tooltip } as P;
};
export default convertToTooltipProps;

View File

@@ -18,7 +18,7 @@ export interface AvatarProps {
/** Shape of avatar, options: `circle`, `square` */
shape?: 'circle' | 'square';
/*
* Size of avatar, options: `large`, `small`, `default`
* Size of avatar, options: `large`, `medium`, `small`
* or a custom number size
* */
size?: AvatarSize;
@@ -111,7 +111,7 @@ const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
}
};
const size = useSize((ctxSize) => customSize ?? avatarCtx?.size ?? ctxSize ?? 'default');
const size = useSize((ctxSize) => customSize ?? avatarCtx?.size ?? ctxSize ?? 'medium');
const needResponsive = Object.keys(typeof size === 'object' ? size || {} : {}).some((key) =>
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].includes(key),

View File

@@ -1,8 +1,12 @@
import * as React from 'react';
import type { ScreenSizeMap } from '../_util/responsiveObserver';
import type { SizeType } from '../config-provider/SizeContext';
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
/**
* 'default' is deprecated and will be removed in v7, please use `medium` instead.
*/
export type AvatarSize = SizeType | 'default' | number | ScreenSizeMap;
export interface AvatarContextType {
size?: AvatarSize;

View File

@@ -44,7 +44,7 @@ export interface AvatarGroupProps {
popover?: PopoverProps;
};
/*
* Size of avatar, options: `large`, `small`, `default`
* Size of avatar, options: `large`, `medium`, `small`
* or a custom number size
* */
size?: AvatarSize;

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { Avatar, Button, Space } from 'antd';
type SizeType = 'large' | 'small' | 'default' | number;
type SizeType = 'large' | 'small' | 'medium' | number;
const App: React.FC = () => {
const [hide, setHide] = useState(true);
@@ -13,7 +13,7 @@ const App: React.FC = () => {
};
const toggleSize = () => {
const sizes = ['small', 'default', 'large'] as SizeType[];
const sizes = ['small', 'medium', 'large'] as SizeType[];
let current = sizes.indexOf(size) + 1;
if (current > 2) {
current = 0;

View File

@@ -36,7 +36,7 @@ Common props ref[Common props](/docs/react/common-props)
| gap | Letter type unit distance between left and right sides | number | 4 | 4.3.0 |
| icon | Custom icon type for an icon avatar | ReactNode | - | |
| shape | The shape of avatar | `circle` \| `square` | `circle` | |
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.7.0 |
| size | The size of the avatar | number \| `large` \| `medium` \| `small` \| { xs: number, sm: number, ...} | `medium` | 4.7.0 |
| src | The address of the image for an image avatar or image element | string \| ReactNode | - | ReactNode: 4.8.0 |
| srcSet | A list of sources to use for different screen resolutions | string | - | |
| draggable | Whether the picture is allowed to be dragged | boolean \| `'true'` \| `'false'` | true | |
@@ -50,7 +50,7 @@ Common props ref[Common props](/docs/react/common-props)
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| max | Set maximum display related configurations, Before `5.18.0` you can use [parameters](https://github.com/ant-design/ant-design/blob/9d134859becbdae5b9ce276f6d9af4264691d81f/components/avatar/group.tsx#L35-L38) | `{ count?: number; style?: CSSProperties; popover?: PopoverProps }` | - | 5.18.0 |
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.8.0 |
| size | The size of the avatar | number \| `large` \| `medium` \| `small` \| { xs: number, sm: number, ...} | `medium` | 4.8.0 |
| shape | The shape of the avatar | `circle` \| `square` | `circle` | 5.8.0 |
## Design Token

View File

@@ -41,7 +41,7 @@ group:
| gap | 字符类型距离左右两侧边界单位像素 | number | 4 | 4.3.0 |
| icon | 设置头像的自定义图标 | ReactNode | - | |
| shape | 指定头像的形状 | `circle` \| `square` | `circle` | |
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.7.0 |
| size | 设置头像的大小 | number \| `large` \| `medium` \| `small` \| { xs: number, sm: number, ...} | `medium` | 4.7.0 |
| src | 图片类头像的资源地址或者图片元素 | string \| ReactNode | - | ReactNode: 4.8.0 |
| srcSet | 设置图片类头像响应式资源地址 | string | - | |
| draggable | 图片是否允许拖动 | boolean \| `'true'` \| `'false'` | true | |
@@ -55,7 +55,7 @@ group:
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| max | 设置最多显示相关配置,`5.18.0` 前可使用 [参数](https://github.com/ant-design/ant-design/blob/9d134859becbdae5b9ce276f6d9af4264691d81f/components/avatar/group.tsx#L35-L38) | `{ count?: number; style?: CSSProperties; popover?: PopoverProps }` | - | 5.18.0 |
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.8.0 |
| size | 设置头像的大小 | number \| `large` \| `medium` \| `small` \| { xs: number, sm: number, ...} | `medium` | 4.8.0 |
| shape | 设置头像的形状 | `circle` \| `square` | `circle` | 5.8.0 |
## 主题变量Design Token{#design-token}

View File

@@ -331,7 +331,7 @@ const InternalCompoundedButton = React.forwardRef<
// ========================== Size ==========================
const { compactSize, compactItemClassnames } = useCompactItemContext(prefixCls, direction);
const sizeClassNameMap = { large: 'lg', small: 'sm', middle: undefined };
const sizeClassNameMap = { large: 'lg', small: 'sm', middle: undefined, medium: undefined };
const sizeFullName = useSize((ctxSize) => customizeSize ?? compactSize ?? groupSize ?? ctxSize);

View File

@@ -225,7 +225,7 @@ const ColorPicker: CompoundedComponent = (props) => {
const rootCls = useCSSVarCls(prefixCls);
const [hashId, cssVarCls] = useStyle(prefixCls, rootCls);
const rtlCls = { [`${prefixCls}-rtl`]: direction };
const mergedRootCls = clsx(mergedClassNames.root, rootClassName, cssVarCls, rootCls, rtlCls);
const mergedRootCls = clsx(rootClassName, cssVarCls, rootCls, rtlCls);
const mergedCls = clsx(
getStatusClassNames(prefixCls, contextStatus),
{
@@ -262,7 +262,7 @@ const ColorPicker: CompoundedComponent = (props) => {
destroyOnHidden: destroyOnHidden ?? !!destroyTooltipOnHide,
};
const mergedStyle: React.CSSProperties = { ...mergedStyles.root, ...contextStyle, ...style };
const mergedStyle: React.CSSProperties = { ...contextStyle, ...style };
// ============================ zIndex ============================
@@ -305,6 +305,8 @@ const ColorPicker: CompoundedComponent = (props) => {
open={popupOpen}
className={mergedCls}
style={mergedStyle}
classNames={mergedClassNames}
styles={mergedStyles}
prefixCls={prefixCls}
disabled={mergedDisabled}
showText={showText}

View File

@@ -9465,7 +9465,7 @@ exports[`renders components/color-picker/demo/style-class.tsx extend context cor
>
<div
aria-describedby="test-id"
class="ant-color-picker-trigger acss-pbemrr css-var-test-id ant-color-picker-css-var"
class="ant-color-picker-trigger css-var-test-id ant-color-picker-css-var acss-pbemrr"
>
<div
class="ant-color-picker-color-block"
@@ -9477,7 +9477,7 @@ exports[`renders components/color-picker/demo/style-class.tsx extend context cor
</div>
</div>
<div
class="ant-popover ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big ant-popover-css-var css-var-test-id css-var-test-id ant-color-picker acss-pbemrr css-var-test-id ant-color-picker-css-var ant-popover-placement-bottomLeft"
class="ant-popover ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big ant-popover-css-var css-var-test-id css-var-test-id ant-color-picker css-var-test-id ant-color-picker-css-var ant-popover-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; right: auto; bottom: auto; box-sizing: border-box; border: 1px solid rgb(255, 255, 255);"
>
<div
@@ -9832,7 +9832,7 @@ exports[`renders components/color-picker/demo/style-class.tsx extend context cor
>
<div
aria-describedby="test-id"
class="ant-color-picker-trigger ant-color-picker-lg acss-pbemrr css-var-test-id ant-color-picker-css-var"
class="ant-color-picker-trigger ant-color-picker-lg css-var-test-id ant-color-picker-css-var acss-pbemrr"
>
<div
class="ant-color-picker-color-block"
@@ -9844,7 +9844,7 @@ exports[`renders components/color-picker/demo/style-class.tsx extend context cor
</div>
</div>
<div
class="ant-popover ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big ant-popover-css-var css-var-test-id css-var-test-id ant-color-picker acss-pbemrr css-var-test-id ant-color-picker-css-var ant-popover-placement-bottomLeft"
class="ant-popover ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big ant-popover-css-var css-var-test-id css-var-test-id ant-color-picker css-var-test-id ant-color-picker-css-var ant-popover-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; right: auto; bottom: auto; box-sizing: border-box; border: 1px solid rgb(114, 46, 209);"
>
<div

View File

@@ -552,7 +552,7 @@ exports[`renders components/color-picker/demo/style-class.tsx correctly 1`] = `
class="ant-flex css-var-test-id ant-flex-gap-small"
>
<div
class="ant-color-picker-trigger acss-pbemrr css-var-test-id ant-color-picker-css-var"
class="ant-color-picker-trigger css-var-test-id ant-color-picker-css-var acss-pbemrr"
>
<div
class="ant-color-picker-color-block"
@@ -572,7 +572,7 @@ exports[`renders components/color-picker/demo/style-class.tsx correctly 1`] = `
class="ant-flex css-var-test-id ant-flex-gap-small"
>
<div
class="ant-color-picker-trigger ant-color-picker-lg acss-pbemrr css-var-test-id ant-color-picker-css-var"
class="ant-color-picker-trigger ant-color-picker-lg css-var-test-id ant-color-picker-css-var acss-pbemrr"
>
<div
class="ant-color-picker-color-block"

View File

@@ -1,5 +1,6 @@
import type { FC } from 'react';
import React from 'react';
import clsx from 'clsx';
import type { AggregationColor } from '../color';
import { generateColor } from '../util';
@@ -8,10 +9,12 @@ interface ColorClearProps {
prefixCls: string;
value?: AggregationColor;
onChange?: (value: AggregationColor) => void;
className?: string;
style?: React.CSSProperties;
}
const ColorClear: FC<ColorClearProps> = ({ prefixCls, value, onChange }) => {
const handleClick = () => {
const ColorClear: FC<ColorClearProps> = ({ prefixCls, value, onChange, className, style }) => {
const onClick = () => {
if (onChange && value && !value.cleared) {
const hsba = value.toHsb();
hsba.a = 0;
@@ -21,7 +24,7 @@ const ColorClear: FC<ColorClearProps> = ({ prefixCls, value, onChange }) => {
onChange(genColor);
}
};
return <div className={`${prefixCls}-clear`} onClick={handleClick} />;
return <div className={clsx(`${prefixCls}-clear`, className)} style={style} onClick={onClick} />;
};
export default ColorClear;

View File

@@ -7,7 +7,12 @@ import { clsx } from 'clsx';
import { useLocale } from '../../locale';
import type { AggregationColor } from '../color';
import type { ColorFormatType, ColorPickerProps } from '../interface';
import type {
ColorFormatType,
ColorPickerProps,
ColorPickerSemanticClassNames,
ColorPickerSemanticStyles,
} from '../interface';
import { getColorAlpha } from '../util';
import ColorClear from './ColorClear';
@@ -20,6 +25,8 @@ export interface ColorTriggerProps {
showText?: ColorPickerProps['showText'];
className?: string;
style?: CSSProperties;
classNames: ColorPickerSemanticClassNames;
styles: ColorPickerSemanticStyles;
onClick?: MouseEventHandler<HTMLDivElement>;
onMouseEnter?: MouseEventHandler<HTMLDivElement>;
onMouseLeave?: MouseEventHandler<HTMLDivElement>;
@@ -27,8 +34,20 @@ export interface ColorTriggerProps {
}
const ColorTrigger = forwardRef<HTMLDivElement, ColorTriggerProps>((props, ref) => {
const { color, prefixCls, open, disabled, format, className, showText, activeIndex, ...rest } =
props;
const {
color,
prefixCls,
open,
disabled,
format,
className,
style,
classNames,
styles,
showText,
activeIndex,
...rest
} = props;
const colorTriggerPrefixCls = `${prefixCls}-trigger`;
const colorTextPrefixCls = `${colorTriggerPrefixCls}-text`;
@@ -85,24 +104,42 @@ const ColorTrigger = forwardRef<HTMLDivElement, ColorTriggerProps>((props, ref)
const containerNode = useMemo<React.ReactNode>(
() =>
color.cleared ? (
<ColorClear prefixCls={prefixCls} />
<ColorClear prefixCls={prefixCls} className={classNames.body} style={styles.body} />
) : (
<ColorBlock prefixCls={prefixCls} color={color.toCssString()} />
<ColorBlock
prefixCls={prefixCls}
color={color.toCssString()}
className={classNames.body}
innerClassName={classNames.content}
style={styles.body}
innerStyle={styles.content}
/>
),
[color, prefixCls],
[color, prefixCls, classNames.body, classNames.content, styles.body, styles.content],
);
return (
<div
ref={ref}
className={clsx(colorTriggerPrefixCls, className, {
className={clsx(colorTriggerPrefixCls, className, classNames.root, {
[`${colorTriggerPrefixCls}-active`]: open,
[`${colorTriggerPrefixCls}-disabled`]: disabled,
})}
style={{
...styles.root,
...style,
}}
{...pickAttrs(rest)}
>
{containerNode}
{showText && <div className={colorTextPrefixCls}>{desc}</div>}
{showText && (
<div
className={clsx(colorTextPrefixCls, classNames.description)}
style={styles.description}
>
{desc}
</div>
)}
</div>
);
});

View File

@@ -1,17 +1,23 @@
import React from 'react';
import type { ColorPickerProps } from 'antd';
import { ColorPicker } from 'antd';
import { ColorPicker, Flex } from 'antd';
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
import useLocale from '../../../.dumi/hooks/useLocale';
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
const locales = {
cn: {
root: '触发器容器,包含边框样式、过渡动画、尺寸控制等样式,显示颜色块和文本内容',
body: '色块容器,包含底色、边框等样式',
content: '色块颜色元素,包含实际选择的颜色样式',
description: '描述文本内容,包含字体样式、颜色等样式',
'popup.root': '弹出面板根容器,包含背景色、阴影效果、色彩选择面板、滑块控制和预设颜色等样式',
},
en: {
root: 'Trigger container with border styles, transition animations, size controls, displaying color block and text content',
body: 'Color block container with background color, border styles',
content: 'Color block element with actual selected color styles',
description: 'Description text content with font styles and color',
'popup.root':
'Popup panel root container with background color, shadow effects, color selection panel, slider controls and preset colors',
},
@@ -20,10 +26,11 @@ const locales = {
const Block: React.FC<Readonly<ColorPickerProps>> = (props) => {
const divRef = React.useRef<HTMLDivElement>(null);
return (
<div ref={divRef} style={{ height: 300 }}>
<Flex ref={divRef} style={{ height: 300 }} align="flex-start" gap="small">
<ColorPicker
defaultValue="#1677ff"
open
showText
{...props}
getPopupContainer={() => divRef!.current!}
styles={{
@@ -32,7 +39,8 @@ const Block: React.FC<Readonly<ColorPickerProps>> = (props) => {
},
}}
/>
</div>
<ColorPicker open={false} allowClear {...props} />
</Flex>
);
};
@@ -43,6 +51,9 @@ const App: React.FC = () => {
componentName="ColorPicker"
semantics={[
{ name: 'root', desc: locale.root },
{ name: 'body', desc: locale.body },
{ name: 'content', desc: locale.content },
{ name: 'description', desc: locale.description },
{ name: 'popup.root', desc: locale['popup.root'] },
]}
>

View File

@@ -59,10 +59,16 @@ export type ColorPickerSemanticName = keyof ColorPickerSemanticClassNames &
export type ColorPickerSemanticClassNames = {
root?: string;
body?: string;
content?: string;
description?: string;
};
export type ColorPickerSemanticStyles = {
root?: React.CSSProperties;
body?: React.CSSProperties;
content?: React.CSSProperties;
description?: React.CSSProperties;
};
export type ColorPickerClassNamesType = SemanticClassNamesType<

View File

@@ -1,6 +1,9 @@
import * as React from 'react';
export type SizeType = 'small' | 'middle' | 'large' | undefined;
/**
* Note: `middle` is deprecated and will be removed in v7, please use `medium` instead.
*/
export type SizeType = 'small' | 'medium' | 'middle' | 'large' | undefined;
const SizeContext = React.createContext<SizeType>(undefined);

View File

@@ -298,6 +298,7 @@ export type FormConfig = ComponentStyleConfig &
| 'variant'
| 'classNames'
| 'styles'
| 'tooltip'
>;
export type FloatButtonConfig = ComponentStyleConfig &

View File

@@ -133,7 +133,7 @@ const {
| flex | Set Flex common props | { className?: string, style?: React.CSSProperties, vertical?: boolean } | - | 5.10.0 |
| floatButton | Set FloatButton common props | { className?: string, style?: React.CSSProperties, classNames?: [FloatButtonProps\["classNames"\]](/components/float-button#semantic-dom), styles?: [FloatButtonProps\["styles"\]](/components/float-button#semantic-dom), backTopIcon?: React.ReactNode } | - | |
| floatButtonGroup | Set FloatButton.Group common props | { closeIcon?: React.ReactNode, className?: string, style?: React.CSSProperties, classNames?: [FloatButtonProps\["classNames"\]](/components/float-button#semantic-dom), styles?: [FloatButtonProps\["styles"\]](/components/float-button#semantic-dom) } | - | |
| form | Set Form common props | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options), classNames?:[FormConfig\["classNames"\]](/components/form#semantic-dom), styles?: [FormConfig\["styles"\]](/components/form#semantic-dom) } | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className` and `style`: 5.7.0 |
| form | Set Form common props | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options), classNames?:[FormConfig\["classNames"\]](/components/form#semantic-dom), styles?: [FormConfig\["styles"\]](/components/form#semantic-dom), tooltip?: [TooltipProps](/components/tooltip#api) & { icon?: ReactNode } } | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className` and `style`: 5.7.0; `tooltip`: 6.3.0 |
| image | Set Image common props | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode, classNames?:[ImageConfig\["classNames"\]](/components/image#semantic-dom), styles?: [ImageConfig\["styles"\]](/components/image#semantic-dom) }, fallback?: string } | - | 5.7.0, `closeIcon`: 5.14.0, `classNames` and `styles`: 6.0.0 |
| input | Set Input common props | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 4.2.0, `allowClear`: 5.15.0 |
| inputNumber | Set InputNumber common props | { className?: string, style?: React.CSSProperties, classNames?: [InputNumberConfig\["classNames"\]](/components/input-number#semantic-dom), styles?: [InputNumberConfig\["styles"\]](/components/input-number#semantic-dom) } | - | |

View File

@@ -135,7 +135,7 @@ const {
| flex | 设置 Flex 组件的通用属性 | { className?: string, style?: React.CSSProperties, vertical?: boolean } | - | 5.10.0 |
| floatButton | 设置 FloatButton 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [FloatButtonProps\["classNames"\]](/components/float-button-cn#semantic-dom), styles?: [FloatButtonProps\["styles"\]](/components/float-button-cn#semantic-dom), backTopIcon?: React.ReactNode } | - | |
| floatButtonGroup | 设置 FloatButton.Group 组件的通用属性 | { closeIcon?: React.ReactNode, className?: string, style?: React.CSSProperties, classNames?: [FloatButtonProps\["classNames"\]](/components/float-button-cn#semantic-dom), styles?: [FloatButtonProps\["styles"\]](/components/float-button-cn#semantic-dom) } | - | |
| form | 设置 Form 组件的通用属性 | { className?: string, style?: React.CSSProperties, 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), classNames?:[FormConfig\["classNames"\]](/components/form-cn#semantic-dom), styles?: [FormConfig\["styles"\]](/components/form-cn#semantic-dom) } | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className``style`: 5.7.0 |
| form | 设置 Form 组件的通用属性 | { className?: string, style?: React.CSSProperties, 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), classNames?:[FormConfig\["classNames"\]](/components/form-cn#semantic-dom), styles?: [FormConfig\["styles"\]](/components/form-cn#semantic-dom), tooltip?: [TooltipProps](/components/tooltip-cn#api) & { icon?: ReactNode } } | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className``style`: 5.7.0; `tooltip`: 6.3.0 |
| image | 设置 Image 组件的通用属性 | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode, classNames?:[ImageConfig\["classNames"\]](/components/image-cn#semantic-dom), styles?: [ImageConfig\["styles"\]](/components/image-cn#semantic-dom) }, fallback?: string } | - | 5.7.0, `closeIcon`: 5.14.0, `classNames``styles`: 6.0.0 |
| input | 设置 Input 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties,classNames?:[InputConfig\["classNames"\]](/components/input-cn#semantic-input), styles?: [InputConfig\["styles"\]](/components/input-cn#semantic-input), allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.7.0, `allowClear`: 5.15.0 |
| inputNumber | 设置 Input 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [InputNumberConfig\["classNames"\]](/components/input-number-cn#semantic-dom), styles?: [InputNumberConfig\["styles"\]](/components/input-number-cn#semantic-dom) } | - | |

View File

@@ -21,6 +21,7 @@ import type { ColProps } from '../grid/col';
import type { FormContextProps } from './context';
import { FormContext, FormProvider, NoFormStyle, VariantContext } from './context';
import type { FeedbackIcons } from './FormItem';
import type { FormTooltipProps } from './FormItemLabel';
import useForm from './hooks/useForm';
import type { FormInstance } from './hooks/useForm';
import useFormWarning from './hooks/useFormWarning';
@@ -74,6 +75,7 @@ export interface FormProps<Values = any> extends Omit<RcFormProps<Values>, 'form
requiredMark?: RequiredMark;
rootClassName?: string;
variant?: Variant;
tooltip?: FormTooltipProps;
}
const InternalForm: React.ForwardRefRenderFunction<FormRef, FormProps> = (props, ref) => {
@@ -88,6 +90,7 @@ const InternalForm: React.ForwardRefRenderFunction<FormRef, FormProps> = (props,
style: contextStyle,
styles: contextStyles,
classNames: contextClassNames,
tooltip: contextTooltip,
} = useComponentConfig('form');
const {
@@ -112,6 +115,7 @@ const InternalForm: React.ForwardRefRenderFunction<FormRef, FormProps> = (props,
variant,
classNames,
styles,
tooltip,
...restFormProps
} = props;
@@ -140,6 +144,8 @@ const InternalForm: React.ForwardRefRenderFunction<FormRef, FormProps> = (props,
const mergedColon = colon ?? contextColon;
const mergedTooltip = { ...contextTooltip, ...tooltip };
const prefixCls = getPrefixCls('form', customizePrefixCls);
// Style
@@ -198,6 +204,7 @@ const InternalForm: React.ForwardRefRenderFunction<FormRef, FormProps> = (props,
itemRef: __INTERNAL__.itemRef,
form: wrapForm,
feedbackIcons,
tooltip: mergedTooltip,
classNames: mergedClassNames,
styles: mergedStyles,
}),
@@ -213,6 +220,7 @@ const InternalForm: React.ForwardRefRenderFunction<FormRef, FormProps> = (props,
feedbackIcons,
mergedClassNames,
mergedStyles,
mergedTooltip,
],
);

View File

@@ -15,7 +15,7 @@ import useCSSVarCls from '../../config-provider/hooks/useCSSVarCls';
import { FormContext, NoStyleItemContext } from '../context';
import type { FormInstance, FormItemLayout } from '../Form';
import type { FormItemInputProps } from '../FormItemInput';
import type { FormItemLabelProps, LabelTooltipType } from '../FormItemLabel';
import type { FormItemLabelProps } from '../FormItemLabel';
import useChildren from '../hooks/useChildren';
import useFormItemStatus from '../hooks/useFormItemStatus';
import useFrameState from '../hooks/useFrameState';
@@ -100,7 +100,6 @@ export interface FormItemProps<Values = any>
hidden?: boolean;
initialValue?: any;
messageVariables?: Record<string, string>;
tooltip?: LabelTooltipType;
layout?: FormItemLayout;
}

View File

@@ -2,7 +2,6 @@ import * as React from 'react';
import QuestionCircleOutlined from '@ant-design/icons/QuestionCircleOutlined';
import { clsx } from 'clsx';
import convertToTooltipProps from '../_util/convertToTooltipProps';
import type { ColProps } from '../grid/col';
import Col from '../grid/col';
import { useLocale } from '../locale';
@@ -13,12 +12,13 @@ import type { FormContextProps } from './context';
import { FormContext } from './context';
import type { RequiredMark } from './Form';
import type { FormLabelAlign } from './interface';
import convertToTooltipProps from '../_util/convertToTooltipProps';
export type WrapperTooltipProps = TooltipProps & {
export type FormTooltipProps = TooltipProps & {
icon?: React.ReactElement;
};
export type LabelTooltipType = WrapperTooltipProps | React.ReactNode;
export type FormItemTooltipType = FormTooltipProps | React.ReactNode;
export interface FormItemLabelProps {
colon?: boolean;
@@ -30,7 +30,7 @@ export interface FormItemLabelProps {
* @internal Used for pass `requiredMark` from `<Form />`
*/
requiredMark?: RequiredMark;
tooltip?: LabelTooltipType;
tooltip?: FormItemTooltipType;
vertical?: boolean;
}
@@ -55,6 +55,7 @@ const FormItemLabel: React.FC<FormItemLabelProps & { required?: boolean; prefixC
colon: contextColon,
classNames: contextClassNames,
styles: contextStyles,
tooltip: contextTooltip,
} = React.useContext<FormContextProps>(FormContext);
if (!label) {
@@ -86,23 +87,19 @@ const FormItemLabel: React.FC<FormItemLabelProps & { required?: boolean; prefixC
labelChildren = label.replace(/[:|]\s*$/, '');
}
// Tooltip
const tooltipProps = convertToTooltipProps(tooltip);
const tooltipProps = convertToTooltipProps<FormTooltipProps>(tooltip, contextTooltip);
if (tooltipProps) {
const { icon = <QuestionCircleOutlined />, ...restTooltipProps } = tooltipProps;
const tooltipNode: React.ReactNode = (
<Tooltip {...restTooltipProps}>
{React.cloneElement(icon, {
className: `${prefixCls}-item-tooltip`,
title: '',
onClick: (e: React.MouseEvent) => {
// Prevent label behavior in tooltip icon
// https://github.com/ant-design/ant-design/issues/46154
<Tooltip {...tooltipProps}>
<span
className={`${prefixCls}-item-tooltip`}
onClick={(e: React.MouseEvent) => {
e.preventDefault();
},
tabIndex: null,
})}
}}
tabIndex={-1}
>
{tooltipProps.icon || tooltipProps.children || <QuestionCircleOutlined />}
</span>
</Tooltip>
);

View File

@@ -11371,27 +11371,31 @@ exports[`renders components/form/demo/register.tsx extend context correctly 1`]
Nickname
<span
aria-describedby="test-id"
aria-label="question-circle"
class="anticon anticon-question-circle ant-form-item-tooltip"
role="img"
title=""
class="ant-form-item-tooltip"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="question-circle"
class="anticon anticon-question-circle"
role="img"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
</span>
</span>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-css-var css-var-test-id ant-tooltip-placement-top"
@@ -12639,27 +12643,31 @@ exports[`renders components/form/demo/required-mark.tsx extend context correctly
Field A
<span
aria-describedby="test-id"
aria-label="question-circle"
class="anticon anticon-question-circle ant-form-item-tooltip"
role="img"
title=""
class="ant-form-item-tooltip"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="question-circle"
class="anticon anticon-question-circle"
role="img"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
</span>
</span>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-css-var css-var-test-id ant-tooltip-placement-top"
@@ -12719,27 +12727,31 @@ exports[`renders components/form/demo/required-mark.tsx extend context correctly
Field B
<span
aria-describedby="test-id"
aria-label="info-circle"
class="anticon anticon-info-circle ant-form-item-tooltip"
role="img"
title=""
class="ant-form-item-tooltip"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="info-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="info-circle"
class="anticon anticon-info-circle"
role="img"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"
/>
</svg>
<svg
aria-hidden="true"
data-icon="info-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</span>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-css-var css-var-test-id ant-tooltip-placement-top"

View File

@@ -7638,27 +7638,31 @@ exports[`renders components/form/demo/register.tsx correctly 1`] = `
>
Nickname
<span
aria-label="question-circle"
class="anticon anticon-question-circle ant-form-item-tooltip"
role="img"
title=""
class="ant-form-item-tooltip"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="question-circle"
class="anticon anticon-question-circle"
role="img"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
</span>
</span>
</label>
</div>
@@ -8529,27 +8533,31 @@ exports[`renders components/form/demo/required-mark.tsx correctly 1`] = `
>
Field A
<span
aria-label="question-circle"
class="anticon anticon-question-circle ant-form-item-tooltip"
role="img"
title=""
class="ant-form-item-tooltip"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="question-circle"
class="anticon anticon-question-circle"
role="img"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
<svg
aria-hidden="true"
data-icon="question-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"
/>
</svg>
</span>
</span>
</label>
</div>
@@ -8588,27 +8596,31 @@ exports[`renders components/form/demo/required-mark.tsx correctly 1`] = `
>
Field B
<span
aria-label="info-circle"
class="anticon anticon-info-circle ant-form-item-tooltip"
role="img"
title=""
class="ant-form-item-tooltip"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="info-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="info-circle"
class="anticon anticon-info-circle"
role="img"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"
/>
</svg>
<svg
aria-hidden="true"
data-icon="info-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</span>
<span
class="ant-form-item-optional"

View File

@@ -1601,7 +1601,7 @@ describe('Form', () => {
expect(container.querySelector('.ant-tooltip-container')).toHaveTextContent('Bamboo');
});
it('config tooltip should show when hover on icon', async () => {
it('TooltipProps', async () => {
const { container } = render(
<Form>
<Form.Item label="light" tooltip={{ title: 'Bamboo' }}>
@@ -1616,6 +1616,24 @@ describe('Form', () => {
expect(container.querySelector('.ant-tooltip-container')).toHaveTextContent('Bamboo');
});
it('ConfigProvider', async () => {
const { container } = render(
<ConfigProvider form={{ tooltip: { icon: <span className="foobar">Foobar</span> } }}>
<Form>
<Form.Item label="light" tooltip={{ title: 'Bamboo' }}>
<Input />
</Form.Item>
</Form>
</ConfigProvider>,
);
fireEvent.mouseEnter(container.querySelector('.foobar')!);
fireEvent.click(container.querySelector('.foobar')!);
await waitFakeTimer();
expect(container.querySelector('.ant-tooltip-container')).toHaveTextContent('Bamboo');
});
});
it('warningOnly validate', async () => {

View File

@@ -15,6 +15,7 @@ import type {
RequiredMark,
} from './Form';
import type { FeedbackIcons, ValidateStatus } from './FormItem';
import type { FormTooltipProps } from './FormItemLabel';
import type { FormLabelAlign, NamePath } from './interface';
/** Form Context. Set top form style and pass to Form Item usage. */
@@ -32,6 +33,7 @@ export interface FormContextProps {
itemRef: (name: (string | number)[]) => (node: React.ReactElement) => void;
form?: FormInstance;
feedbackIcons?: FeedbackIcons;
tooltip?: FormTooltipProps;
}
export const FormContext = React.createContext<FormContextProps>({

View File

@@ -85,6 +85,7 @@ Common props ref[Common props](/docs/react/common-props)
| scrollToFirstError | Auto scroll to first failed field when submit | boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) \| { focus: boolean } | false | focus: 5.24.0 |
| size | Set field component size (antd components only) | `small` \| `middle` \| `large` | - | |
| styles | Customize inline style for each semantic structure inside the component. Supports object or function. | Record<[SemanticDOM](#semantic-dom), CSSProperties> \| (info: { props })=> Record<[SemanticDOM](#semantic-dom), CSSProperties> | - | |
| tooltip | Config tooltip props | [TooltipProps](/components/tooltip#api) & { icon?: ReactNode } | - | 6.3.0 |
| validateMessages | Validation prompt template, description [see below](#validatemessages) | [ValidateMessages](https://github.com/ant-design/ant-design/blob/6234509d18bac1ac60fbb3f92a5b2c6a6361295a/components/locale/en_US.ts#L88-L134) | - | |
| validateTrigger | Config field validate trigger | string \| string\[] | `onChange` | 4.3.0 |
| variant | Variant of components inside form | `outlined` \| `borderless` \| `filled` \| `underlined` | `outlined` | 5.13.0 \| `underlined`: 5.24.0 |
@@ -150,7 +151,7 @@ Form field component for data bidirectional binding, validation, layout, and so
| required | Display required style. It will be generated by the validation rule | boolean | false | |
| rules | Rules for field validation. Click [here](#form-demo-basic) to see an example | [Rule](#rule)\[] | - | |
| shouldUpdate | Custom field update logic. See [below](#shouldupdate) | boolean \| (prevValue, curValue) => boolean | false | |
| tooltip | Config tooltip info | ReactNode \| [TooltipProps & { icon: ReactNode }](/components/tooltip#api) | - | 4.7.0 |
| tooltip | Config tooltip content | ReactNode \| ([TooltipProps](/components/tooltip#api) & { icon?: ReactNode }) | - | 4.7.0 |
| trigger | When to collect the value of children node. Click [here](#form-demo-customized-form-controls) to see an example | string | `onChange` | |
| validateDebounce | Delay milliseconds to start validation | number | - | 5.9.0 |
| validateFirst | Whether stop validate on first rule of error for this field. Will parallel validate when `parallel` configured | boolean \| `parallel` | false | `parallel`: 4.5.0 |

View File

@@ -86,6 +86,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*ylFATY6w-ygAAA
| scrollToFirstError | 提交失败自动滚动到第一个错误字段 | boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) \| { focus: boolean } | false | focus: 5.24.0 |
| size | 设置字段组件的尺寸(仅限 antd 组件) | `small` \| `middle` \| `large` | - | |
| styles | 用于自定义组件内部各语义化结构的行内 style支持对象或函数 | Record<[SemanticDOM](#semantic-dom), CSSProperties> \| (info: { props })=> Record<[SemanticDOM](#semantic-dom), CSSProperties> | - | |
| tooltip | 配置提示属性 | [TooltipProps](/components/tooltip-cn#api) & { icon?: ReactNode } | - | 6.3.0 |
| validateMessages | 验证提示模板,说明[见下](#validatemessages) | [ValidateMessages](https://github.com/ant-design/ant-design/blob/6234509d18bac1ac60fbb3f92a5b2c6a6361295a/components/locale/en_US.ts#L88-L134) | - | |
| validateTrigger | 统一设置字段触发验证的时机 | string \| string\[] | `onChange` | 4.3.0 |
| variant | 表单内控件变体 | `outlined` \| `borderless` \| `filled` \| `underlined` | `outlined` | 5.13.0 \| `underlined`: 5.24.0 |
@@ -151,7 +152,7 @@ const validateMessages = {
| required | 必填样式设置。如不设置,则会根据校验规则自动生成 | boolean | false | |
| rules | 校验规则,设置字段的校验逻辑。点击[此处](#form-demo-basic)查看示例 | [Rule](#rule)\[] | - | |
| shouldUpdate | 自定义字段更新逻辑,说明[见下](#shouldupdate) | boolean \| (prevValue, curValue) => boolean | false | |
| tooltip | 配置提示信息 | ReactNode \| [TooltipProps & { icon: ReactNode }](/components/tooltip-cn#api) | - | 4.7.0 |
| tooltip | 配置提示信息 | ReactNode \| ([TooltipProps](/components/tooltip-cn#api) & { icon?: ReactNode }) | - | 4.7.0 |
| trigger | 设置收集字段值变更的时机。点击[此处](#form-demo-customized-form-controls)查看示例 | string | `onChange` | |
| validateFirst | 当某一规则校验不通过时,是否停止剩下的规则的校验。设置 `parallel` 时会并行校验 | boolean \| `parallel` | false | `parallel`: 4.5.0 |
| validateDebounce | 设置防抖,延迟毫秒数后进行校验 | number | - | 5.9.0 |

View File

@@ -118,7 +118,7 @@
"@rc-component/cascader": "~1.11.0",
"@rc-component/checkbox": "~1.0.1",
"@rc-component/collapse": "~1.2.0",
"@rc-component/color-picker": "~3.0.3",
"@rc-component/color-picker": "~3.1.0",
"@rc-component/dialog": "~1.8.0",
"@rc-component/drawer": "~1.4.0",
"@rc-component/dropdown": "~1.0.2",