Merge branch 'feature' into fix/remove-duplicate-ant-upload-classname-from-parent-to-child

This commit is contained in:
afc163 2023-12-25 23:49:19 +08:00 committed by GitHub
commit fd10198641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
670 changed files with 71536 additions and 41399 deletions

View File

@ -1,35 +0,0 @@
# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1
# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
jobs:
test-argos-ci:
docker:
- image: cimg/node:21.1-browsers
environment:
NODE_OPTIONS: --openssl-legacy-provider
steps:
- checkout
- run:
name: Install node_modules
command: yarn
- run:
name: Build dist file
command: npm run dist:esbuild
- run:
name: Run image screenshot tests
command: npm run test-image
- run:
name: Upload screenshots to Argos CI
command: npm run argos
# The resource_class feature allows configuring CPU and RAM resources for each job. Different resource classes are available for different executors. https://circleci.com/docs/2.0/configuration-reference/#resourceclass
resource_class: large
# Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
workflows:
test-argos-ci-workflow:
jobs:
- test-argos-ci

View File

@ -1,4 +1,5 @@
{
"installCommand": "npm-install",
"sandboxes": ["antd-reproduction-template-forked-jyh2k9"],
"node": "18"
}

View File

@ -1,8 +1,10 @@
.demo-logo {
width: 120px;
min-width: 120px;
height: 32px;
background: rgba(255, 255, 255, 0.2);
border-radius: 6px;
margin-inline-end: 24px;
}
.demo-logo-vertical {

View File

@ -68,6 +68,7 @@ const useThemeAnimation = () => {
if (!(event && typeof document.startViewTransition === 'function')) {
return;
}
const time = Date.now();
const x = event.clientX;
const y = event.clientY;
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
@ -98,6 +99,7 @@ const useThemeAnimation = () => {
root.classList.add(isDark ? 'light' : 'dark');
})
.ready.then(() => {
console.log(`Theme transition finished in ${Date.now() - time}ms`);
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,

View File

@ -1,19 +1,19 @@
import * as React from 'react';
import { createStyles, css, useTheme } from 'antd-style';
import classNames from 'classnames';
import type { FC } from 'react';
import { useContext } from 'react';
import { Typography, Skeleton, Carousel } from 'antd';
import type { Extra, Icon } from './util';
import SiteContext from '../../../theme/slots/SiteContext';
import { getCarouselStyle, useSiteData } from './util';
import useLocale from '../../../hooks/useLocale';
import { Badge, Carousel, Skeleton, Typography } from 'antd';
import { createStyles, useTheme } from 'antd-style';
import classNames from 'classnames';
const useStyle = createStyles(({ token }) => {
import useLocale from '../../../hooks/useLocale';
import SiteContext from '../../../theme/slots/SiteContext';
import type { Extra, Icon } from './util';
import { getCarouselStyle, useSiteData } from './util';
const useStyle = createStyles(({ token, css, cx }) => {
const { carousel } = getCarouselStyle();
return {
itemBase: css`
const itemBase = css`
display: flex;
flex: 1 1 0;
flex-direction: column;
@ -25,9 +25,17 @@ const useStyle = createStyles(({ token }) => {
transition: all ${token.motionDurationSlow};
padding-block: ${token.paddingMD}px;
padding-inline: ${token.paddingLG}px;
box-sizing: border-box;
`;
return {
itemBase,
ribbon: css`
& > .${cx(itemBase)} {
height: 100%;
}
`,
cardItem: css`
width: 33%;
&:hover {
box-shadow: ${token.boxShadowCard};
}
@ -45,6 +53,9 @@ const useStyle = createStyles(({ token }) => {
column-gap: ${token.paddingMD * 2}px;
align-items: stretch;
text-align: start;
> * {
width: calc((100% - ${token.marginXXL * 2}px) / 3);
}
`,
carousel,
};
@ -56,7 +67,7 @@ interface RecommendItemProps {
icons: Icon[];
className?: string;
}
const RecommendItem = ({ extra, index, icons, className }: RecommendItemProps) => {
const RecommendItem: React.FC<RecommendItemProps> = ({ extra, index, icons, className }) => {
const token = useTheme();
const { styles } = useStyle();
@ -65,7 +76,7 @@ const RecommendItem = ({ extra, index, icons, className }: RecommendItemProps) =
}
const icon = icons.find((i) => i.name === extra.source);
return (
const card = (
<a
key={extra?.title}
href={extra.href}
@ -83,6 +94,16 @@ const RecommendItem = ({ extra, index, icons, className }: RecommendItemProps) =
</div>
</a>
);
if (index === 0) {
return (
<Badge.Ribbon text="HOT" color="red" rootClassName={styles.ribbon}>
{card}
</Badge.Ribbon>
);
}
return card;
};
export const BannerRecommendsFallback: FC = () => {
@ -93,8 +114,8 @@ export const BannerRecommendsFallback: FC = () => {
return isMobile ? (
<Carousel className={styles.carousel}>
{list.map((extra, index) => (
<div key={index}>
{list.map((_, index) => (
<div key={index} className={styles.itemBase}>
<Skeleton active style={{ padding: '0 24px' }} />
</div>
))}
@ -102,20 +123,26 @@ export const BannerRecommendsFallback: FC = () => {
) : (
<div className={styles.container}>
{list.map((_, index) => (
<Skeleton key={index} active />
<div key={index} className={styles.itemBase}>
<Skeleton active />
</div>
))}
</div>
);
};
export default function BannerRecommends() {
const BannerRecommends: React.FC = () => {
const { styles } = useStyle();
const [, lang] = useLocale();
const { isMobile } = React.useContext(SiteContext);
const data = useSiteData();
const extras = data?.extras?.[lang];
const icons = data?.icons;
const first3 = extras.length === 0 ? Array(3).fill(null) : extras.slice(0, 3);
const icons = data?.icons || [];
const first3 = !extras || extras.length === 0 ? Array(3).fill(null) : extras.slice(0, 3);
if (!data) {
return <BannerRecommendsFallback />;
}
return (
<div>
@ -147,4 +174,6 @@ export default function BannerRecommends() {
)}
</div>
);
}
};
export default BannerRecommends;

View File

@ -17,9 +17,9 @@ import {
Tooltip,
} from 'antd';
import { createStyles } from 'antd-style';
import classNames from 'classnames';
import useLocale from '../../../../hooks/useLocale';
import Tilt from './Tilt';
const { _InternalPanelDoNotUseOrYouWillBeFired: ModalPanel } = Modal;
const { _InternalPanelDoNotUseOrYouWillBeFired: InternalTooltip } = Tooltip;
@ -72,16 +72,14 @@ const locales = {
const useStyle = createStyles(({ token, css }) => {
const gap = token.padding;
return {
holder: css`
width: 500px;
display: flex;
flex-direction: column;
row-gap: ${gap}px;
opacity: 0.65;
opacity: 0.8;
`,
flex: css`
display: flex;
flex-wrap: nowrap;
@ -105,25 +103,16 @@ const useStyle = createStyles(({ token, css }) => {
};
});
export interface ComponentsBlockProps {
className?: string;
style?: React.CSSProperties;
}
const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
const { className, style } = props;
const ComponentsBlock: React.FC = () => {
const [locale] = useLocale(locales);
const { styles } = useStyle();
return (
<div className={classNames(className, styles.holder)} style={style}>
<Tilt options={{ max: 20, glare: true, scale: 1 }} className={styles.holder}>
<ModalPanel title="Ant Design 5.0" width="100%">
{locale.text}
</ModalPanel>
<Alert message={locale.infoText} type="info" />
{/* Line */}
<div className={styles.flex}>
<ColorPicker style={{ flex: 'none' }} />
@ -139,57 +128,34 @@ const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
{locale.dropdown}
</Dropdown.Button>
</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,
},
{ 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>
<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,
},
{ title: locale.finished },
{ title: locale.inProgress },
{ title: locale.waiting },
]}
/>
{/* Line */}
<div className={styles.block}>
<Slider
@ -200,16 +166,13 @@ const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
26: '26°C',
37: '37°C',
100: {
style: {
color: '#f50',
},
style: { color: '#f50' },
label: <strong>100°C</strong>,
},
}}
defaultValue={[26, 37]}
/>
</div>
{/* Line */}
<div className={styles.flex}>
<Button className={styles.ptg_20} type="primary">
@ -226,7 +189,6 @@ const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
{locale.icon}
</Button>
</div>
{/* Line */}
<div className={styles.block}>
<div className={styles.flex}>
@ -236,7 +198,6 @@ const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
checkedChildren={<CheckOutlined />}
unCheckedChildren={<CloseOutlined />}
/>
<Checkbox.Group
className={styles.ptg_none}
options={[locale.apple, locale.banana, locale.orange]}
@ -244,15 +205,12 @@ const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
/>
</div>
</div>
<div>
<InternalMessage content={locale.release} type="success" />
</div>
<InternalTooltip title={locale.hello} placement="topLeft" className={styles.noMargin} />
<Alert message="Ant Design love you!" type="success" />
</div>
</Tilt>
);
};

View File

@ -0,0 +1,34 @@
import React, { useEffect, useRef } from 'react';
import VanillaTilt from 'vanilla-tilt';
import type { TiltOptions } from 'vanilla-tilt';
interface TiltProps extends React.HTMLAttributes<HTMLDivElement> {
options?: TiltOptions;
}
// https://micku7zu.github.io/vanilla-tilt.js/index.html
const defaultTiltOptions: TiltOptions = {
scale: 1.02,
max: 8,
speed: 1500,
glare: true,
'max-glare': 0.8,
};
const Tilt: React.FC<TiltProps> = ({ options, ...props }) => {
const node = useRef<HTMLDivElement>(null);
useEffect(() => {
if (node.current) {
VanillaTilt.init(node.current, {
...defaultTiltOptions,
...options,
});
}
return () => {
(node.current as any)?.vanillaTilt.destroy();
};
}, []);
return <div ref={node} {...props} />;
};
export default Tilt;

View File

@ -7,7 +7,6 @@ import useLocale from '../../../../hooks/useLocale';
import SiteContext from '../../../../theme/slots/SiteContext';
import * as utils from '../../../../theme/utils';
import { GroupMask } from '../Group';
import useMouseTransform from './useMouseTransform';
const ComponentsBlock = React.lazy(() => import('./ComponentsBlock'));
@ -28,7 +27,6 @@ const locales = {
const useStyle = () => {
const { direction } = React.useContext(ConfigProvider.ConfigContext);
const isRTL = direction === 'rtl';
return createStyles(({ token, css, cx }) => {
const textShadow = `0 0 3px ${token.colorBgContainer}`;
@ -37,12 +35,14 @@ const useStyle = () => {
inset: 0;
backdrop-filter: blur(4px);
opacity: 1;
transition: opacity 1s ease;
background-color: rgba(255, 255, 255, 0.2);
transition: all 1s ease;
pointer-events: none;
`);
return {
holder: css`
height: 520px;
height: 640px;
display: flex;
flex-direction: column;
align-items: center;
@ -94,6 +94,7 @@ const useStyle = () => {
child: css`
position: relative;
width: 100%;
z-index: 1;
`,
};
@ -114,10 +115,8 @@ const PreviewBanner: React.FC<PreviewBannerProps> = (props) => {
const { pathname, search } = useLocation();
const isZhCN = utils.isZhCN(pathname);
const [componentsBlockStyle, mouseEvents] = useMouseTransform();
return (
<GroupMask {...mouseEvents}>
<GroupMask>
{/* Image Left Top */}
<img
style={{ position: 'absolute', left: isMobile ? -120 : 0, top: 0, width: 240 }}
@ -134,7 +133,11 @@ const PreviewBanner: React.FC<PreviewBannerProps> = (props) => {
<div className={styles.holder}>
{/* Mobile not show the component preview */}
<Suspense fallback={null}>
{!isMobile && <ComponentsBlock className={styles.block} style={componentsBlockStyle} />}
{isMobile ? null : (
<div className={styles.block}>
<ComponentsBlock />
</div>
)}
</Suspense>
<div className={styles.mask} />

View File

@ -1,73 +0,0 @@
import React, { startTransition } from 'react';
import { ConfigProvider } from 'antd';
const getTransformRotateStyle = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>,
currentTarget: EventTarget & HTMLDivElement,
multiple: number,
isRTL: boolean,
): string => {
const box = currentTarget?.getBoundingClientRect();
const calcX = -(event.clientY - box.y - box.height / 2) / multiple;
const calcY = (event.clientX - box.x - box.width / 2) / multiple;
return isRTL
? `rotate3d(${24 + calcX}, ${83 + calcY}, -45, 57deg)`
: `rotate3d(${24 + calcX}, ${-83 + calcY}, 45, 57deg)`;
};
const useMouseTransform = ({ transitionDuration = 500, multiple = 36 } = {}) => {
const [componentsBlockStyle, setComponentsBlockStyle] = React.useState<React.CSSProperties>({});
const { direction } = React.useContext(ConfigProvider.ConfigContext);
const isRTL = direction === 'rtl';
const onMouseMove: React.MouseEventHandler<HTMLDivElement> = (event) => {
const { currentTarget } = event;
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transform: getTransformRotateStyle(event, currentTarget, multiple, isRTL),
}));
});
};
const onMouseEnter: React.MouseEventHandler<HTMLDivElement> = () => {
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transition: `transform ${transitionDuration / 1000}s`,
}));
});
setTimeout(() => {
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transition: '',
}));
});
}, transitionDuration);
};
const onMouseLeave: React.MouseEventHandler<HTMLDivElement> = () => {
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transition: `transform ${transitionDuration / 1000}s`,
transform: '',
}));
});
};
return [
componentsBlockStyle,
{
onMouseMove,
onMouseEnter,
onMouseLeave,
},
] as const;
};
export default useMouseTransform;

View File

@ -1,99 +0,0 @@
import * as React from 'react';
import { createStyles, css, useTheme } from 'antd-style';
import { Row, Col, Typography } from 'antd';
import type { Recommendation } from './util';
const useStyle = createStyles(({ token }) => ({
card: css`
height: 300px;
background-size: 100% 100%;
background-position: center;
position: relative;
overflow: hidden;
&:before {
position: absolute;
background: linear-gradient(
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.25) 40%,
rgba(0, 0, 0, 0.65) 100%
);
opacity: 0.3;
transition: all 0.5s;
content: '';
pointer-events: none;
inset: 0;
}
&:hover {
&:before {
opacity: 1;
}
.intro {
transform: translate3d(0, 0, 0);
h4${token.antCls}-typography {
padding-bottom: 0;
}
}
}
.intro {
position: absolute;
right: 0;
bottom: 0;
left: 0;
transform: translate3d(0, 100%, 0);
transition: all ${token.motionDurationSlow};
${token.antCls}-typography {
margin: 0;
color: #fff;
font-weight: normal;
text-shadow: 0 0 1px rgba(0, 0, 0, 0.5);
transition: all ${token.motionDurationSlow};
}
h4${token.antCls}-typography {
position: absolute;
padding: 0 ${token.paddingMD}px ${token.paddingMD}px;
transform: translate3d(0, -100%, 0);
}
div${token.antCls}-typography {
padding: ${token.paddingXS}px ${token.paddingMD}px ${token.paddingLG}px;
}
}
`,
}));
export interface RecommendsProps {
recommendations?: Recommendation[];
}
export default function Recommends({ recommendations = [] }: RecommendsProps) {
const token = useTheme();
const { styles } = useStyle();
return (
<Row gutter={token.marginLG}>
{new Array(3).fill(null).map((_, index) => {
const data = recommendations[index];
return (
<Col key={index} span={8}>
{data ? (
<div className={styles.card} style={{ backgroundImage: `url(${data.img})` }}>
<div className="intro">
<Typography.Title level={4}>{data?.title}</Typography.Title>
<Typography.Paragraph>{data.description}</Typography.Paragraph>
</div>
</div>
) : null}
</Col>
);
})}
</Row>
);
}

View File

@ -403,13 +403,12 @@ export default function Theme() {
...themeToken,
colorPrimary: colorPrimaryValue,
},
hashed: true,
algorithm: algorithmFn,
components: {
Layout: isLight
? {
colorBgHeader: 'transparent',
colorBgBody: 'transparent',
headerBg: 'transparent',
bodyBg: 'transparent',
}
: {
// colorBgBody: 'transparent',

View File

@ -1,5 +1,6 @@
import { css } from 'antd-style';
import useFetch from '../../../hooks/useFetch';
import { useEffect, useState } from 'react';
import fetch from 'cross-fetch';
export interface Author {
avatar: string;
@ -80,8 +81,18 @@ export function preLoad(list: string[]) {
}
}
export function useSiteData(): Partial<SiteData> {
return useFetch('https://render.alipay.com/p/h5data/antd4-config_website-h5data.json');
export function useSiteData(): Partial<SiteData> | undefined {
const [data, setData] = useState<SiteData | undefined>(undefined);
useEffect(() => {
fetch('https://render.alipay.com/p/h5data/antd4-config_website-h5data.json').then(
async (res) => {
setData(await res.json());
},
);
}, []);
return data;
}
export const getCarouselStyle = () => ({

View File

@ -4,7 +4,7 @@ import { createStyles, css } from 'antd-style';
import useDark from '../../hooks/useDark';
import useLocale from '../../hooks/useLocale';
// import BannerRecommends, { BannerRecommendsFallback } from './components/BannerRecommends';
import BannerRecommends from './components/BannerRecommends';
import PreviewBanner from './components/PreviewBanner';
import Group from './components/Group';
@ -46,10 +46,7 @@ const Homepage: React.FC = () => {
return (
<section>
<PreviewBanner>
{/* 文档很久没更新了,先藏起来 */}
{/* <Suspense fallback={<BannerRecommendsFallback />}>
<BannerRecommends />
</Suspense> */}
</PreviewBanner>
<div>

View File

@ -1,13 +1,26 @@
import { RightOutlined, LinkOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import React, { useMemo, useState } from 'react';
import { LinkOutlined, QuestionCircleOutlined, RightOutlined } from '@ant-design/icons';
import { ConfigProvider, Popover, Table, Typography } from 'antd';
import { createStyles, css, useTheme } from 'antd-style';
import { getDesignToken } from 'antd-token-previewer';
import React, { useMemo, useState } from 'react';
import tokenMeta from 'antd/es/version/token-meta.json';
import tokenData from 'antd/es/version/token.json';
import { ConfigProvider, Table, Popover, Typography } from 'antd';
import useLocale from '../../../hooks/useLocale';
import { useColumns } from '../TokenTable';
const compare = (token1: string, token2: string) => {
const hasColor1 = token1.toLowerCase().includes('color');
const hasColor2 = token2.toLowerCase().includes('color');
if (hasColor1 && !hasColor2) {
return -1;
}
if (!hasColor1 && hasColor2) {
return 1;
}
return token1 < token2 ? -1 : 1;
};
const defaultToken = getDesignToken();
const locales = {
@ -18,6 +31,8 @@ const locales = {
value: '默认值',
componentToken: '组件 Token',
globalToken: '全局 Token',
componentComment: '这里是你的组件 token',
globalComment: '这里是你的全局 token',
help: '如何定制?',
customizeTokenLink: '/docs/react/customize-theme-cn#修改主题变量',
customizeComponentTokenLink: '/docs/react/customize-theme-cn#修改组件变量',
@ -29,6 +44,8 @@ const locales = {
value: 'Default Value',
componentToken: 'Component Token',
globalToken: 'Global Token',
componentComment: 'here is your component tokens',
globalComment: 'here is your global tokens',
help: 'How to use?',
customizeTokenLink: '/docs/react/customize-theme#customize-design-token',
customizeComponentTokenLink: 'docs/react/customize-theme#customize-component-token',
@ -46,13 +63,13 @@ const useStyle = createStyles(() => ({
`,
arrowIcon: css`
font-size: 16px;
margin-right: 8px;
margin-inline-end: 8px;
& svg {
transition: all 0.3s;
}
`,
help: css`
margin-left: 8px;
margin-inline-start: 8px;
font-size: 12px;
font-weight: normal;
color: #999;
@ -69,16 +86,14 @@ interface SubTokenTableProps {
helpLink: string;
tokens: string[];
component?: string;
comment?: {
componentComment?: string;
globalComment?: string;
};
}
const SubTokenTable: React.FC<SubTokenTableProps> = ({
defaultOpen,
tokens,
title,
helpText,
helpLink,
component,
}) => {
const SubTokenTable: React.FC<SubTokenTableProps> = (props) => {
const { defaultOpen, tokens, title, helpText, helpLink, component, comment } = props;
const [, lang] = useLocale(locales);
const token = useTheme();
const columns = useColumns();
@ -92,24 +107,7 @@ const SubTokenTable: React.FC<SubTokenTableProps> = ({
}
const data = tokens
.sort(
component
? undefined
: (token1, token2) => {
const hasColor1 = token1.toLowerCase().includes('color');
const hasColor2 = token2.toLowerCase().includes('color');
if (hasColor1 && !hasColor2) {
return -1;
}
if (!hasColor1 && hasColor2) {
return 1;
}
return token1 < token2 ? -1 : 1;
},
)
.sort(component ? undefined : compare)
.map((name) => {
const meta = component
? tokenMeta.components[component].find((item) => item.token === name)
@ -133,7 +131,7 @@ const SubTokenTable: React.FC<SubTokenTableProps> = ({
theme={{
components: {
${component}: {
/* here is your component tokens */
/* ${comment?.componentComment} */
},
},
}}
@ -143,7 +141,7 @@ const SubTokenTable: React.FC<SubTokenTableProps> = ({
: `<ConfigProvider
theme={{
token: {
/* here is your global tokens */
/* ${comment?.globalComment} */
},
}}
>
@ -161,16 +159,17 @@ const SubTokenTable: React.FC<SubTokenTableProps> = ({
popupStyle={{ width: 400 }}
content={
<Typography>
{/* <SourceCode lang="jsx">{code}</SourceCode> */}
<pre style={{ fontSize: 12 }}>{code}</pre>
<a href={helpLink} target="_blank" rel="noreferrer">
<LinkOutlined style={{ marginRight: 4 }} />
<LinkOutlined style={{ marginInlineEnd: 4 }} />
{helpText}
</a>
</Typography>
}
>
<span className={styles.help}>
<QuestionCircleOutlined style={{ marginRight: 3 }} />
<QuestionCircleOutlined style={{ marginInlineEnd: 4 }} />
{helpText}
</span>
</Popover>
@ -217,12 +216,16 @@ const ComponentTokenTable: React.FC<ComponentTokenTableProps> = ({ component })
<>
{tokenMeta.components[component] && (
<SubTokenTable
defaultOpen
title={locale.componentToken}
helpText={locale.help}
helpLink={locale.customizeTokenLink}
tokens={tokenMeta.components[component].map((item) => item.token)}
component={component}
defaultOpen
comment={{
componentComment: locale.componentComment,
globalComment: locale.globalComment,
}}
/>
)}
<SubTokenTable
@ -230,6 +233,10 @@ const ComponentTokenTable: React.FC<ComponentTokenTableProps> = ({ component })
helpText={locale.help}
helpLink={locale.customizeComponentTokenLink}
tokens={mergedGlobalTokens}
comment={{
componentComment: locale.componentComment,
globalComment: locale.globalComment,
}}
/>
</>
);

View File

@ -0,0 +1,39 @@
/**
* copied: https://github.com/arvinxx/dumi-theme-antd-style/tree/master/src/builtins/Container
*/
import * as React from 'react';
import { Alert } from 'antd';
import { type FC, type ReactNode } from 'react';
import useStyles from './style';
const Container: FC<{
type: 'info' | 'warning' | 'success' | 'error';
title?: string;
children: ReactNode;
}> = ({ type, title, children }) => {
const { styles, cx } = useStyles();
return (
<div data-type={type} className={styles.container}>
<Alert
showIcon
type={type}
message={title || type.toUpperCase()}
description={
<div
className={cx(
styles.desc,
// 为了让 markdown 的样式生效,需要在这里添加一个额外的 class
'markdown',
)}
>
{children}
</div>
}
className={styles.alert}
/>
</div>
);
};
export default Container;

View File

@ -0,0 +1,22 @@
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ prefixCls, css }) => ({
container: css`
margin: 8px 0;
`,
alert: css`
.${prefixCls}-alert-message {
font-weight: bold;
}
`,
/* 使用 `&&` 加一点点权重 */
desc: css`
&& p {
margin: 0;
}
`,
}));
export default useStyles;

View File

@ -1,15 +1,36 @@
import React, { useContext } from 'react';
import { DumiDemoGrid, FormattedMessage } from 'dumi';
import { BugFilled, BugOutlined, CodeFilled, CodeOutlined } from '@ant-design/icons';
import {
BugFilled,
BugOutlined,
CodeFilled,
CodeOutlined,
ExperimentFilled,
ExperimentOutlined,
} from '@ant-design/icons';
import classNames from 'classnames';
import { Tooltip } from 'antd';
import { ConfigProvider, Tooltip } from 'antd';
import DemoContext from '../../slots/DemoContext';
import useLayoutState from '../../../hooks/useLayoutState';
import useLocale from '../../../hooks/useLocale';
const locales = {
cn: {
enableCssVar: '启用 CSS 变量',
disableCssVar: '禁用 CSS 变量',
},
en: {
enableCssVar: 'Enable CSS Var',
disableCssVar: 'Disable CSS Var',
},
};
const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
const { showDebug, setShowDebug } = useContext(DemoContext);
const [locale] = useLocale(locales);
const [expandAll, setExpandAll] = useLayoutState(false);
const [enableCssVar, setEnableCssVar] = useLayoutState(true);
const expandTriggerClass = classNames('code-box-expand-trigger', {
'code-box-expand-trigger-active': expandAll,
@ -23,9 +44,14 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
setExpandAll(!expandAll);
};
const handleCssVarToggle = () => {
setEnableCssVar((v) => !v);
};
const demos = React.useMemo(
() =>
items.reduce((acc, item) => {
items.reduce(
(acc, item) => {
const { previewerProps } = item;
const { debug } = previewerProps;
@ -45,7 +71,9 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
originDebug: debug,
},
});
}, [] as typeof items),
},
[] as typeof items,
),
[expandAll, showDebug],
);
@ -74,8 +102,17 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
<BugOutlined className={expandTriggerClass} onClick={handleVisibleToggle} />
)}
</Tooltip>
<Tooltip title={enableCssVar ? locale.disableCssVar : locale.enableCssVar}>
{enableCssVar ? (
<ExperimentFilled className={expandTriggerClass} onClick={handleCssVarToggle} />
) : (
<ExperimentOutlined className={expandTriggerClass} onClick={handleCssVarToggle} />
)}
</Tooltip>
</span>
<ConfigProvider theme={{ cssVar: enableCssVar }}>
<DumiDemoGrid items={demos} />
</ConfigProvider>
</div>
);
};

View File

@ -1,7 +1,8 @@
import SourceCode from 'dumi/theme-default/builtins/SourceCode';
import React from 'react';
import type { TabsProps } from 'antd';
import { Tabs } from 'antd';
import { ConfigProvider, Tabs } from 'antd';
import SourceCode from 'dumi/theme-default/builtins/SourceCode';
import type { Tab } from 'rc-tabs/lib/interface';
import NpmLogo from './npm';
import PnpmLogo from './pnpm';
import YarnLogo from './yarn';
@ -12,51 +13,34 @@ interface InstallProps {
pnpm?: string;
}
const npmLabel = (
<span className="snippet-label">
<NpmLogo />
npm
</span>
);
const pnpmLabel = (
<span className="snippet-label">
<PnpmLogo />
pnpm
</span>
);
const yarnLabel = (
<span className="snippet-label">
<YarnLogo />
yarn
</span>
);
const InstallDependencies: React.FC<InstallProps> = (props) => {
const { npm, yarn, pnpm } = props;
const items = React.useMemo<TabsProps['items']>(
() =>
[
const items: Tab[] = [
{
key: 'npm',
label: 'npm',
children: npm ? <SourceCode lang="bash">{npm}</SourceCode> : null,
label: npmLabel,
icon: <NpmLogo />,
},
{
key: 'yarn',
label: 'yarn',
children: yarn ? <SourceCode lang="bash">{yarn}</SourceCode> : null,
label: yarnLabel,
icon: <YarnLogo />,
},
{
key: 'pnpm',
label: 'pnpm',
children: pnpm ? <SourceCode lang="bash">{pnpm}</SourceCode> : null,
label: pnpmLabel,
icon: <PnpmLogo />,
},
].filter((item) => item.children),
[npm, yarn, pnpm],
].filter((item) => item.children);
return (
<ConfigProvider theme={{ components: { Tabs: { horizontalMargin: '0' } } }}>
<Tabs className="markdown" size="small" defaultActiveKey="npm" items={items} />
</ConfigProvider>
);
return <Tabs className="antd-site-snippet" defaultActiveKey="npm" items={items} />;
};
export default InstallDependencies;

View File

@ -1,16 +1,28 @@
import React from 'react';
import { createStyles, css } from 'antd-style';
import classNames from 'classnames';
interface IconProps {
className?: string;
style?: React.CSSProperties;
}
const useStyle = createStyles(() => ({
iconWrap: css`
display: inline-flex;
align-items: center;
line-height: 0;
text-align: center;
vertical-align: -0.125em;
`,
}));
const NpmIcon: React.FC<IconProps> = (props) => {
const { className, style } = props;
const { styles } = useStyle();
return (
<span className={classNames(styles.iconWrap, className)} style={style}>
<svg
className={className}
style={style}
fill="#E53E3E"
focusable="false"
height="1em"
@ -21,6 +33,7 @@ const NpmIcon: React.FC<IconProps> = (props) => {
>
<path d="M0 0v16h16v-16h-16zM13 13h-2v-8h-3v8h-5v-10h10v10z" />
</svg>
</span>
);
};

View File

@ -1,16 +1,28 @@
import React from 'react';
import { createStyles, css } from 'antd-style';
import classNames from 'classnames';
interface IconProps {
className?: string;
style?: React.CSSProperties;
}
const useStyle = createStyles(() => ({
iconWrap: css`
display: inline-flex;
align-items: center;
line-height: 0;
text-align: center;
vertical-align: -0.125em;
`,
}));
const PnpmIcon: React.FC<IconProps> = (props) => {
const { className, style } = props;
const { styles } = useStyle();
return (
<span className={classNames(styles.iconWrap, className)} style={style}>
<svg
className={className}
style={style}
aria-hidden="true"
fill="#F69220"
focusable="false"
@ -23,6 +35,7 @@ const PnpmIcon: React.FC<IconProps> = (props) => {
>
<path d="M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z" />
</svg>
</span>
);
};

View File

@ -1,16 +1,28 @@
import React from 'react';
import { createStyles, css } from 'antd-style';
import classNames from 'classnames';
interface IconProps {
className?: string;
style?: React.CSSProperties;
}
const useStyle = createStyles(() => ({
iconWrap: css`
display: inline-flex;
align-items: center;
line-height: 0;
text-align: center;
vertical-align: -0.125em;
`,
}));
const YarnIcon: React.FC<IconProps> = (props) => {
const { className, style } = props;
const { styles } = useStyle();
return (
<span className={classNames(styles.iconWrap, className)} style={style}>
<svg
className={className}
style={style}
aria-hidden="true"
fill="#2C8EBB"
focusable="false"
@ -22,6 +34,7 @@ const YarnIcon: React.FC<IconProps> = (props) => {
>
<path d="M393.9 345.2c-39 9.3-48.4 32.1-104 47.4 0 0-2.7 4-10.4 5.8-13.4 3.3-63.9 6-68.5 6.1-12.4.1-19.9-3.2-22-8.2-6.4-15.3 9.2-22 9.2-22-8.1-5-9-9.9-9.8-8.1-2.4 5.8-3.6 20.1-10.1 26.5-8.8 8.9-25.5 5.9-35.3.8-10.8-5.7.8-19.2.8-19.2s-5.8 3.4-10.5-3.6c-6-9.3-17.1-37.3 11.5-62-1.3-10.1-4.6-53.7 40.6-85.6 0 0-20.6-22.8-12.9-43.3 5-13.4 7-13.3 8.6-13.9 5.7-2.2 11.3-4.6 15.4-9.1 20.6-22.2 46.8-18 46.8-18s12.4-37.8 23.9-30.4c3.5 2.3 16.3 30.6 16.3 30.6s13.6-7.9 15.1-5c8.2 16 9.2 46.5 5.6 65.1-6.1 30.6-21.4 47.1-27.6 57.5-1.4 2.4 16.5 10 27.8 41.3 10.4 28.6 1.1 52.7 2.8 55.3.8 1.4 13.7.8 36.4-13.2 12.8-7.9 28.1-16.9 45.4-17 16.7-.5 17.6 19.2 4.9 22.2zM496 256c0 136.9-111.1 248-248 248S0 392.9 0 256 111.1 8 248 8s248 111.1 248 248zm-79.3 75.2c-1.7-13.6-13.2-23-28-22.8-22 .3-40.5 11.7-52.8 19.2-4.8 3-8.9 5.2-12.4 6.8 3.1-44.5-22.5-73.1-28.7-79.4 7.8-11.3 18.4-27.8 23.4-53.2 4.3-21.7 3-55.5-6.9-74.5-1.6-3.1-7.4-11.2-21-7.4-9.7-20-13-22.1-15.6-23.8-1.1-.7-23.6-16.4-41.4 28-12.2.9-31.3 5.3-47.5 22.8-2 2.2-5.9 3.8-10.1 5.4h.1c-8.4 3-12.3 9.9-16.9 22.3-6.5 17.4.2 34.6 6.8 45.7-17.8 15.9-37 39.8-35.7 82.5-34 36-11.8 73-5.6 79.6-1.6 11.1 3.7 19.4 12 23.8 12.6 6.7 30.3 9.6 43.9 2.8 4.9 5.2 13.8 10.1 30 10.1 6.8 0 58-2.9 72.6-6.5 6.8-1.6 11.5-4.5 14.6-7.1 9.8-3.1 36.8-12.3 62.2-28.7 18-11.7 24.2-14.2 37.6-17.4 12.9-3.2 21-15.1 19.4-28.2z" />
</svg>
</span>
);
};

View File

@ -255,7 +255,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
'react@18/umd/react.development.js',
'react-dom@18/umd/react-dom.development.js',
'dayjs@1/dayjs.min.js',
`antd@${pkg.version}/dist/antd-with-locales.js`,
`antd@${pkg.version}/dist/antd-with-locales.min.js`,
`@ant-design/icons/dist/index.umd.js`,
'react-router-dom/dist/umd/react-router-dom.production.min.js',
'react-router/dist/umd/react-router.production.min.js',

View File

@ -10,8 +10,9 @@ const Previewer = React.lazy(() => import('./Previewer'));
const useStyle = createStyles(({ css }) => ({
skeletonWrapper: css`
width: 100% !important;
height: 500px;
height: 250px;
margin-bottom: 16px;
border-radius: 8px;
`,
}));

View File

@ -1,11 +1,10 @@
/* eslint-disable react/no-array-index-key */
import * as React from 'react';
import { Suspense } from 'react';
import dayjs from 'dayjs';
import { FormattedMessage } from 'dumi';
import { createStyles } from 'antd-style';
import { Avatar, Divider, Empty, Skeleton, Tabs } from 'antd';
import type { Article, Authors } from '../../../pages/index/components/util';
import type { Article, Authors, SiteData } from '../../../pages/index/components/util';
import { useSiteData } from '../../../pages/index/components/util';
import useLocale from '../../../hooks/useLocale';
@ -97,10 +96,11 @@ const ArticleList: React.FC<ArticleListProps> = ({ name, data = [], authors = []
);
};
const Articles: React.FC = () => {
const Articles: React.FC<{ data: Partial<SiteData> }> = ({ data }) => {
const [, lang] = useLocale();
const isZhCN = lang === 'cn';
const { articles = { cn: [], en: [] }, authors = [] } = useSiteData();
const { articles = { cn: [], en: [] }, authors = [] } = data;
// ========================== Data ==========================
const mergedData = React.useMemo(() => {
@ -149,11 +149,13 @@ const Articles: React.FC = () => {
export default () => {
const { styles } = useStyle();
const data = useSiteData();
const articles = data ? <Articles data={data} /> : <Skeleton active />;
return (
<div id="articles" className={styles.articles}>
<Suspense fallback={<Skeleton active />}>
<Articles />
</Suspense>
{articles}
</div>
);
};

View File

@ -44,7 +44,7 @@ const ColorPaletteTool: React.FC = () => {
text += locale.saturation((s * 100).toFixed(2));
}
if (b * 100 < primaryMinBrightness) {
text += locale.brightness((s * 100).toFixed(2));
text += locale.brightness((b * 100).toFixed(2));
}
}
return (

View File

@ -11,10 +11,16 @@ const Loading: React.FC = () => {
pathname.startsWith('/changelog')
) {
return (
<Space direction="vertical" style={{ width: '100%', marginTop: 24 }} size={40}>
<Skeleton title={false} active paragraph={{ rows: 3 }} />
<div style={{ maxWidth: '70vw', width: '100%', margin: '80px auto 0', textAlign: 'center' }}>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
width={40}
alt="loading"
style={{ marginBottom: 24, filter: 'grayscale(1)', opacity: 0.33 }}
/>
<Skeleton active paragraph={{ rows: 3 }} />
</Space>
<Skeleton active paragraph={{ rows: 4 }} style={{ marginTop: 32 }} />
</div>
);
}

View File

@ -26,7 +26,7 @@ const GlobalDemoStyles: React.FC = () => {
margin: 0 0 16px;
background-color: ${token.colorBgContainer};
border: 1px solid ${token.colorSplit};
border-radius: ${token.borderRadius}px;
border-radius: ${token.borderRadiusLG}px;
transition: all 0.2s;
.code-box-title {
@ -39,7 +39,7 @@ const GlobalDemoStyles: React.FC = () => {
.code-box-demo {
background-color: ${token.colorBgContainer};
border-radius: ${token.borderRadius}px ${token.borderRadius}px 0 0;
border-radius: ${token.borderRadiusLG}px ${token.borderRadiusLG}px 0 0;
> .demo {
overflow: auto;
}
@ -85,10 +85,6 @@ const GlobalDemoStyles: React.FC = () => {
transition: background-color 0.4s;
margin-inline-start: 16px;
${antCls}-row-rtl & {
border-radius: ${token.borderRadius}px 0 0 ${token.borderRadius}px;
}
a,
a:hover {
color: ${token.colorText};

View File

@ -199,28 +199,6 @@ const GlobalStyle: React.FC = () => {
font-size: 30px;
}
}
.antd-site-snippet {
.ant-tabs-tab {
.snippet-label {
display: flex;
align-items: center;
justify-content: center;
svg {
margin-inline-end: 8px;
}
}
}
.dumi-default-source-code {
margin: 0 auto;
background-color: ${token.siteMarkdownCodeBg};
border-radius: ${token.borderRadius}px;
> pre.prism-code {
padding: 12px 20px;
font-size: 13px;
line-height: 2;
}
}
}
.markdown table td > a:not(:last-child) {
margin-right: 0 !important;

View File

@ -4,7 +4,7 @@ import {
createCache,
extractStyle,
legacyNotSelectorLinter,
logicalPropertiesLinter,
NaNLinter,
parentSelectorLinter,
StyleProvider,
} from '@ant-design/cssinjs';
@ -45,7 +45,7 @@ const getAlgorithm = (themes: ThemeName[] = []) =>
}
return null;
})
.filter((item) => item) as typeof antdTheme.darkAlgorithm[];
.filter((item) => item) as (typeof antdTheme.darkAlgorithm)[];
const GlobalLayout: React.FC = () => {
const outlet = useOutlet();
@ -168,7 +168,7 @@ const GlobalLayout: React.FC = () => {
<DarkContext.Provider value={theme.includes('dark')}>
<StyleProvider
cache={styleCache}
linters={[logicalPropertiesLinter, legacyNotSelectorLinter, parentSelectorLinter]}
linters={[legacyNotSelectorLinter, parentSelectorLinter, NaNLinter]}
>
<SiteContext.Provider value={siteContextValue}>
<SiteThemeProvider
@ -177,6 +177,7 @@ const GlobalLayout: React.FC = () => {
token: {
motion: !theme.includes('motion-off'),
},
cssVar: true,
}}
>
<HappyProvider disabled={!theme.includes('happy-work')}>{content}</HappyProvider>

View File

@ -111,6 +111,8 @@
"app.footer.seeconf": "Experience Tech Conference",
"app.footer.xtech": "Ant Financial Experience Tech",
"app.footer.xtech.slogan": "Experience The Beauty",
"app.footer.galacean": "Galacean",
"app.footer.galacean.slogan": "Interactive Graphics Solution",
"app.docs.color.pick-primary": "Pick your primary color",
"app.docs.color.pick-background": "Pick your background color",
"app.docs.components.icon.search.placeholder": "Search icons here, click icon to copy code",

View File

@ -110,6 +110,8 @@
"app.footer.seeconf": "蚂蚁体验科技大会",
"app.footer.xtech": "蚂蚁体验科技",
"app.footer.xtech.slogan": "让用户体验美好",
"app.footer.galacean": "Galacean",
"app.footer.galacean.slogan": "互动图形解决方案",
"app.docs.color.pick-primary": "选择你的主色",
"app.docs.color.pick-background": "选择你的背景色",
"app.docs.components.icon.search.placeholder": "在此搜索图标,点击图标可复制代码",

View File

@ -166,7 +166,7 @@ const RoutesPlugin = (api: IApi) => {
});
// Insert antd style to head
const matchRegex = /<style data-type="antd-cssinjs">(.*?)<\/style>/;
const matchRegex = /<style data-type="antd-cssinjs">([\S\s]+?)<\/style>/;
const matchList = file.content.match(matchRegex) || [];
let antdStyle = '';

View File

@ -0,0 +1,38 @@
import React from 'react';
import { Avatar, Skeleton, Tooltip } from 'antd';
const AvatarPlaceholder: React.FC<{ num?: number }> = ({ num = 3 }) => (
<li>
{Array.from({ length: num }).map((_, i) => (
<Skeleton.Avatar size="small" active key={i} style={{ marginLeft: i === 0 ? 0 : -8 }} />
))}
</li>
);
interface ContributorAvatarProps {
username?: string;
url?: string;
loading?: boolean;
}
const ContributorAvatar: React.FC<ContributorAvatarProps> = ({ username, url, loading }) => {
if (loading) {
return <AvatarPlaceholder />;
}
if (username?.includes('github-actions')) {
return null;
}
return (
<Tooltip title={username}>
<li>
<a href={`https://github.com/${username}`} target="_blank" rel="noopener noreferrer">
<Avatar size="small" src={url} alt={username}>
{username}
</Avatar>
</a>
</li>
</Tooltip>
);
};
export default ContributorAvatar;

View File

@ -0,0 +1,82 @@
import React, { useContext } from 'react';
import classNames from 'classnames';
import { useIntl } from 'dumi';
import { createStyles } from 'antd-style';
import ContributorsList from '@qixian.cs/github-contributors-list';
import ContributorAvatar from './ContributorAvatar';
import SiteContext from '../SiteContext';
const useStyle = createStyles(({ token, css }) => {
const { antCls } = token;
return {
contributorsList: css`
margin-top: 120px !important;
`,
listMobile: css`
margin: 1em 0 !important;
`,
title: css`
font-size: 12px;
opacity: 0.45;
`,
list: css`
display: flex;
flex-wrap: wrap;
clear: both;
li {
height: 24px;
}
li,
${antCls}-avatar + ${antCls}-avatar {
transition: all ${token.motionDurationSlow};
margin-inline-end: -8px;
}
&:hover {
li,
${antCls}-avatar {
margin-inline-end: 0;
}
}
`,
};
});
interface ContributorsProps {
filename?: string;
}
const Contributors: React.FC<ContributorsProps> = ({ filename }) => {
const { formatMessage } = useIntl();
const { styles } = useStyle();
const { isMobile } = useContext(SiteContext);
if (!filename) {
return null;
}
return (
<div className={classNames(styles.contributorsList, { [styles.listMobile]: isMobile })}>
<div className={styles.title}>{formatMessage({ id: 'app.content.contributors' })}</div>
<ContributorsList
cache
repo="ant-design"
owner="ant-design"
fileName={filename}
className={styles.list}
renderItem={(item, loading) => (
<ContributorAvatar
key={item?.username}
username={item?.username}
url={item?.url}
loading={loading}
/>
)}
/>
</div>
);
};
export default Contributors;

View File

@ -0,0 +1,137 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
import { Anchor } from 'antd';
import { createStyles, useTheme } from 'antd-style';
import { useRouteMeta, useTabMeta } from 'dumi';
const useStyle = createStyles(({ token, css }) => {
const { antCls } = token;
return {
toc: css`
${antCls}-anchor {
${antCls}-anchor-link-title {
font-size: 12px;
}
}
`,
tocWrapper: css`
position: fixed;
top: ${token.headerHeight + token.contentMarginTop}px;
inset-inline-end: 0;
width: 160px;
margin: 0 0 12px 0;
padding: 8px 0;
padding-inline: 4px 8px;
backdrop-filter: blur(8px);
border-radius: ${token.borderRadius}px;
box-sizing: border-box;
z-index: 1000;
.toc-debug {
color: ${token.purple6};
&:hover {
color: ${token.purple5};
}
}
> div {
box-sizing: border-box;
width: 100%;
max-height: calc(100vh - 40px) !important;
margin: 0 auto;
overflow: auto;
padding-inline: 4px;
}
@media only screen and (max-width: ${token.screenLG}px) {
display: none;
}
`,
articleWrapper: css`
padding: 0 170px 32px 64px;
&.rtl {
padding: 0 64px 144px 170px;
}
@media only screen and (max-width: ${token.screenLG}px) {
&,
&.rtl {
padding: 0 48px;
}
}
`,
};
});
interface DocAnchorProps {
showDebug?: boolean;
debugDemos?: string[];
}
type AnchorItem = {
id: string;
title: string;
children?: AnchorItem[];
};
const DocAnchor: React.FC<DocAnchorProps> = ({ showDebug, debugDemos = [] }) => {
const { styles } = useStyle();
const token = useTheme();
const meta = useRouteMeta();
const tab = useTabMeta();
const renderAnchorItem = (item: AnchorItem) => ({
href: `#${item.id}`,
title: item.title,
key: item.id,
children: item.children
?.filter((child) => showDebug || !debugDemos.includes(child.id))
.map((child) => ({
key: child.id,
href: `#${child.id}`,
title: (
<span className={classNames(debugDemos.includes(child.id) && 'toc-debug')}>
{child?.title}
</span>
),
})),
});
const anchorItems = useMemo(
() =>
(tab?.toc || meta.toc).reduce<AnchorItem[]>((result, item) => {
if (item.depth === 2) {
result.push({ ...item });
} else if (item.depth === 3) {
const parent = result[result.length - 1];
if (parent) {
parent.children = parent.children || [];
parent.children.push({ ...item });
}
}
return result;
}, []),
[tab?.toc, meta.toc],
);
if (!meta.frontmatter.toc) {
return null;
}
return (
<section className={styles.tocWrapper}>
<Anchor
className={styles.toc}
affix={false}
targetOffset={token.anchorTop}
showInkInFixed
items={anchorItems.map(renderAnchorItem)}
/>
</section>
);
};
export default DocAnchor;

View File

@ -0,0 +1,79 @@
import React, { useState, useLayoutEffect, useMemo } from 'react';
import { Typography, Space, Skeleton, Avatar } from 'antd';
import { useRouteMeta } from 'dumi';
import DayJS from 'dayjs';
import { CalendarOutlined } from '@ant-design/icons';
const AuthorAvatar: React.FC<{ name: string; avatar: string }> = ({ name, avatar }) => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
useLayoutEffect(() => {
const img = new Image();
img.src = avatar;
img.onload = () => setLoading(false);
img.onerror = () => setError(true);
}, []);
if (error) {
return null;
}
if (loading) {
return <Skeleton.Avatar size="small" active />;
}
return (
<Avatar size="small" src={avatar} alt={name}>
{name}
</Avatar>
);
};
const DocMeta: React.FC<{}> = () => {
const meta = useRouteMeta();
const mergedAuthorInfos = useMemo(() => {
const { author } = meta.frontmatter;
if (!author) {
return [];
}
if (typeof author === 'string') {
return author.split(',').map((item) => ({
name: item,
avatar: `https://github.com/${item}.png`,
}));
}
if (Array.isArray(author)) {
return author;
}
return [];
}, [meta.frontmatter.author]);
if (!meta.frontmatter.date && !meta.frontmatter.author) {
return null;
}
return (
<Typography.Paragraph>
<Space>
{meta.frontmatter.date && (
<span style={{ opacity: 0.65 }}>
<CalendarOutlined /> {DayJS(meta.frontmatter.date).format('YYYY-MM-DD')}
</span>
)}
{mergedAuthorInfos.map((info) => (
<a
href={`https://github.com/${info.name}`}
target="_blank"
rel="noopener noreferrer"
key={info.name}
>
<Space size={3}>
<AuthorAvatar name={info.name} avatar={info.avatar} />
<span style={{ opacity: 0.65 }}>@{info.name}</span>
</Space>
</a>
))}
</Space>
</Typography.Paragraph>
);
};
export default DocMeta;

View File

@ -1,93 +1,25 @@
import { CalendarOutlined } from '@ant-design/icons';
import { createStyles, useTheme } from 'antd-style';
import ContributorsList from '@qixian.cs/github-contributors-list';
import classNames from 'classnames';
import DayJS from 'dayjs';
import { FormattedMessage, useIntl, useRouteMeta, useTabMeta } from 'dumi';
import { FormattedMessage, useRouteMeta } from 'dumi';
import type { ReactNode } from 'react';
import React, { useContext, useLayoutEffect, useMemo, useState } from 'react';
import { Anchor, Avatar, Col, ConfigProvider, Skeleton, Space, Tooltip, Typography } from 'antd';
import React, { Suspense, useContext, useLayoutEffect, useMemo } from 'react';
import { Col, Space, Typography, Skeleton } from 'antd';
import { createStyles } from 'antd-style';
import useLayoutState from '../../../hooks/useLayoutState';
import useLocation from '../../../hooks/useLocation';
import EditButton from '../../common/EditButton';
import PrevAndNext from '../../common/PrevAndNext';
import ComponentChangelog from '../../common/ComponentChangelog';
import type { DemoContextProps } from '../DemoContext';
import DemoContext from '../DemoContext';
import Footer from '../Footer';
import SiteContext from '../SiteContext';
import ColumnCard from './ColumnCard';
const useStyle = createStyles(({ token, css }) => {
const { antCls } = token;
const Contributors = React.lazy(() => import('./Contributors'));
const ColumnCard = React.lazy(() => import('./ColumnCard'));
const DocAnchor = React.lazy(() => import('./DocAnchor'));
const DocMeta = React.lazy(() => import('./DocMeta'));
const Footer = React.lazy(() => import('../Footer'));
const PrevAndNext = React.lazy(() => import('../../common/PrevAndNext'));
const ComponentChangelog = React.lazy(() => import('../../common/ComponentChangelog'));
const EditButton = React.lazy(() => import('../../common/EditButton'));
return {
contributorsList: css`
display: flex;
flex-wrap: wrap;
margin-top: 120px !important;
clear: both;
li {
height: 24px;
}
li,
${antCls}-avatar + ${antCls}-avatar {
transition: all ${token.motionDurationSlow};
margin-inline-end: -8px;
}
&:hover {
li,
${antCls}-avatar {
margin-inline-end: 0;
}
}
`,
listMobile: css`
margin: 1em 0 !important;
`,
toc: css`
${antCls}-anchor {
${antCls}-anchor-link-title {
font-size: 12px;
}
}
`,
tocWrapper: css`
position: fixed;
top: ${token.headerHeight + token.contentMarginTop}px;
inset-inline-end: 0;
width: 160px;
margin: 0 0 12px 0;
padding: 8px 0;
padding-inline: 4px 8px;
backdrop-filter: blur(8px);
border-radius: ${token.borderRadius}px;
box-sizing: border-box;
z-index: 1000;
.toc-debug {
color: ${token.purple6};
&:hover {
color: ${token.purple5};
}
}
> div {
box-sizing: border-box;
width: 100%;
max-height: calc(100vh - 40px) !important;
margin: 0 auto;
overflow: auto;
padding-inline: 4px;
}
@media only screen and (max-width: ${token.screenLG}px) {
display: none;
}
`,
const useStyle = createStyles(({ token, css }) => ({
articleWrapper: css`
padding: 0 170px 32px 64px;
@ -102,53 +34,13 @@ const useStyle = createStyles(({ token, css }) => {
}
}
`,
};
});
type AnchorItem = {
id: string;
title: string;
children?: AnchorItem[];
};
const AvatarPlaceholder: React.FC<{ num?: number }> = ({ num = 3 }) => (
<li>
{Array.from({ length: num }).map((_, i) => (
<Skeleton.Avatar size="small" active key={i} style={{ marginLeft: i === 0 ? 0 : -8 }} />
))}
</li>
);
const AuthorAvatar: React.FC<{ name: string; avatar: string }> = ({ name, avatar }) => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
useLayoutEffect(() => {
const img = new Image();
img.src = avatar;
img.onload = () => setLoading(false);
img.onerror = () => setError(true);
}, []);
if (error) {
return null;
}
if (loading) {
return <Skeleton.Avatar size="small" active />;
}
return (
<Avatar size="small" src={avatar} alt={name}>
{name}
</Avatar>
);
};
}));
const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
const meta = useRouteMeta();
const tab = useTabMeta();
const { pathname, hash } = useLocation();
const { formatMessage } = useIntl();
const { direction } = useContext(SiteContext);
const { styles } = useStyle();
const token = useTheme();
const { direction, isMobile } = useContext(SiteContext);
const [showDebug, setShowDebug] = useLayoutState(false);
const debugDemos = useMemo(
@ -167,71 +59,14 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
[showDebug, debugDemos],
);
const anchorItems = useMemo(
() =>
(tab?.toc || meta.toc).reduce<AnchorItem[]>((result, item) => {
if (item.depth === 2) {
result.push({ ...item });
} else if (item.depth === 3) {
const parent = result[result.length - 1];
if (parent) {
parent.children = parent.children || [];
parent.children.push({ ...item });
}
}
return result;
}, []),
[tab?.toc, meta.toc],
);
const isRTL = direction === 'rtl';
const mergedAuthorInfos = useMemo(() => {
const { author } = meta.frontmatter;
if (!author) {
return [];
}
if (typeof author === 'string') {
return author.split(',').map((item) => ({
name: item,
avatar: `https://github.com/${item}.png`,
}));
}
if (Array.isArray(author)) {
return author;
}
return [];
}, [meta.frontmatter.author]);
return (
<DemoContext.Provider value={contextValue}>
<Col xxl={20} xl={19} lg={18} md={18} sm={24} xs={24}>
{!!meta.frontmatter.toc && (
<section className={styles.tocWrapper}>
<Anchor
className={styles.toc}
affix={false}
targetOffset={token.anchorTop}
showInkInFixed
items={anchorItems.map((item) => ({
href: `#${item.id}`,
title: item.title,
key: item.id,
children: item.children
?.filter((child) => showDebug || !debugDemos.includes(child.id))
.map((child) => ({
key: child.id,
href: `#${child.id}`,
title: (
<span className={classNames(debugDemos.includes(child.id) && 'toc-debug')}>
{child?.title}
</span>
),
})),
}))}
/>
</section>
)}
<Suspense fallback={<Skeleton.Input active size="small" />}>
<DocAnchor showDebug={showDebug} debugDemos={debugDemos} />
</Suspense>
<article className={classNames(styles.articleWrapper, { rtl: isRTL })}>
{meta.frontmatter?.title ? (
<Typography.Title style={{ fontSize: 30, position: 'relative' }}>
@ -240,92 +75,43 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
{meta.frontmatter?.subtitle}
{!pathname.startsWith('/components/overview') && (
<Suspense fallback={null}>
<EditButton
title={<FormattedMessage id="app.content.edit-page" />}
filename={meta.frontmatter.filename}
/>
</Suspense>
)}
</Space>
{pathname.startsWith('/components/') && <ComponentChangelog pathname={pathname} />}
{pathname.startsWith('/components/') && (
<Suspense fallback={null}>
<ComponentChangelog pathname={pathname} />
</Suspense>
)}
</Typography.Title>
) : null}
{/* 添加作者、时间等信息 */}
{meta.frontmatter.date || meta.frontmatter.author ? (
<Typography.Paragraph>
<Space>
{meta.frontmatter.date && (
<span style={{ opacity: 0.65 }}>
<CalendarOutlined /> {DayJS(meta.frontmatter.date).format('YYYY-MM-DD')}
</span>
)}
{mergedAuthorInfos.map((info) => (
<a
href={`https://github.com/${info.name}`}
target="_blank"
rel="noopener noreferrer"
key={info.name}
>
<Space size={3}>
<AuthorAvatar name={info.name} avatar={info.avatar} />
<span style={{ opacity: 0.65 }}>@{info.name}</span>
</Space>
</a>
))}
</Space>
</Typography.Paragraph>
) : null}
<Suspense fallback={<Skeleton.Input active size="small" />}>
<DocMeta />
</Suspense>
{!meta.frontmatter.__autoDescription && meta.frontmatter.description}
<ConfigProvider theme={{ cssVar: {} }}>
<div style={{ minHeight: 'calc(100vh - 64px)' }}>{children}</div>
</ConfigProvider>
{(meta.frontmatter?.zhihu_url ||
meta.frontmatter?.yuque_url ||
meta.frontmatter?.juejin_url) && (
<Suspense fallback={<Skeleton.Input active size="small" />}>
<ColumnCard
zhihuLink={meta.frontmatter.zhihu_url}
yuqueLink={meta.frontmatter.yuque_url}
juejinLink={meta.frontmatter.juejin_url}
/>
)}
{meta.frontmatter.filename && (
<ContributorsList
cache
repo="ant-design"
owner="ant-design"
className={classNames(styles.contributorsList, { [styles.listMobile]: isMobile })}
fileName={meta.frontmatter.filename}
renderItem={(item, loading) => {
if (!item || loading) {
return <AvatarPlaceholder />;
}
if (item.username?.includes('github-actions')) {
return null;
}
return (
<Tooltip
mouseEnterDelay={0.3}
title={`${formatMessage({ id: 'app.content.contributors' })}: ${item.username}`}
key={item.username}
>
<li>
<a
href={`https://github.com/${item.username}`}
target="_blank"
rel="noopener noreferrer"
>
<Avatar size="small" src={item.url} alt={item.username}>
{item.username}
</Avatar>
</a>
</li>
</Tooltip>
);
}}
/>
)}
</Suspense>
<Suspense fallback={<Skeleton.Input active size="small" />}>
<Contributors filename={meta.frontmatter.filename} />
</Suspense>
</article>
<Suspense fallback={<Skeleton.Input active size="small" />}>
<PrevAndNext rtl={isRTL} />
</Suspense>
<Suspense fallback={null}>
<Footer />
</Suspense>
</Col>
</DemoContext.Provider>
);

View File

@ -1,12 +1,12 @@
import type { FC, ReactNode } from 'react';
import React from 'react';
import { CodeOutlined, SkinOutlined } from '@ant-design/icons';
import { Tabs } from 'antd';
import { useRouteMeta } from 'dumi';
import type { IContentTabsProps } from 'dumi/theme-default/slots/ContentTabs';
import type { TabsProps } from 'rc-tabs';
import { Tabs } from 'antd';
const titleMap: Record<string, string> = {
const titleMap: Record<string, ReactNode> = {
design: '设计',
};
@ -23,24 +23,17 @@ const ContentTabs: FC<IContentTabsProps> = ({ tabs, tabKey, onChange }) => {
const items: TabsProps['items'] = [
{
label: (
<span>
<CodeOutlined />
</span>
),
key: 'development',
label: '开发',
icon: <CodeOutlined />,
},
];
tabs?.forEach((tab) => {
items.push({
label: (
<span>
{iconMap[tab.key]}
{titleMap[tab.key]}
</span>
),
key: tab.key,
label: titleMap[tab.key],
icon: iconMap[tab.key],
});
});
@ -48,7 +41,7 @@ const ContentTabs: FC<IContentTabsProps> = ({ tabs, tabKey, onChange }) => {
<Tabs
items={items}
activeKey={tabKey || 'development'}
onChange={(key) => onChange(tabs.find((tab) => tab.key === key))}
onChange={(key) => onChange(tabs?.find((tab) => tab.key === key))}
style={{ margin: '32px 0 -16px' }}
/>
);

View File

@ -363,6 +363,20 @@ const Footer: React.FC = () => {
url: 'https://kitchen.alipay.com',
openExternal: true,
},
{
icon: (
<img
src="https://mdn.alipayobjects.com/huamei_j9rjmc/afts/img/A*3ittT5OEo2gAAAAAAAAAAAAADvGmAQ/original"
width={16}
height={16}
alt="Galacean"
/>
),
title: <FormattedMessage id="app.footer.galacean" />,
description: <FormattedMessage id="app.footer.galacean.slogan" />,
url: 'https://galacean.antgroup.com/',
openExternal: true,
},
{
icon: (
<img

View File

@ -25,15 +25,16 @@ const RESPONSIVE_SM = 1200;
const locales = {
cn: {
message:
'语雀公益计划:大学生认证教育邮箱,即可免费获得语雀会员。语雀,支付宝匠心打造的在线文档平台。',
shortMessage: '支付宝语雀 · 大学生公益计划火热进行中!',
more: '了解更多',
message: '语雀征文 · 说说你和开源的故事,赢取 Ant Design 精美周边 🎁',
shortMessage: '语雀征文 · 说说你和开源的故事,赢取 Ant Design 精美周边 🎁',
more: '前往了解',
link: 'https://www.yuque.com/opensource2023',
},
en: {
message: '',
shortMessage: '',
more: '',
link: '',
},
};
@ -222,9 +223,11 @@ const Header: React.FC = () => {
// Mirror url must have `/`, we add this for compatible
const urlObj = new URL(currentUrl.replace(window.location.origin, url));
if (urlObj.host.includes('antgroup')) {
window.location.href = `${urlObj.href.replace(/\/$/, '')}/`;
}
urlObj.pathname = `${urlObj.pathname.replace(/\/$/, '')}/`;
window.location.href = urlObj.toString();
} else {
window.location.href = urlObj.href.replace(/\/$/, '');
}
}, []);
const onLangChange = useCallback(() => {
@ -366,26 +369,28 @@ const Header: React.FC = () => {
</Popover>
)}
{isZhCN && bannerVisible && (
<ConfigProvider theme={{ token: { colorInfoBg: '#daf5eb', colorTextBase: '#000' } }}>
<ConfigProvider
theme={{
token: {
colorInfoBg: 'linear-gradient(90deg, #84fab0, #8fd3f4)',
colorTextBase: '#000',
},
}}
>
<Alert
className={styles.banner}
message={
<>
<img
className={styles.icon}
src="https://gw.alipayobjects.com/zos/rmsportal/XuVpGqBFxXplzvLjJBZB.svg"
alt="yuque"
/>
<span>{isMobile ? locale.shortMessage : locale.message}</span>
<a
className={styles.link}
href="https://www.yuque.com/yuque/blog/welfare-edu?source=antd"
href={locale.link}
target="_blank"
rel="noreferrer"
onClick={() => {
window.gtag?.('event', '点击', {
event_category: 'top_banner',
event_label: 'https://www.yuque.com/yuque/blog/welfare-edu?source=antd',
event_label: locale.link,
});
}}
>

View File

@ -61,18 +61,3 @@ Describe changes from the user side, and list all potential break changes or oth
- [ ] Demo is updated/provided or not needed
- [ ] TypeScript definition is updated/provided or not needed
- [ ] Changelog is provided or not needed
---
<!--
Below are template for copilot to generate CR message.
Please DO NOT modify it.
-->
### 🚀 Summary
copilot:summary
### 🔍 Walkthrough
copilot:walkthrough

View File

@ -61,17 +61,3 @@
- [ ] 代码演示已提供或无须提供
- [ ] TypeScript 定义已补充或无须补充
- [ ] Changelog 已提供或无须提供
---
<!--
以下为 copilot 自动生成的 CR 结果,请勿修改
-->
### 🚀 概述
copilot:summary
### 🔍 实现细节
copilot:walkthrough

View File

@ -19,7 +19,7 @@ jobs:
DING_TALK_TOKEN: |
${{ secrets.DINGDING_BOT_TOKEN }}
${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
notify_title: '🔥 @${{ github.event.discussion.user.login }} 创建了讨论:${{ github.event.discussion.title }} #${{ github.event.discussion.number }}'
notify_title: '🔥 @${{ github.event.discussion.user.login }} 创建了讨论:${{ github.event.discussion.title }} ${{ github.event.discussion.html_url }}'
notify_body: '### 🔥 @${{ github.event.discussion.user.login }} 创建了讨论:[${{ github.event.discussion.title }}](${{ github.event.discussion.html_url }}) <hr />'
notify_footer: '> 💬 欢迎前往 GitHub 进行讨论,社区可能需要你的帮助。'
at_all: false # whether to ding everybody

View File

@ -40,7 +40,9 @@ jobs:
body: |
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking codesandbox of [antd@5.x](https://u.ant.design/codesandbox-repro) or [antd@4.x](https://u.ant.design/codesandbox-repro-4x), or provide a minimal GitHub repository. Issues labeled by `Need Reproduce` will be closed if no activities in 3 days.
你好 @${{ github.event.issue.user.login }}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击这里创建一个 [antd@5.x](https://u.ant.design/codesandbox-repro) 或 [antd@4.x](https://u.ant.design/codesandbox-repro-4x) 的 codesandbox或者提供一个最小化的 GitHub 仓库。3 天内未跟进此 issue 将会被自动关闭。
你好 @${{ github.event.issue.user.login }},我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击这里创建一个 [antd@5.x](https://u.ant.design/codesandbox-repro) 或 [antd@4.x](https://u.ant.design/codesandbox-repro-4x) 的 codesandbox或者提供一个最小化的 GitHub 仓库。3 天内未跟进此 issue 将会被自动关闭。
> [什么是最小化重现,为什么这是必需的?](https://github.com/ant-design/ant-design/wiki/%E4%BB%80%E4%B9%88%E6%98%AF%E6%9C%80%E5%B0%8F%E5%8C%96%E9%87%8D%E7%8E%B0%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%99%E6%98%AF%E5%BF%85%E9%9C%80%E7%9A%84%EF%BC%9F)
![](https://gw.alipayobjects.com/zos/antfincdn/y9kwg7DVCd/reproduce.gif)

View File

@ -99,7 +99,7 @@ jobs:
DING_TALK_TOKEN: |
${{ secrets.DINGDING_BOT_TOKEN }}
${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
notify_title: '🔥 @${{ github.event.issue.user.login }} 创建了 issue${{ github.event.issue.title }} #${{ github.event.issue.number }}'
notify_title: '🔥 @${{ github.event.issue.user.login }} 创建了 issue${{ github.event.issue.title }} ${{ github.event.issue.html_url }}'
notify_body: '### 🔥 @${{ github.event.issue.user.login }} 创建了 issue[${{ github.event.issue.title }}](${{ github.event.issue.html_url }}) <hr />'
notify_footer: '> 💬 欢迎前往 GitHub 进行讨论,社区可能需要你的帮助。'
at_all: false # whether to ding everybody

View File

@ -0,0 +1,28 @@
# 当 PR 被合并时,留言欢迎加入共建群
name: PullRequest Contributor Welcome
on:
pull_request:
types:
- closed
paths:
- 'components/**'
jobs:
comment:
if: github.event.pull_request.merged == true && github.repository == 'ant-design/ant-design'
runs-on: ubuntu-latest
steps:
- name: Comment on PR
uses: actions-cool/maintain-one-comment@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
🎉 Thank you for your contribution! If you have not yet joined our DingTalk community group, please feel free to join us (when joining, please provide the link to this PR).
🎉 感谢您的贡献!如果您还没有加入钉钉社区群,请扫描下方二维码加入我们(加群时请提供此 PR 链接)。
<img src="https://github.com/ant-design/ant-design/assets/5378891/e24c6080-bf38-4523-b1cd-f6c43ad7375f" height="200" />
<!-- WELCOME_CONTRIBUTION -->
body-include: '<!-- WELCOME_CONTRIBUTION -->'

View File

@ -19,10 +19,13 @@ jobs:
refuse-issue-label: '🎱 Collaborate PR only'
need-creator-authority: 'write'
comment: |
Hi @${{ github.event.pull_request.user.login }}. The issue mentioned in this PR needs to be confirmed with the designer or core team. This PR is temporarily not accepted. Thank you again for your contribution! 😊
Hi @${{ github.event.pull_request.user.login }}. The issue mentioned in this PR needs to be confirmed with the designer or core team. Thank you for your contribution! 😊
你好 @${{ github.event.pull_request.user.login }}。这个 PR 提及的 issue 需要和设计师或核心团队进行确认,暂时不接受 PR再次感谢你的贡献😊
close: true
你好 @${{ github.event.pull_request.user.login }}。这个 PR 提及的 issue 需要和设计师或核心团队进行确认!感谢您的贡献!😊
close: false
reviewers: |
MadCcc
zombieJ
check-changelog:
permissions:

View File

@ -74,7 +74,7 @@ jobs:
run: npm run site
env:
SITE_ENV: development
NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider"
NODE_OPTIONS: "--max_old_space_size=4096"
- name: upload site artifact
uses: actions/upload-artifact@v3

View File

@ -1,21 +1,21 @@
name: 🐦 Release to Tweet
on:
release:
types: [published]
create
permissions:
contents: read
jobs:
tweet:
if: ${{ github.event.ref_type == 'tag' && !contains(github.event.ref, 'alpha') }}
runs-on: ubuntu-latest
steps:
- name: Tweet
uses: nearform-actions/github-action-notify-twitter@v1
with:
message: |
Ant Design (antd@${{ github.event.release.tag_name }}) has been released ~ 🎊🎊🎊 Check out the release notes: ${{ github.event.release.html_url }}
🤖 Ant Design just released antd@${{ github.event.ref }} ✨🎊✨ Check out the full release note: https://github.com/ant-design/ant-design/releases/tag/${{ github.event.ref }}
twitter-app-key: ${{ secrets.TWITTER_API_KEY }}
twitter-app-secret: ${{ secrets.TWITTER_API_SECRET_KEY }}
twitter-access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }}

View File

@ -70,13 +70,13 @@ jobs:
- name: build site
run: npm run predeploy
env:
NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider"
NODE_OPTIONS: "--max_old_space_size=4096"
- name: build dist and bundle analyzer report
run: npm run dist
env:
ANALYZER: 1
NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider"
NODE_OPTIONS: "--max_old_space_size=4096"
- name: Get version
id: publish-version

View File

@ -63,5 +63,5 @@ jobs:
build_script: dist
skip_step: install
env:
NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider"
NODE_OPTIONS: "--max_old_space_size=4096"
PRODUCTION_ONLY: 1

View File

@ -131,7 +131,7 @@ jobs:
- name: dist
run: npm run dist
env:
NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider"
NODE_OPTIONS: "--max_old_space_size=4096"
CI: 1
needs: setup
@ -141,7 +141,7 @@ jobs:
strategy:
matrix:
react: ['16', '17', '18']
module: ['dom', 'node', 'dist']
module: ['dom', 'node', 'dist', 'dist-min']
shard: ['1/2', '2/2']
env:
REACT: ${{ matrix.react }}
@ -179,7 +179,7 @@ jobs:
run: npm run install-react-18
- name: restore cache from dist
if: ${{ matrix.module == 'dist' }}
if: ${{ matrix.module == 'dist' || matrix.module == 'dist-min' }}
uses: actions/cache@v3
with:
path: dist
@ -224,6 +224,13 @@ jobs:
run: npm test
env:
LIB_DIR: dist
# dist min test
- name: dist-min test
if: ${{ matrix.module == 'dist-min' }}
run: npm test
env:
LIB_DIR: dist-min
needs: [setup, dist]
############################ Test Coverage ###########################

View File

@ -1,63 +0,0 @@
# Due to some special reasons, some accounts are blocked by circleCI
# and cannot trigger argos jobs through circleCI.
# These accounts can be configured in the whitelist list
# and do not need to rely on circleCI to directly trigger argos in the PR workflow
name: Trigger Argos with white-listed users
on: [push]
permissions:
contents: read
jobs:
trigger_argos_with_whitelist_users:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Read white listed users
id: read_users
run: |
whitelist_file="argos-white-listed-users"
if [[ -f $whitelist_file ]]; then
users=$(cat $whitelist_file)
echo "whitelisted_users=$users" >> $GITHUB_OUTPUT
fi
- name: Check if user is whitelisted
id: check_user
run: |
whitelisted_users="${{ steps.read_users.outputs.whitelisted_users }}"
current_user="${{ github.actor }}"
if grep -Fxq "$current_user" <<< "$whitelisted_users"; then
echo "User is whitelisted"
echo "whitelisted=true" >> $GITHUB_OUTPUT
else
echo "User is not whitelisted"
echo "whitelisted=false" >> $GITHUB_OUTPUT
fi
- name: install dependencies
if: ${{ steps.check_user.outputs.whitelisted == 'true' }}
run: yarn
- name: Build dist file
id: build
if: ${{ steps.check_user.outputs.whitelisted == 'true' }}
run: npm run dist:esbuild
- name: Run image screenshot tests
id: screenshot
if: ${{ steps.check_user.outputs.whitelisted == 'true' }}
run: npm run test-image
- name: Upload screenshots to Argos CI
id: upload
if: ${{ steps.check_user.outputs.whitelisted == 'true' }}
env:
ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }}
ARGOS_PARALLEL_NONCE: ${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}
run: npm run argos

View File

@ -0,0 +1,115 @@
# Each PR will visual-regression diff that help to check code is work as expect.
name: 👀 Visual Regression Diff Build
on:
pull_request:
branches: [master, feature]
types: [opened, synchronize, reopened]
# Cancel prev CI if new commit come
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
# Prepare node modules. Reuse cache if available
setup:
name: prepare node_modules
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
- name: cache package-lock.json
uses: actions/cache@v3
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: create package-lock.json
run: npm i --package-lock-only --ignore-scripts
- name: hack for single file
run: |
if [ ! -d "package-temp-dir" ]; then
mkdir package-temp-dir
fi
cp package-lock.json package-temp-dir
- name: cache node_modules
id: node_modules_cache_id
uses: actions/cache@v3
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: install
if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
run: npm ci
visual-diff-report:
name: visual-diff report
runs-on: ubuntu-latest
needs: setup
steps:
- name: checkout
uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 18
- name: restore cache from package-lock.json
uses: actions/cache@v3
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v3
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: generate image snapshots
id: test-image
run: |
node node_modules/puppeteer/install.mjs
npm run version
npm run test-image
env:
NODE_OPTIONS: "--max_old_space_size=4096"
# Execute visual regression diff task and zip then
# output as visualRegressionReport.tar.gz
- name: visual regression diff
env:
EVENT_NUMBER: ${{ github.event.number }}
BASE_REF: ${{ github.base_ref }}
run: |
npm run visual-regression -- --pr-id=$EVENT_NUMBER --base-ref=$BASE_REF
# Upload report in `visualRegressionReport`
- name: upload report artifact
uses: actions/upload-artifact@v3
if: ${{ always() }}
with:
name: visual-regression-report
path: visualRegressionReport.tar.gz
# Upload git ref for next workflow `visual-regression-diff-finish` use
- name: Save persist key
if: ${{ always() }}
# should be pr id
run: echo ${{ github.event.number }} > ./visual-regression-pr-id.txt
- name: Upload persist key
if: ${{ always() }}
uses: actions/upload-artifact@v3
with:
name: visual-regression-diff-ref
path: ./visual-regression-pr-id.txt

View File

@ -0,0 +1,135 @@
# Each PR will visual-regression diff that help to check code is work as expect.
name: 👀 Visual Regression Diff Finish
on:
workflow_run:
workflows: ["👀 Visual Regression Diff Build"]
types:
- completed
permissions:
contents: read
jobs:
upstream-workflow-summary:
name: upstream workflow summary
runs-on: ubuntu-latest
outputs:
jobs: ${{ steps.visual_diff_build_job_status.outputs.result }}
build-status: ${{ steps.visual_diff_build_job_status.outputs.build-status }}
steps:
- name: summary jobs status
uses: actions/github-script@v6
id: visual_diff_build_job_status
with:
script: |
const response = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
// { [name]: [conclusion] }, e.g. { 'test image': 'success' }
const jobs = (response.data?.jobs ?? []).reduce((acc, job) => {
if(job?.status === 'completed' && 'name' in job && 'conclusion' in job) {
acc[job.name] = job.conclusion;
}
return acc;
}, {});
const total = Object.keys(jobs).length;
if(total === 0) core.setFailed('no jobs found');
// the name here must be the same as `jobs.xxx.{name}`
console.log('visual-diff report job status: %s', jobs['visual-diff report']);
// set output
core.setOutput('build-status', jobs['visual-diff report']);
return jobs;
download-visual-regression-report:
name: download visual-regression report
permissions:
actions: read # for dawidd6/action-download-artifact to query and download artifacts
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
runs-on: ubuntu-latest
needs: [upstream-workflow-summary]
steps:
- name: checkout
uses: actions/checkout@v4
# We need get persist-index first
- name: download image snapshot artifact
uses: dawidd6/action-download-artifact@v2
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
name: visual-regression-diff-ref
# Save PR id to output
- name: save PR id
id: pr
run: echo "id=$(<visual-regression-pr-id.txt)" >> $GITHUB_OUTPUT
# Download report artifact
- name: download report artifact
id: download_report
if: ${{ needs.upstream-workflow-summary.outputs.build-status == 'success' || needs.upstream-workflow-summary.outputs.build-status == 'failure' }}
uses: dawidd6/action-download-artifact@v2
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
name: visual-regression-report
# unzip report and then upload them to oss
- name: upload visual-regression report
id: report
env:
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}
PR_ID: ${{ steps.pr.outputs.id }}
run: |
mkdir ./visualRegressionReport
tar -xzvf visualRegressionReport.tar.gz -C ./visualRegressionReport
echo "✅ Uncompress Finished"
rm package.json
npm i ali-oss --no-save
echo "✅ Install `ali-oss` Finished"
echo "🤖 Uploading"
node scripts/visual-regression/upload.js ./visualRegressionReport --ref=pr-$PR_ID
echo "✅ Uploaded"
delimiter="$(openssl rand -hex 8)"
echo "content<<${delimiter}" >> "${GITHUB_OUTPUT}"
echo "$(<visualRegressionReport/report.md)" >> "${GITHUB_OUTPUT}"
echo "${delimiter}" >> "${GITHUB_OUTPUT}"
- name: success comment
uses: actions-cool/maintain-one-comment@v3
if: ${{ steps.report.outcome == 'success' }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
${{ steps.report.outputs.content }}
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
number: ${{ steps.pr.outputs.id }}
- name: failed comment
if: ${{ steps.download_report.outcome == 'failure' || steps.report.outcome == 'failure' || failure() }}
uses: actions-cool/maintain-one-comment@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
## Visual Regression Build for PR #${{ steps.pr.outputs.id }} Failed ❌
Potential causes:
- `upstream workflow` status: ${{ needs.upstream-workflow-summary.outputs.build-status }}
- `download report artifact` status: ${{ steps.download_report.outcome }}
- `report upload` status: ${{ steps.report.outcome }}
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
number: ${{ steps.pr.outputs.id }}

View File

@ -0,0 +1,32 @@
# When `visual-regression-diff-build` start. Leave a message on the PR
#
# 🚨🚨🚨 Important 🚨🚨🚨
# Never do any `checkout` or `npm install` action!
# `pull_request_target` will enable PR to access the secrets!
name: 👀 Visual Regression Diff Start
on:
pull_request_target:
branches: [master, feature]
types: [opened, synchronize, reopened]
permissions:
contents: read
jobs:
visual-regression-diff-start:
permissions:
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
name: start visual-regression diff
runs-on: ubuntu-latest
steps:
- name: update status comment
uses: actions-cool/maintain-one-comment@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
## Visual-Regression Diff Building...
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'

View File

@ -0,0 +1,104 @@
# Each `push on master` will persist image-snapshots that used as compare target in visual regression.
name: 👁️ Visual Regression Persist Finish
on:
workflow_run:
workflows: ["👁️ Visual Regression Persist Start"]
types:
- completed
permissions:
contents: read
jobs:
upstream-workflow-summary:
name: upstream workflow summary
runs-on: ubuntu-latest
outputs:
jobs: ${{ steps.persist_start_job_status.outputs.result }}
build-success: ${{ steps.persist_start_job_status.outputs.build-success }}
build-failure: ${{ steps.persist_start_job_status.outputs.build-failure }}
steps:
- name: summary jobs status
uses: actions/github-script@v6
id: persist_start_job_status
with:
script: |
const response = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
// { [name]: [conclusion] }, e.g. { 'test image': 'success' }
const jobs = (response.data?.jobs ?? []).reduce((acc, job) => {
if(job?.status === 'completed' && 'name' in job && 'conclusion' in job) {
acc[job.name] = job.conclusion;
}
return acc;
}, {});
const total = Object.keys(jobs).length;
if(total === 0) core.setFailed('no jobs found');
// the name here must be the same as `jobs.xxx.{name}`
console.log('visual-diff report job status: %s', jobs['test image']);
// set output
core.setOutput('build-success', jobs['test image'] === 'success');
core.setOutput('build-failure', jobs['test image'] === 'failure');
return jobs;
persist-image-snapshots:
name: persist image-snapshots
permissions:
actions: read # for dawidd6/action-download-artifact to query and download artifacts
runs-on: ubuntu-latest
needs: [upstream-workflow-summary]
steps:
- name: checkout
uses: actions/checkout@v4
with:
# checkout the head sha/branch that triggered this workflow
ref: ${{ github.event.workflow_run.head_sha || github.event.workflow_run.head_branch}}
# We need get persist key first
- name: Download Visual Regression Ref
uses: dawidd6/action-download-artifact@v2
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
name: visual-regression-ref
# Save visual-regression ref to output
- name: Extra Visual Regression Ref
id: visual_regression
run: echo "id=$(<visual-regression-ref.txt)" >> $GITHUB_OUTPUT
- name: Download Visual-Regression Artifact
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
uses: dawidd6/action-download-artifact@v2
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
name: image-snapshots
path: ./
- name: Persist Image Snapshot to OSS
if: github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature')
env:
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
rm package.json
npm i ali-oss --no-save
echo "✅ Install `ali-oss` Finished"
echo "🤖 Uploading"
node scripts/visual-regression/upload.js ./imageSnapshots.tar.gz --ref=$HEAD_SHA
node scripts/visual-regression/upload.js ./visual-regression-ref.txt --ref=$HEAD_BRANCH
echo "✅ Uploaded"

View File

@ -0,0 +1,95 @@
# Each `push on master` will persist image-snapshots that used as compare target in visual regression.
name: 👁️ Visual Regression Persist Start
on:
push:
branches:
- master
- feature
permissions:
contents: read
jobs:
# Prepare node modules. Reuse cache if available
setup:
name: prepare node_modules
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
- name: cache package-lock.json
uses: actions/cache@v3
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: create package-lock.json
run: npm i --package-lock-only --ignore-scripts
- name: hack for single file
run: |
if [ ! -d "package-temp-dir" ]; then
mkdir package-temp-dir
fi
cp package-lock.json package-temp-dir
- name: cache node_modules
id: node_modules_cache_id
uses: actions/cache@v3
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: install
if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
run: npm ci
test-image:
name: test image
runs-on: ubuntu-latest
needs: setup
steps:
- name: checkout
uses: actions/checkout@v4
- name: restore cache from package-lock.json
uses: actions/cache@v3
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v3
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: generate image snapshots
run: |
node node_modules/puppeteer/install.mjs
npm run version
npm run test-image
tar -czvf imageSnapshots.tar.gz imageSnapshots/*
env:
NODE_OPTIONS: "--max_old_space_size=4096"
# Upload `imageSnapshots` on master
- name: upload report artifact
uses: actions/upload-artifact@v3
with:
name: image-snapshots
path: imageSnapshots.tar.gz
# Upload git ref for next workflow `visual-regression-persist-finish` use
- name: Save persist key
if: ${{ always() }}
run: echo ${{ github.sha }} > ./visual-regression-ref.txt
- name: Upload persist key
if: ${{ always() }}
uses: actions/upload-artifact@v3
with:
name: visual-regression-ref
path: ./visual-regression-ref.txt

3
.gitignore vendored
View File

@ -61,8 +61,9 @@ components/version/token-meta.json
__diff_output__/
__image_snapshots__/
/jest-stare
/imageSnapshots
/imageSnapshots*
/imageDiffSnapshots
/visualRegressionReport*
.devcontainer*
.husky/prepare-commit-msg

View File

@ -2,7 +2,7 @@ const { moduleNameMapper, transformIgnorePatterns } = require('./.jest');
// jest config for image snapshots
module.exports = {
setupFiles: ['./tests/setup.js'],
setupFiles: ['./tests/setup.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'md'],
moduleNameMapper,
transform: {
@ -19,5 +19,5 @@ module.exports = {
},
},
preset: 'jest-puppeteer',
testTimeout: 10000,
testTimeout: 20000,
};

View File

@ -23,7 +23,7 @@ const transformIgnorePatterns = [
];
function getTestRegex(libDir) {
if (['dist', 'lib', 'es'].includes(libDir)) {
if (['dist', 'lib', 'es', 'dist-min'].includes(libDir)) {
return 'demo\\.test\\.(j|t)sx?$';
}
return '.*\\.test\\.(j|t)sx?$';
@ -32,7 +32,7 @@ function getTestRegex(libDir) {
module.exports = {
verbose: true,
testEnvironment: 'jsdom',
setupFiles: ['./tests/setup.js', 'jest-canvas-mock'],
setupFiles: ['./tests/setup.ts', 'jest-canvas-mock'],
setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'md'],
modulePathIgnorePatterns: ['/_site/'],

View File

@ -2,7 +2,7 @@ const { moduleNameMapper, transformIgnorePatterns } = require('./.jest');
// jest config for server render environment
module.exports = {
setupFiles: ['./tests/setup.js'],
setupFiles: ['./tests/setup.ts'],
setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'md'],
moduleNameMapper,

View File

@ -16,6 +16,137 @@ tag: vVERSION
---
## 5.12.5
`2023-12-22`
- 💄 Fix Tabs style issue of editable mode when there is only "new" button left. [#46585](https://github.com/ant-design/ant-design/pull/46585) [@hzyhbk](https://github.com/hzyhbk)
- 💄 Fix Progress style issue of `line` mode with `strokeLinecap`. [#46551](https://github.com/ant-design/ant-design/pull/46551) [@ZN1996](https://github.com/ZN1996)
- 🐞 Fix ColorPicker not support `prefixCls`. [#46561](https://github.com/ant-design/ant-design/pull/46561)
## 5.12.4
`2023-12-19`
- 🐞 Fix DatePicker style in `cssVar` mode. [#46526](https://github.com/ant-design/ant-design/pull/46526)
## 5.12.3
`2023-12-18`
- 💄 Fix Tag that style would be missing in SSR. [#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc)
- 🐞 Upload `disabled` prop should not affect download icon. [#46454](https://github.com/ant-design/ant-design/pull/46454)
- 💄 Upload.Dragger add vertical padding style. [#46457](https://github.com/ant-design/ant-design/pull/46457)
- 🐞 Fix Upload actions color issue. [#46456](https://github.com/ant-design/ant-design/pull/46456)
- 🐞 Fix Form with `getValueProps` not working with value update. [#46445](https://github.com/ant-design/ant-design/pull/46445)
- 💄 Fix Checkbox style when customize `token.lineWidth`. [#46431](https://github.com/ant-design/ant-design/pull/46431)
- 🐞 Fix Select that custom token make `padding` broken. [#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc)
- 🐞 Fix Message that token overrides not work in `cssVar` mode. [#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc)
- 💄 Fix Flex component don't apply extra style. [#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan)
## 5.12.2
`2023-12-11`
- 🐞 MISC: Fix `useId` error when webpack build with React 17. [#46261](https://github.com/ant-design/ant-design/pull/46261)
- Pagination
- 🐞 Fix Pagination throws error in legacy browsers. [react-component/pagination#545](https://github.com/react-component/pagination/pull/545)
- 🐞 Fix Pagination `current` not working in `simple` mode. [react-component/pagination#546](https://github.com/react-component/pagination/pull/546)
- 🐞 Fix Table filter dropdown lost background color in CSS variables mode. [#46314](https://github.com/ant-design/ant-design/pull/46314)
- 🐞 Prevent interaction when Spin component enable `fullscreen` prop. [#46303](https://github.com/ant-design/ant-design/pull/46303) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 Fix Form `hideRequiredMark` prop's priority compared with ConfigProvider `form` prop. [#46299](https://github.com/ant-design/ant-design/pull/46299) [@linhf123](https://github.com/linhf123)
- TypeScript
- 🤖 Fix Descriptions `id` type. [#46367](https://github.com/ant-design/ant-design/pull/46367) [@RSS1102](https://github.com/RSS1102)
## 5.12.1
`2023-12-04`
- 🐞 MISC: Fix missing color less variables converted from token. [#46250](https://github.com/ant-design/ant-design/pull/46250)
- 🐞 Fix Notification title overlaps with the close icon when it is too long。 [#46211](https://github.com/ant-design/ant-design/pull/46211) [@zh-lx](https://github.com/zh-lx)
## 5.12.0
`2023-12-04`
- 🔥 Component Token support CSS variables mode. For more detail, see [CSS Variables](/docs/react/css-variables). Special thank for contributors of this feature: [@li-jia-nan](https://github.com/li-jia-nan) [@RedJue](https://github.com/RedJue) [@c0dedance](https://github.com/c0dedance) [@kiner-tang](https://github.com/kiner-tang) [@JarvisArt](https://github.com/JarvisArt) [@cc-hearts](https://github.com/cc-hearts)
- 🛠 Refactor rc-pagination from class component to FC. [#46204](https://github.com/ant-design/ant-design/pull/46204) [@Wxh16144](https://github.com/Wxh16144)
- 🆕 Alert could support linear-gradient background by `colorInfoBg` token. [#46188](https://github.com/ant-design/ant-design/pull/46188)
- 🆕 `Form.useWatch` support selector function param. [#46180](https://github.com/ant-design/ant-design/pull/46180) [@crazyair](https://github.com/crazyair)
- 🆕 Slider support `onChangeComplete` and deprecate `onAfterChange`. [#46182](https://github.com/ant-design/ant-design/pull/46182) [@MadCcc](https://github.com/MadCcc)
- 🆕 Tabs `items` support `icon` prop. [#46096](https://github.com/ant-design/ant-design/pull/46096) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Tour supports `getPopupContainer` property. [#45751](https://github.com/ant-design/ant-design/pull/45751) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Switch support for `value` and `defaultValue` props. [#45747](https://github.com/ant-design/ant-design/pull/45747) [@Wxh16144](https://github.com/Wxh16144)
- 🐞 Fix that clicking Form `tooltip` icon should not trigger Switch. [#46155](https://github.com/ant-design/ant-design/pull/46155)
- 🐞 Fix Notification that icon should have line-height. [#46148](https://github.com/ant-design/ant-design/pull/46148) [@MadCcc](https://github.com/MadCcc)
- 🐞 Fix Progress that gradient in line should follow percent. [#46209](https://github.com/ant-design/ant-design/pull/46209) [@MadCcc](https://github.com/MadCcc)
- 💄 Button could be customized to gradient style. [#46192](https://github.com/ant-design/ant-design/pull/46192)
- 💄 Fix style of InputNumber with `addon` inside Space.Compact. [#46130](https://github.com/ant-design/ant-design/pull/46130) [@MadCcc](https://github.com/MadCcc)
- TypeScript
- 🤖 Update `FloatButtonProps` type with `React.DOMAttributes` in FloatButton. [#46175](https://github.com/ant-design/ant-design/pull/46175) [@li-jia-nan](https://github.com/li-jia-nan)
## 5.11.5
`2023-11-27`
- 🐞 MISC: Fix error in `dist` artifact. [#46103](https://github.com/ant-design/ant-design/pull/46103) [@MadCcc](https://github.com/MadCcc)
- 💄 Fix DatePicker style when disabled and hovered. [#45940](https://github.com/ant-design/ant-design/pull/45940) [@crazyair](https://github.com/crazyair)
## 5.11.4
`2023-11-24`
- 🐞 Fix where Image sets `z-index` abnormally in nested Modal. [#46035](https://github.com/ant-design/ant-design/pull/46035)
- 🐞 Fix Button that disabled link button should not have navigate options when right click. [#46021](https://github.com/ant-design/ant-design/pull/46021)
- Card
- 🛠 Refactor the Card internal method `getAction` into a function component. [#46032](https://github.com/ant-design/ant-design/pull/46032)
- 🐞 Fix the problem of Card warning `invalid annotation` in Rollup. [#46024](https://github.com/ant-design/ant-design/pull/46024)
- TypeScript
- 🤖 Export the type definition for the `required` property of the Radio and Checkbox components. [#46028](https://github.com/ant-design/ant-design/pull/46028) [@nnmax](https://github.com/nnmax)
## 5.11.3
`2023-11-22`
- 🐞 Fix Modal static method create `zIndex` too high will cover other popup content. [#46012](https://github.com/ant-design/ant-design/pull/46012)
- Image
- 🆕 Image preview support mobile touch interactive. [#45989](https://github.com/ant-design/ant-design/pull/45989) [@JarvisArt](https://github.com/JarvisArt)
- 🐞 Fixed Image preview `z-index` conflict when in a nested pop-up. [#45979](https://github.com/ant-design/ant-design/pull/45979) [@kiner-tang](https://github.com/kiner-tang)
- 🐞 Fix Collapse header cursor style. [#45994](https://github.com/ant-design/ant-design/pull/45994)
- 🐞 Fix ColorPicker not support Form disabled config. [#45978](https://github.com/ant-design/ant-design/pull/45978) [@RedJue](https://github.com/RedJue)
- 🐞 Fix Typography.Text `ellipsis.tooltip` cannot open under Layout component. [#45962](https://github.com/ant-design/ant-design/pull/45962)
- 🐞 Remove Select native 🔍 icon from search input in Safari. [#46008](https://github.com/ant-design/ant-design/pull/46008)
- 💄 Remove Rate useless style.[#45927](https://github.com/ant-design/ant-design/pull/45927) [@JarvisArt](https://github.com/JarvisArt)
- 🛠 UMD `antd.js` will try to reuse global `@ant-design/cssinjs` first now. [#46009](https://github.com/ant-design/ant-design/pull/46009)
- 🌐 Improve `eu_ES` localization. [#45928](https://github.com/ant-design/ant-design/pull/45928) [@ionlizarazu](https://github.com/ionlizarazu)
## 5.11.2
`2023-11-17`
- 🆕 Table with `virtual` can now customize `components` except the `components.body`. [#45857](https://github.com/ant-design/ant-design/pull/45857)
- 🐞 Fix Button with href and disabled that could be focused. [#45910](https://github.com/ant-design/ant-design/pull/45910) [@MadCcc](https://github.com/MadCcc)
- 🐞 Fix `zIndex` logic problem that message and notification are covered when multiple Modal are opened. [#45911](https://github.com/ant-design/ant-design/pull/45911) [#45864](https://github.com/ant-design/ant-design/pull/45864) [@kiner-tang](https://github.com/kiner-tang)
- 💄 Fix QRCode `style.padding` is not working. [#45815](https://github.com/ant-design/ant-design/pull/45815)
- 💄 Optimize Carousel dots border radius style. [#45817](https://github.com/ant-design/ant-design/pull/45817)
- TypeScript
- 🤖 Optimize List `gutter` property type definition. [#45791](https://github.com/ant-design/ant-design/pull/45791) [@Asanio06](https://github.com/Asanio06)
## 5.11.1
`2023-11-09`
- 🐞 Fix Dropdown use wrong `zIndex` when nest items. [#45761](https://github.com/ant-design/ant-design/pull/45761)
- 🐞 Fix Upload should show remove icon when `showRemoveIcon` is specified to true explicitly. [#45752](https://github.com/ant-design/ant-design/pull/45752)
- 🐞 Fix Descriptions use `children` structure missing the Descriptions.Item `key` prop. [#45757](https://github.com/ant-design/ant-design/pull/45757)
- 🐞 Fix Message that token specified in component scope not work. [#45721](https://github.com/ant-design/ant-design/pull/45721) [@MadCcc](https://github.com/MadCcc)
- 🐞 Fix Popconfirm not compatible with `visible` prop. [#45702](https://github.com/ant-design/ant-design/pull/45702) [@linhf123](https://github.com/linhf123)
- 🐞 Fix Tag default background color not correct. [#45711](https://github.com/ant-design/ant-design/pull/45711) [@kiner-tang](https://github.com/kiner-tang)
- 💄 Fix Notification that `style.width` not work. [#45681](https://github.com/ant-design/ant-design/pull/45681) [@MadCcc](https://github.com/MadCcc)
- 🐞 Fix App console unexpected attr warning when set `component=false`. [#45671](https://github.com/ant-design/ant-design/pull/45671) [@li-jia-nan](https://github.com/li-jia-nan)
- TypeScript
- 🤖 App support generic type definition. [#45669](https://github.com/ant-design/ant-design/pull/45669) [@JexLau](https://github.com/JexLau)
## 5.11.0
`2023-11-03`

View File

@ -16,6 +16,137 @@ tag: vVERSION
---
## 5.12.5
`2023-12-22`
- 💄 修复 Tabs 在 可编辑模式下只剩新增按钮时按钮的样式问题[#46585](https://github.com/ant-design/ant-design/pull/46585) [@hzyhbk](https://github.com/hzyhbk)
- 💄 修复 Progress `strokeLinecap` 不生效的问题。[#46551](https://github.com/ant-design/ant-design/pull/46551) [@ZN1996](https://github.com/ZN1996)
- 🐞 修复 ColorPicker 配置 `prefixCls` 不生效的问题。[#46561](https://github.com/ant-design/ant-design/pull/46561)
## 5.12.4
`2023-12-19`
- 🐞 修复 DatePicker 组件在 CSS 变量模式下的样式错乱问题。[#46526](https://github.com/ant-design/ant-design/pull/46526)
## 5.12.3
`2023-12-18`
- 💄 修复 Tag 组件在 SSR 场景下的样式丢失问题。[#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc)
- 🐞 Upload 的 `disabled` 属性不再对下载按钮生效。[#46454](https://github.com/ant-design/ant-design/pull/46454)
- 💄 Upload.Dragger 增加一个水平内边距。[#46457](https://github.com/ant-design/ant-design/pull/46457)
- 🐞 修复 Upload `actions` 的颜色问题。[#46456](https://github.com/ant-design/ant-design/pull/46456)
- 🐞 修复 Form 使用 `getValueProps` 展示值无法更新的问题。[#46445](https://github.com/ant-design/ant-design/pull/46445)
- 💄 修复 Checkbox 自定义 `token.lineWidth` 时勾选箭头错位问题。[#46431](https://github.com/ant-design/ant-design/pull/46431)
- 🐞 修复 Select 组件定制 token 会让 padding 失效的问题。[#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc)
- 🐞 修复 Message 在 `cssVar` 模式下覆盖组件 token 无效的问题。[#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc)
- 💄 Flex 组件不应该应用额外的样式。[#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan)
## 5.12.2
`2023-12-11`
- 🐞 MISC: 修复 React 17 以下使用 webpack 构建时报错 `useId` 找不到的问题。[#46261](https://github.com/ant-design/ant-design/pull/46261)
- Pagination
- 🐞 修复 Pagination 在低版本浏览器上报错的问题。[react-component/pagination#545](https://github.com/react-component/pagination/pull/545)
- 🐞 修复 Pagination `simple` 模式下 `current` 受控选中分页不生效的问题。[react-component/pagination#546](https://github.com/react-component/pagination/pull/546)
- 🐞 修复 Table 筛选菜单在 CSS 变量模式下丢失背景色的问题。[#46314](https://github.com/ant-design/ant-design/pull/46314)
- 🐞 优化 Spin 交互,全屏状态时禁止用户触发鼠标事件。[#46303](https://github.com/ant-design/ant-design/pull/46303) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 修复 Form `hideRequiredMark` 属性的优先级低于 ConfigProvider 的 form 配置的问题。[#46299](https://github.com/ant-design/ant-design/pull/46299) [@linhf123](https://github.com/linhf123)
- TypeScript
- 🤖 修复 Descriptions TS 定义不支持 `id` 属性的问题。[#46367](https://github.com/ant-design/ant-design/pull/46367) [@RSS1102](https://github.com/RSS1102)
## 5.12.1
`2023-12-04`
- 🐞 MISC: 修复 token 转换 less 变量丢失的问题。[#46250](https://github.com/ant-design/ant-design/pull/46250)
- 🐞 修复 Notification 标题太长时会与关闭图标重叠的问题。[#46211](https://github.com/ant-design/ant-design/pull/46211) [@zh-lx](https://github.com/zh-lx)
## 5.12.0
`2023-12-04`
- 🔥 Component Token 支持 CSS 变量模式,详情见 [使用 CSS 变量](/docs/react/css-variables-cn)。感谢以下同学对此的贡献:[@li-jia-nan](https://github.com/li-jia-nan) [@RedJue](https://github.com/RedJue) [@c0dedance](https://github.com/c0dedance) [@kiner-tang](https://github.com/kiner-tang) [@JarvisArt](https://github.com/JarvisArt) [@cc-hearts](https://github.com/cc-hearts)
- 🛠 rc-pagination 重构为 FC。[#46204](https://github.com/ant-design/ant-design/pull/46204) [@Wxh16144](https://github.com/Wxh16144)
- 🆕 `Form.useWatch` 支持 selector 函数参数调用。[#46180](https://github.com/ant-design/ant-design/pull/46180) [@crazyair](https://github.com/crazyair)
- 🆕 Slider 组件支持 `onChangeComplete` 事件,并废弃 `onAfterChange`。[#46182](https://github.com/ant-design/ant-design/pull/46182) [@MadCcc](https://github.com/MadCcc)
- 🆕 Tabs 配置项 `items` 支持 `icon` 属性。[#46096](https://github.com/ant-design/ant-design/pull/46096) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Tour 支持 `getPopupContainer` 属性。[#45751](https://github.com/ant-design/ant-design/pull/45751) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Switch 支持 `value` and `defaultValue` 属性。[#45747](https://github.com/ant-design/ant-design/pull/45747) [@Wxh16144](https://github.com/Wxh16144)
- 🐞 修复 Progress 进度条视觉效果,渐变效果应该随着百分比改变。[#46209](https://github.com/ant-design/ant-design/pull/46209) [@MadCcc](https://github.com/MadCcc)
- 🐞 修复点击 Form `tooltip` 图标会触发 Switch 切换的问题。[#46155](https://github.com/ant-design/ant-design/pull/46155)
- 🐞 修复 Notification 图标行高为 0 的问题。[#46148](https://github.com/ant-design/ant-design/pull/46148) [@MadCcc](https://github.com/MadCcc)
- 💄 Button 按钮支持自定义为渐变色风格。[#46192](https://github.com/ant-design/ant-design/pull/46192)
- 💄 Alert 背景色现在可以通过 `colorInfoBg` token 定义为渐变色。[#46188](https://github.com/ant-design/ant-design/pull/46188)
- 💄 修复 InputNumber 带有 `addon` 时在 Space.Compact 下使用的样式问题。[#46130](https://github.com/ant-design/ant-design/pull/46130) [@MadCcc](https://github.com/MadCcc)
- TypeScript
- 🤖 更新 FloatButton 的类型定义,透出原生事件处理函数类型。[#46175](https://github.com/ant-design/ant-design/pull/46175) [@li-jia-nan](https://github.com/li-jia-nan)
## 5.11.5
`2023-11-27`
- 🐞 MISC: 修复打包 `dist` 产物错误。[#46103](https://github.com/ant-design/ant-design/pull/46103) [@MadCcc](https://github.com/MadCcc)
- 💄 修复 DatePicker 禁用状态下悬浮样式。[#45940](https://github.com/ant-design/ant-design/pull/45940) [@crazyair](https://github.com/crazyair)
## 5.11.4
`2023-11-24`
- 🐞 修复 Image 在嵌套 Modal 中设置 `z-index` 异常的问题。[#46035](https://github.com/ant-design/ant-design/pull/46035)
- 🐞 修复 Button 禁用的链接按钮右键点击时会有打开新链接选项的问题。[#46021](https://github.com/ant-design/ant-design/pull/46021)
- Card
- 🛠 把 Card 内部方法 `getAction` 重构为函数组件。[#46032](https://github.com/ant-design/ant-design/pull/46032)
- 🐞 解决 Card 在 Rollup 中会警告 `invalid annotation` 的问题。[#46024](https://github.com/ant-design/ant-design/pull/46024)
- TypeScript
- 🤖 导出 Radio 和 Checkbox 组件的 `required` 属性的类型定义。[#46028](https://github.com/ant-design/ant-design/pull/46028) [@nnmax](https://github.com/nnmax)
## 5.11.3
`2023-11-22`
- 🐞 修复 Modal 静态方法创建 `zIndex` 过高会覆盖其他弹出内容的问题。[#46012](https://github.com/ant-design/ant-design/pull/46012)
- Image
- 🆕 Image 预览支持移动触摸事件交互。[#45989](https://github.com/ant-design/ant-design/pull/45989) [@JarvisArt](https://github.com/JarvisArt)
- 🐞 修复 Image 预览在嵌套弹框中 `z-index` 设置不正确的问题。[#45979](https://github.com/ant-design/ant-design/pull/45979) [@kiner-tang](https://github.com/kiner-tang)
- 🐞 修复 Collapse 可折叠区域鼠标 `hover` 样式问题。[#45994](https://github.com/ant-design/ant-design/pull/45994)
- 🐞 修复 ColorPicker 不支持 Form 组件的禁用问题。[#45978](https://github.com/ant-design/ant-design/pull/45978) [@RedJue](https://github.com/RedJue)
- 🐞 修复 Typography.Text `code` 在 Layout 下开启 `ellipsis` 时 tooltip 无效的问题。[#45962](https://github.com/ant-design/ant-design/pull/45962)
- 🐞 修复 Select 搜索框在 Safari 下显示多余的 🔍 图标。[#46008](https://github.com/ant-design/ant-design/pull/46008)
- 💄 删除 Rate 组件无用样式。 [#45927](https://github.com/ant-design/ant-design/pull/45927) [@JarvisArt](https://github.com/JarvisArt)
- 🛠 UMD 版本 `antd.js` 现在会优先使用全局的 `@ant-design/cssinjs` 依赖。[#46009](https://github.com/ant-design/ant-design/pull/46009)
- 🌐 补充 `eu_ES` 国际化内容。[#45928](https://github.com/ant-design/ant-design/pull/45928) [@ionlizarazu](https://github.com/ionlizarazu)
## 5.11.2
`2023-11-17`
- 🆕 放开 Table `virtual``components` 的限制,现在除了 `components.body` 都可以自定义。[#45857](https://github.com/ant-design/ant-design/pull/45857)
- 🐞 修复 Button 带有链接且禁用时可以被聚焦到的问题。[#45910](https://github.com/ant-design/ant-design/pull/45910) [@MadCcc](https://github.com/MadCcc)
- 🐞 修复 `zIndex` 逻辑,解决多层 Modal 打开时message 与 notification 被遮盖的问题。[#45911](https://github.com/ant-design/ant-design/pull/45911) [#45864](https://github.com/ant-design/ant-design/pull/45864) [@kiner-tang](https://github.com/kiner-tang)
- 💄 修复 QRCode 设置 `style.padding` 时无效的问题。[#45815](https://github.com/ant-design/ant-design/pull/45815)
- 💄 优化 Carousel 切换条圆角样式。[#45817](https://github.com/ant-design/ant-design/pull/45817)
- TypeScript
- 🤖 优化 List 属性 `gutter` 的类型定义。[#45791](https://github.com/ant-design/ant-design/pull/45791) [@Asanio06](https://github.com/Asanio06)
## 5.11.1
`2023-11-09`
- 🐞 修复 Dropdown 在嵌套列表时 `zIndex` 错误的问题。[#45761](https://github.com/ant-design/ant-design/pull/45761)
- 🐞 修复 Upload 显式指定 `showRemoveIcon: true` 时删除图标未显示的问题。[#45752](https://github.com/ant-design/ant-design/pull/45752)
- 🐞 修复 Descriptions 使用 `children` 结构语法糖时,会丢失 Descriptions.Item 的 `key` 的问题。[#45757](https://github.com/ant-design/ant-design/pull/45757)
- 🐞 修复 Message 组件在组件范围设置全局 `token` 无效的问题。[#45721](https://github.com/ant-design/ant-design/pull/45721) [@MadCcc](https://github.com/MadCcc)
- 🐞 修复 Popconfirm 不兼容 `visible` 的问题。[#45702](https://github.com/ant-design/ant-design/pull/45702) [@linhf123](https://github.com/linhf123)
- 🐞 修复默认 Tag 的背景颜色不正确的问题。[#45711](https://github.com/ant-design/ant-design/pull/45711) [@kiner-tang](https://github.com/kiner-tang)
- 💄 修复 Notification 组件设置 `style.width` 无效的问题。[#45681](https://github.com/ant-design/ant-design/pull/45681) [@MadCcc](https://github.com/MadCcc)
- 🐞 修复 App 设置 `component=false` 时,会报非预期的属性警告的问题。[#45671](https://github.com/ant-design/ant-design/pull/45671) [@li-jia-nan](https://github.com/li-jia-nan)
- TypeScript
- 🤖 App 支持泛型定义。[#45669](https://github.com/ant-design/ant-design/pull/45669) [@JexLau](https://github.com/JexLau)
## 5.11.0
`2023-11-03`

View File

@ -1,21 +1,21 @@
<p align="center">
<a href="https://ant.design">
<img width="200" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
</a>
</p>
<div align="center"><a name="readme-top"></a>
<h1 align="center">Ant Design</h1>
<img height="180" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
<div align="center">
<h1>Ant Design</h1>
一套企业级 UI 设计语言和 React 组件库。
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url] [![Covered by Argos Visual Testing][argos-ci-image]][argos-ci-url]
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
[更新日志](./CHANGELOG-zh-CN.md) · [报告问题][github-issues-url] · [特性需求][github-issues-url] · [English](./README.md) · 中文
![](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
[npm-url]: http://npmjs.org/package/antd
[github-action-image]: https://github.com/ant-design/ant-design/workflows/%E2%9C%85%20test/badge.svg
@ -34,21 +34,29 @@
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
[bundlephobia-url]: https://bundlephobia.com/package/antd
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
[issues-helper-url]: https://github.com/actions-cool/issues-helper
[issues-helper-image]: https://img.shields.io/badge/using-actions--cool-blue?style=flat-square
[issues-helper-url]: https://github.com/actions-cool
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
[dumi-url]: https://github.com/umijs/dumi
[argos-ci-image]: https://argos-ci.com/badge.svg
[argos-ci-url]: https://app.argos-ci.com/ant-design/ant-design/reference
[github-issues-url]: https://new-issue.ant.design
<!-- Copy-paste in your Readme.md file -->
<a href="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats?repo_id=34526884" target="_blank" style="display: block" align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=34526884&image_size=auto&color_scheme=dark" width="655" height="auto">
<img alt="Performance Stats of ant-design/ant-design - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=34526884&image_size=auto&color_scheme=light" width="655" height="auto">
</picture>
</a>
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
</div>
[![](https://user-images.githubusercontent.com/507615/209472919-6f7e8561-be8c-4b0b-9976-eb3c692aa20a.png)](https://ant.design)
[English](./README.md) | 中文
## ✨ 特性
- 🌈 提炼自企业级中后台产品的交互语言和视觉风格。
@ -154,6 +162,17 @@ $ npm start
## 🤝 参与共建 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
<!-- Copy-paste in your Readme.md file -->
<a href="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors?repo_id=34526884&limit=30" target="_blank" style="display: block" align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=34526884&limit=30&image_size=auto&color_scheme=dark" width="655" height="auto">
<img alt="Active Contributors of ant-design/ant-design - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=34526884&limit=30&image_size=auto&color_scheme=light" width="655" height="auto">
</picture>
</a>
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
请参考[贡献指南](https://ant.design/docs/react/contributing-cn).
> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。

View File

@ -1,20 +1,29 @@
<p align="center">
<a href="https://ant.design">
<img width="200" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
</a>
</p>
<div align="center"><a name="readme-top"></a>
<h1 align="center">Ant Design</h1>
<img height="180" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
<div align="center">
<h1>Ant Design</h1>
An enterprise-class UI design language and React UI library.
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
[![CI status][github-action-image]][github-action-url]
[![codecov][codecov-image]][codecov-url]
[![NPM version][npm-image]][npm-url]
[![NPM downloads][download-image]][download-url]
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url] [![Covered by Argos Visual Testing][argos-ci-image]][argos-ci-url]
[![][bundlephobia-image]][bundlephobia-url]
[![][bundlesize-js-image]][unpkg-js-url]
[![FOSSA Status][fossa-image]][fossa-url]
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
[![Follow Twitter][twitter-image]][twitter-url]
[![Renovate status][renovate-image]][renovate-dashboard-url]
[![][issues-helper-image]][issues-helper-url]
[![dumi][dumi-image]][dumi-url]
[![Issues need help][help-wanted-image]][help-wanted-url]
[Changelog](./CHANGELOG.en-US.md) · [Report Bug][github-issues-url] · [Request Feature][github-issues-url] · English · [中文](./README-zh_CN.md)
![](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
[npm-url]: http://npmjs.org/package/antd
@ -40,15 +49,23 @@ An enterprise-class UI design language and React UI library.
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
[dumi-url]: https://github.com/umijs/dumi
[argos-ci-image]: https://argos-ci.com/badge.svg
[argos-ci-url]: https://app.argos-ci.com/ant-design/ant-design/reference
[github-issues-url]: https://new-issue.ant.design
<!-- Copy-paste in your Readme.md file -->
<a href="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats?repo_id=34526884" target="_blank" style="display: block" align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=34526884&image_size=auto&color_scheme=dark" width="655" height="auto">
<img alt="Performance Stats of ant-design/ant-design - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=34526884&image_size=auto&color_scheme=light" width="655" height="auto">
</picture>
</a>
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
</div>
[![](https://user-images.githubusercontent.com/507615/209472919-6f7e8561-be8c-4b0b-9976-eb3c692aa20a.png)](https://ant.design)
English | [中文](./README-zh_CN.md)
## ✨ Features
- 🌈 Enterprise-class UI designed for web applications.
@ -85,27 +102,16 @@ pnpm add antd
## 🔨 Usage
```tsx
import React from 'react';
import { Button, DatePicker } from 'antd';
const App = () => (
export default () => (
<>
<Button type="primary">PRESS ME</Button>
<DatePicker placeholder="select date" />
</>
);
export default App;
```
### TypeScript
`antd` is written in TypeScript with complete definitions, check [Usage with create-react-app](https://ant.design/docs/react/use-with-create-react-app) to get started.
## 🌍 Internationalization
Dozens of languages are supported in `antd`, see [i18n](https://ant.design/docs/react/i18n).
## 🔗 Links
- [Home page](https://ant.design/)
@ -148,6 +154,17 @@ Open your browser and visit http://127.0.0.1:8001 , see more at [Development](ht
## 🤝 Contributing [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
<!-- Copy-paste in your Readme.md file -->
<a href="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors?repo_id=34526884&limit=30" target="_blank" style="display: block" align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=34526884&limit=30&image_size=auto&color_scheme=dark" width="655" height="auto">
<img alt="Active Contributors of ant-design/ant-design - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=34526884&limit=30&image_size=auto&color_scheme=light" width="655" height="auto">
</picture>
</a>
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
Let's build a better antd together.
We welcome all contributions. Please read our [Contributing Guide](https://ant.design/docs/react/contributing) first. You can submit any ideas as [Pull Requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub Issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :)

19
alias/cssinjs.js Normal file
View File

@ -0,0 +1,19 @@
/* eslint-disable global-require, import/no-unresolved */
// This is a alias proxy, which will use global `@ant-design/cssinjs` first.
// Use local if global not found.
let cssinjs;
if (typeof window !== 'undefined' && window.antdCssinjs) {
// Use window UMD version
cssinjs = window.antdCssinjs;
} else if (typeof global !== 'undefined' && global.antdCssinjs) {
// Use global UMD version
cssinjs = global.antdCssinjs;
} else {
// Use local version.
// Use relative path since webpack will also replace module here.
cssinjs = require('../node_modules/@ant-design/cssinjs');
}
module.exports = cssinjs;

View File

@ -1 +0,0 @@
kiner-tang

View File

@ -1,22 +1,15 @@
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import * as React from 'react';
import ConfigProvider, { ConfigContext } from '../config-provider';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
export function withPureRenderTheme(Component: any) {
return function PureRenderThemeComponent(props: any) {
return (
<ConfigProvider
theme={{
token: {
motion: false,
zIndexPopupBase: 0,
},
}}
>
import ConfigProvider, { ConfigContext } from '../config-provider';
import type { AnyObject } from './type';
export function withPureRenderTheme<T extends AnyObject = AnyObject>(Component: React.FC<T>) {
return (props: T) => (
<ConfigProvider theme={{ token: { motion: false, zIndexPopupBase: 0 } }}>
<Component {...props} />
</ConfigProvider>
);
};
}
export interface BaseProps {
@ -25,15 +18,15 @@ export interface BaseProps {
}
/* istanbul ignore next */
export default function genPurePanel<ComponentProps extends BaseProps>(
const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
Component: any,
defaultPrefixCls?: string,
getDropdownCls?: null | ((prefixCls: string) => string),
postProps?: (props: ComponentProps) => ComponentProps,
) {
type WrapProps = Omit<ComponentProps, 'open' | 'visible'> & { open?: boolean };
) => {
type WrapProps = ComponentProps & AnyObject;
function PurePanel(props: WrapProps) {
const PurePanel: React.FC<WrapProps> = (props) => {
const { prefixCls: customizePrefixCls, style } = props;
const holderRef = React.useRef<HTMLDivElement>(null);
@ -88,22 +81,21 @@ export default function genPurePanel<ComponentProps extends BaseProps>(
};
if (postProps) {
mergedProps = postProps(mergedProps as ComponentProps);
mergedProps = postProps(mergedProps);
}
return (
<div
ref={holderRef}
style={{
const mergedStyle: React.CSSProperties = {
paddingBottom: popupHeight,
position: 'relative',
minWidth: popupWidth,
}}
>
};
return (
<div ref={holderRef} style={mergedStyle}>
<Component {...mergedProps} />
</div>
);
}
};
return withPureRenderTheme(PurePanel);
}
return withPureRenderTheme<AnyObject>(PurePanel);
};
export default genPurePanel;

View File

@ -1,7 +1,7 @@
import type { PropsWithChildren } from 'react';
import React, { useEffect } from 'react';
import { render } from '@testing-library/react';
import type { MenuProps } from 'antd';
import type { ImageProps, MenuProps } from 'antd';
import {
AutoComplete,
Cascader,
@ -9,6 +9,7 @@ import {
DatePicker,
Drawer,
Dropdown,
Image,
Menu,
Modal,
Popconfirm,
@ -150,6 +151,7 @@ const consumerComponent: Record<ZIndexConsumer, React.FC<{ rootClassName: string
options={options}
open
/>
<ColorPicker {...props} open rootClassName={`${rootClassName} comp-item comp-ColorPicker`} />
</>
),
Dropdown: (props) => (
@ -166,7 +168,6 @@ const consumerComponent: Record<ZIndexConsumer, React.FC<{ rootClassName: string
<button type="button">test</button>
</Dropdown>
),
ColorPicker: (props) => <ColorPicker {...props} open />,
DatePicker: ({ rootClassName, ...props }) => (
<>
<DatePicker {...props} rootClassName={`${rootClassName} comp-item comp-DatePicker`} open />
@ -178,13 +179,36 @@ const consumerComponent: Record<ZIndexConsumer, React.FC<{ rootClassName: string
</>
),
Menu: (props) => <Menu {...props} items={items} defaultOpenKeys={['SubMenu']} />,
ImagePreview: ({ rootClassName }: ImageProps) => (
<>
<Image
src="xxx"
preview={{
visible: true,
rootClassName: `${rootClassName} comp-item comp-ImagePreview`,
}}
/>
<Image.PreviewGroup
preview={{
visible: true,
rootClassName: `${rootClassName} comp-item comp-ImagePreviewGroup`,
}}
>
<Image src="xxx" />
</Image.PreviewGroup>
</>
),
};
function getConsumerSelector(baseSelector: string, consumer: ZIndexConsumer): string {
let selector = baseSelector;
if (consumer === 'SelectLike') {
selector = ['Select', 'Cascader', 'TreeSelect', 'AutoComplete']
.map((item) => `${baseSelector}.comp-${item}.ant-slide-up`)
selector = ['Select', 'Cascader', 'TreeSelect', 'AutoComplete', 'ColorPicker']
.map((item) =>
item === 'ColorPicker'
? `${baseSelector}.ant-popover-placement-bottomLeft`
: `${baseSelector}.comp-${item}.ant-slide-up`,
)
.join(',');
} else if (consumer === 'DatePicker') {
selector = ['DatePicker', 'TimePicker']
@ -192,8 +216,13 @@ function getConsumerSelector(baseSelector: string, consumer: ZIndexConsumer): st
.join(',');
} else if (['Menu'].includes(consumer)) {
selector = `${baseSelector}.ant-menu-submenu-placement-rightTop`;
} else if (consumer === 'ColorPicker') {
selector = `${baseSelector}.ant-popover-placement-bottomLeft`;
} else if (consumer === 'ImagePreview') {
selector = ['ImagePreview', 'ImagePreviewGroup']
.map(
(item) =>
`${baseSelector}.comp-${item} .ant-image-preview-wrap, ${baseSelector}.comp-${item}.ant-image-preview-operations-wrapper`,
)
.join(',');
}
return selector;
}
@ -232,7 +261,8 @@ describe('Test useZIndex hooks', () => {
);
render(<App />);
expect(fn).toHaveBeenLastCalledWith(
(1000 + containerBaseZIndexOffset[containerKey as ZIndexContainer]) * 3 +
1000 +
containerBaseZIndexOffset[containerKey as ZIndexContainer] * 3 +
consumerBaseZIndexOffset[key as ZIndexConsumer],
);
});
@ -261,28 +291,45 @@ describe('Test useZIndex hooks', () => {
const selector2 = getConsumerSelector('.consumer2', key as ZIndexConsumer);
const selector3 = getConsumerSelector('.consumer3', key as ZIndexConsumer);
if (['SelectLike', 'DatePicker'].includes(key)) {
if (['SelectLike', 'DatePicker', 'ImagePreview'].includes(key)) {
let comps = document.querySelectorAll(selector1);
comps.forEach((comp) => {
expect((comp as HTMLDivElement).style.zIndex).toBeFalsy();
});
comps = document.querySelectorAll(selector2);
comps.forEach((comp) => {
const isColorPicker = (comp as HTMLDivElement).className.includes('comp-ColorPicker');
const consumerOffset = isColorPicker
? containerBaseZIndexOffset.Popover
: consumerBaseZIndexOffset[key as ZIndexConsumer];
const operOffset = comp.classList.contains('ant-image-preview-operations-wrapper')
? 1
: 0;
expect((comp as HTMLDivElement).style.zIndex).toBe(
String(
1000 +
containerBaseZIndexOffset[containerKey as ZIndexContainer] +
consumerBaseZIndexOffset[key as ZIndexConsumer],
consumerOffset +
operOffset,
),
);
});
comps = document.querySelectorAll(selector3);
comps.forEach((comp) => {
const isColorPicker = (comp as HTMLDivElement).className.includes('comp-ColorPicker');
const consumerOffset = isColorPicker
? containerBaseZIndexOffset.Popover
: consumerBaseZIndexOffset[key as ZIndexConsumer];
const operOffset = comp.classList.contains('ant-image-preview-operations-wrapper')
? 1
: 0;
expect((comp as HTMLDivElement).style.zIndex).toBe(
String(
(1000 + containerBaseZIndexOffset[containerKey as ZIndexContainer]) * 2 +
consumerBaseZIndexOffset[key as ZIndexConsumer],
1000 +
containerBaseZIndexOffset[containerKey as ZIndexContainer] * 2 +
consumerOffset +
operOffset,
),
);
});
@ -296,6 +343,7 @@ describe('Test useZIndex hooks', () => {
(document.querySelector(selector1) as HTMLDivElement).style.zIndex,
).toBeFalsy();
}
expect((document.querySelector(selector2) as HTMLDivElement).style.zIndex).toBe(
String(
1000 +
@ -306,15 +354,44 @@ describe('Test useZIndex hooks', () => {
expect((document.querySelector(selector3) as HTMLDivElement).style.zIndex).toBe(
String(
(1000 + containerBaseZIndexOffset[containerKey as ZIndexContainer]) * 2 +
1000 +
containerBaseZIndexOffset[containerKey as ZIndexContainer] * 2 +
consumerBaseZIndexOffset[key as ZIndexConsumer],
),
);
}
unmount();
}, 15000);
}, 20000);
});
});
});
it('Modal static func should always use max zIndex', async () => {
jest.useFakeTimers();
const instance = Modal.confirm({
title: 'bamboo',
content: <Select open />,
});
await waitFakeTimer();
expect(document.querySelector('.ant-modal-wrap')).toHaveStyle({
zIndex: '2000',
});
expect(document.querySelector('.ant-select-dropdown')).toHaveStyle({
zIndex: '2050',
});
instance.destroy();
await waitFakeTimer();
// Clean up for static method
document.body.innerHTML = '';
jest.useRealTimers();
});
});

View File

@ -1,7 +1,7 @@
type RecordType = Record<string, any>;
import type { AnyObject } from './type';
function extendsObject<T extends RecordType>(...list: T[]) {
const result: RecordType = { ...list[0] };
const extendsObject = <T extends AnyObject = AnyObject>(...list: T[]) => {
const result: AnyObject = { ...list[0] };
for (let i = 1; i < list.length; i++) {
const obj = list[i];
@ -16,6 +16,6 @@ function extendsObject<T extends RecordType>(...list: T[]) {
}
return result;
}
};
export default extendsObject;

View File

@ -0,0 +1,20 @@
import React from 'react';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import type { BaseInputProps } from 'rc-input/lib/interface';
export type AllowClear = BaseInputProps['allowClear'];
const getAllowClear = (allowClear: AllowClear): AllowClear => {
let mergedAllowClear: AllowClear;
if (typeof allowClear === 'object' && allowClear?.clearIcon) {
mergedAllowClear = allowClear;
} else if (allowClear) {
mergedAllowClear = {
clearIcon: <CloseCircleFilled />,
};
}
return mergedAllowClear;
};
export default getAllowClear;

View File

@ -9,9 +9,5 @@ export const getRenderPropValue = (
return null;
}
if (typeof propValue === 'function') {
return propValue();
}
return propValue;
return typeof propValue === 'function' ? propValue() : propValue;
};

View File

@ -1,25 +1,36 @@
import React from 'react';
import useToken from '../../theme/useToken';
import zIndexContext from '../zindexContext';
export type ZIndexContainer = 'Modal' | 'Drawer' | 'Popover' | 'Popconfirm' | 'Tooltip' | 'Tour';
export type ZIndexConsumer = 'SelectLike' | 'Dropdown' | 'ColorPicker' | 'DatePicker' | 'Menu';
export type ZIndexConsumer = 'SelectLike' | 'Dropdown' | 'DatePicker' | 'Menu' | 'ImagePreview';
// Z-Index control range
// Container: 1000 + offset 100 (max base + 10 * offset = 2000)
// Popover: offset 50
// Notification: Container Max zIndex + componentOffset
const CONTAINER_OFFSET = 100;
const CONTAINER_OFFSET_MAX_COUNT = 10;
export const CONTAINER_MAX_OFFSET = CONTAINER_OFFSET * CONTAINER_OFFSET_MAX_COUNT;
export const containerBaseZIndexOffset: Record<ZIndexContainer, number> = {
Modal: 0,
Drawer: 0,
Popover: 70,
Popconfirm: 70,
Tooltip: 70,
Tour: 70,
Modal: CONTAINER_OFFSET,
Drawer: CONTAINER_OFFSET,
Popover: CONTAINER_OFFSET,
Popconfirm: CONTAINER_OFFSET,
Tooltip: CONTAINER_OFFSET,
Tour: CONTAINER_OFFSET,
};
export const consumerBaseZIndexOffset: Record<ZIndexConsumer, number> = {
SelectLike: 50,
Dropdown: 50,
ColorPicker: 30,
DatePicker: 50,
Menu: 50,
ImagePreview: 1,
};
function isContainerType(type: ZIndexContainer | ZIndexConsumer): type is ZIndexContainer {
@ -33,9 +44,21 @@ export function useZIndex(
const [, token] = useToken();
const parentZIndex = React.useContext(zIndexContext);
const isContainer = isContainerType(componentType);
if (customZIndex !== undefined) {
return [customZIndex, customZIndex];
}
let zIndex = parentZIndex ?? 0;
if (isContainer) {
zIndex += token.zIndexPopupBase + containerBaseZIndexOffset[componentType];
zIndex +=
// Use preset token zIndex by default but not stack when has parent container
(parentZIndex ? 0 : token.zIndexPopupBase) +
// Container offset
containerBaseZIndexOffset[componentType];
zIndex = Math.min(zIndex, token.zIndexPopupBase + CONTAINER_MAX_OFFSET);
} else {
zIndex += consumerBaseZIndexOffset[componentType];
}

View File

@ -2,4 +2,8 @@ import React from 'react';
const zIndexContext = React.createContext<number | undefined>(undefined);
if (process.env.NODE_ENV !== 'production') {
zIndexContext.displayName = 'zIndexContext';
}
export default zIndexContext;

View File

@ -243,9 +243,9 @@ const Affix = React.forwardRef<AffixRef, AffixProps>((props, ref) => {
updatePosition();
}, [target, offsetTop, offsetBottom]);
const [wrapSSR, hashId] = useStyle(affixPrefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(affixPrefixCls);
const rootCls = classNames(rootClassName, hashId, affixPrefixCls);
const rootCls = classNames(rootClassName, hashId, affixPrefixCls, cssVarCls);
const mergedCls = classNames({ [rootCls]: affixStyle });
@ -262,7 +262,7 @@ const Affix = React.forwardRef<AffixRef, AffixProps>((props, ref) => {
otherProps = omit(otherProps, ['onTestUpdatePosition' as any]);
}
return wrapSSR(
return wrapCSSVar(
<ResizeObserver onResize={updatePosition}>
<div style={style} className={className} ref={placeholderNodeRef} {...otherProps}>
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}

View File

@ -1,15 +1,19 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks } from '../../theme/internal';
export interface ComponentToken {
zIndexPopup: number;
}
interface AffixToken extends FullToken<'Affix'> {
zIndexPopup: number;
//
}
// ============================== Shared ==============================
const genSharedAffixStyle: GenerateStyle<AffixToken> = (token): CSSObject => {
const { componentCls } = token;
return {
[componentCls]: {
position: 'fixed',
@ -18,10 +22,9 @@ const genSharedAffixStyle: GenerateStyle<AffixToken> = (token): CSSObject => {
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Affix', (token) => {
const affixToken = mergeToken<AffixToken>(token, {
export const prepareComponentToken: GetDefaultToken<'Affix'> = (token) => ({
zIndexPopup: token.zIndexBase + 10,
});
return [genSharedAffixStyle(affixToken)];
});
// ============================== Export ==============================
export default genStyleHooks('Affix', genSharedAffixStyle, prepareComponentToken);

View File

@ -12,7 +12,6 @@ import pickAttrs from 'rc-util/lib/pickAttrs';
import { replaceElement } from '../_util/reactNode';
import { devUseWarning } from '../_util/warning';
import { ConfigContext } from '../config-provider';
// CSSINJS
import useStyle from './style';
export interface AlertProps {
@ -127,7 +126,8 @@ const Alert: React.FC<AlertProps> = (props) => {
const ref = React.useRef<HTMLDivElement>(null);
const { getPrefixCls, direction, alert } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('alert', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
const handleClose = (e: React.MouseEvent<HTMLButtonElement>) => {
setClosed(true);
@ -169,12 +169,13 @@ const Alert: React.FC<AlertProps> = (props) => {
alert?.className,
className,
rootClassName,
cssVarCls,
hashId,
);
const restProps = pickAttrs(otherProps, { aria: true, data: true });
return wrapSSR(
return wrapCSSVar(
<CSSMotion
visible={!closed}
motionName={`${prefixCls}-motion`}

View File

@ -1,8 +1,10 @@
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import type { CSSProperties } from 'react';
import type { CSSObject } from '@ant-design/cssinjs';
import { unit } from '@ant-design/cssinjs';
import { resetComponent } from '../../style';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook } from '../../theme/internal';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks } from '../../theme/internal';
export interface ComponentToken {
// Component token here
@ -34,8 +36,8 @@ const genAlertTypeStyle = (
token: AlertToken,
alertCls: string,
): CSSObject => ({
backgroundColor: bgColor,
border: `${token.lineWidth}px ${token.lineType} ${borderColor}`,
background: bgColor,
border: `${unit(token.lineWidth)} ${token.lineType} ${borderColor}`,
[`${alertCls}-icon`]: {
color: iconColor,
},
@ -113,7 +115,6 @@ export const genBaseStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSO
[`${componentCls}-with-description`]: {
alignItems: 'flex-start',
padding: withDescriptionPadding,
[`${componentCls}-icon`]: {
marginInlineEnd: marginSM,
fontSize: withDescriptionIconSize,
@ -212,7 +213,7 @@ export const genActionStyle: GenerateStyle<AlertToken> = (token: AlertToken): CS
padding: 0,
overflow: 'hidden',
fontSize: fontSizeIcon,
lineHeight: `${fontSizeIcon}px`,
lineHeight: unit(fontSizeIcon),
backgroundColor: 'transparent',
border: 'none',
outline: 'none',
@ -238,22 +239,17 @@ export const genActionStyle: GenerateStyle<AlertToken> = (token: AlertToken): CS
};
};
export const genAlertStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSInterpolation => [
genBaseStyle(token),
genTypeStyle(token),
genActionStyle(token),
];
export default genComponentStyleHook(
'Alert',
(token) => [genAlertStyle(token)],
(token) => {
export const prepareComponentToken: GetDefaultToken<'Alert'> = (token) => {
const paddingHorizontal = 12; // Fixed value here.
return {
withDescriptionIconSize: token.fontSizeHeading3,
defaultPadding: `${token.paddingContentVerticalSM}px ${paddingHorizontal}px`,
withDescriptionPadding: `${token.paddingMD}px ${token.paddingContentHorizontalLG}px`,
};
},
};
export default genStyleHooks(
'Alert',
(token) => [genBaseStyle(token), genTypeStyle(token), genActionStyle(token)],
prepareComponentToken,
);

View File

@ -9,6 +9,7 @@ import { devUseWarning } from '../_util/warning';
import Affix from '../affix';
import type { ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import type { AnchorLinkBaseProps } from './AnchorLink';
import AnchorLink from './AnchorLink';
import AnchorContext from './context';
@ -79,11 +80,6 @@ export interface AnchorProps {
replace?: boolean;
}
interface InternalAnchorProps extends AnchorProps {
anchorPrefixCls: string;
rootClassName: string;
}
export interface AnchorState {
activeLink: null | string;
}
@ -109,10 +105,10 @@ export interface AntAnchor {
direction: AnchorDirection;
}
const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
const Anchor: React.FC<AnchorProps> = (props) => {
const {
rootClassName,
anchorPrefixCls: prefixCls,
prefixCls: customPrefixCls,
className,
style,
offsetTop,
@ -151,9 +147,14 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
const spanLinkNode = React.useRef<HTMLSpanElement>(null);
const animating = React.useRef<boolean>(false);
const { direction, getTargetContainer, anchor } =
const { direction, anchor, getTargetContainer, getPrefixCls } =
React.useContext<ConfigConsumerProps>(ConfigContext);
const prefixCls = getPrefixCls('anchor', customPrefixCls);
const rootCls = useCSSVarCls(prefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
const getCurrentContainer = getContainer ?? getTargetContainer ?? getDefaultContainer;
const dependencyListItem: React.DependencyList[number] = JSON.stringify(links);
@ -182,10 +183,7 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
inkStyle.left = horizontalAnchor ? `${linkNode.offsetLeft}px` : '';
inkStyle.width = horizontalAnchor ? `${linkNode.clientWidth}px` : '';
if (horizontalAnchor) {
scrollIntoView(linkNode, {
scrollMode: 'if-needed',
block: 'nearest',
});
scrollIntoView(linkNode, { scrollMode: 'if-needed', block: 'nearest' });
}
}
};
@ -274,6 +272,9 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
);
const wrapperClass = classNames(
hashId,
cssVarCls,
rootCls,
rootClassName,
`${prefixCls}-wrapper`,
{
@ -347,7 +348,7 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
[activeLink, onClick, handleScrollTo, anchorDirection],
);
return (
return wrapCSSVar(
<AnchorContext.Provider value={memoizedContextValue}>
{affix ? (
<Affix offsetTop={offsetTop} target={getCurrentContainer}>
@ -356,23 +357,7 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
) : (
anchorContent
)}
</AnchorContext.Provider>
);
};
const Anchor: React.FC<AnchorProps> = (props) => {
const { prefixCls: customizePrefixCls, rootClassName } = props;
const { getPrefixCls } = React.useContext<ConfigConsumerProps>(ConfigContext);
const anchorPrefixCls = getPrefixCls('anchor', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(anchorPrefixCls);
return wrapSSR(
<AnchorContent
{...props}
rootClassName={classNames(hashId, rootClassName)}
anchorPrefixCls={anchorPrefixCls}
/>,
</AnchorContext.Provider>,
);
};

View File

@ -1,7 +1,8 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { unit } from '@ant-design/cssinjs';
import { resetComponent, textEllipsis } from '../../style';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks, mergeToken } from '../../theme/internal';
export interface ComponentToken {
/**
@ -18,13 +19,13 @@ export interface ComponentToken {
interface AnchorToken extends FullToken<'Anchor'> {
holderOffsetBlock: number;
anchorPaddingBlockSecondary: number;
anchorBallSize: number;
anchorTitleBlock: number;
anchorPaddingBlockSecondary: number | string;
anchorBallSize: number | string;
anchorTitleBlock: number | string;
}
// ============================== Shared ==============================
const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token) => {
const {
componentCls,
holderOffsetBlock,
@ -33,11 +34,12 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
colorPrimary,
lineType,
colorSplit,
calc,
} = token;
return {
[`${componentCls}-wrapper`]: {
marginBlockStart: -holderOffsetBlock,
marginBlockStart: calc(holderOffsetBlock).mul(-1).equal(),
paddingBlockStart: holderOffsetBlock,
// delete overflow: auto
@ -50,7 +52,7 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
[`${componentCls}-link`]: {
paddingBlock: token.linkPaddingBlock,
paddingInline: `${token.linkPaddingInlineStart}px 0`,
paddingInline: `${unit(token.linkPaddingInlineStart)} 0`,
'&-title': {
...textEllipsis,
@ -83,7 +85,7 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
insetInlineStart: 0,
top: 0,
height: '100%',
borderInlineStart: `${lineWidthBold}px ${lineType} ${colorSplit}`,
borderInlineStart: `${unit(lineWidthBold)} ${lineType} ${colorSplit}`,
content: '" "',
},
@ -95,7 +97,6 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
transition: `top ${motionDurationSlow} ease-in-out`,
width: lineWidthBold,
backgroundColor: colorPrimary,
[`&${componentCls}-ink-visible`]: {
display: 'inline-block',
},
@ -110,7 +111,7 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
};
};
const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = (token) => {
const { componentCls, motionDurationSlow, lineWidthBold, colorPrimary } = token;
return {
@ -128,7 +129,7 @@ const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = (token): CSSO
value: 0,
},
bottom: 0,
borderBottom: `1px ${token.lineType} ${token.colorSplit}`,
borderBottom: `${unit(token.lineWidth)} ${token.lineType} ${token.colorSplit}`,
content: '" "',
},
@ -158,22 +159,23 @@ const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = (token): CSSO
};
};
export const prepareComponentToken: GetDefaultToken<'Anchor'> = (token) => ({
linkPaddingBlock: token.paddingXXS,
linkPaddingInlineStart: token.padding,
});
// ============================== Export ==============================
export default genComponentStyleHook(
export default genStyleHooks(
'Anchor',
(token) => {
const { fontSize, fontSizeLG, paddingXXS } = token;
const { fontSize, fontSizeLG, paddingXXS, calc } = token;
const anchorToken = mergeToken<AnchorToken>(token, {
holderOffsetBlock: paddingXXS,
anchorPaddingBlockSecondary: paddingXXS / 2,
anchorTitleBlock: (fontSize / 14) * 3,
anchorBallSize: fontSizeLG / 2,
anchorPaddingBlockSecondary: calc(paddingXXS).div(2).equal(),
anchorTitleBlock: calc(fontSize).div(14).mul(3).equal(),
anchorBallSize: calc(fontSizeLG).div(2).equal(),
});
return [genSharedAnchorStyle(anchorToken), genSharedAnchorHorizontalStyle(anchorToken)];
},
(token) => ({
linkPaddingBlock: token.paddingXXS,
linkPaddingInlineStart: token.padding,
}),
prepareComponentToken,
);

View File

@ -36,8 +36,8 @@ const App: React.FC<AppProps> & { useApp: () => useAppProps } = (props) => {
} = props;
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
const prefixCls = getPrefixCls('app', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls);
const customClassName = classNames(hashId, prefixCls, className, rootClassName);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
const customClassName = classNames(hashId, prefixCls, className, rootClassName, cssVarCls);
const appConfig = useContext<AppConfig>(AppConfigContext);
@ -71,7 +71,7 @@ const App: React.FC<AppProps> & { useApp: () => useAppProps } = (props) => {
style,
};
return wrapSSR(
return wrapCSSVar(
<AppContext.Provider value={memoizedContextValue}>
<AppConfigContext.Provider value={mergedAppConfig}>
<Component {...(component === false ? undefined : rootProps)}>

View File

@ -1,5 +1,5 @@
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook } from '../../theme/internal';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks } from '../../theme/internal';
export type ComponentToken = {};
@ -18,5 +18,7 @@ const genBaseStyle: GenerateStyle<AppToken> = (token) => {
};
};
export const prepareComponentToken: GetDefaultToken<'App'> = () => ({});
// ============================== Export ==============================
export default genComponentStyleHook('App', (token) => [genBaseStyle(token)]);
export default genStyleHooks('App', genBaseStyle, prepareComponentToken);

View File

@ -3,7 +3,7 @@
exports[`renders components/auto-complete/demo/allowClear.tsx extend context correctly 1`] = `
Array [
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<div
@ -48,7 +48,7 @@ Array [
<br />,
<br />,
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search"
style="width: 200px;"
>
<div
@ -98,7 +98,7 @@ exports[`renders components/auto-complete/demo/allowClear.tsx extend context cor
exports[`renders components/auto-complete/demo/basic.tsx extend context correctly 1`] = `
Array [
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<div
@ -143,7 +143,7 @@ Array [
<br />,
<br />,
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<div
@ -190,57 +190,9 @@ Array [
exports[`renders components/auto-complete/demo/basic.tsx extend context correctly 2`] = `[]`;
exports[`renders components/auto-complete/demo/borderless.tsx extend context correctly 1`] = `
<div
class="ant-select ant-select-borderless ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<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="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"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-empty ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
class="ant-select-item-empty"
id="rc_select_TEST_OR_SSR_list"
role="listbox"
/>
</div>
</div>
</div>
`;
exports[`renders components/auto-complete/demo/borderless.tsx extend context correctly 2`] = `[]`;
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 1`] = `
<div
class="ant-select ant-select-lg ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
style="width: 250px;"
>
<div
@ -250,7 +202,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-select-selection-search-input ant-input-group-wrapper-lg"
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-group-wrapper-outlined ant-input-search ant-input-search-large ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -262,7 +214,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-input ant-input-lg"
class="ant-input ant-input-lg ant-input-outlined"
id="rc_select_TEST_OR_SSR"
placeholder="input here"
role="combobox"
@ -609,7 +561,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte
exports[`renders components/auto-complete/demo/custom.tsx extend context correctly 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
style="width: 200px;"
>
<div
@ -625,7 +577,7 @@ exports[`renders components/auto-complete/demo/custom.tsx extend context correct
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-input ant-select-selection-search-input custom"
class="ant-input ant-input-outlined ant-select-selection-search-input custom"
id="rc_select_TEST_OR_SSR"
placeholder="input here"
role="combobox"
@ -685,7 +637,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-show-search"
>
<div
class="ant-select-selector"
@ -755,7 +707,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -902,7 +854,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width: 30%;"
>
<div
@ -1017,7 +969,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
>
<div
class="ant-select-selector"
@ -1088,7 +1040,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -1097,7 +1049,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-select-selection-search"
>
<span
class="ant-input-affix-wrapper ant-select-selection-search-input"
class="ant-input-affix-wrapper ant-input-outlined ant-select-selection-search-input"
>
<input
aria-autocomplete="list"
@ -1188,7 +1140,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width: 30%;"
>
<div
@ -1303,7 +1255,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -1312,7 +1264,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-select-selection-search"
>
<span
class="ant-input-affix-wrapper ant-select-selection-search-input"
class="ant-input-affix-wrapper ant-input-outlined ant-select-selection-search-input"
>
<input
aria-autocomplete="list"
@ -1404,7 +1356,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width: 30%;"
>
<div
@ -1519,7 +1471,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -1528,7 +1480,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-select-selection-search-input"
class="ant-input-group-wrapper ant-input-group-wrapper-outlined ant-input-search ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -1540,7 +1492,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-input"
class="ant-input ant-input-outlined"
id="rc_select_TEST_OR_SSR"
role="combobox"
type="search"
@ -1633,7 +1585,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width: 20%;"
>
<div
@ -1748,7 +1700,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -1757,7 +1709,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-select-selection-search-input"
class="ant-input-group-wrapper ant-input-group-wrapper-outlined ant-input-search ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -1769,7 +1721,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-input"
class="ant-input ant-input-outlined"
id="rc_select_TEST_OR_SSR"
role="combobox"
type="search"
@ -1875,7 +1827,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
exports[`renders components/auto-complete/demo/non-case-sensitive.tsx extend context correctly 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<div
@ -1999,7 +1951,7 @@ exports[`renders components/auto-complete/demo/non-case-sensitive.tsx extend con
exports[`renders components/auto-complete/demo/options.tsx extend context correctly 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<div
@ -2081,7 +2033,7 @@ exports[`renders components/auto-complete/demo/render-panel.tsx extend context c
style="padding-bottom: 0px; position: relative; min-width: 0;"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 120px; margin: 0px;"
>
<div
@ -2236,7 +2188,7 @@ exports[`renders components/auto-complete/demo/status.tsx extend context correct
class="ant-space-item"
>
<div
class="ant-select ant-select-status-error ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-status-error ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<div
@ -2281,7 +2233,7 @@ exports[`renders components/auto-complete/demo/status.tsx extend context correct
class="ant-space-item"
>
<div
class="ant-select ant-select-status-warning ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-status-warning ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<div
@ -2329,7 +2281,7 @@ exports[`renders components/auto-complete/demo/status.tsx extend context correct
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 1`] = `
<div
class="ant-select ant-select-lg ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
style="width: 300px;"
>
<div
@ -2339,7 +2291,7 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx extend con
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input ant-input-group-wrapper-lg"
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-group-wrapper-outlined ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -2351,7 +2303,7 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx extend con
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-input ant-input-lg"
class="ant-input ant-input-lg ant-input-outlined"
id="rc_select_TEST_OR_SSR"
placeholder="input here"
role="combobox"
@ -2417,3 +2369,142 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx extend con
"Warning: [antd: AutoComplete] You need to control style self instead of setting \`size\` when using customize input.",
]
`;
exports[`renders components/auto-complete/demo/variant.tsx extend context correctly 1`] = `
<div
class="ant-flex ant-flex-align-stretch ant-flex-vertical"
style="gap: 12px;"
>
<div
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<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="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"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Outlined
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-empty ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
class="ant-select-item-empty"
id="rc_select_TEST_OR_SSR_list"
role="listbox"
/>
</div>
</div>
</div>
<div
class="ant-select ant-select-filled ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<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="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"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Filled
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-empty ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
class="ant-select-item-empty"
id="rc_select_TEST_OR_SSR_list"
role="listbox"
/>
</div>
</div>
</div>
<div
class="ant-select ant-select-borderless ant-select-auto-complete ant-select-single ant-select-show-search"
style="width: 200px;"
>
<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="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"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-empty ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
class="ant-select-item-empty"
id="rc_select_TEST_OR_SSR_list"
role="listbox"
/>
</div>
</div>
</div>
</div>
`;
exports[`renders components/auto-complete/demo/variant.tsx extend context correctly 2`] = `[]`;

View File

@ -3,7 +3,7 @@
exports[`renders components/auto-complete/demo/allowClear.tsx correctly 1`] = `
Array [
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
@ -35,7 +35,7 @@ Array [
<br />,
<br />,
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search"
style="width:200px"
>
<div
@ -70,7 +70,7 @@ Array [
exports[`renders components/auto-complete/demo/basic.tsx correctly 1`] = `
Array [
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
@ -102,7 +102,7 @@ Array [
<br />,
<br />,
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
@ -134,42 +134,9 @@ Array [
]
`;
exports[`renders components/auto-complete/demo/borderless.tsx correctly 1`] = `
<div
class="ant-select ant-select-borderless ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
</div>
`;
exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`] = `
<div
class="ant-select ant-select-lg ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
style="width:250px"
>
<div
@ -179,7 +146,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-select-selection-search-input ant-input-group-wrapper-lg"
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-group-wrapper-outlined ant-input-search ant-input-search-large ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -191,7 +158,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-input ant-input-lg"
class="ant-input ant-input-lg ant-input-outlined"
placeholder="input here"
role="combobox"
type="search"
@ -241,7 +208,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`
exports[`renders components/auto-complete/demo/custom.tsx correctly 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
style="width:200px"
>
<div
@ -257,7 +224,7 @@ exports[`renders components/auto-complete/demo/custom.tsx correctly 1`] = `
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-input ant-select-selection-search-input custom"
class="ant-input ant-input-outlined ant-select-selection-search-input custom"
placeholder="input here"
role="combobox"
style="height:50px"
@ -302,7 +269,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-show-search"
>
<div
class="ant-select-selector"
@ -359,7 +326,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -448,7 +415,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width:30%"
>
<div
@ -505,7 +472,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
>
<div
class="ant-select-selector"
@ -563,7 +530,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -572,7 +539,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-select-selection-search"
>
<span
class="ant-input-affix-wrapper ant-select-selection-search-input"
class="ant-input-affix-wrapper ant-input-outlined ant-select-selection-search-input"
>
<input
aria-autocomplete="list"
@ -650,7 +617,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width:30%"
>
<div
@ -707,7 +674,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -716,7 +683,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-select-selection-search"
>
<span
class="ant-input-affix-wrapper ant-select-selection-search-input"
class="ant-input-affix-wrapper ant-input-outlined ant-select-selection-search-input"
>
<input
aria-autocomplete="list"
@ -795,7 +762,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width:30%"
>
<div
@ -852,7 +819,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -861,7 +828,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-select-selection-search-input"
class="ant-input-group-wrapper ant-input-group-wrapper-outlined ant-input-search ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -873,7 +840,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-input"
class="ant-input ant-input-outlined"
role="combobox"
type="search"
value=""
@ -953,7 +920,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-input-group ant-input-group-compact"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-outlined ant-select-single ant-select-show-arrow"
style="width:20%"
>
<div
@ -1010,7 +977,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
</span>
</div>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -1019,7 +986,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-select-selection-search-input"
class="ant-input-group-wrapper ant-input-group-wrapper-outlined ant-input-search ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -1031,7 +998,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-input"
class="ant-input ant-input-outlined"
role="combobox"
type="search"
value=""
@ -1118,7 +1085,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
exports[`renders components/auto-complete/demo/non-case-sensitive.tsx correctly 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
@ -1151,7 +1118,7 @@ exports[`renders components/auto-complete/demo/non-case-sensitive.tsx correctly
exports[`renders components/auto-complete/demo/options.tsx correctly 1`] = `
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
@ -1218,7 +1185,7 @@ exports[`renders components/auto-complete/demo/render-panel.tsx correctly 1`] =
style="padding-bottom:0;position:relative;min-width:0"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:120px;margin:0"
>
<div
@ -1256,7 +1223,7 @@ exports[`renders components/auto-complete/demo/status.tsx correctly 1`] = `
class="ant-space-item"
>
<div
class="ant-select ant-select-status-error ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-status-error ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
@ -1288,7 +1255,7 @@ exports[`renders components/auto-complete/demo/status.tsx correctly 1`] = `
class="ant-space-item"
>
<div
class="ant-select ant-select-status-warning ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-outlined ant-select-status-warning ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
@ -1321,7 +1288,7 @@ exports[`renders components/auto-complete/demo/status.tsx correctly 1`] = `
exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly 1`] = `
<div
class="ant-select ant-select-lg ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
style="width:300px"
>
<div
@ -1331,7 +1298,7 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly
class="ant-select-selection-search"
>
<span
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input ant-input-group-wrapper-lg"
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-group-wrapper-outlined ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input"
>
<span
class="ant-input-wrapper ant-input-group"
@ -1343,7 +1310,7 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-input ant-input-lg"
class="ant-input ant-input-lg ant-input-outlined"
placeholder="input here"
role="combobox"
type="search"
@ -1390,3 +1357,101 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly
</div>
</div>
`;
exports[`renders components/auto-complete/demo/variant.tsx correctly 1`] = `
<div
class="ant-flex ant-flex-align-stretch ant-flex-vertical"
style="gap:12px"
>
<div
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Outlined
</span>
</div>
</div>
<div
class="ant-select ant-select-filled ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Filled
</span>
</div>
</div>
<div
class="ant-select ant-select-borderless ant-select-auto-complete ant-select-single ant-select-show-search"
style="width:200px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
role="combobox"
type="search"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
</div>
</div>
`;

View File

@ -2,7 +2,7 @@
exports[`AutoComplete rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-select ant-select-rtl ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-rtl ant-select-outlined ant-select-auto-complete ant-select-single ant-select-show-search"
>
<div
class="ant-select-selector"

View File

@ -1,7 +0,0 @@
## zh-CN
没有边框。
## en-US
No border.

View File

@ -1,26 +0,0 @@
import React, { useState } from 'react';
import { AutoComplete } from 'antd';
const mockVal = (str: string, repeat = 1) => ({
value: str.repeat(repeat),
});
const App: React.FC = () => {
const [options, setOptions] = useState<{ value: string }[]>([]);
const getPanelValue = (searchText: string) =>
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
return (
<AutoComplete
options={options}
style={{ width: 200 }}
placeholder="Borderless"
onSearch={(text) => setOptions(getPanelValue(text))}
onSelect={globalThis.console.log}
bordered={false}
/>
);
};
export default App;

View File

@ -0,0 +1,7 @@
## zh-CN
可选 `outlined` `filled` `borderless` 三种形态。
## en-US
There are `outlined` `fille` and `borderless`, totally three variants to choose from.

View File

@ -0,0 +1,43 @@
import React, { useState } from 'react';
import { AutoComplete, Flex } from 'antd';
const mockVal = (str: string, repeat = 1) => ({
value: str.repeat(repeat),
});
const App: React.FC = () => {
const [options, setOptions] = useState<{ value: string }[]>([]);
const getPanelValue = (searchText: string) =>
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
return (
<Flex vertical gap={12}>
<AutoComplete
options={options}
style={{ width: 200 }}
placeholder="Outlined"
onSearch={(text) => setOptions(getPanelValue(text))}
onSelect={globalThis.console.log}
/>
<AutoComplete
options={options}
style={{ width: 200 }}
placeholder="Filled"
onSearch={(text) => setOptions(getPanelValue(text))}
onSelect={globalThis.console.log}
variant="filled"
/>
<AutoComplete
options={options}
style={{ width: 200 }}
placeholder="Borderless"
onSearch={(text) => setOptions(getPanelValue(text))}
onSelect={globalThis.console.log}
variant="borderless"
/>
</Flex>
);
};
export default App;

View File

@ -32,7 +32,7 @@ The differences with Select are:
<code src="./demo/certain-category.tsx">Lookup-Patterns - Certain Category</code>
<code src="./demo/uncertain-category.tsx">Lookup-Patterns - Uncertain Category</code>
<code src="./demo/status.tsx">Status</code>
<code src="./demo/borderless.tsx">Borderless</code>
<code src="./demo/variant.tsx" version="5.13.0">Variants</code>
<code src="./demo/allowClear.tsx">Customize clear button</code>
<code src="./demo/form-debug.tsx" debug>Debug in Form</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
@ -46,7 +46,6 @@ Common props ref[Common props](/docs/react/common-props)
| allowClear | Show clear button | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: Support Object type |
| autoFocus | If get focus when component mounted | boolean | false | |
| backfill | If backfill selected item the input when using keyboard | boolean | false | |
| bordered | Whether has border style | boolean | true | |
| children (for customize input element) | Customize input element | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement&lt;InputProps> | &lt;Input /> | |
| children (for dataSource) | Data source to auto complete | React.ReactElement&lt;OptionProps> \| Array&lt;React.ReactElement&lt;OptionProps>> | - | |
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
@ -62,6 +61,7 @@ Common props ref[Common props](/docs/react/common-props)
| placeholder | The placeholder of input | string | - | |
| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
| value | Selected option | string | - | |
| variant | Variants of input | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 |
| onBlur | Called when leaving the component | function() | - | |
| onChange | Called when selecting an option or changing an input value | function(value) | - | |
| onDropdownVisibleChange | Call when dropdown open | function(open) | - | |

View File

@ -33,7 +33,7 @@ demo:
<code src="./demo/certain-category.tsx">查询模式 - 确定类目</code>
<code src="./demo/uncertain-category.tsx">查询模式 - 不确定类目</code>
<code src="./demo/status.tsx">自定义状态</code>
<code src="./demo/borderless.tsx">无边框</code>
<code src="./demo/variant.tsx" version="5.13.0">多种形态</code>
<code src="./demo/allowClear.tsx">自定义清除按钮</code>
<code src="./demo/form-debug.tsx" debug>在 Form 中 Debug</code>
<code src="./demo/render-panel.tsx" debug>\_InternalPanelDoNotUseOrYouWillBeFired</code>
@ -47,13 +47,13 @@ demo:
| allowClear | 支持清除 | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: 支持对象形式 |
| autoFocus | 自动获取焦点 | boolean | false | |
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
| bordered | 是否有边框 | boolean | true | |
| children (自动完成的数据源) | 自动完成的数据源 | React.ReactElement&lt;OptionProps> \| Array&lt;React.ReactElement&lt;OptionProps>> | - | |
| children (自定义输入框) | 自定义输入框 | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement&lt;InputProps> | &lt;Input /> | |
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
| defaultValue | 指定默认选中的条目 | string | - | |
| disabled | 是否禁用 | boolean | false | |
| dropdownRender | 自定义下拉框内容 | (menus: ReactNode) => ReactNode | - | 4.24.0 |
| popupClassName | 下拉菜单的 className 属性 | string | - | 4.23.0 |
| dropdownMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动 | boolean \| number | true | |
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 true反之则返回 false | boolean \| function(inputValue, option) | true | |
@ -64,6 +64,7 @@ demo:
| placeholder | 输入框提示 | string | - | |
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
| value | 指定当前选中的条目 | string | - | |
| variant | 形态变体 | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 |
| onBlur | 失去焦点时的回调 | function() | - | |
| onChange | 选中 option或 input 的 value 变化时,调用此函数 | function(value) | - | |
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |

View File

@ -439,7 +439,7 @@ Array [
</span>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 2140;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 1200;"
>
<div
class="ant-tooltip-arrow"
@ -822,7 +822,7 @@ Array [
</span>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 2140;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 1200;"
>
<div
class="ant-tooltip-arrow"
@ -948,7 +948,7 @@ Array [
</span>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 2140;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 1200;"
>
<div
class="ant-tooltip-arrow"
@ -1074,7 +1074,7 @@ Array [
</span>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 2140;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 1200;"
>
<div
class="ant-tooltip-arrow"

View File

@ -12,6 +12,7 @@ import useBreakpoint from '../grid/hooks/useBreakpoint';
import type { AvatarContextType, AvatarSize } from './AvatarContext';
import AvatarContext from './AvatarContext';
import useStyle from './style';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
export interface AvatarProps {
/** Shape of avatar, options: `circle`, `square` */
@ -144,7 +145,8 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
}
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls);
const rootCls = useCSSVarCls(prefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
const sizeCls = classNames({
[`${prefixCls}-lg`]: size === 'large',
@ -164,6 +166,8 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
[`${prefixCls}-image`]: hasImageElement || (src && isImgExist),
[`${prefixCls}-icon`]: !!icon,
},
cssVarCls,
rootCls,
className,
rootClassName,
hashId,
@ -234,7 +238,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
delete others.onError;
delete others.gap;
return wrapSSR(
return wrapCSSVar(
<span
{...others}
style={{ ...sizeStyle, ...responsiveSizeStyle, ...avatar?.style, ...others.style }}

View File

@ -8,6 +8,7 @@ import Avatar from './avatar';
import AvatarContext from './AvatarContext';
import type { AvatarContextType, AvatarSize } from './AvatarContext';
import useStyle from './style';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
interface ContextProps {
children?: React.ReactNode;
@ -60,13 +61,16 @@ const Group: React.FC<GroupProps> = (props) => {
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
const [wrapSSR, hashId] = useStyle(prefixCls);
const rootCls = useCSSVarCls(prefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
const cls = classNames(
groupPrefixCls,
{
[`${groupPrefixCls}-rtl`]: direction === 'rtl',
},
cssVarCls,
rootCls,
className,
rootClassName,
hashId,
@ -91,7 +95,7 @@ const Group: React.FC<GroupProps> = (props) => {
<Avatar style={maxStyle}>{`+${numOfChildren - maxCount}`}</Avatar>
</Popover>,
);
return wrapSSR(
return wrapCSSVar(
<AvatarContextProvider shape={shape} size={size}>
<div className={cls} style={style}>
{childrenShow}
@ -100,7 +104,7 @@ const Group: React.FC<GroupProps> = (props) => {
);
}
return wrapSSR(
return wrapCSSVar(
<AvatarContextProvider shape={shape} size={size}>
<div className={cls} style={style}>
{childrenWithProps}

View File

@ -1,7 +1,8 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { type CSSObject, unit } from '@ant-design/cssinjs';
import { resetComponent } from '../../style';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks, mergeToken } from '../../theme/internal';
export interface ComponentToken {
/**
@ -75,13 +76,14 @@ const genBaseStyle: GenerateStyle<AvatarToken> = (token) => {
borderRadiusSM,
lineWidth,
lineType,
calc,
} = token;
// Avatar size style
const avatarSizeStyle = (size: number, fontSize: number, radius: number): CSSObject => ({
width: size,
height: size,
lineHeight: `${size - lineWidth * 2}px`,
lineHeight: unit(calc(size).sub(calc(lineWidth).mul(2)).equal()),
borderRadius: '50%',
[`&${componentCls}-square`]: {
@ -116,7 +118,7 @@ const genBaseStyle: GenerateStyle<AvatarToken> = (token) => {
textAlign: 'center',
verticalAlign: 'middle',
background: avatarBg,
border: `${lineWidth}px ${lineType} transparent`,
border: `${unit(lineWidth)} ${lineType} transparent`,
[`&-image`]: {
background: 'transparent',
@ -169,7 +171,33 @@ const genGroupStyle: GenerateStyle<AvatarToken> = (token) => {
};
};
export default genComponentStyleHook(
export const prepareComponentToken: GetDefaultToken<'Avatar'> = (token) => {
const {
controlHeight,
controlHeightLG,
controlHeightSM,
fontSize,
fontSizeLG,
fontSizeXL,
fontSizeHeading3,
marginXS,
marginXXS,
colorBorderBg,
} = token;
return {
containerSize: controlHeight,
containerSizeLG: controlHeightLG,
containerSizeSM: controlHeightSM,
textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
textFontSizeLG: fontSizeHeading3,
textFontSizeSM: fontSize,
groupSpace: marginXXS,
groupOverlapping: -marginXS,
groupBorderColor: colorBorderBg,
};
};
export default genStyleHooks(
'Avatar',
(token) => {
const { colorTextLightSolid, colorTextPlaceholder } = token;
@ -179,33 +207,5 @@ export default genComponentStyleHook(
});
return [genBaseStyle(avatarToken), genGroupStyle(avatarToken)];
},
(token) => {
const {
controlHeight,
controlHeightLG,
controlHeightSM,
fontSize,
fontSizeLG,
fontSizeXL,
fontSizeHeading3,
marginXS,
marginXXS,
colorBorderBg,
} = token;
return {
containerSize: controlHeight,
containerSizeLG: controlHeightLG,
containerSizeSM: controlHeightSM,
textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
textFontSizeLG: fontSizeHeading3,
textFontSizeSM: fontSize,
groupSpace: marginXXS,
groupOverlapping: -marginXS,
groupBorderColor: colorBorderBg,
};
},
prepareComponentToken,
);

View File

@ -74,11 +74,14 @@ const BackTop: React.FC<BackTopProps> = (props) => {
const { getPrefixCls, direction } = React.useContext<ConfigConsumerProps>(ConfigContext);
const prefixCls = getPrefixCls('back-top', customizePrefixCls);
const rootPrefixCls = getPrefixCls();
const [wrapSSR, hashId] = useStyle(prefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
const classString = classNames(
hashId,
cssVarCls,
prefixCls,
{
[`${prefixCls}-rtl`]: direction === 'rtl',
@ -105,7 +108,7 @@ const BackTop: React.FC<BackTopProps> = (props) => {
</div>
);
return wrapSSR(
return wrapCSSVar(
<div {...divProps} className={classString} onClick={scrollToTop} ref={ref}>
<CSSMotion visible={visible} motionName={`${rootPrefixCls}-fade`}>
{({ className: motionClassName }) =>

View File

@ -1,7 +1,8 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { type CSSObject, unit } from '@ant-design/cssinjs';
import { resetComponent } from '../../style';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks, mergeToken } from '../../theme/internal';
/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {
@ -16,10 +17,10 @@ type BackTopToken = FullToken<'BackTop'> & {
backTopSize: number;
// Position
backTopBlockEnd: number;
backTopInlineEnd: number;
backTopInlineEndMD: number;
backTopInlineEndXS: number;
backTopBlockEnd: number | string;
backTopInlineEnd: number | string;
backTopInlineEndMD: number | string;
backTopInlineEndXS: number | string;
};
// ============================== Shared ==============================
@ -61,34 +62,35 @@ const genSharedBackTopStyle: GenerateStyle<BackTopToken, CSSObject> = (token): C
// change to .backtop .backtop-icon
[`${componentCls}-icon`]: {
fontSize: backTopFontSize,
lineHeight: `${backTopSize}px`,
lineHeight: unit(backTopSize),
},
},
};
};
const genMediaBackTopStyle: GenerateStyle<BackTopToken> = (token): CSSObject => {
const { componentCls } = token;
const { componentCls, screenMD, screenXS, backTopInlineEndMD, backTopInlineEndXS } = token;
return {
[`@media (max-width: ${token.screenMD}px)`]: {
[`@media (max-width: ${unit(screenMD)})`]: {
[componentCls]: {
insetInlineEnd: token.backTopInlineEndMD,
insetInlineEnd: backTopInlineEndMD,
},
},
[`@media (max-width: ${token.screenXS}px)`]: {
[`@media (max-width: ${unit(screenXS)})`]: {
[componentCls]: {
insetInlineEnd: token.backTopInlineEndXS,
insetInlineEnd: backTopInlineEndXS,
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook<'BackTop'>(
'BackTop',
export const prepareComponentToken: GetDefaultToken<'BackTop'> = (token) => ({
zIndexPopup: token.zIndexBase + 10,
});
// ============================== Export ==============================
export default genStyleHooks(
'BackTop',
(token) => {
const {
fontSizeHeading3,
@ -96,23 +98,20 @@ export default genComponentStyleHook<'BackTop'>(
colorTextLightSolid,
colorText,
controlHeightLG,
calc,
} = token;
const backTopToken = mergeToken<BackTopToken>(token, {
backTopBackground: colorTextDescription,
backTopColor: colorTextLightSolid,
backTopHoverBackground: colorText,
backTopFontSize: fontSizeHeading3,
backTopSize: controlHeightLG,
backTopBlockEnd: controlHeightLG * 1.25,
backTopInlineEnd: controlHeightLG * 2.5,
backTopInlineEndMD: controlHeightLG * 1.5,
backTopInlineEndXS: controlHeightLG * 0.5,
backTopBlockEnd: calc(controlHeightLG).mul(1.25).equal(),
backTopInlineEnd: calc(controlHeightLG).mul(2.5).equal(),
backTopInlineEndMD: calc(controlHeightLG).mul(1.5).equal(),
backTopInlineEndXS: calc(controlHeightLG).mul(0.5).equal(),
});
return [genSharedBackTopStyle(backTopToken), genMediaBackTopStyle(backTopToken)];
},
(token) => ({
zIndexPopup: token.zIndexBase + 10,
}),
prepareComponentToken,
);

View File

@ -33,6 +33,10 @@ const Ribbon: React.FC<RibbonProps> = (props) => {
} = props;
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('ribbon', customizePrefixCls);
const wrapperCls = `${prefixCls}-wrapper`;
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, wrapperCls);
const colorInPreset = isPresetColor(color, false);
const ribbonCls = classNames(
prefixCls,
@ -43,15 +47,15 @@ const Ribbon: React.FC<RibbonProps> = (props) => {
},
className,
);
const [wrapSSR, hashId] = useStyle(prefixCls);
const colorStyle: React.CSSProperties = {};
const cornerColorStyle: React.CSSProperties = {};
if (color && !colorInPreset) {
colorStyle.background = color;
cornerColorStyle.color = color;
}
return wrapSSR(
<div className={classNames(`${prefixCls}-wrapper`, rootClassName, hashId)}>
return wrapCSSVar(
<div className={classNames(wrapperCls, rootClassName, hashId, cssVarCls)}>
{children}
<div className={classNames(ribbonCls, hashId)} style={{ ...colorStyle, ...style }}>
<span className={`${prefixCls}-text`}>{text}</span>

View File

@ -1,7 +1,8 @@
import classnames from 'classnames';
import CSSMotion from 'rc-motion';
import * as React from 'react';
import { useMemo, useRef } from 'react';
import classnames from 'classnames';
import CSSMotion from 'rc-motion';
import type { PresetStatusColorType } from '../_util/colors';
import { isPresetColor } from '../_util/colors';
import { cloneElement } from '../_util/reactNode';
@ -75,8 +76,7 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
const { getPrefixCls, direction, badge } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('badge', customizePrefixCls);
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
// ================================ Misc ================================
const numberedDisplayCount = (
@ -183,12 +183,13 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
badge?.classNames?.root,
classNames?.root,
hashId,
cssVarCls,
);
// <Badge status="success" />
if (!children && hasStatus) {
const statusTextColor = mergedStyle.color;
return wrapSSR(
return wrapCSSVar(
<span
{...restProps}
className={badgeClassName}
@ -207,7 +208,7 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
);
}
return wrapSSR(
return wrapCSSVar(
<span
ref={ref}
{...restProps}

Some files were not shown because too many files have changed in this diff Show More