mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-22 08:53:29 +08:00
Merge branch 'feature' into feat/collapse-icon-vertical-position
This commit is contained in:
commit
ca90069956
@ -66,7 +66,7 @@ const useStyle = createStyles(({ token }, markPos: [number, number, number, numb
|
||||
|
||||
export interface SemanticPreviewProps {
|
||||
semantics: { name: string; desc: string; version?: string }[];
|
||||
children: React.ReactElement;
|
||||
children: React.ReactElement<any>;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
|
||||
// ======================== Hover =========================
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const timerRef = React.useRef<ReturnType<typeof setTimeout>>();
|
||||
const timerRef = React.useRef<ReturnType<typeof setTimeout>>(null);
|
||||
|
||||
const [positionMotion, setPositionMotion] = React.useState<boolean>(false);
|
||||
const [hoverSemantic, setHoverSemantic] = React.useState<string | null>(null);
|
||||
@ -111,12 +111,14 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
|
||||
const targetElement = containerRef.current?.querySelector<HTMLElement>(`.${targetClassName}`);
|
||||
const containerRect = containerRef.current?.getBoundingClientRect();
|
||||
const targetRect = targetElement?.getBoundingClientRect();
|
||||
|
||||
setMarkPos([
|
||||
(targetRect?.left || 0) - (containerRect?.left || 0),
|
||||
(targetRect?.top || 0) - (containerRect?.top || 0),
|
||||
targetRect?.width || 0,
|
||||
targetRect?.height || 0,
|
||||
]);
|
||||
|
||||
timerRef.current = setTimeout(() => {
|
||||
setPositionMotion(true);
|
||||
}, 10);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ColorPicker, Flex, Input } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import type { ColorPickerProps, GetProp } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { generateColor } from 'antd/es/color-picker/util';
|
||||
import classNames from 'classnames';
|
||||
|
||||
@ -61,7 +61,7 @@ const DebouncedColorPicker: React.FC<React.PropsWithChildren<ThemeColorPickerPro
|
||||
<ColorPicker
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
presets={[{ label: 'PresetColors', colors: PRESET_COLORS }]}
|
||||
presets={[{ label: 'PresetColors', key: 'PresetColors', colors: PRESET_COLORS }]}
|
||||
>
|
||||
{children}
|
||||
</ColorPicker>
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
HomeOutlined,
|
||||
QuestionCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { FastColor } from '@ant-design/fast-color';
|
||||
import type { ColorPickerProps, GetProp, MenuProps, ThemeConfig } from 'antd';
|
||||
import {
|
||||
Breadcrumb,
|
||||
@ -324,7 +324,7 @@ const ThemesInfo: Record<THEME, Partial<ThemeData>> = {
|
||||
const normalize = (value: number) => value / 255;
|
||||
|
||||
function rgbToColorMatrix(color: string) {
|
||||
const rgb = new TinyColor(color).toRgb();
|
||||
const rgb = new FastColor(color).toRgb();
|
||||
const { r, g, b } = rgb;
|
||||
|
||||
const invertValue = normalize(r) * 100;
|
||||
|
15
.dumi/theme/builtins/Antd.tsx
Normal file
15
.dumi/theme/builtins/Antd.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import * as all from 'antd';
|
||||
|
||||
interface AntdProps {
|
||||
component: keyof typeof all;
|
||||
}
|
||||
|
||||
function Antd(props: AntdProps) {
|
||||
const { component, ...restProps } = props;
|
||||
const Component = (all[component] ?? React.Fragment) as React.ComponentType;
|
||||
|
||||
return <Component {...restProps} />;
|
||||
}
|
||||
|
||||
export default Antd;
|
@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import type { ColorInput } from '@ctrl/tinycolor';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { FastColor } from '@ant-design/fast-color';
|
||||
import type { ColorInput } from '@ant-design/fast-color';
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => ({
|
||||
@ -22,7 +22,7 @@ const useStyle = createStyles(({ token, css }) => ({
|
||||
}));
|
||||
|
||||
interface ColorChunkProps {
|
||||
value?: ColorInput;
|
||||
value: ColorInput;
|
||||
}
|
||||
|
||||
const ColorChunk: React.FC<React.PropsWithChildren<ColorChunkProps>> = (props) => {
|
||||
@ -30,7 +30,7 @@ const ColorChunk: React.FC<React.PropsWithChildren<ColorChunkProps>> = (props) =
|
||||
const { value, children } = props;
|
||||
|
||||
const dotColor = React.useMemo(() => {
|
||||
const _color = new TinyColor(value).toHex8String();
|
||||
const _color = new FastColor(value).toHexString();
|
||||
return _color.endsWith('ff') ? _color.slice(0, -2) : _color;
|
||||
}, [value]);
|
||||
|
||||
|
@ -154,7 +154,9 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
|
||||
colon={false}
|
||||
column={1}
|
||||
style={{ marginTop: token.margin }}
|
||||
labelStyle={{ paddingInlineEnd: token.padding, width: 56 }}
|
||||
styles={{
|
||||
label: { paddingInlineEnd: token.padding, width: 56 },
|
||||
}}
|
||||
items={
|
||||
[
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ const Overview: React.FC = () => {
|
||||
{cardContent}
|
||||
</a>
|
||||
) : (
|
||||
<Link to={url} prefetch key={component.title}>
|
||||
<Link to={url} key={component.title}>
|
||||
{cardContent}
|
||||
</Link>
|
||||
);
|
||||
|
@ -157,7 +157,7 @@ const SubTokenTable: React.FC<SubTokenTableProps> = (props) => {
|
||||
{title}
|
||||
<Popover
|
||||
title={null}
|
||||
overlayStyle={{ width: 400 }}
|
||||
styles={{ root: { width: 400 } }}
|
||||
content={
|
||||
<Typography>
|
||||
{/* <SourceCode lang="jsx">{code}</SourceCode> */}
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React, { Suspense, useContext } from 'react';
|
||||
import { BugOutlined, CodeOutlined, ExperimentOutlined } from '@ant-design/icons';
|
||||
import { ConfigProvider, Tooltip, Button } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { DumiDemoGrid, FormattedMessage } from 'dumi';
|
||||
import { DumiDemoGrid, FormattedMessage, DumiDemo } from 'dumi';
|
||||
import { css, Global } from '@emotion/react';
|
||||
|
||||
import useLayoutState from '../../../hooks/useLayoutState';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import DemoContext from '../../slots/DemoContext';
|
||||
import DemoFallback from '../Previewer/DemoFallback';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
@ -113,7 +114,14 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
|
||||
</Tooltip>
|
||||
</span>
|
||||
<ConfigProvider theme={{ cssVar: enableCssVar, hashed: !enableCssVar }}>
|
||||
<DumiDemoGrid items={demos} />
|
||||
<DumiDemoGrid
|
||||
items={demos}
|
||||
demoRender={(item) => (
|
||||
<Suspense fallback={<DemoFallback />}>
|
||||
<DumiDemo key={item.demo.id} {...item} />
|
||||
</Suspense>
|
||||
)}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { CSSProperties } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import Icon, * as AntdIcons from '@ant-design/icons';
|
||||
import type { SegmentedProps } from 'antd';
|
||||
import { Affix, Empty, Input, Segmented } from 'antd';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import type { SegmentedOptions } from 'antd/es/segmented';
|
||||
import { useIntl } from 'dumi';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
@ -28,26 +28,6 @@ const useStyle = createStyles(({ token, css }) => ({
|
||||
`,
|
||||
}));
|
||||
|
||||
const options = (
|
||||
formatMessage: (values: Record<string, string>) => React.ReactNode,
|
||||
): SegmentedProps['options'] => [
|
||||
{
|
||||
value: ThemeType.Outlined,
|
||||
icon: <Icon component={OutlinedIcon} />,
|
||||
label: formatMessage({ id: 'app.docs.components.icon.outlined' }),
|
||||
},
|
||||
{
|
||||
value: ThemeType.Filled,
|
||||
icon: <Icon component={FilledIcon} />,
|
||||
label: formatMessage({ id: 'app.docs.components.icon.filled' }),
|
||||
},
|
||||
{
|
||||
value: ThemeType.TwoTone,
|
||||
icon: <Icon component={TwoToneIcon} />,
|
||||
label: formatMessage({ id: 'app.docs.components.icon.two-tone' }),
|
||||
},
|
||||
];
|
||||
|
||||
interface IconSearchState {
|
||||
theme: ThemeType;
|
||||
searchKey: string;
|
||||
@ -124,14 +104,35 @@ const IconSearch: React.FC = () => {
|
||||
backgroundColor: colorBgContainer,
|
||||
};
|
||||
|
||||
const memoizedOptions = React.useMemo<SegmentedOptions<ThemeType>>(
|
||||
() => [
|
||||
{
|
||||
value: ThemeType.Outlined,
|
||||
icon: <Icon component={OutlinedIcon} />,
|
||||
label: intl.formatMessage({ id: 'app.docs.components.icon.outlined' }),
|
||||
},
|
||||
{
|
||||
value: ThemeType.Filled,
|
||||
icon: <Icon component={FilledIcon} />,
|
||||
label: intl.formatMessage({ id: 'app.docs.components.icon.filled' }),
|
||||
},
|
||||
{
|
||||
value: ThemeType.TwoTone,
|
||||
icon: <Icon component={TwoToneIcon} />,
|
||||
label: intl.formatMessage({ id: 'app.docs.components.icon.two-tone' }),
|
||||
},
|
||||
],
|
||||
[intl],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="markdown">
|
||||
<Affix offsetTop={anchorTop} onChange={setSearchBarAffixed}>
|
||||
<div className={styles.iconSearchAffix} style={searchBarAffixed ? affixedStyle : {}}>
|
||||
<Segmented
|
||||
<Segmented<ThemeType>
|
||||
size="large"
|
||||
value={displayState.theme}
|
||||
options={options(intl.formatMessage)}
|
||||
options={memoizedOptions}
|
||||
onChange={handleChangeTheme}
|
||||
/>
|
||||
<Input.Search
|
||||
|
80
.dumi/theme/builtins/Previewer/CodeBlockButton.tsx
Normal file
80
.dumi/theme/builtins/Previewer/CodeBlockButton.tsx
Normal file
@ -0,0 +1,80 @@
|
||||
import React, { Suspense, useEffect, useState } from 'react';
|
||||
import { Tooltip } from 'antd';
|
||||
import { FormattedMessage } from 'dumi';
|
||||
|
||||
import { ping } from '../../utils';
|
||||
|
||||
let pingDeferrer: PromiseLike<boolean>;
|
||||
|
||||
const codeBlockJs =
|
||||
'https://renderoffice.a' +
|
||||
'lipay' +
|
||||
'objects.com/p' +
|
||||
'/yuyan/180020010001206410/parseFileData-v1.0.1.js';
|
||||
|
||||
function useShowCodeBlockButton() {
|
||||
const [showCodeBlockButton, setShowCodeBlockButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
pingDeferrer ??= new Promise<boolean>((resolve) => {
|
||||
ping((status) => {
|
||||
if (status !== 'timeout' && status !== 'error') {
|
||||
// Async insert `codeBlockJs` into body end
|
||||
const script = document.createElement('script');
|
||||
script.src = codeBlockJs;
|
||||
script.async = true;
|
||||
document.body.appendChild(script);
|
||||
|
||||
return resolve(true);
|
||||
}
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
pingDeferrer.then(setShowCodeBlockButton);
|
||||
}, []);
|
||||
|
||||
return showCodeBlockButton;
|
||||
}
|
||||
|
||||
interface CodeBlockButtonProps {
|
||||
title?: string;
|
||||
dependencies: Record<PropertyKey, string>;
|
||||
jsx: string;
|
||||
}
|
||||
|
||||
const CodeBlockButton: React.FC<CodeBlockButtonProps> = ({ title, dependencies = {}, jsx }) => {
|
||||
const showCodeBlockButton = useShowCodeBlockButton();
|
||||
|
||||
const codeBlockPrefillConfig = {
|
||||
title: `${title} - antd@${dependencies.antd}`,
|
||||
js: `${
|
||||
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
|
||||
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
css: '',
|
||||
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
|
||||
};
|
||||
|
||||
return showCodeBlockButton ? (
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codeblock" />}>
|
||||
<div className="code-box-code-action">
|
||||
<img
|
||||
alt="codeblock"
|
||||
src="https://mdn.alipayobjects.com/huamei_wtld8u/afts/img/A*K8rjSJpTNQ8AAAAAAAAAAAAADhOIAQ/original"
|
||||
className="code-box-codeblock"
|
||||
onClick={() => {
|
||||
openHituCodeBlock(JSON.stringify(codeBlockPrefillConfig));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default (props: CodeBlockButtonProps) => (
|
||||
<Suspense>
|
||||
<CodeBlockButton {...props} />
|
||||
</Suspense>
|
||||
);
|
@ -16,11 +16,10 @@ import EditButton from '../../common/EditButton';
|
||||
import CodePenIcon from '../../icons/CodePenIcon';
|
||||
import CodeSandboxIcon from '../../icons/CodeSandboxIcon';
|
||||
import ExternalLinkIcon from '../../icons/ExternalLinkIcon';
|
||||
import RiddleIcon from '../../icons/RiddleIcon';
|
||||
import DemoContext from '../../slots/DemoContext';
|
||||
import type { SiteContextProps } from '../../slots/SiteContext';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import { ping } from '../../utils';
|
||||
import CodeBlockButton from './CodeBlockButton';
|
||||
import type { AntdPreviewerProps } from './Previewer';
|
||||
|
||||
const { ErrorBoundary } = Alert;
|
||||
@ -39,27 +38,6 @@ const track = ({ type, demo }: { type: string; demo: string }) => {
|
||||
window.gtag('event', 'demo', { event_category: type, event_label: demo });
|
||||
};
|
||||
|
||||
let pingDeferrer: PromiseLike<boolean>;
|
||||
|
||||
function useShowRiddleButton() {
|
||||
const [showRiddleButton, setShowRiddleButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
pingDeferrer ??= new Promise<boolean>((resolve) => {
|
||||
ping((status) => {
|
||||
if (status !== 'timeout' && status !== 'error') {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
pingDeferrer.then(setShowRiddleButton);
|
||||
}, []);
|
||||
|
||||
return showRiddleButton;
|
||||
}
|
||||
|
||||
const useStyle = createStyles(({ token }) => {
|
||||
const { borderRadius } = token;
|
||||
return {
|
||||
@ -98,7 +76,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
title,
|
||||
description,
|
||||
originDebug,
|
||||
jsx,
|
||||
jsx = '',
|
||||
style,
|
||||
compact,
|
||||
background,
|
||||
@ -117,7 +95,6 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
|
||||
const entryName = 'index.tsx';
|
||||
const entryCode = asset.dependencies[entryName].value;
|
||||
const showRiddleButton = useShowRiddleButton();
|
||||
|
||||
const previewDemo = useRef<React.ReactNode>(null);
|
||||
const demoContainer = useRef<HTMLElement>(null);
|
||||
@ -127,11 +104,10 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
setSource: setLiveDemoSource,
|
||||
} = useLiveDemo(asset.id, {
|
||||
iframe: Boolean(iframe),
|
||||
containerRef: demoContainer,
|
||||
containerRef: demoContainer as React.RefObject<HTMLElement>,
|
||||
});
|
||||
const anchorRef = useRef<HTMLAnchorElement>(null);
|
||||
const codeSandboxIconRef = useRef<HTMLFormElement>(null);
|
||||
const riddleIconRef = useRef<HTMLFormElement>(null);
|
||||
const codepenIconRef = useRef<HTMLFormElement>(null);
|
||||
const [codeExpand, setCodeExpand] = useState<boolean>(false);
|
||||
const { theme } = useContext<SiteContextProps>(SiteContext);
|
||||
@ -278,18 +254,6 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
js_pre_processor: 'typescript',
|
||||
};
|
||||
|
||||
const riddlePrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
js: `${
|
||||
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
|
||||
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
css: '',
|
||||
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
|
||||
};
|
||||
|
||||
// Reorder source code
|
||||
let parsedSourceCode = suffix === 'tsx' ? entryCode : jsx;
|
||||
let importReactContent = "import React from 'react';";
|
||||
@ -440,24 +404,7 @@ createRoot(document.getElementById('container')).render(<Demo />);
|
||||
<CodeSandboxIcon className="code-box-codesandbox" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
{showRiddleButton ? (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="//riddle.alibaba-inc.com/riddles/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={riddleIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'riddle', demo: asset.id });
|
||||
riddleIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
|
||||
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
|
||||
<RiddleIcon className="code-box-riddle" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
) : null}
|
||||
<CodeBlockButton title={localizedTitle} dependencies={dependencies} jsx={jsx} />
|
||||
<Tooltip title={<FormattedMessage id="app.demo.stackblitz" />}>
|
||||
<span
|
||||
className="code-box-code-action"
|
||||
|
27
.dumi/theme/builtins/Previewer/DemoFallback.tsx
Normal file
27
.dumi/theme/builtins/Previewer/DemoFallback.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { Skeleton } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => ({
|
||||
skeletonWrapper: css`
|
||||
width: 100% !important;
|
||||
height: 250px;
|
||||
margin-bottom: ${token.margin}px;
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
`,
|
||||
}));
|
||||
|
||||
const DemoFallback = () => {
|
||||
const { styles } = useStyle();
|
||||
return (
|
||||
<Skeleton.Node
|
||||
active
|
||||
className={styles.skeletonWrapper}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
>
|
||||
{' '}
|
||||
</Skeleton.Node>
|
||||
);
|
||||
};
|
||||
|
||||
export default DemoFallback;
|
@ -7,6 +7,7 @@ import DesignPreviewer from './DesignPreviewer';
|
||||
|
||||
export interface AntdPreviewerProps extends IPreviewerProps {
|
||||
originDebug?: IPreviewerProps['debug'];
|
||||
jsx?: string;
|
||||
}
|
||||
|
||||
const Previewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
|
91
.dumi/theme/builtins/Previewer/RiddleButton.tsx
Normal file
91
.dumi/theme/builtins/Previewer/RiddleButton.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import React, { Suspense, useEffect, useRef, useState } from 'react';
|
||||
import { Tooltip } from 'antd';
|
||||
import { FormattedMessage } from 'dumi';
|
||||
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
|
||||
import RiddleIcon from '../../icons/RiddleIcon';
|
||||
import { ping } from '../../utils';
|
||||
|
||||
let pingDeferrer: PromiseLike<boolean>;
|
||||
|
||||
function useShowRiddleButton() {
|
||||
const [showRiddleButton, setShowRiddleButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
pingDeferrer ??= new Promise<boolean>((resolve) => {
|
||||
ping((status) => {
|
||||
if (status !== 'timeout' && status !== 'error') {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
pingDeferrer.then(setShowRiddleButton);
|
||||
}, []);
|
||||
|
||||
return showRiddleButton;
|
||||
}
|
||||
|
||||
interface RiddleButtonProps {
|
||||
title?: string;
|
||||
dependencies: Record<PropertyKey, string>;
|
||||
jsx: string;
|
||||
track: ({
|
||||
type,
|
||||
demo,
|
||||
}: {
|
||||
type: string;
|
||||
demo: string;
|
||||
}) => void;
|
||||
asset: IPreviewerProps['asset'];
|
||||
}
|
||||
|
||||
const RiddleButton: React.FC<RiddleButtonProps> = ({
|
||||
title,
|
||||
dependencies = {},
|
||||
jsx,
|
||||
track,
|
||||
asset,
|
||||
}) => {
|
||||
const riddleIconRef = useRef<HTMLFormElement>(null);
|
||||
const showRiddleButton = useShowRiddleButton();
|
||||
|
||||
const riddlePrefillConfig = {
|
||||
title: `${title} - antd@${dependencies.antd}`,
|
||||
js: `${
|
||||
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
|
||||
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
css: '',
|
||||
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
|
||||
};
|
||||
|
||||
return showRiddleButton ? (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="//riddle.alibaba-inc.com/riddles/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={riddleIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'riddle', demo: asset.id });
|
||||
riddleIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
|
||||
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
|
||||
<RiddleIcon className="code-box-riddle" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default (props: RiddleButtonProps) => (
|
||||
<Suspense>
|
||||
<RiddleButton {...props} />
|
||||
</Suspense>
|
||||
);
|
@ -1,39 +1,17 @@
|
||||
import React, { Suspense } from 'react';
|
||||
import { Alert, Skeleton } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { Alert } from 'antd';
|
||||
import Previewer from './Previewer';
|
||||
import DemoFallback from './DemoFallback';
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
|
||||
const { ErrorBoundary } = Alert;
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => ({
|
||||
skeletonWrapper: css`
|
||||
width: 100% !important;
|
||||
height: 250px;
|
||||
margin-bottom: ${token.margin}px;
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
`,
|
||||
}));
|
||||
|
||||
const PreviewerSuspense: React.FC<IPreviewerProps> = (props) => {
|
||||
const { styles } = useStyle();
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
<Skeleton.Node
|
||||
active
|
||||
className={styles.skeletonWrapper}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
>
|
||||
{' '}
|
||||
</Skeleton.Node>
|
||||
}
|
||||
>
|
||||
<Previewer {...props} />
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
const PreviewerSuspense: React.FC<IPreviewerProps> = (props) => (
|
||||
<ErrorBoundary>
|
||||
<Suspense fallback={<DemoFallback />}>
|
||||
<Previewer {...props} />
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
export default PreviewerSuspense;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// 用于 color.md 中的颜色对比
|
||||
import React from 'react';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { FastColor } from '@ant-design/fast-color';
|
||||
import { Flex, theme } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import tokenMeta from 'antd/es/version/token-meta.json';
|
||||
@ -55,7 +55,7 @@ const useStyle = createStyles(({ token, css }) => {
|
||||
});
|
||||
|
||||
function color2Rgba(color: string) {
|
||||
return `#${new TinyColor(color).toHex8().toUpperCase()}`;
|
||||
return `#${new FastColor(color).toHexString().toUpperCase()}`;
|
||||
}
|
||||
|
||||
interface ColorCircleProps {
|
||||
|
@ -99,7 +99,7 @@ const TokenTable: FC<TokenTableProps> = ({ type }) => {
|
||||
name: token,
|
||||
desc: lang === 'cn' ? meta.desc : meta.descEn,
|
||||
type: meta.type,
|
||||
value: defaultToken[token],
|
||||
value: defaultToken[token as keyof typeof defaultToken],
|
||||
})),
|
||||
[type, lang],
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Col, ColorPicker, Row } from 'antd';
|
||||
import { FormattedMessage } from 'dumi';
|
||||
import type { Color } from 'antd/es/color-picker';
|
||||
import { FormattedMessage } from 'dumi';
|
||||
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import ColorPatterns from './ColorPatterns';
|
||||
@ -34,7 +34,7 @@ const ColorPaletteTool: React.FC = () => {
|
||||
setPrimaryColorInstance(color);
|
||||
};
|
||||
|
||||
const handleChangeBackgroundColor = (_, hex: string) => {
|
||||
const handleChangeBackgroundColor = (_: Color, hex: string) => {
|
||||
setBackgroundColor(hex);
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,9 @@ import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
const rgbToHex = (rgbString: string): string => {
|
||||
const rgb = rgbString.match(/\d+/g);
|
||||
if (!rgb) {
|
||||
return '';
|
||||
}
|
||||
let r = parseInt(rgb[0], 10).toString(16);
|
||||
let g = parseInt(rgb[1], 10).toString(16);
|
||||
let b = parseInt(rgb[2], 10).toString(16);
|
||||
|
@ -20,6 +20,7 @@ interface ChangelogInfo {
|
||||
version: string;
|
||||
changelog: string;
|
||||
refs: string[];
|
||||
contributors: string[];
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
@ -160,14 +161,30 @@ const ParseChangelog: React.FC<{ changelog: string }> = (props) => {
|
||||
return <span>{parsedChangelog}</span>;
|
||||
};
|
||||
|
||||
const RefLinks: React.FC<{ refs: string[] }> = ({ refs }) => {
|
||||
const RefLinks: React.FC<{ refs: string[]; contributors: string[] }> = ({ refs, contributors }) => {
|
||||
const { styles } = useStyle();
|
||||
|
||||
return (
|
||||
<>
|
||||
{refs?.map((ref) => (
|
||||
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
|
||||
#{ref.match(/^.*\/(\d+)$/)?.[1]}
|
||||
</a>
|
||||
<React.Fragment key={ref}>
|
||||
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
|
||||
#{ref.match(/[^/]+$/)?.[0]}
|
||||
</a>
|
||||
</React.Fragment>
|
||||
))}
|
||||
{contributors?.map((contributor) => (
|
||||
<React.Fragment key={contributor}>
|
||||
<a
|
||||
className={styles.linkRef}
|
||||
key={contributor}
|
||||
href={`https://github.com/${contributor}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
@{contributor}
|
||||
</a>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
@ -178,7 +195,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
|
||||
const { styles } = useStyle();
|
||||
const len = changelogList.length;
|
||||
for (let i = 0; i < len; i += 1) {
|
||||
const { refs, changelog } = changelogList[i];
|
||||
const { refs, changelog, contributors } = changelogList[i];
|
||||
// Check if the next line is an image link and append it to the current line
|
||||
if (i + 1 < len && changelogList[i + 1].changelog.trim().startsWith('<img')) {
|
||||
const imgDom = new DOMParser().parseFromString(changelogList[i + 1].changelog, 'text/html');
|
||||
@ -186,7 +203,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
|
||||
elements.push(
|
||||
<li key={i}>
|
||||
<ParseChangelog changelog={changelog} />
|
||||
<RefLinks refs={refs} />
|
||||
<RefLinks refs={refs} contributors={contributors} />
|
||||
<br />
|
||||
<img
|
||||
src={imgElement?.getAttribute('src') || ''}
|
||||
@ -200,7 +217,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
|
||||
elements.push(
|
||||
<li key={i}>
|
||||
<ParseChangelog changelog={changelog} />
|
||||
<RefLinks refs={refs} />
|
||||
<RefLinks refs={refs} contributors={contributors} />
|
||||
</li>,
|
||||
);
|
||||
}
|
||||
@ -306,7 +323,7 @@ const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props)
|
||||
return (
|
||||
<>
|
||||
{isValidElement(children) &&
|
||||
cloneElement(children as React.ReactElement, {
|
||||
cloneElement(children as React.ReactElement<any>, {
|
||||
onClick: () => setShow(true),
|
||||
})}
|
||||
<Drawer
|
||||
|
@ -1,16 +1,20 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import type { JSONEditorPropsOptional } from 'vanilla-jsoneditor';
|
||||
import { JSONEditor, Mode } from 'vanilla-jsoneditor';
|
||||
import type { JsonEditor, JSONEditorPropsOptional } from 'vanilla-jsoneditor';
|
||||
import { createJSONEditor, Mode } from 'vanilla-jsoneditor';
|
||||
|
||||
const Editor: React.FC<JSONEditorPropsOptional> = (props) => {
|
||||
const editorRef = useRef<JSONEditor>(null);
|
||||
const editorRef = useRef<JsonEditor>();
|
||||
const container = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
editorRef.current = new JSONEditor({
|
||||
target: container.current,
|
||||
props: { mode: Mode.text },
|
||||
});
|
||||
if (container.current) {
|
||||
editorRef.current = createJSONEditor({
|
||||
target: container.current,
|
||||
props: {
|
||||
mode: Mode.text,
|
||||
},
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
editorRef.current?.destroy();
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
import type { MouseEvent, MouseEventHandler } from 'react';
|
||||
import React, { forwardRef, useLayoutEffect, useTransition } from 'react';
|
||||
import { Link as DumiLink, useLocation, useNavigate } from 'dumi';
|
||||
import nprogress from 'nprogress';
|
||||
import React, { useMemo, forwardRef } from 'react';
|
||||
import { Link as DumiLink, useLocation, useAppData, useNavigate } from 'dumi';
|
||||
|
||||
export interface LinkProps {
|
||||
to: string | { pathname?: string; search?: string; hash?: string };
|
||||
@ -9,64 +8,49 @@ export interface LinkProps {
|
||||
className?: string;
|
||||
onClick?: MouseEventHandler;
|
||||
component?: React.ComponentType<any>;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
nprogress.configure({ showSpinner: false });
|
||||
|
||||
const Link = forwardRef<HTMLAnchorElement, React.PropsWithChildren<LinkProps>>((props, ref) => {
|
||||
const { to, children, component, ...rest } = props;
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const navigate = useNavigate();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const href = React.useMemo<string>(() => {
|
||||
if (typeof to === 'object') {
|
||||
return `${to.pathname || pathname}${to.search || ''}${to.hash || ''}`;
|
||||
}
|
||||
return to;
|
||||
}, [to]);
|
||||
|
||||
const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {
|
||||
props.onClick?.(e);
|
||||
if (!href?.startsWith('http')) {
|
||||
// Should support open in new tab
|
||||
if (!e.metaKey && !e.ctrlKey && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
startTransition(() => {
|
||||
if (href) {
|
||||
navigate(href);
|
||||
}
|
||||
});
|
||||
const Link = forwardRef<HTMLAnchorElement, React.PropsWithChildren<LinkProps>>(
|
||||
({ component, children, to, ...rest }, ref) => {
|
||||
const { pathname } = useLocation();
|
||||
const { preloadRoute } = useAppData();
|
||||
const navigate = useNavigate();
|
||||
const href = useMemo<string>(() => {
|
||||
if (typeof to === 'object') {
|
||||
return `${to.pathname || pathname}${to.search || ''}${to.hash || ''}`;
|
||||
}
|
||||
return to;
|
||||
}, [to]);
|
||||
const onClick = (e: MouseEvent<HTMLAnchorElement>) => {
|
||||
rest.onClick?.(e);
|
||||
if (!href?.startsWith('http')) {
|
||||
// Should support open in new tab
|
||||
if (!e.metaKey && !e.ctrlKey && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
navigate(href);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (component) {
|
||||
return React.createElement(
|
||||
component,
|
||||
{
|
||||
...rest,
|
||||
ref,
|
||||
href,
|
||||
onClick,
|
||||
onMouseEnter: () => preloadRoute?.(href),
|
||||
},
|
||||
children,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (isPending) {
|
||||
nprogress.start();
|
||||
} else {
|
||||
nprogress.done();
|
||||
}
|
||||
}, [isPending]);
|
||||
|
||||
if (component) {
|
||||
return React.createElement(
|
||||
component,
|
||||
{
|
||||
...rest,
|
||||
ref,
|
||||
onClick: handleClick,
|
||||
href,
|
||||
},
|
||||
children,
|
||||
return (
|
||||
<DumiLink ref={ref} {...rest} to={href} prefetch>
|
||||
{children}
|
||||
</DumiLink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DumiLink ref={ref} onClick={handleClick} {...rest} to={href} prefetch>
|
||||
{children}
|
||||
</DumiLink>
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export default Link;
|
||||
|
@ -141,13 +141,23 @@ const PrevAndNext: React.FC<{ rtl?: boolean }> = ({ rtl }) => {
|
||||
return (
|
||||
<section className={styles.prevNextNav}>
|
||||
{prev &&
|
||||
React.cloneElement(prev.label as ReactElement, {
|
||||
className: classNames(styles.pageNav, styles.prevNav, prev.className),
|
||||
})}
|
||||
React.cloneElement(
|
||||
prev.label as ReactElement<{
|
||||
className: string;
|
||||
}>,
|
||||
{
|
||||
className: classNames(styles.pageNav, styles.prevNav, prev.className),
|
||||
},
|
||||
)}
|
||||
{next &&
|
||||
React.cloneElement(next.label as ReactElement, {
|
||||
className: classNames(styles.pageNav, styles.nextNav, next.className),
|
||||
})}
|
||||
React.cloneElement(
|
||||
next.label as ReactElement<{
|
||||
className: string;
|
||||
}>,
|
||||
{
|
||||
className: classNames(styles.pageNav, styles.nextNav, next.className),
|
||||
},
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
@ -282,12 +282,13 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-riddle {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
&-codeblock {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
&-codesandbox {
|
||||
@ -347,12 +348,12 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: ${token.marginXS}px;
|
||||
}
|
||||
|
||||
${antCls}-btn {
|
||||
opacity: 0.6;
|
||||
&.icon-enabled {
|
||||
background: ${token.colorFillSecondary};
|
||||
opacity: 1;
|
||||
${antCls}-btn {
|
||||
&.icon-enabled {
|
||||
background-color: ${token.colorFillSecondary};
|
||||
opacity: 1;
|
||||
${iconCls} {
|
||||
color: ${token.colorTextBase};
|
||||
font-weight: bold;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { FastColor } from '@ant-design/fast-color';
|
||||
import { css, Global } from '@emotion/react';
|
||||
import { useTheme } from 'antd-style';
|
||||
|
||||
@ -410,7 +410,7 @@ const GlobalStyle: React.FC = () => {
|
||||
background: ${demoGridColor};
|
||||
|
||||
&:nth-child(2n + 1) {
|
||||
background: ${new TinyColor(demoGridColor).setAlpha(0.75).toHex8String()};
|
||||
background: ${new FastColor(demoGridColor).setA(0.75).toHexString()};
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,12 +426,12 @@ const GlobalStyle: React.FC = () => {
|
||||
}
|
||||
|
||||
${antCls}-row .demo-col-1 {
|
||||
background: ${new TinyColor(demoGridColor).setAlpha(0.75).toHexString()};
|
||||
background: ${new FastColor(demoGridColor).setA(0.75).toHexString()};
|
||||
}
|
||||
|
||||
${antCls}-row .demo-col-2,
|
||||
.code-box-demo ${antCls}-row .demo-col-2 {
|
||||
background: ${new TinyColor(demoGridColor).setAlpha(0.75).toHexString()};
|
||||
background: ${new FastColor(demoGridColor).setA(0.75).toHexString()};
|
||||
}
|
||||
|
||||
${antCls}-row .demo-col-3,
|
||||
@ -442,7 +442,7 @@ const GlobalStyle: React.FC = () => {
|
||||
|
||||
${antCls}-row .demo-col-4,
|
||||
.code-box-demo ${antCls}-row .demo-col-4 {
|
||||
background: ${new TinyColor(demoGridColor).setAlpha(0.6).toHexString()};
|
||||
background: ${new FastColor(demoGridColor).setA(0.6).toHexString()};
|
||||
}
|
||||
|
||||
${antCls}-row .demo-col-5,
|
||||
|
@ -37,7 +37,7 @@ const DocLayout: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const { pathname, search, hash } = location;
|
||||
const [locale, lang] = useLocale(locales);
|
||||
const timerRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
const timerRef = useRef<ReturnType<typeof setTimeout>>(null!);
|
||||
const { direction } = useContext(SiteContext);
|
||||
const { loading } = useSiteData();
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { Suspense, useCallback, useEffect } from 'react';
|
||||
import { Monitoring } from 'react-scan/monitoring';
|
||||
import {
|
||||
createCache,
|
||||
extractStyle,
|
||||
@ -12,7 +13,13 @@ import { getSandpackCssText } from '@codesandbox/sandpack-react';
|
||||
import { theme as antdTheme, App } from 'antd';
|
||||
import type { MappingAlgorithm } from 'antd';
|
||||
import type { DirectionType, ThemeConfig } from 'antd/es/config-provider';
|
||||
import { createSearchParams, useOutlet, useSearchParams, useServerInsertedHTML } from 'dumi';
|
||||
import {
|
||||
createSearchParams,
|
||||
useOutlet,
|
||||
useParams,
|
||||
useSearchParams,
|
||||
useServerInsertedHTML,
|
||||
} from 'dumi';
|
||||
|
||||
import { DarkContext } from '../../hooks/useDark';
|
||||
import useLayoutState from '../../hooks/useLayoutState';
|
||||
@ -22,6 +29,8 @@ import SiteThemeProvider from '../SiteThemeProvider';
|
||||
import type { SiteContextProps } from '../slots/SiteContext';
|
||||
import SiteContext from '../slots/SiteContext';
|
||||
|
||||
import '@ant-design/v5-patch-for-react-19';
|
||||
|
||||
const ThemeSwitch = React.lazy(() => import('../common/ThemeSwitch'));
|
||||
|
||||
type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
|
||||
@ -61,6 +70,7 @@ const getAlgorithm = (themes: ThemeName[] = []) =>
|
||||
const GlobalLayout: React.FC = () => {
|
||||
const outlet = useOutlet();
|
||||
const { pathname } = useLocation();
|
||||
const params = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [{ theme = [], direction, isMobile, bannerVisible = false }, setSiteState] =
|
||||
useLayoutState<SiteState>({
|
||||
@ -70,6 +80,9 @@ const GlobalLayout: React.FC = () => {
|
||||
bannerVisible: false,
|
||||
});
|
||||
|
||||
// TODO: This can be remove in v6
|
||||
const useCssVar = searchParams.get('cssVar') !== 'false';
|
||||
|
||||
const updateSiteConfig = useCallback(
|
||||
(props: SiteState) => {
|
||||
setSiteState((prev) => ({ ...prev, ...props }));
|
||||
@ -150,8 +163,8 @@ const GlobalLayout: React.FC = () => {
|
||||
() => ({
|
||||
algorithm: getAlgorithm(theme),
|
||||
token: { motion: !theme.includes('motion-off') },
|
||||
cssVar: true,
|
||||
hashed: false,
|
||||
cssVar: useCssVar,
|
||||
hashed: !useCssVar,
|
||||
}),
|
||||
[theme],
|
||||
);
|
||||
@ -220,7 +233,17 @@ const GlobalLayout: React.FC = () => {
|
||||
>
|
||||
<SiteContext.Provider value={siteContextValue}>
|
||||
<SiteThemeProvider theme={themeConfig}>
|
||||
<HappyProvider disabled={!theme.includes('happy-work')}>{content}</HappyProvider>
|
||||
<HappyProvider disabled={!theme.includes('happy-work')}>
|
||||
{content}
|
||||
<Monitoring
|
||||
apiKey="GhrCCNrHZHXlf4P6E03ntrFwhRLxJL30" // Safe to expose publically
|
||||
url="https://monitoring.react-scan.com/api/v1/ingest"
|
||||
commit={process.env.COMMIT_HASH}
|
||||
branch={process.env.BRANCH}
|
||||
params={params as Record<string, string>}
|
||||
path={pathname}
|
||||
/>
|
||||
</HappyProvider>
|
||||
</SiteThemeProvider>
|
||||
</SiteContext.Provider>
|
||||
</StyleProvider>
|
||||
|
@ -35,7 +35,7 @@
|
||||
"app.demo.codepen": "Open in CodePen",
|
||||
"app.demo.codesandbox": "Open in CodeSandbox",
|
||||
"app.demo.stackblitz": "Open in Stackblitz",
|
||||
"app.demo.riddle": "Open in Riddle",
|
||||
"app.demo.codeblock": "Open in Hitu",
|
||||
"app.demo.separate": "Open in a new window",
|
||||
"app.demo.online": "Online Address",
|
||||
"app.home.introduce": "A design system for enterprise-level products. Create an efficient and enjoyable work experience.",
|
||||
|
@ -35,7 +35,7 @@
|
||||
"app.demo.codepen": "在 CodePen 中打开",
|
||||
"app.demo.codesandbox": "在 CodeSandbox 中打开",
|
||||
"app.demo.stackblitz": "在 Stackblitz 中打开",
|
||||
"app.demo.riddle": "在 Riddle 中打开",
|
||||
"app.demo.codeblock": "在海兔中打开",
|
||||
"app.demo.separate": "在新窗口打开",
|
||||
"app.demo.online": "线上地址",
|
||||
"app.home.introduce": "企业级产品设计体系,创造高效愉悦的工作体验",
|
||||
|
@ -2,7 +2,6 @@ import { createHash } from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import createEmotionServer from '@emotion/server/create-instance';
|
||||
import chalk from 'chalk';
|
||||
import type { IApi, IRoute } from 'dumi';
|
||||
import ReactTechStack from 'dumi/dist/techStacks/react';
|
||||
import sylvanas from 'sylvanas';
|
||||
@ -126,7 +125,8 @@ class AntdReactTechStack extends ReactTechStack {
|
||||
|
||||
const resolve = (p: string): string => require.resolve(p);
|
||||
|
||||
const RoutesPlugin = (api: IApi) => {
|
||||
const RoutesPlugin = async (api: IApi) => {
|
||||
const chalk = await import('chalk').then((m) => m.default);
|
||||
// const ssrCssFileName = `ssr-${Date.now()}.css`;
|
||||
|
||||
const writeCSSFile = (key: string, hashKey: string, cssString: string) => {
|
||||
|
@ -8,9 +8,6 @@ import SiteContext from '../SiteContext';
|
||||
import ContributorAvatar from './ContributorAvatar';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => ({
|
||||
contributorsList: css`
|
||||
margin-top: 120px !important;
|
||||
`,
|
||||
listMobile: css`
|
||||
margin: 1em 0 !important;
|
||||
`,
|
||||
@ -50,7 +47,7 @@ const Contributors: React.FC<ContributorsProps> = ({ filename }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.contributorsList, { [styles.listMobile]: isMobile })}>
|
||||
<div className={classNames({ [styles.listMobile]: isMobile })}>
|
||||
<div className={styles.title}>{formatMessage({ id: 'app.content.contributors' })}</div>
|
||||
<ContributorsList
|
||||
cache
|
||||
|
@ -94,9 +94,11 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||
juejinLink={meta.frontmatter.juejin_url}
|
||||
/>
|
||||
</InViewSuspense>
|
||||
<InViewSuspense fallback={<div style={{ height: 50, marginTop: 120 }} />}>
|
||||
<Contributors filename={meta.frontmatter.filename} />
|
||||
</InViewSuspense>
|
||||
<div style={{ marginTop: 120 }}>
|
||||
<InViewSuspense fallback={<div style={{ height: 50 }} />}>
|
||||
<Contributors filename={meta.frontmatter.filename} />
|
||||
</InViewSuspense>
|
||||
</div>
|
||||
</article>
|
||||
<InViewSuspense fallback={null}>
|
||||
<PrevAndNext rtl={isRTL} />
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
UsergroupAddOutlined,
|
||||
ZhihuOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { FastColor } from '@ant-design/fast-color';
|
||||
import { createStyles } from 'antd-style';
|
||||
import getAlphaColor from 'antd/es/theme/util/getAlphaColor';
|
||||
import { FormattedMessage, Link } from 'dumi';
|
||||
@ -37,7 +37,7 @@ const locales = {
|
||||
const useStyle = () => {
|
||||
const { isMobile } = useContext(SiteContext);
|
||||
return createStyles(({ token, css }) => {
|
||||
const background = new TinyColor(getAlphaColor('#f0f3fa', '#fff'))
|
||||
const background = new FastColor(getAlphaColor('#f0f3fa', '#fff'))
|
||||
.onBackground(token.colorBgContainer)
|
||||
.toHexString();
|
||||
|
||||
@ -101,6 +101,11 @@ const Footer: React.FC = () => {
|
||||
const col1 = {
|
||||
title: <FormattedMessage id="app.footer.resources" />,
|
||||
items: [
|
||||
{
|
||||
title: 'Ant Design X',
|
||||
url: isZhCN ? 'https://ant-design-x.antgroup.com' : 'https://x.ant.design',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'Ant Design Charts',
|
||||
url: isZhCN ? 'https://ant-design-charts.antgroup.com' : 'https://charts.ant.design',
|
||||
@ -112,7 +117,7 @@ const Footer: React.FC = () => {
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'Ant Design Pro Components',
|
||||
title: 'Pro Components',
|
||||
url: 'https://procomponents.ant.design',
|
||||
openExternal: true,
|
||||
},
|
||||
@ -126,6 +131,11 @@ const Footer: React.FC = () => {
|
||||
url: isZhCN ? 'https://ant-design-mini.antgroup.com/' : 'https://mini.ant.design',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'Ant Design Web3',
|
||||
url: isZhCN ? 'https://web3.antdigital.dev' : 'https://web3.ant.design',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'Ant Design Landing',
|
||||
description: <FormattedMessage id="app.footer.landing" />,
|
||||
@ -156,12 +166,6 @@ const Footer: React.FC = () => {
|
||||
url: 'https://qiankun.umijs.org',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'ahooks',
|
||||
description: <FormattedMessage id="app.footer.hooks" />,
|
||||
url: 'https://github.com/alibaba/hooks',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'Ant Motion',
|
||||
description: <FormattedMessage id="app.footer.motion" />,
|
||||
|
@ -357,7 +357,7 @@ const Header: React.FC = () => {
|
||||
<header className={headerClassName}>
|
||||
{isMobile && (
|
||||
<Popover
|
||||
overlayClassName={styles.popoverMenu}
|
||||
classNames={{ root: styles.popoverMenu }}
|
||||
placement="bottomRight"
|
||||
content={menu}
|
||||
trigger="click"
|
||||
|
@ -8,13 +8,14 @@ import useMenu from '../../../hooks/useMenu';
|
||||
import SiteContext from '../SiteContext';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => {
|
||||
const { antCls, fontFamily, colorSplit } = token;
|
||||
const { antCls, fontFamily, colorSplit, marginXXL, paddingXXS } = token;
|
||||
|
||||
return {
|
||||
asideContainer: css`
|
||||
min-height: 100%;
|
||||
padding-bottom: 48px;
|
||||
padding-bottom: ${marginXXL}px !important;
|
||||
font-family: Avenir, ${fontFamily}, sans-serif;
|
||||
padding: 0 ${paddingXXS}px;
|
||||
|
||||
&${antCls}-menu-inline {
|
||||
${antCls}-menu-submenu-title h4,
|
||||
@ -94,14 +95,10 @@ const useStyle = createStyles(({ token, css }) => {
|
||||
position: sticky;
|
||||
top: ${token.headerHeight + token.contentMarginTop}px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: calc(100vh - ${token.headerHeight + token.contentMarginTop}px);
|
||||
overflow: hidden;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-gutter: stable;
|
||||
.ant-menu {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
|
@ -9,7 +9,11 @@ import { version } from './package.json';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: ['dumi-plugin-color-chunk'],
|
||||
|
||||
// For <Link prefetch />
|
||||
routePrefetch: {},
|
||||
manifest: {},
|
||||
|
||||
conventionRoutes: {
|
||||
// to avoid generate routes for .dumi/pages/index/components/xx
|
||||
exclude: [/index\/components\//],
|
||||
|
86
.github/workflows/issue-inactivity-reminder.yml
vendored
Normal file
86
.github/workflows/issue-inactivity-reminder.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: Issue Inactivity Reminder
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # Run at 00:00 every day
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
reminder_job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send reminders for inactive issues
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const daysBeforeReminder = 14;
|
||||
let page = 1;
|
||||
const perPage = 100;
|
||||
|
||||
const reminderSignature = "This issue has been inactive for more than 14 days";
|
||||
|
||||
while (true) {
|
||||
const { data: issues } = await github.rest.issues.listForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
assignee: '*',
|
||||
per_page: perPage,
|
||||
page: page,
|
||||
});
|
||||
|
||||
if (issues.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
|
||||
for (const issue of issues) {
|
||||
if (issue.pull_request) continue;
|
||||
|
||||
const updatedAt = new Date(issue.updated_at);
|
||||
const daysInactive = (now - updatedAt) / (1000 * 60 * 60 * 24);
|
||||
|
||||
const { data: timeline } = await github.rest.issues.listEventsForTimeline({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
});
|
||||
|
||||
const hasLinkedPR = timeline.some(event =>
|
||||
event.event === 'connected' || // PR connected via keywords
|
||||
event.event === 'referenced' && event.commit_id // Connected via commit
|
||||
);
|
||||
|
||||
if (daysInactive >= daysBeforeReminder && !hasLinkedPR) {
|
||||
// get issue comments
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
});
|
||||
|
||||
// check if reminder has been sent
|
||||
const hasReminder = comments.some(comment =>
|
||||
comment.body.includes(reminderSignature)
|
||||
);
|
||||
|
||||
if (!hasReminder) {
|
||||
const assigneesMentions = issue.assignees
|
||||
.map(user => `@${user.login}`)
|
||||
.join(' ');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
body: `${assigneesMentions} 这个 issue 已经超过 14 天没有更新或关联 PR。如果您仍在处理这个 issue,请更新进度;如果您无法继续处理,请联系维护者重新分配。\n\nThis issue has been inactive for more than 14 days without any updates or linked PR. If you are still working on this issue, please provide a progress update. If you are unable to continue, please contact the maintainers for reassignment.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page += 1;
|
||||
}
|
2
.github/workflows/pr-check-merge.yml
vendored
2
.github/workflows/pr-check-merge.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
issues: write # for actions-cool/issues-helper to update issues
|
||||
pull-requests: write # for actions-cool/issues-helper to update PRs
|
||||
runs-on: ubuntu-latest
|
||||
if: (github.event.pull_request.head.ref == 'feature' || github.event.pull_request.head.ref == 'master') && github.event.pull_request.head.user.login == 'ant-design'
|
||||
if: (github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'feature' || github.event.pull_request.head.ref == 'master') && github.event.pull_request.head.user.login == 'ant-design'
|
||||
steps:
|
||||
- uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
|
4
.github/workflows/preview-deploy.yml
vendored
4
.github/workflows/preview-deploy.yml
vendored
@ -61,7 +61,7 @@ jobs:
|
||||
steps:
|
||||
# We need get PR id first
|
||||
- name: download pr artifact
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
@ -81,7 +81,7 @@ jobs:
|
||||
# Download site artifact
|
||||
- name: download site artifact
|
||||
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
|
69
.github/workflows/site-deploy.yml
vendored
69
.github/workflows/site-deploy.yml
vendored
@ -11,9 +11,14 @@ permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
build-site:
|
||||
runs-on: ubuntu-latest
|
||||
if: (startsWith(github.ref, 'refs/tags/') && (contains(github.ref_name, '-') == false)) || github.event_name == 'workflow_dispatch'
|
||||
|
||||
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#example-defining-outputs-for-a-job
|
||||
outputs:
|
||||
formatted_version: ${{ steps.shared-formatted_version.outputs.VERSION }}
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -33,15 +38,42 @@ jobs:
|
||||
ANALYZER: 1
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
|
||||
- name: Get version
|
||||
id: publish-version
|
||||
- name: move report.html to _site
|
||||
run: |
|
||||
if [ -f report.html ]; then
|
||||
mv report.html _site && echo "report.html moved to _site"
|
||||
fi
|
||||
|
||||
- name: upload site artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: real-site
|
||||
path: _site/
|
||||
retention-days: 1 # Not need to keep for too long
|
||||
|
||||
- name: Format version
|
||||
if: ${{ always() }}
|
||||
id: shared-formatted_version
|
||||
run: echo "VERSION=$(echo ${{ github.ref_name }} | sed 's/\./-/g')" >> $GITHUB_OUTPUT
|
||||
|
||||
deploy-to-pages:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-site
|
||||
steps:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./_site
|
||||
exclude_files: ./_site/report.html # 👈 这个功能是 beta, 但即便不排除,也不 care
|
||||
force_orphan: true
|
||||
|
||||
# Since force_orphan will not trigger Sync to Gitee, we need to force run it here
|
||||
@ -55,14 +87,37 @@ jobs:
|
||||
|
||||
- name: Deploy to Surge (with TAG)
|
||||
run: |
|
||||
export DEPLOY_DOMAIN=ant-design-${{ steps.publish-version.outputs.VERSION }}.surge.sh
|
||||
cp report.html ./_site
|
||||
export DEPLOY_DOMAIN=ant-design-${{ needs.build-site.outputs.formatted_version }}.surge.sh
|
||||
bunx surge --project ./_site --domain $DEPLOY_DOMAIN --token ${{ secrets.SURGE_TOKEN }}
|
||||
|
||||
- name: Create Commit Comment
|
||||
uses: peter-evans/commit-comment@v3
|
||||
with:
|
||||
body: |
|
||||
- Documentation site for this release: https://ant-design-${{ steps.publish-version.outputs.VERSION }}.surge.sh
|
||||
- Webpack bundle analyzer report page: https://ant-design-${{ steps.publish-version.outputs.VERSION }}.surge.sh/report.html
|
||||
- Documentation site for this release: https://ant-design-${{ needs.build-site.outputs.formatted_version }}.surge.sh
|
||||
- Webpack bundle analyzer report page: https://ant-design-${{ needs.build-site.outputs.formatted_version }}.surge.sh/report.html
|
||||
|
||||
# https://github.com/ant-design/ant-design/pull/49213/files#r1625446496
|
||||
upload-to-release:
|
||||
runs-on: ubuntu-latest
|
||||
# 仅在 tag 的时候工作,因为我们要将内容发布到以 tag 为版本号的 release 里
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: build-site
|
||||
steps:
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
|
||||
- name: Tarball site
|
||||
run: |
|
||||
cd ./_site
|
||||
tar -czf ../website.tar.gz --transform 's|^|antd-${{ needs.build-site.outputs.formatted_version }}-website/|' .
|
||||
cd ..
|
||||
|
||||
- name: Upload to Release
|
||||
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
files: website.tar.gz
|
||||
|
233
.github/workflows/test-v6.yml
vendored
Normal file
233
.github/workflows/test-v6.yml
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
# Origin Source
|
||||
# https://github.com/ant-design/ant-design/blob/79f566b7f8abb1012ef55b0d2793bfdf5595b85d/.github/workflows/test.yml
|
||||
name: ✅ test v6
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [next]
|
||||
pull_request:
|
||||
branches: [next]
|
||||
|
||||
# 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:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
- run: bun run lint
|
||||
|
||||
################################ Test ################################
|
||||
test-react-legacy:
|
||||
name: test-react-legacy
|
||||
strategy:
|
||||
matrix:
|
||||
react: ['18']
|
||||
shard: [1/2, 2/2]
|
||||
env:
|
||||
REACT: ${{ matrix.react }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
- name: install react 18
|
||||
if: ${{ matrix.react == '18' }}
|
||||
run: bun run bun-install-react-18
|
||||
# dom test
|
||||
- name: dom test
|
||||
run: bun run test -- --maxWorkers=2 --shard=${{matrix.shard}}
|
||||
|
||||
test-node:
|
||||
name: test-node
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
- run: bun run test:node
|
||||
|
||||
test-react-latest:
|
||||
name: test-react-latest
|
||||
strategy:
|
||||
matrix:
|
||||
module: [dom]
|
||||
shard: [1/2, 2/2]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
# dom test
|
||||
- name: dom test
|
||||
run: bun run test -- --maxWorkers=2 --shard=${{matrix.shard}} --coverage
|
||||
|
||||
- name: persist coverages
|
||||
run: |
|
||||
mkdir persist-coverage
|
||||
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
name: upload coverages
|
||||
with:
|
||||
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
|
||||
path: persist-coverage/
|
||||
|
||||
test-react-latest-dist:
|
||||
name: test-react-latest-dist
|
||||
strategy:
|
||||
matrix:
|
||||
module: [dist, dist-min]
|
||||
shard: [1/2, 2/2]
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
- name: restore cache from dist
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: dist
|
||||
key: dist-${{ github.sha }}
|
||||
|
||||
- name: dist-min test
|
||||
if: ${{ matrix.module == 'dist-min' }}
|
||||
run: bun run test
|
||||
env:
|
||||
LIB_DIR: dist-min
|
||||
|
||||
- name: dist test
|
||||
if: ${{ matrix.module == 'dist' }}
|
||||
run: bun run test
|
||||
env:
|
||||
LIB_DIR: dist
|
||||
|
||||
############################ Test Coverage ###########################
|
||||
upload-test-coverage:
|
||||
name: test-coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: test-react-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
merge-multiple: true
|
||||
path: persist-coverage
|
||||
- name: Merge Code Coverage
|
||||
run: |
|
||||
bunx nyc merge persist-coverage/ coverage/coverage-final.json
|
||||
bunx nyc report --reporter text -t coverage --report-dir coverage
|
||||
rm -rf persist-coverage
|
||||
- name: Upload coverage to codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
# use own token to upload coverage reports
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
########################### Compile & Test ###########################
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
- name: cache lib
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: lib
|
||||
key: lib-${{ github.sha }}
|
||||
|
||||
- name: cache es
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: es
|
||||
key: es-${{ github.sha }}
|
||||
|
||||
- name: compile
|
||||
run: bun run compile
|
||||
|
||||
- name: cache dist
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: dist
|
||||
key: dist-${{ github.sha }}
|
||||
|
||||
- name: dist
|
||||
run: bun run dist
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
CI: 1
|
||||
|
||||
- name: check build files
|
||||
run: bun run test:dekko
|
||||
|
||||
# Artifact build files
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
with:
|
||||
name: build artifacts
|
||||
path: |
|
||||
dist
|
||||
locale
|
||||
es
|
||||
lib
|
||||
|
||||
- name: zip builds
|
||||
if: github.repository == 'ant-design/ant-design' && github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
env:
|
||||
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
|
||||
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}
|
||||
HEAD_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
zip -r oss-artifacts.zip dist locale es lib
|
||||
echo "🤖 Uploading"
|
||||
node scripts/visual-regression/upload.js ./oss-artifacts.zip --ref=$HEAD_SHA
|
||||
|
||||
test-lib-es:
|
||||
name: test lib/es module
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
module: [lib, es]
|
||||
shard: [1/2, 2/2]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
- name: restore cache from ${{ matrix.module }}
|
||||
# lib only run in master branch not in pull request
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ matrix.module }}
|
||||
key: ${{ matrix.module }}-${{ github.sha }}
|
||||
|
||||
- name: compile
|
||||
# lib only run in master branch not in pull request
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
run: bun run compile
|
||||
|
||||
- name: test
|
||||
# lib only run in master branch not in pull request
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
run: bun run test -- --maxWorkers=2 --shard=${{matrix.shard}}
|
||||
env:
|
||||
LIB_DIR: ${{ matrix.module }}
|
11
.github/workflows/test.yml
vendored
11
.github/workflows/test.yml
vendored
@ -2,7 +2,11 @@
|
||||
# https://github.com/ant-design/ant-design/blob/79f566b7f8abb1012ef55b0d2793bfdf5595b85d/.github/workflows/test.yml
|
||||
name: ✅ test
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches: [master, feature]
|
||||
pull_request:
|
||||
branches: [master, feature]
|
||||
|
||||
# Cancel prev CI if new commit come
|
||||
concurrency:
|
||||
@ -133,7 +137,7 @@ jobs:
|
||||
bunx nyc report --reporter text -t coverage --report-dir coverage
|
||||
rm -rf persist-coverage
|
||||
- name: Upload coverage to codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
# use own token to upload coverage reports
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@ -171,10 +175,11 @@ jobs:
|
||||
run: bun run dist
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
CI: 1
|
||||
|
||||
- name: check build files
|
||||
run: node ./tests/dekko/index.test.js
|
||||
run: bun run test:dekko
|
||||
|
||||
# Artifact build files
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
@ -58,7 +58,13 @@ jobs:
|
||||
if (comment.body.includes('VISUAL_DIFF_FAILED')) {
|
||||
hasDiffFailed = true;
|
||||
}
|
||||
if (comment.body.includes('- [x] Visual diff is acceptable')) {
|
||||
|
||||
// https://regex101.com/r/kLjudz/1
|
||||
const RE = /(?<=\>\s\[!IMPORTANT\].*?- \[ \])/s;
|
||||
if (
|
||||
comment.body.includes('- [x] Visual diff is acceptable') &&
|
||||
comment.body.match(RE) == null /** 检查 IMPORTANT 是否存在未勾选的 */
|
||||
) {
|
||||
hasMemberApprove = true;
|
||||
}
|
||||
}
|
||||
@ -71,15 +77,26 @@ jobs:
|
||||
const mergedStatus = diffPassed ? 'success' : hasDiffFailed ? 'failure' : 'pending';
|
||||
console.log('Status:', mergedStatus);
|
||||
|
||||
await github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: prHeadSha,
|
||||
state: mergedStatus,
|
||||
context: 'Visual Regression Diff Wait Approve',
|
||||
description: diffPassed ? 'Visual diff is acceptable' : 'Visual diff is not pass',
|
||||
const { data: currentStatuses } = await github.rest.repos.listCommitStatusesForRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: prHeadSha,
|
||||
});
|
||||
|
||||
const currentStatus = currentStatuses.find(status => status.context === 'Visual Regression Diff Wait Approve');
|
||||
if (currentStatus && currentStatus.state === mergedStatus) {
|
||||
console.log('Status has not changed, no need to update:', currentStatus.state);
|
||||
} else {
|
||||
await github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: prHeadSha,
|
||||
state: mergedStatus,
|
||||
context: 'Visual Regression Diff Wait Approve',
|
||||
description: diffPassed ? 'Visual diff is acceptable' : 'Visual diff is not pass',
|
||||
});
|
||||
}
|
||||
|
||||
if (hasDiffSuccess || (hasDiffFailed && hasMemberApprove)) {
|
||||
return 'success';
|
||||
} else if (hasDiffFailed) {
|
||||
|
@ -4,7 +4,7 @@ name: 👀 Visual Regression Diff Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, feature]
|
||||
branches: [master, feature, next]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
# Cancel prev CI if new commit come
|
||||
|
@ -68,7 +68,7 @@ jobs:
|
||||
|
||||
# We need get persist-index first
|
||||
- name: download image snapshot artifact
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
@ -90,7 +90,7 @@ jobs:
|
||||
- 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@v6
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
|
@ -8,7 +8,7 @@ name: 👀 Visual Regression Diff Start
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
branches: [master, feature]
|
||||
branches: [master, feature, next]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
|
@ -65,7 +65,7 @@ jobs:
|
||||
|
||||
# We need get persist key first
|
||||
- name: Download Visual Regression Ref
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Download Visual-Regression Artifact
|
||||
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
@ -87,7 +87,7 @@ jobs:
|
||||
path: ./tmp
|
||||
|
||||
- name: Persist Image Snapshot to OSS
|
||||
if: github.repository == 'ant-design/ant-design' && github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature')
|
||||
if: github.repository == 'ant-design/ant-design' && github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature' || github.event.workflow_run.head_branch == 'next')
|
||||
env:
|
||||
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
|
||||
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}
|
||||
|
@ -7,6 +7,7 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- feature
|
||||
- next
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
2
.husky/pre-commit
Executable file → Normal file
2
.husky/pre-commit
Executable file → Normal file
@ -1 +1 @@
|
||||
lint-staged
|
||||
lint-staged
|
1
.jest.js
1
.jest.js
@ -5,6 +5,7 @@ const compileModules = [
|
||||
'@ant-design',
|
||||
'countup.js',
|
||||
'.pnpm',
|
||||
'@asamuzakjp/css-color',
|
||||
];
|
||||
|
||||
const ignoreList = [];
|
||||
|
@ -61,5 +61,19 @@
|
||||
"5.21.0": [
|
||||
"https://github.com/ant-design/ant-design/issues/50960",
|
||||
"https://github.com/ant-design/ant-design/issues/50969"
|
||||
]
|
||||
],
|
||||
"5.21.6": [
|
||||
"https://github.com/ant-design/ant-design/issues/51420",
|
||||
"https://github.com/ant-design/ant-design/issues/51430"
|
||||
],
|
||||
"5.22.0": [
|
||||
"https://github.com/ant-design/ant-design/issues/51601",
|
||||
"https://github.com/ant-design/ant-design/issues/51420",
|
||||
"https://github.com/ant-design/ant-design/issues/51430"
|
||||
],
|
||||
"5.22.1": [
|
||||
"https://github.com/ant-design/ant-design/issues/51420",
|
||||
"https://github.com/ant-design/ant-design/issues/51430"
|
||||
],
|
||||
"5.22.6": ["https://github.com/ant-design/ant-design/issues/52124"]
|
||||
}
|
||||
|
@ -15,6 +15,206 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.23.1
|
||||
|
||||
`2025-01-13`
|
||||
|
||||
- 🆕 Add Tree leaf node className for differentiate node type. [#52274](https://github.com/ant-design/ant-design/pull/52274) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 Fix DatePicker switch buttons is not hidden when `superPrevIcon/superNextIcon/prevIcon/nextIcon` is null. [#52327](https://github.com/ant-design/ant-design/pull/52327) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix Select throws `error not a valid selector` in Jest tests. [#51844](https://github.com/ant-design/ant-design/pull/51844) [@renovate](https://github.com/renovate)
|
||||
- 🐞 Fix Layout.Sider under ConfigProvider directly, the `theme` not working. [#52302](https://github.com/ant-design/ant-design/pull/52302) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Splitter lost previous state when re-expanding. [#52222](https://github.com/ant-design/ant-design/pull/52222) [@jjlstruggle](https://github.com/jjlstruggle)
|
||||
- 🐞 Fix Table unexpected row selections when set `checkStrictly` to false in tree mode. [#52338](https://github.com/ant-design/ant-design/pull/52338) [@LeeSSHH](https://github.com/LeeSSHH)
|
||||
- Button
|
||||
- 🐞 Fix Button alignment and icon centering by adjusting the icon size for icon-only Buttons. [#52353](https://github.com/ant-design/ant-design/pull/52353) [@afc163](https://github.com/afc163)
|
||||
- 💄 Fix Button missing `box-shadow` style. [#52304](https://github.com/ant-design/ant-design/pull/52304) [@zombieJ](https://github.com/zombieJ)
|
||||
- RTL
|
||||
- 💄 Fix Collapse arrow direction in RTL mode. [#52374](https://github.com/ant-design/ant-design/pull/52374) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 💄 Fix Layout.Sider arrow direction in RTL mode. [#52374](https://github.com/ant-design/ant-design/pull/52374) [@aojunhao123](https://github.com/aojunhao123)
|
||||
|
||||
## 5.23.0
|
||||
|
||||
`2025-01-06`
|
||||
|
||||
- 🔥 TreeSelect support `maxCount` to limit the maximum number of selections. [#51759](https://github.com/ant-design/ant-design/pull/51759) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🔥 Modal `width` support responsive size. [#51653](https://github.com/ant-design/ant-design/pull/51653) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🔥 Splitter support `lazy` mode. [#51557](https://github.com/ant-design/ant-design/pull/51557) [@OysterD3](https://github.com/OysterD3)
|
||||
- Button
|
||||
- 🔥 Button `color` support full color palette. [#51550](https://github.com/ant-design/ant-design/pull/51550) [@OysterD3](https://github.com/OysterD3)
|
||||
<img width="520" alt="Button Colors" src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*ApyYQpXQQfgAAAAAAAAAAAAADgCCAQ/original">
|
||||
- 🆕 Button support `loading={{ icon: ReactNode }}` to customize loading icon. [#51758](https://github.com/ant-design/ant-design/pull/51758) [@zhangchao-wooc](https://github.com/zhangchao-wooc)
|
||||
- Menu
|
||||
- 🐞 Fix Menu `extra` font size and vertical align issue. [#52217](https://github.com/ant-design/ant-design/pull/52217) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🆕 Menu add token `subMenuItemSelectedColor` to resolve submenu title color being overrided by `itemSelectedColor`. [#52182](https://github.com/ant-design/ant-design/pull/52182) [@afc163](https://github.com/afc163)
|
||||
- 🆕 Semantic Props
|
||||
- 🆕 ConfigProvider support Empty semantic props `classNames` and `styles`. [#52208](https://github.com/ant-design/ant-design/pull/52208) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider support Popconfirm semantic props `classNames` and `styles`. [#52126](https://github.com/ant-design/ant-design/pull/52126) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider support Popover semantic props `classNames` and `styles`. [#52110](https://github.com/ant-design/ant-design/pull/52110) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider support Tooltip semantic props `classNames` and `styles`. [#51872](https://github.com/ant-design/ant-design/pull/51872) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider support Descriptions semantic props `classNames` and `styles`. [#52120](https://github.com/ant-design/ant-design/pull/52120) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider support Slider semantic props `classNames` and `styles`. [#52185](https://github.com/ant-design/ant-design/pull/52185) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 Transfer support `showSearch` config `defaultValue` & `placeholder`. [#52125](https://github.com/ant-design/ant-design/pull/52125) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🆕 Calendar now supports `showWeek` prop. [#52072](https://github.com/ant-design/ant-design/pull/52072) [@afc163](https://github.com/afc163)
|
||||
- 🆕 Mentions support `onPopupScroll` props. [#51858](https://github.com/ant-design/ant-design/pull/51858) [@OysterD3](https://github.com/OysterD3)
|
||||
- 🆕 Card support `bodyPaddingSM`, `headerPaddingSM`, `bodyPadding`, `headerPadding` component token. [#51762](https://github.com/ant-design/ant-design/pull/51762) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ColorPicker `presets` support `key` prop. [#51794](https://github.com/ant-design/ant-design/pull/51794) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🆕 Cascader support `optionSelectedColor` token. [#51769](https://github.com/ant-design/ant-design/pull/51769) [@thinkasany](https://github.com/thinkasany)
|
||||
- Tree
|
||||
- 🛠 Refactor Tree part code to Function Component for React 19 perf preparing. [#52209](https://github.com/ant-design/ant-design/pull/52209) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 💄 Optimize Tree `disabled` & `selected` node display style. [#52173](https://github.com/ant-design/ant-design/pull/52173) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 Fix Slider crash when `tipFormatter` is undefined. [#52184](https://github.com/ant-design/ant-design/pull/52184) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🐞 Fix Layout.Sider `trigger` style not correct. [#46a8eff](https://github.com/ant-design/ant-design/commit/46a8eff) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- Table
|
||||
- 🐞 Fix Table `fixed:right` is not working in `expandable`. [#52176](https://github.com/ant-design/ant-design/pull/52176) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix Table sticky scrollbar not working in rtl direction. [#52176](https://github.com/ant-design/ant-design/pull/52176) [@afc163](https://github.com/afc163)
|
||||
- 💄 Optimize Flex to always reset `margin` & `padding` for customize component. [#52170](https://github.com/ant-design/ant-design/pull/52170) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fix DatePicker.RangePicker `needConfirm` sometime can switch panel without confirm. [#52102](https://github.com/ant-design/ant-design/pull/52102) [@Zyf665](https://github.com/Zyf665)
|
||||
- 💄 Optimize Collapse focus styles and items border radius. [#52086](https://github.com/ant-design/ant-design/pull/52086) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ Add Radio.Group default `name` prop to improve a11y. [#52076](https://github.com/ant-design/ant-design/pull/52076) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ Input.Search add `type=search` by default. [#52083](https://github.com/ant-design/ant-design/pull/52083) [@Kaikiat1126](https://github.com/Kaikiat1126)
|
||||
- ⌨️ Improve Tabs focus style for keyboard operation. [#52002](https://github.com/ant-design/ant-design/pull/52002) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- Segmented
|
||||
- ⌨️ Optimize Segmented focus style to improve a11y. [#51934](https://github.com/ant-design/ant-design/pull/51934) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ Segmented support `name` prop to improve a11y. [#51725](https://github.com/ant-design/ant-design/pull/51725) [@thinkasany](https://github.com/thinkasany)
|
||||
- 📦 MISC: Reduce bundle size by replacing `@ctrl/tinycolor` with `@ant-design/fast-color`. [#52190](https://github.com/ant-design/ant-design/pull/52190) [#52157](https://github.com/ant-design/ant-design/pull/52157) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ Adjust Input, InputNumber, Mentions, Textarea clear icon from `span` to `button` to improve a11y. [#52180](https://github.com/ant-design/ant-design/pull/52180) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 MISC: Fix build error when using React 19. [#52168](https://github.com/ant-design/ant-design/pull/52168) [@zombieJ](https://github.com/zombieJ)
|
||||
- TypeScript
|
||||
- 🤖 Adjust Table `ref` type to React.Ref. [#52205](https://github.com/ant-design/ant-design/pull/52205) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🤖 Calendar export CalendarMode type. [#52160](https://github.com/ant-design/ant-design/pull/52160) [@Kaikiat1126](https://github.com/Kaikiat1126)
|
||||
|
||||
## 5.22.7
|
||||
|
||||
`2024-12-27`
|
||||
|
||||
- 🐞 Fix Button text and icon not align. [#52132](https://github.com/ant-design/ant-design/pull/52132) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix Button throws `reactRender is not a function` under React 19. [#52105](https://github.com/ant-design/ant-design/pull/52105) [@afc163](https://github.com/afc163)
|
||||
- TypeScript
|
||||
- 🤖 Fix Menu interface type error from external module. [#51715](https://github.com/ant-design/ant-design/pull/51715) [@msyavuz](https://github.com/msyavuz)
|
||||
|
||||
## 5.22.6
|
||||
|
||||
`2024-12-23`
|
||||
|
||||
- 🐞 Align Button with and without icons consistently. [#52070](https://github.com/ant-design/ant-design/pull/52070)
|
||||
- 🐞 Fix Splitter collapsible icon `z-index` too low. [#52065](https://github.com/ant-design/ant-design/pull/52065) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 Fix Button motion not smooth when set `loading`. [#52059](https://github.com/ant-design/ant-design/pull/52059) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Button issue where solid default button text disappears on hover in dark mode. [#52024](https://github.com/ant-design/ant-design/pull/52024) [@DDDDD12138](https://github.com/DDDDD12138)
|
||||
|
||||
## 5.22.5
|
||||
|
||||
`2024-12-15`
|
||||
|
||||
- 🛠 Refactor Wave/Menu/Form `ref` check logic to resolve React 19 `ref` conflict (Note, this is not finally support React 19 but we will resolve step by step in future version). [#51952](https://github.com/ant-design/ant-design/pull/51952) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Dropdown cannot accept ReactNode as `children`. [#50174](https://github.com/ant-design/ant-design/pull/50174) [@coding-ice](https://github.com/coding-ice)
|
||||
- 🐞 Fix Carousel cannot display correctly in Modal without icon. [#51988](https://github.com/ant-design/ant-design/pull/51988) [@quan060798](https://github.com/quan060798)
|
||||
- 🐞 Fix Select label overflow issue. [#52011](https://github.com/ant-design/ant-design/pull/52011) [@OysterD3](https://github.com/OysterD3)
|
||||
- 🐞 Fix Form `setFieldValue` not reset field validation. [#51993](https://github.com/ant-design/ant-design/pull/51993) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Pagination with setting `showSizeChanger.showSearch` not working. [#51962](https://github.com/ant-design/ant-design/pull/51962) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🇰🇷 Improve Korean locales for DatePicker. [#51983](https://github.com/ant-design/ant-design/pull/51983) [@DevLeti](https://github.com/DevLeti)
|
||||
- 🤖 Export `CheckboxChangeEvent` from antd. [#52008](https://github.com/ant-design/ant-design/pull/52008) [@SpecLad](https://github.com/SpecLad)
|
||||
|
||||
## 5.22.4
|
||||
|
||||
`2024-12-09`
|
||||
|
||||
- Transfer
|
||||
- 🐞 Fix the background overflow when Transfer selects the last item on the current page. [#51884](https://github.com/ant-design/ant-design/pull/51884) [@ayangweb](https://github.com/ayangweb)
|
||||
- 🐞 Fix Transfer toggle button being enabled when all items are disabled. [#51784](https://github.com/ant-design/ant-design/pull/51784) [@WwwHhhYran](https://github.com/WwwHhhYran)
|
||||
- 🐞 Fix the arrow would be outside the container when the Tooltip content was too small. [#51904](https://github.com/ant-design/ant-design/pull/51904)
|
||||
- 🐞 Fix where clicking the Radio or Checkbox under Upload would trigger the popup window twice. [#51874](https://github.com/ant-design/ant-design/pull/51874)
|
||||
- 💄 Fix Menu icon alignment when using `collapsedIconSize`. [#51863](https://github.com/ant-design/ant-design/pull/51863) [@Gnomeek](https://github.com/Gnomeek)
|
||||
- 💄 Fix incorrect styling of Tabs component when `type="editable-card"`. [#51935](https://github.com/ant-design/ant-design/pull/51935) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 💄 Fix insufficient trigger style priority in Layout.Sider component in `zero-width` mode. [#51936](https://github.com/ant-design/ant-design/pull/51936) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 💄 MISC: Fix the icon styles were created repeatedly. [#51897](https://github.com/ant-design/ant-design/pull/51897) [@YumoImer](https://github.com/YumoImer)
|
||||
- 💄 MISC: Inline styles refactored to cssinjs. [#51843](https://github.com/ant-design/ant-design/pull/51843)
|
||||
|
||||
## 5.22.3
|
||||
|
||||
`2024-12-02`
|
||||
|
||||
- 🐞 Fix Select clear button may has incorrect position within Form.item. [#51649](https://github.com/ant-design/ant-design/pull/51649) [@dislido](https://github.com/dislido)
|
||||
- 🐞 Fix InputNumber `handleVisible` token not work as expected. [#51728](https://github.com/ant-design/ant-design/pull/51728) [@dengfuping](https://github.com/dengfuping)
|
||||
- 🐞 Fix ColorPicker error when pass `ReactNode` to `label` field of `presets` property. [#51808](https://github.com/ant-design/ant-design/pull/51808) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fix Menu `inlineCollapsed` property not works bug within Layout. [#51775](https://github.com/ant-design/ant-design/pull/51775) [@coderz-w](https://github.com/coderz-w)
|
||||
- 🐞 Fix Table `onHeaderCell` provided part `style` can not override. [#51793](https://github.com/ant-design/ant-design/pull/51793) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- ⌨️ Improve Collapse accessibility. [#51836](https://github.com/ant-design/ant-design/pull/51836) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- TypeScript
|
||||
- 🤖 Add Table argument type for `clearFilters` function property. [#51754](https://github.com/ant-design/ant-design/pull/51754) [@fubd](https://github.com/fubd)
|
||||
- 🤖 Fix Form.List with nest field will miss value with remove when set Form `preserve` to `false`. [#51796](https://github.com/ant-design/ant-design/pull/51796) [@zombieJ](https://github.com/zombieJ)
|
||||
|
||||
## 5.22.2
|
||||
|
||||
`2024-11-21`
|
||||
|
||||
- 🐞 Fix Input.OTP focus from advancing when previous input is empty. [#51664](https://github.com/ant-design/ant-design/pull/51664) [@thecodesalim](https://github.com/thecodesalim)
|
||||
- 🐞 Adjust Modal function call not to scroll the confirm button when it get auto focused. [#51647](https://github.com/ant-design/ant-design/pull/51647) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Form `rules` with same error content will cause React render warning. [#51636](https://github.com/ant-design/ant-design/pull/51636) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Refactor Button `focus` logic trigger with `useEffect` to resolve some async load case not get `autoFocus`. [#51624](https://github.com/ant-design/ant-design/pull/51624) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Button custom icon not center-aligned. [#51652](https://github.com/ant-design/ant-design/pull/51652) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix Table `getCheckboxProps` event handlers being overridden by internal selection logic. [#51661](https://github.com/ant-design/ant-design/pull/51661) [@Zyf665](https://github.com/Zyf665)
|
||||
- 🐞 Fix Tree that `onCheck` and `onSelect` were not properly triggered. [#51448](https://github.com/ant-design/ant-design/pull/51448) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🐞 Fix vertical alignment of clear icon in Input component. [#51700](https://github.com/ant-design/ant-design/pull/51700) [@jynxio](https://github.com/jynxio)
|
||||
- 🐞 Fix Select with `prefix` style issue with color, line break, status error. [#51694](https://github.com/ant-design/ant-design/pull/51694) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🌐 Localization
|
||||
- 🇷🇺 Add support for Russian translation. [#51619](https://github.com/ant-design/ant-design/pull/51619) [@avvakumovid](https://github.com/avvakumovid)
|
||||
- 🇮🇹 Add support for Italian translation in TimePicker. [#51685](https://github.com/ant-design/ant-design/pull/51685) [@LorenzoCardinali](https://github.com/LorenzoCardinali)
|
||||
|
||||
## 5.22.1
|
||||
|
||||
`2024-11-13`
|
||||
|
||||
- 🛠 Adjust DatePicker.RangePicker to not allow switching to the next field by clicking the input when `needConfirm` and the user has not submitted the date. [#51591](https://github.com/ant-design/ant-design/pull/51591) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🛠 Lock Input.OTP `ctrl + z` operation to avoid data not correct. [#51609](https://github.com/ant-design/ant-design/pull/51609) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Select `tags` or `multiple` mode display issue. [#51605](https://github.com/ant-design/ant-design/pull/51605) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 Fix Badge `count` motion missing in Safari. [#51598](https://github.com/ant-design/ant-design/pull/51598) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Tabs with `centered` the tabs can not fully display. [#51571](https://github.com/ant-design/ant-design/pull/51571) [@DDDDD12138](https://github.com/DDDDD12138)
|
||||
- 🐞 Fix Transfer with controlled `dataSource` & `selectedKeys` sometime miss sync checked state. [#51523](https://github.com/ant-design/ant-design/pull/51523) [@IsKaros](https://github.com/IsKaros)
|
||||
- 🐞 Revert Button `display` `inline-flex` back to `inline-block` to resolve Icon align issue. [#51588](https://github.com/ant-design/ant-design/pull/51588) [@Wxh16144](https://github.com/Wxh16144)
|
||||
|
||||
## 5.22.0
|
||||
|
||||
`2024-11-12`
|
||||
|
||||
- Form
|
||||
- 🆕 Form.Item supports hiding labels. [#51524](https://github.com/ant-design/ant-design/pull/51524) [@crazyair](https://github.com/crazyair)
|
||||
- 🐞 Form removes the div used to expand the error height, wraps errorDom and extraDom with a div, and sets a minimum height for the div. [#51254](https://github.com/ant-design/ant-design/pull/51254) [@hongzzz](https://github.com/hongzzz)
|
||||
- 🐞 Fix the problem that `onValuesChange` is still triggered when the Form field triggers change but the value does not change. [#51437](https://github.com/ant-design/ant-design/pull/51437) [@crazyair](https://github.com/crazyair)
|
||||
- 🆕 Form supports the focus property in scrollToFirstError when form validation fails. [#51231](https://github.com/ant-design/ant-design/pull/51231) [@nathanlao](https://github.com/nathanlao)
|
||||
- Table
|
||||
- 🆕 Table column filter drop-down box supports `filterDropdownProps`. [#51297](https://github.com/ant-design/ant-design/pull/51297) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🆕 Table `expandedRowClassName` supports string . [#51067](https://github.com/ant-design/ant-design/pull/51067) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- Tree
|
||||
- 💄 Fix the problem of missing padding style for selected nodes in Tree. [#51492](https://github.com/ant-design/ant-design/pull/51492) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🆕 Tree component Token adds `nodeHoverColor` and `nodeSelectedColor` support. [#51367](https://github.com/ant-design/ant-design/pull/51367) [@zmbxy](https://github.com/zmbxy)
|
||||
- 🆕 Tree adds `indentSize` token for custom indent width. [#51010](https://github.com/ant-design/ant-design/pull/51010) [@afc163](https://github.com/afc163)
|
||||
- DatePicker
|
||||
- 🆕 DatePicker supports prefix attribute. [#51335](https://github.com/ant-design/ant-design/pull/51335) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 💄 Fixed the issue of DatePicker.RangePicker flashing when the mouse moves between cells. [#51533](https://github.com/ant-design/ant-design/pull/51533) [@afc163](https://github.com/afc163)
|
||||
- Input.OTP
|
||||
- 🆕 In the `Input.OTP` component, add `onInput` event to get the value of each user input. At the same time, the relevant documentation has been updated. [#51289](https://github.com/ant-design/ant-design/pull/51289) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🐞 Fixed the problem that Input.OTP cannot specify `inputMode`. [#51271](https://github.com/ant-design/ant-design/pull/51271) [@alan-rudzinski](https://github.com/alan-rudzinski)
|
||||
- 🆕 ColorPicker supports `disabledFormat`. [#51539](https://github.com/ant-design/ant-design/pull/51539) [@su-muzhi](https://github.com/su-muzhi)
|
||||
- 🆕 Add `cursor` configuration item to the `focus` method of InputNumber component to control the cursor position. [#51444](https://github.com/ant-design/ant-design/pull/51444) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🆕 Cascader adds `disabled` attribute to disable all first-level directory items of the component. [#51272](https://github.com/ant-design/ant-design/pull/51272) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🆕 Descriptions supports single-line spreading. [#51365](https://github.com/ant-design/ant-design/pull/51365) [@crazyair](https://github.com/crazyair)
|
||||
- 🆕 Select/TreeSelect/Cascader components add `prefix` property to support custom prefix. [#51186](https://github.com/ant-design/ant-design/pull/51186) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 Fix the problem that the preview image class name is lost when setting `ImageProps.preview.rootClassName` in Image. [#51538](https://github.com/ant-design/ant-design/pull/51538) [@dislido](https://github.com/dislido)
|
||||
- 🐞 Fixed the issue that the last item in the TimePicker panel column cannot be scrolled to the top. [#51481](https://github.com/ant-design/ant-design/pull/51481) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix TreeSelect dropdown height not enough. [#51567](https://github.com/ant-design/ant-design/pull/51567) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fixed the issue that Typography is not updated immediately when the ConfigProvider language is switched. [#51453](https://github.com/ant-design/ant-design/pull/51453) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🐞 Fixed the issue that Upload `itemRender` calling `action.preview` will cause a crash. [#51419](https://github.com/ant-design/ant-design/pull/51419) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 Fixed Splitter pseudo-element symbol issue. [#51536](https://github.com/ant-design/ant-design/pull/51536) [@dislido](https://github.com/dislido)
|
||||
- 💄 Optimize Collapse accessibility attribute and mouse hover style. [#51400](https://github.com/ant-design/ant-design/pull/51400) [@afc163](https://github.com/afc163)
|
||||
- 💄 Fix styling issue of Menu title content. [#51425](https://github.com/ant-design/ant-design/pull/51425) [@coding-ice](https://github.com/coding-ice)
|
||||
- 🇵🇹 Fix translation in Portuguese (pt_PT) localization file for better accuracy and consistency. [#51501](https://github.com/ant-design/ant-design/pull/51501) [@alexandre-p-marques-alb](https://github.com/alexandre-p-marques-alb)
|
||||
- 🇺🇿 Optimize uz_UZ internationalization. [#51407](https://github.com/ant-design/ant-design/pull/51407) [@Zukhrik](https://github.com/Zukhrik)
|
||||
- TypeScript
|
||||
- 🤖 Upload exports type DraggerProps. [#51546](https://github.com/ant-design/ant-design/pull/51546) [@DBvc](https://github.com/DBvc)
|
||||
- 🤖 Add defaultValue property to TimePicker.RangePicker example. [#51413](https://github.com/ant-design/ant-design/pull/51413) [@nathanlao](https://github.com/nathanlao)
|
||||
- 🤖 Message Optimize the top type in message.config. [#51468](https://github.com/ant-design/ant-design/pull/51468) [@Fog3211](https://github.com/Fog3211)
|
||||
- 🤖 Optimize the TS definition of Tree and TreeSelect. [#51251](https://github.com/ant-design/ant-design/pull/51251) [@afc163](https://github.com/afc163)
|
||||
|
||||
## 5.21.6
|
||||
|
||||
`2024-10-28`
|
||||
@ -1902,7 +2102,7 @@ tag: vVERSION
|
||||
- 💄 Adjust Select, TreeSelect, Cascader always show the `arrow` by default when multiple. [#41028](https://github.com/ant-design/ant-design/pull/41028)
|
||||
- 🐞 Fix Form `Form.Item.useStatus` problem with sever-side-rendering. [#40977](https://github.com/ant-design/ant-design/pull/40977) [@AndyBoat](https://github.com/AndyBoat)
|
||||
- 🐞 MISC: Fix arrow shape in some components. [#40971](https://github.com/ant-design/ant-design/pull/40971)
|
||||
- 🐞 Fix Layout throw `React does not recognize the `suffixCls` prop on a DOM element` warning. [#40969](https://github.com/ant-design/ant-design/pull/40969)
|
||||
- 🐞 Fix Layout throw "React does not recognize the `suffixCls` prop on a DOM element" warning. [#40969](https://github.com/ant-design/ant-design/pull/40969)
|
||||
- 🐞 Fix Watermark that text will be displayed when the picture loads abnormally. [#40770](https://github.com/ant-design/ant-design/pull/40770) [@OriginRing](https://github.com/OriginRing)
|
||||
- 🐞 Image support flip function in preview mode. Fix Image `fallback` when used in ssr. [#40660](https://github.com/ant-design/ant-design/pull/40660)
|
||||
- 🐞 Fix Typography component is not centered in the Select component. [#40422](https://github.com/ant-design/ant-design/pull/40422) [@Yuiai01](https://github.com/Yuiai01)
|
||||
|
@ -15,6 +15,206 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.23.1
|
||||
|
||||
`2025-01-13`
|
||||
|
||||
- 🆕 新增 Tree 组件叶子节点的 className 用于区分节点类型。[#52274](https://github.com/ant-design/ant-design/pull/52274) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 修复 DatePicker `superPrevIcon/superNextIcon/prevIcon/nextIcon` 设置为 null 时切换按钮依旧存在的问题。[#52327](https://github.com/ant-design/ant-design/pull/52327) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Select 组件在 jest 测试中报错 `not a valid selector` 的问题。[#51844](https://github.com/ant-design/ant-design/pull/51844) [@renovate](https://github.com/renovate)
|
||||
- 🐞 修复 Layout.Sider 直接嵌套在 ConfigProvider 下时,`theme` 配置无效的问题。[#52302](https://github.com/ant-design/ant-design/pull/52302) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Splitter 二次展开时丢失上一次状态的问题。[#52222](https://github.com/ant-design/ant-design/pull/52222) [@jjlstruggle](https://github.com/jjlstruggle)
|
||||
- 🐞 修复 Table 树形展示且设置 `checkStrictly` 为 false 时,某些行被错误选中的问题。[#52338](https://github.com/ant-design/ant-design/pull/52338) [@LeeSSHH](https://github.com/LeeSSHH)
|
||||
- Button
|
||||
- 🐞 调整 Button 纯图标的大小从而修复按钮对齐和图标居中问题。[#52353](https://github.com/ant-design/ant-design/pull/52353) [@afc163](https://github.com/afc163)
|
||||
- 💄 修复 Button 丢失阴影样式的问题。[#52304](https://github.com/ant-design/ant-design/pull/52304) [@zombieJ](https://github.com/zombieJ)
|
||||
- RTL
|
||||
- 💄 修复 Collapse 在 RTL 模式下的箭头方向。[#52374](https://github.com/ant-design/ant-design/pull/52374) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 💄 修复 Layout.Sider 在 RTL 模式下的箭头方向。[#52374](https://github.com/ant-design/ant-design/pull/52374) [@aojunhao123](https://github.com/aojunhao123)
|
||||
|
||||
## 5.23.0
|
||||
|
||||
`2025-01-06`
|
||||
|
||||
- 🔥 TreeSelect 新增 `maxCount` 属性以限制最大选择数量。[#51759](https://github.com/ant-design/ant-design/pull/51759) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🔥 Modal `width` 支持响应式尺寸。[#51653](https://github.com/ant-design/ant-design/pull/51653) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🔥 Splitter 增加 `lazy` 模式。[#51557](https://github.com/ant-design/ant-design/pull/51557) [@OysterD3](https://github.com/OysterD3)
|
||||
- Button
|
||||
- 🔥 Button `color` 属性支持完整色板。[#51550](https://github.com/ant-design/ant-design/pull/51550) [@OysterD3](https://github.com/OysterD3)
|
||||
<img width="520" alt="Button Colors" src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*ApyYQpXQQfgAAAAAAAAAAAAADgCCAQ/original">
|
||||
- 🆕 Button 组件新增 `loading={{ icon: ReactNode }}` 以自定义加载图标。[#51758](https://github.com/ant-design/ant-design/pull/51758) [@zhangchao-wooc](https://github.com/zhangchao-wooc)
|
||||
- Menu
|
||||
- 🆕 Menu 新增 token `subMenuItemSelectedColor`,避免 `itemSelectedColor` 覆盖子菜单标题样式。[#52182](https://github.com/ant-design/ant-design/pull/52182) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Menu `extra` 字体大小和垂直居中对齐问题。[#52217](https://github.com/ant-design/ant-design/pull/52217) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🆕 语义化
|
||||
- 🆕 ConfigProvider 支持 Empty 组件语义化 `classNames` 和 `styles`。[#52208](https://github.com/ant-design/ant-design/pull/52208) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider 支持 Slider 组件语义化 `classNames` 和 `styles`。[#52185](https://github.com/ant-design/ant-design/pull/52185) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider 支持 Popconfirm 组件语义化 `classNames` 和 `styles`。[#52126](https://github.com/ant-design/ant-design/pull/52126) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider 支持 Popover 组件语义化 `classNames` 和 `styles`。[#52110](https://github.com/ant-design/ant-design/pull/52110) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider 支持 Tooltip 组件语义化 `classNames` 和 `styles`。[#51872](https://github.com/ant-design/ant-design/pull/51872) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ConfigProvider 支持 Descriptions 组件语义化 `classNames` 和 `styles`。[#52120](https://github.com/ant-design/ant-design/pull/52120) [@thinkasany](https://github.com/thinkasany)
|
||||
- Tree
|
||||
- 🛠 重构 Tree 部分代码为 Function Component 以为 React 19 做更好性能准备。[#52209](https://github.com/ant-design/ant-design/pull/52209) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 💄 优化 Tree `disabled` 与 `selected` 节点状态下的颜色展示。[#52173](https://github.com/ant-design/ant-design/pull/52173) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🆕 Transfer 支持 `showSearch` 配置 `defaultValue` 和 `placeholder`。[#52125](https://github.com/ant-design/ant-design/pull/52125) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🆕 Calendar 支持 `showWeek` 属性用于显示周数列。[#52072](https://github.com/ant-design/ant-design/pull/52072) [@afc163](https://github.com/afc163)
|
||||
- 🆕 Mentions 新增 `onPopupScroll` 属性。[#51858](https://github.com/ant-design/ant-design/pull/51858) [@OysterD3](https://github.com/OysterD3)
|
||||
- 🆕 Card 增加 `bodyPaddingSM`、`headerPaddingSM`、`bodyPadding`、`headerPadding` 组件 token。[#51762](https://github.com/ant-design/ant-design/pull/51762) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🆕 ColorPicker `presets` 支持传入 `key`。[#51794](https://github.com/ant-design/ant-design/pull/51794) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🆕 Cascader 新增 `optionSelectedColor` token。[#51769](https://github.com/ant-design/ant-design/pull/51769) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🐞 修复 Layout.Sider `trigger` 样式不正确的问题。[#46a8eff](https://github.com/ant-design/ant-design/commit/46a8eff) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- Table
|
||||
- 🐞 修复 Table `expandable` 中设置 `fixed:right` 不生效的问题。[#52176](https://github.com/ant-design/ant-design/pull/52176) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Table `sticky` 模式下水平固定滚动条在 rtl 模式下不生效的问题。[#52176](https://github.com/ant-design/ant-design/pull/52176) [@afc163](https://github.com/afc163)
|
||||
- 💄 优化 Flex 使其在自定义渲染组件时总是重置 `margin`、`padding` 样式。[#52170](https://github.com/ant-design/ant-design/pull/52170) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 DatePicker.RangePicker `needConfirm` 模式偶尔在不确认仍然可以切换面板的问题。[#52102](https://github.com/ant-design/ant-design/pull/52102) [@Zyf665](https://github.com/Zyf665)
|
||||
- 🐞 修复 Slider 当 `tipFormatter` 未定义时导致崩溃的问题。[#52184](https://github.com/ant-design/ant-design/pull/52184) [@thinkasany](https://github.com/thinkasany)
|
||||
- 💄 优化 Collapse 聚焦样式以及折叠项圆角。[#52086](https://github.com/ant-design/ant-design/pull/52086) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ 为 Radio.Group 添加默认 `name` 属性以提升无障碍体验。[#52076](https://github.com/ant-design/ant-design/pull/52076) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ Input.Search 添加默认 `type=search` 类型。[#52083](https://github.com/ant-design/ant-design/pull/52083) [@Kaikiat1126](https://github.com/Kaikiat1126)
|
||||
- ⌨️ 优化 Tabs 键盘操作时的焦点样式。[#52002](https://github.com/ant-design/ant-design/pull/52002) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- Segmented
|
||||
- ⌨️ 优化 Segmented 聚焦样式以提升无障碍体验。[#51934](https://github.com/ant-design/ant-design/pull/51934) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ Segmented 支持 `name` 属性以提升无障碍体验。[#51725](https://github.com/ant-design/ant-design/pull/51725) [@thinkasany](https://github.com/thinkasany)
|
||||
- 📦 MISC: 用 `@ant-design/fast-color` 替换 `@ctrl/tinycolor` 以降低打包体积。[#52190](https://github.com/ant-design/ant-design/pull/52190) [#52157](https://github.com/ant-design/ant-design/pull/52157) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- ⌨️ 调整 Input、InputNumber、Mentions、Textarea 组件清除图标从 `span` 元素更改为 `button` 元素,提高了可访问性和交互性。[#52180](https://github.com/ant-design/ant-design/pull/52180) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 MISC: 修复 React 19 下构建报错的问题。[#52168](https://github.com/ant-design/ant-design/pull/52168) [@zombieJ](https://github.com/zombieJ)
|
||||
- TypeScript
|
||||
- 🤖 调整 Table `ref` 类型为 React.Ref。[#52205](https://github.com/ant-design/ant-design/pull/52205) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🤖 Calendar 导出 CalendarMode 类型。[#52160](https://github.com/ant-design/ant-design/pull/52160) [@Kaikiat1126](https://github.com/Kaikiat1126)
|
||||
|
||||
## 5.22.7
|
||||
|
||||
`2024-12-27`
|
||||
|
||||
- 🐞 修复 Button 文字和图标不对齐的问题。[#52132](https://github.com/ant-design/ant-design/pull/52132) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复在 React 19 下点击 Button 时抛出 `reactRender is not a function` 错误的问题。[#52105](https://github.com/ant-design/ant-design/pull/52105) [@afc163](https://github.com/afc163)
|
||||
- TypeScript
|
||||
- 🤖 修复 Menu `component` 属性类型抛错。[#51715](https://github.com/ant-design/ant-design/pull/51715) [@msyavuz](https://github.com/msyavuz)
|
||||
|
||||
## 5.22.6
|
||||
|
||||
`2024-12-23`
|
||||
|
||||
- 🐞 修复 Button 有图标和无图标按钮对齐差一像素的问题。[#52070](https://github.com/ant-design/ant-design/pull/52070)
|
||||
- 🐞 修复 Splitter 组件折叠图标 `z-index` 层级过低问题。[#52065](https://github.com/ant-design/ant-design/pull/52065) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 修复 Button 启用 `loading` 时,动画不够顺滑的问题。[#52059](https://github.com/ant-design/ant-design/pull/52059) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Button 暗色模式下默认填充按钮文本在悬停时消失的问题。[#52024](https://github.com/ant-design/ant-design/pull/52024) [@DDDDD12138](https://github.com/DDDDD12138)
|
||||
|
||||
## 5.22.5
|
||||
|
||||
`2024-12-15`
|
||||
|
||||
- 🛠 重构 Wave/Menu/Form `ref` 检查逻辑以解决 React 19 `ref` 部分冲突(注:该更新不会完全解决 React 19 兼容问题,后续将会持续更新)。[#51952](https://github.com/ant-design/ant-design/pull/51952) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Dropdown `children` 不支持传入 ReactNode 的问题。[#50174](https://github.com/ant-design/ant-design/pull/50174) [@coding-ice](https://github.com/coding-ice)
|
||||
- 🐞 修复 Carousel 某些情况下在 Modal 中无法正确展示的问题。[#51988](https://github.com/ant-design/ant-design/pull/51988) [@quan060798](https://github.com/quan060798)
|
||||
- 🐞 修复 Select 选中文本溢出的问题 。[#52011](https://github.com/ant-design/ant-design/pull/52011) [@OysterD3](https://github.com/OysterD3)
|
||||
- 🐞 修复 Form `setFieldValue` 没有重置字段校验信息的问题。[#51993](https://github.com/ant-design/ant-design/pull/51993) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Pagination 配置 `showSizeChanger.showSearch` 无效的问题。[#51962](https://github.com/ant-design/ant-design/pull/51962) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🇰🇷 优化 DatePicker 韩语本地化文案。[#51983](https://github.com/ant-design/ant-design/pull/51983) [@DevLeti](https://github.com/DevLeti)
|
||||
- 🤖 从 antd 里导出 `CheckboxChangeEvent` 类型。[#52008](https://github.com/ant-design/ant-design/pull/52008) [@SpecLad](https://github.com/SpecLad)
|
||||
|
||||
## 5.22.4
|
||||
|
||||
`2024-12-09`
|
||||
|
||||
- Transfer
|
||||
- 🐞 修复 Transfer 选中当前页最后一项时背景溢出的问题。[#51884](https://github.com/ant-design/ant-design/pull/51884) [@ayangweb](https://github.com/ayangweb)
|
||||
- 🐞 修正 Transfer 切换按钮当所有 item 禁用时依然可用的问题。[#51784](https://github.com/ant-design/ant-design/pull/51784) [@WwwHhhYran](https://github.com/WwwHhhYran)
|
||||
- 🐞 修复 Tooltip 内容过少时,箭头会在容器外的问题。[#51904](https://github.com/ant-design/ant-design/pull/51904)
|
||||
- 🐞 修复点击 Upload 下的 Radio 或 Checkbox 会触发两次弹窗的问题。[#51874](https://github.com/ant-design/ant-design/pull/51874)
|
||||
- 💄 修复 Menu 在使用 `collapsedIconSize` 时图标对齐的问题。[#51863](https://github.com/ant-design/ant-design/pull/51863) [@Gnomeek](https://github.com/Gnomeek)
|
||||
- 💄 修复 Tabs 组件在 `type="editable-card"` 时样式不正确的问题。[#51935](https://github.com/ant-design/ant-design/pull/51935) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 💄 修复 Layout.Sider 组件在 `zero-width` 模式下触发器样式优先级不足的问题。[#51936](https://github.com/ant-design/ant-design/pull/51936) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 💄 MISC: 修复 icon 样式被重复创建的问题。[#51897](https://github.com/ant-design/ant-design/pull/51897) [@YumoImer](https://github.com/YumoImer)
|
||||
- 💄 MISC: 行内样式重构为 cssinjs。[#51843](https://github.com/ant-design/ant-design/pull/51843)
|
||||
|
||||
## 5.22.3
|
||||
|
||||
`2024-12-02`
|
||||
|
||||
- 🐞 修复 Select 清除按钮在 Form.Item 中位置可能错误的问题。[#51649](https://github.com/ant-design/ant-design/pull/51649) [@dislido](https://github.com/dislido)
|
||||
- 🐞 修复 InputNumber `handleVisible` token 不生效的问题。[#51728](https://github.com/ant-design/ant-design/pull/51728) [@dengfuping](https://github.com/dengfuping)
|
||||
- 🐞 修复 ColorPicker 的 `presets` 属性中的 `label` 字段传入 `ReactNode` 会报错的问题。[#51808](https://github.com/ant-design/ant-design/pull/51808) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 Menu 的 `inlineCollapsed` 属性在 Layout 中不生效的问题。[#51775](https://github.com/ant-design/ant-design/pull/51775) [@coderz-w](https://github.com/coderz-w)
|
||||
- 🐞 修复 Table `onHeaderCell` 提供的 `style` 无法被覆盖的问题。[#51793](https://github.com/ant-design/ant-design/pull/51793) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- ⌨️ 优化 Collapse 组件的可访问性。[#51836](https://github.com/ant-design/ant-design/pull/51836) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- TypeScript
|
||||
- 🤖 增加 Table 属性中 `clearFilters` 函数的入参类型。[#51754](https://github.com/ant-design/ant-design/pull/51754) [@fubd](https://github.com/fubd)
|
||||
- 🤖 修复 Form 设置 `preserve` 为 `false` 时,Form.List 中嵌套的字段卸载会丢失值的问题。[#51796](https://github.com/ant-design/ant-design/pull/51796) [@zombieJ](https://github.com/zombieJ)
|
||||
|
||||
## 5.22.2
|
||||
|
||||
`2024-11-21`
|
||||
|
||||
- 🐞 修复 Input.OTP 组件在有非法输入时仍会切换到下一个输入框的问题。[#51664](https://github.com/ant-design/ant-design/pull/51664) [@thecodesalim](https://github.com/thecodesalim)
|
||||
- 🐞 调整 Modal 确认函数,使其在弹出后聚焦确认按钮时不要滚动窗体。[#51647](https://github.com/ant-design/ant-design/pull/51647) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Form `rules` 生成多条相同错误时会报 React 渲染错误的问题。[#51636](https://github.com/ant-design/ant-design/pull/51636) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 调整 Button 使用 `useEffect` 来触发 `autoFocus` 逻辑,以解决一些异步渲染场景下 Button 无法自动聚焦的问题。[#51624](https://github.com/ant-design/ant-design/pull/51624) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Button 中使用自定义三方图标库时图标未居中的问题。[#51652](https://github.com/ant-design/ant-design/pull/51652) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Table 组件 `getCheckboxProps` 中的事件处理器被内部选择逻辑覆盖的问题。[#51661](https://github.com/ant-design/ant-design/pull/51661) [@Zyf665](https://github.com/Zyf665)
|
||||
- 🐞 修复 Tree 组件的 `onCheck` 和 `onSelect` 事件没有被正确触发的问题。[#51448](https://github.com/ant-design/ant-design/pull/51448) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🐞 修复 Input 组件的清除按钮未能垂直居中的问题。[#51700](https://github.com/ant-design/ant-design/pull/51700) [@jynxio](https://github.com/jynxio)
|
||||
- 🐞 修复 Select 组件的 `prefix` 组合导致的颜色、折行、状态等一系列样式问题。[#51694](https://github.com/ant-design/ant-design/pull/51694) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🌐 本地化
|
||||
- 🇷🇺 添加了俄语翻译支持。[#51619](https://github.com/ant-design/ant-design/pull/51619) [@avvakumovid](https://github.com/avvakumovid)
|
||||
- 🇮🇹 为 TimePicker 添加了意大利语翻译。[#51685](https://github.com/ant-design/ant-design/pull/51685) [@LorenzoCardinali](https://github.com/LorenzoCardinali)
|
||||
|
||||
## 5.22.1
|
||||
|
||||
`2024-11-13`
|
||||
|
||||
- 🛠 调整 DatePicker.RangePicker 当 `needConfirm` 切用户未提交日期时,不允许通过点击输入框切换到下一个字段。[#51591](https://github.com/ant-design/ant-design/pull/51591) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🛠 禁用 Input.OTP `ctrl + z` 操作以防止数据变化非预期的问题。[#51609](https://github.com/ant-design/ant-design/pull/51609) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Select 标签模式下展示异常的问题。[#51605](https://github.com/ant-design/ant-design/pull/51605) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 Badge `count` 在 Safari 下动画丢失的问题。[#51598](https://github.com/ant-design/ant-design/pull/51598) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Tabs `centered` 下标签展示不全的问题。[#51571](https://github.com/ant-design/ant-design/pull/51571) [@DDDDD12138](https://github.com/DDDDD12138)
|
||||
- 🐞 修复 Transfer 受控 `dataSource` 和 `selectedKeys` 时,偶尔会出现勾选不正确的问题。[#51523](https://github.com/ant-design/ant-design/pull/51523) [@IsKaros](https://github.com/IsKaros)
|
||||
- 🐞 回滚 Button `display` 的 `inline-flex` 为 `inline-block` 以解决 Icon 位置偏移的问题。[#51588](https://github.com/ant-design/ant-design/pull/51588) [@Wxh16144](https://github.com/Wxh16144)
|
||||
|
||||
## 5.22.0
|
||||
|
||||
`2024-11-12`
|
||||
|
||||
- Form
|
||||
- 🆕 Form.Item 支持隐藏 label。[#51524](https://github.com/ant-design/ant-design/pull/51524) [@crazyair](https://github.com/crazyair)
|
||||
- 🐞 Form 移除了用于撑开 error 高度的 div,将 errorDom 和 extraDom 用一个 div 包裹,并为该 div 设置了最小高度。[#51254](https://github.com/ant-design/ant-design/pull/51254) [@hongzzz](https://github.com/hongzzz)
|
||||
- 🐞 修复 Form 在字段触发 change 但是值没有变化时,`onValuesChange` 仍然会触发的问题。[#51437](https://github.com/ant-design/ant-design/pull/51437) [@crazyair](https://github.com/crazyair)
|
||||
- 🆕 Form 支持在表单验证失败时,scrollToFirstError 中的 focus 属性。[#51231](https://github.com/ant-design/ant-design/pull/51231) [@nathanlao](https://github.com/nathanlao)
|
||||
- Table
|
||||
- 🆕 Table 列过滤下拉框支持 `filterDropdownProps`。[#51297](https://github.com/ant-design/ant-design/pull/51297) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🆕 Table `expandedRowClassName` 支持 string 。[#51067](https://github.com/ant-design/ant-design/pull/51067) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- Tree
|
||||
- 💄 修复 Tree 选中节点丢失 padding 样式的问题。[#51492](https://github.com/ant-design/ant-design/pull/51492) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🆕 Tree 组件 Token 增加 `nodeHoverColor` 和 `nodeSelectedColor` 支持。[#51367](https://github.com/ant-design/ant-design/pull/51367) [@zmbxy](https://github.com/zmbxy)
|
||||
- 🆕 Tree 新增 `indentSize` token 用于自定义缩进宽度。[#51010](https://github.com/ant-design/ant-design/pull/51010) [@afc163](https://github.com/afc163)
|
||||
- DatePicker
|
||||
- 🆕 DatePicker 支持 `prefix` 属性。[#51335](https://github.com/ant-design/ant-design/pull/51335) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 💄 修复 DatePicker.RangePicker 当鼠标移动到单元格之间时出现闪烁样式的问题。[#51533](https://github.com/ant-design/ant-design/pull/51533) [@afc163](https://github.com/afc163)
|
||||
- Input.OTP
|
||||
- 🆕 Input.OTP 组件新增 `onInput` 事件用于获取用户每一次输入的值。[#51289](https://github.com/ant-design/ant-design/pull/51289) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🐞 修复 Input.OTP 无法指定 `inputMode` 的问题。[#51271](https://github.com/ant-design/ant-design/pull/51271) [@alan-rudzinski](https://github.com/alan-rudzinski)
|
||||
- 🆕 ColorPicker 支持 `disabledFormat` 属性以禁用格式切换器。[#51539](https://github.com/ant-design/ant-design/pull/51539) [@su-muzhi](https://github.com/su-muzhi)
|
||||
- 🆕 为 InputNumber 组件的 `focus` 方法增加 `cursor` 配置项以控制光标位置。[#51444](https://github.com/ant-design/ant-design/pull/51444) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🆕 Cascader 新增 `disabled` 属性以禁用组件的所有一级目录项。[#51272](https://github.com/ant-design/ant-design/pull/51272) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🆕 Descriptions 支持单行铺满。[#51365](https://github.com/ant-design/ant-design/pull/51365) [@crazyair](https://github.com/crazyair)
|
||||
- 🆕 Select/TreeSelect/Cascader 组件增加 `prefix` 属性以支持自定义前缀。[#51186](https://github.com/ant-design/ant-design/pull/51186) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 Image 设置 `ImageProps.preview.rootClassName` 导致预览图类名丢失。[#51538](https://github.com/ant-design/ant-design/pull/51538) [@dislido](https://github.com/dislido)
|
||||
- 🐞 修复 TimePicker 面板列的最后一项无法滚动到最上面的问题。[#51481](https://github.com/ant-design/ant-design/pull/51481) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 TreeSelect 弹层高度不够的问题。[#51567](https://github.com/ant-design/ant-design/pull/51567) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Typography 在 ConfigProvider 语言切换时候没有立即更新。[#51453](https://github.com/ant-design/ant-design/pull/51453) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🐞 修复 Upload `itemRender` 调用 `action.preview` 会导致崩溃的问题。[#51419](https://github.com/ant-design/ant-design/pull/51419) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 修复 Splitter 伪元素符号问题。[#51536](https://github.com/ant-design/ant-design/pull/51536) [@dislido](https://github.com/dislido)
|
||||
- 💄 优化 Collapse 可访问性属性和鼠标 hover 样式。[#51400](https://github.com/ant-design/ant-design/pull/51400) [@afc163](https://github.com/afc163)
|
||||
- 💄 修复 Menu title 内容的样式问题。[#51425](https://github.com/ant-design/ant-design/pull/51425) [@coding-ice](https://github.com/coding-ice)
|
||||
- 🇵🇹 修正葡萄牙语 (pt_PT) 本地化文件中的翻译,以提高准确性和一致性。[#51501](https://github.com/ant-design/ant-design/pull/51501) [@alexandre-p-marques-alb](https://github.com/alexandre-p-marques-alb)
|
||||
- 🇺🇿 优化 uz_UZ 国际化。[#51407](https://github.com/ant-design/ant-design/pull/51407) [@Zukhrik](https://github.com/Zukhrik)
|
||||
- TypeScript
|
||||
- 🤖 Upload 导出类型 DraggerProps。[#51546](https://github.com/ant-design/ant-design/pull/51546) [@DBvc](https://github.com/DBvc)
|
||||
- 🤖 将 defaultValue 属性添加到 TimePicker.RangePicker 示例中。[#51413](https://github.com/ant-design/ant-design/pull/51413) [@nathanlao](https://github.com/nathanlao)
|
||||
- 🤖 Message 优化 message.config 中的 top 类型。[#51468](https://github.com/ant-design/ant-design/pull/51468) [@Fog3211](https://github.com/Fog3211)
|
||||
- 🤖 优化 Tree 和 TreeSelect 的 TS 定义。[#51251](https://github.com/ant-design/ant-design/pull/51251) [@afc163](https://github.com/afc163)
|
||||
|
||||
## 5.21.6
|
||||
|
||||
`2024-10-28`
|
||||
@ -52,6 +252,7 @@ tag: vVERSION
|
||||
- 💄 修改 Button `textHoverBg` 在悬浮状态下的背景色为 `colorFillTertiary`。[#51187](https://github.com/ant-design/ant-design/pull/51187) [@coding-ice](https://github.com/coding-ice)
|
||||
- TypeScript
|
||||
- 🤖 优化 Switch `eventHandler` 类型。[#51165](https://github.com/ant-design/ant-design/pull/51165) [@thinkasany](https://github.com/thinkasany)
|
||||
|
||||
## 5.21.3
|
||||
|
||||
`2024-10-09`
|
||||
@ -100,17 +301,17 @@ tag: vVERSION
|
||||
<img width="520" alt="Splitter" src="https://github.com/user-attachments/assets/25fc4e3c-1aa5-41bb-8f39-f34f7149e0f6">
|
||||
- Button
|
||||
- 🔥 Button 支持 `variant` 变体和 `color` 颜色属性,以支持更多组合样式。[#50051](https://github.com/ant-design/ant-design/pull/50051) [@coding-ice](https://github.com/coding-ice)
|
||||
<img width="420" alt="Button" src="https://github.com/user-attachments/assets/cd5cb7fb-25e8-445f-b217-7fdd4ae0f9b4">
|
||||
<img width="420" alt="Button" src="https://github.com/user-attachments/assets/cd5cb7fb-25e8-445f-b217-7fdd4ae0f9b4">
|
||||
- 💄 Button 添加 `textColor`、`textHoverColor` 和 `textActiveColor` 三个 token。[#47870](https://github.com/ant-design/ant-design/pull/47870) [@madocto](https://github.com/madocto)
|
||||
- FloatButton
|
||||
- 🆕 FloatButton 组件支持 `placement` 属性,支持从四个方向弹出菜单。(实现方式改为 `position: absolute` + flex 布局,可能会对你现有的布局造成 breaking change,请注意兼容)[#50407](https://github.com/ant-design/ant-design/pull/50407) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
<img width="300" alt="float button" src="https://github.com/user-attachments/assets/4b53c0f6-7bdd-4e2a-91cc-2fb804f6e6d3" />
|
||||
<img width="300" alt="float button" src="https://github.com/user-attachments/assets/4b53c0f6-7bdd-4e2a-91cc-2fb804f6e6d3" />
|
||||
- 💄 统一 FloatButton 和 FloatButton.Group 的按钮圆角。[#50513](https://github.com/ant-design/ant-design/pull/50513) [@Layouwen](https://github.com/Layouwen)
|
||||
- 💄 FloatButton 组件的 `z-index` 加入 `useZIndex` 管理,兼容弹层类组件。[#50311](https://github.com/ant-design/ant-design/pull/50311) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🆕 FloatButton 支持传入 `htmlType` 属性。[#50892](https://github.com/ant-design/ant-design/pull/50892) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- Menu
|
||||
- 🆕 Menu.Item 和 Dropdown 的 menu 支持 `extra` 属性。[#50431](https://github.com/ant-design/ant-design/pull/50431) [@coding-ice](https://github.com/coding-ice)
|
||||
<img width="259" alt="menu extra" src="https://github.com/user-attachments/assets/fee57c43-b948-4f98-8a6b-0d94094a8a65">
|
||||
<img width="259" alt="menu extra" src="https://github.com/user-attachments/assets/fee57c43-b948-4f98-8a6b-0d94094a8a65">
|
||||
- 🐞 修复 Menu `popupStyle` 在 SubMenu 上失效的问题。[#50922](https://github.com/ant-design/ant-design/pull/50922) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- Table
|
||||
- 🆕 Table 列支持配置 `minWidth` 属性。[#50416](https://github.com/ant-design/ant-design/pull/50416) [@linxianxi](https://github.com/linxianxi)
|
||||
@ -1902,7 +2103,7 @@ tag: vVERSION
|
||||
- 💄 调整 Select, TreeSelect, Cascader 在多选时总是默认显示下拉箭头。[#41028](https://github.com/ant-design/ant-design/pull/41028)
|
||||
- 🐞 修复 Form 组件 `Form.Item.useStatus` 导致的服务端渲染问题。[#40977](https://github.com/ant-design/ant-design/pull/40977) [@AndyBoat](https://github.com/AndyBoat)
|
||||
- 🐞 杂项:修复部分组件箭头形状问题。[#40971](https://github.com/ant-design/ant-design/pull/40971)
|
||||
- 🐞 修复 Layout 报错 `React does not recognize the `suffixCls` prop on a DOM element` 的问题。[#40969](https://github.com/ant-design/ant-design/pull/40969)
|
||||
- 🐞 修复 Layout 报错 "React does not recognize the `suffixCls` prop on a DOM element" 的问题。[#40969](https://github.com/ant-design/ant-design/pull/40969)
|
||||
- 🐞 修复 Watermark 组件图片加载异常时的问题,默认展示文字。[#40770](https://github.com/ant-design/ant-design/pull/40770) [@OriginRing](https://github.com/OriginRing)
|
||||
- 🐞 Image 预览新增图片翻转功能。并修复 Image `fallback` 在 ssr 下失效的问题。[#40660](https://github.com/ant-design/ant-design/pull/40660)
|
||||
- 🐞 修复 Select 中使用 Typography 不居中的问题。[#40422](https://github.com/ant-design/ant-design/pull/40422) [@Yuiai01](https://github.com/Yuiai01)
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
[![](https://opencollective.com/ant-design/tiers/sponsors.svg?avatarHeight=72)](https://opencollective.com/ant-design/contribute/sponsors-218/checkout) [![](https://opencollective.com/ant-design/tiers/backers.svg?avatarHeight=72)](https://opencollective.com/ant-design/contribute/backers-217/checkout)
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
[npm-image]: https://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: https://npmjs.org/package/antd
|
||||
[github-action-image]: https://github.com/ant-design/ant-design/workflows/%E2%9C%85%20test/badge.svg
|
||||
[github-action-url]: https://github.com/ant-design/ant-design/actions?query=workflow%3A%22%E2%9C%85+test%22
|
||||
[codecov-image]: https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square
|
||||
@ -65,7 +65,7 @@
|
||||
- 支持服务端渲染。
|
||||
- [Electron](https://www.electronjs.org/)
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Electron |
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Electron |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
@ -115,18 +115,17 @@ export default App;
|
||||
|
||||
- [首页](https://ant.design/)
|
||||
- [所有组件](https://ant.design/components/overview-cn)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [更新日志](CHANGELOG.zh-CN.md)
|
||||
- [React 底层基础组件](http://react-component.github.io/)
|
||||
- [移动端组件](http://mobile.ant.design)
|
||||
- [小程序组件](http://mini.ant.design)
|
||||
- [页面级组件](https://procomponents.ant.design)
|
||||
- [Ant Design 图表](https://charts.ant.design)
|
||||
- [Ant Design 图标](https://github.com/ant-design/ant-design-icons)
|
||||
- [Ant Design 色彩](https://github.com/ant-design/ant-design-colors)
|
||||
- [首页模板集](https://landing.ant.design)
|
||||
- [React 底层基础组件](https://react-component.github.io/)
|
||||
- [🆕 Ant Design X](https://x.ant.design/index-cn)
|
||||
- [Ant Design Pro](https://pro.ant.design/)
|
||||
- [Pro Components](https://procomponents.ant.design)
|
||||
- [Ant Design Mobile](https://mobile.ant.design)
|
||||
- [Ant Design Mini](https://mini.ant.design)
|
||||
- [Ant Design Charts](https://charts.ant.design)
|
||||
- [Ant Design Web3](https://web3.ant.design)
|
||||
- [动效](https://motion.ant.design)
|
||||
- [脚手架市场](http://scaffold.ant.design)
|
||||
- [脚手架市场](https://scaffold.ant.design)
|
||||
- [设计规范速查手册](https://github.com/ant-design/ant-design/wiki/Ant-Design-%E8%AE%BE%E8%AE%A1%E5%9F%BA%E7%A1%80%E7%AE%80%E7%89%88)
|
||||
- [开发者说明](https://github.com/ant-design/ant-design/wiki/Development)
|
||||
- [版本发布规则](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
|
||||
@ -153,7 +152,7 @@ $ npm start
|
||||
|
||||
打开浏览器访问 http://127.0.0.1:8001 ,更多[本地开发文档](https://github.com/ant-design/ant-design/wiki/Development)。
|
||||
|
||||
## 🤝 参与共建 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
|
||||
## 🤝 参与共建 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
@ -188,7 +187,7 @@ $ npm start
|
||||
|
||||
请参考[贡献指南](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),更好的问题更容易获得帮助。
|
||||
> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](https://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。
|
||||
|
||||
[![赞助链接](https://raw.githubusercontent.com/BoostIO/issuehunt-materials/master/v1/issuehunt-button-v1.svg)](https://issuehunt.io/repos/34526884)
|
||||
|
||||
@ -201,7 +200,7 @@ $ npm start
|
||||
通过 Stack Overflow 或者 Segment Fault 提问时,建议加上 `antd` 标签。
|
||||
|
||||
1. [GitHub Discussions](https://github.com/ant-design/ant-design/discussions)
|
||||
2. [Stack Overflow](http://stackoverflow.com/questions/tagged/antd)(英文)
|
||||
2. [Stack Overflow](https://stackoverflow.com/questions/tagged/antd)(英文)
|
||||
3. [Segment Fault](https://segmentfault.com/t/antd)(中文)
|
||||
|
||||
## Issue 赞助
|
||||
|
26
README.md
26
README.md
@ -18,8 +18,8 @@ An enterprise-class UI design language and React UI library.
|
||||
|
||||
[![](https://opencollective.com/ant-design/tiers/sponsors.svg?avatarHeight=72)](https://opencollective.com/ant-design/contribute/sponsors-218/checkout) [![](https://opencollective.com/ant-design/tiers/backers.svg?avatarHeight=72)](https://opencollective.com/ant-design/contribute/backers-217/checkout)
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
[npm-image]: https://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: https://npmjs.org/package/antd
|
||||
[github-action-image]: https://github.com/ant-design/ant-design/workflows/%E2%9C%85%20test/badge.svg
|
||||
[github-action-url]: https://github.com/ant-design/ant-design/actions?query=workflow%3A%22%E2%9C%85+test%22
|
||||
[codecov-image]: https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square
|
||||
@ -63,7 +63,7 @@ An enterprise-class UI design language and React UI library.
|
||||
- Server-side Rendering
|
||||
- [Electron](https://www.electronjs.org/)
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Electron |
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)<br>Electron |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
@ -98,18 +98,18 @@ export default () => (
|
||||
|
||||
- [Home page](https://ant.design/)
|
||||
- [Components Overview](https://ant.design/components/overview)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [Change Log](CHANGELOG.en-US.md)
|
||||
- [rc-components](http://react-component.github.io/)
|
||||
- [Mobile UI](http://mobile.ant.design)
|
||||
- [Mini Program UI](http://mini.ant.design)
|
||||
- [Ant Design Pro Components](https://procomponents.ant.design)
|
||||
- [rc-components](https://react-component.github.io/)
|
||||
- [🆕 Ant Design X](https://x.ant.design/index-cn)
|
||||
- [Ant Design Pro](https://pro.ant.design/)
|
||||
- [Pro Components](https://procomponents.ant.design)
|
||||
- [Ant Design Mobile](https://mobile.ant.design)
|
||||
- [Ant Design Mini](https://mini.ant.design)
|
||||
- [Ant Design Charts](https://charts.ant.design)
|
||||
- [Ant Design Icons](https://github.com/ant-design/ant-design-icons)
|
||||
- [Ant Design Colors](https://github.com/ant-design/ant-design-colors)
|
||||
- [Ant Design Web3](https://web3.ant.design)
|
||||
- [Landing Pages](https://landing.ant.design)
|
||||
- [Motion](https://motion.ant.design)
|
||||
- [Scaffold Market](http://scaffold.ant.design)
|
||||
- [Ant Motion](https://motion.ant.design)
|
||||
- [Scaffold Market](https://scaffold.ant.design)
|
||||
- [Developer Instruction](https://github.com/ant-design/ant-design/wiki/Development)
|
||||
- [Versioning Release Note](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
|
||||
- [FAQ](https://ant.design/docs/react/faq)
|
||||
@ -134,7 +134,7 @@ $ npm start
|
||||
|
||||
Open your browser and visit http://127.0.0.1:8001 , see more at [Development](https://github.com/ant-design/ant-design/wiki/Development).
|
||||
|
||||
## 🤝 Contributing [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
|
||||
## 🤝 Contributing [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -65,6 +65,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"formatter": {
|
||||
"quoteStyle": "single"
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"include": ["**/*.test.ts", "**/*.test.tsx", "tests/**/*", "scripts/**/*", ".dumi/**/*"],
|
||||
|
@ -74,6 +74,7 @@ exports[`antd exports modules correctly 1`] = `
|
||||
"message",
|
||||
"notification",
|
||||
"theme",
|
||||
"unstableSetRender",
|
||||
"version",
|
||||
]
|
||||
`;
|
||||
|
44
components/__tests__/unstable.test.ts
Normal file
44
components/__tests__/unstable.test.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { Modal, unstableSetRender } from 'antd';
|
||||
|
||||
import { waitFakeTimer19 } from '../../tests/utils';
|
||||
|
||||
// TODO: Remove this. Mock for React 19
|
||||
jest.mock('react-dom', () => {
|
||||
const realReactDOM = jest.requireActual('react-dom');
|
||||
|
||||
if (realReactDOM.version.startsWith('19')) {
|
||||
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||
}
|
||||
|
||||
return realReactDOM;
|
||||
});
|
||||
|
||||
describe('unstable', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('unstableSetRender', async () => {
|
||||
if (ReactDOM.version.startsWith('19')) {
|
||||
unstableSetRender((node, container) => {
|
||||
const root = (ReactDOM as any).createRoot(container);
|
||||
root.render(node);
|
||||
return async () => {
|
||||
root.unmount();
|
||||
};
|
||||
});
|
||||
|
||||
Modal.info({ content: 'unstableSetRender' });
|
||||
|
||||
await waitFakeTimer19();
|
||||
|
||||
expect(document.querySelector('.ant-modal')).toBeTruthy();
|
||||
}
|
||||
});
|
||||
});
|
@ -52,7 +52,9 @@ const ActionButton: React.FC<ActionButtonProps> = (props) => {
|
||||
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
if (autoFocus) {
|
||||
timeoutId = setTimeout(() => {
|
||||
buttonRef.current?.focus();
|
||||
buttonRef.current?.focus({
|
||||
preventScroll: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
|
@ -20,9 +20,10 @@ export interface BaseProps {
|
||||
/* istanbul ignore next */
|
||||
const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
|
||||
Component: any,
|
||||
defaultPrefixCls?: string,
|
||||
getDropdownCls?: null | ((prefixCls: string) => string),
|
||||
alignPropName?: 'align' | 'dropdownAlign' | 'popupAlign',
|
||||
postProps?: (props: ComponentProps) => ComponentProps,
|
||||
defaultPrefixCls?: string,
|
||||
getDropdownCls?: (prefixCls: string) => string,
|
||||
) => {
|
||||
type WrapProps = ComponentProps & AnyObject;
|
||||
|
||||
@ -55,7 +56,6 @@ const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
|
||||
? `.${getDropdownCls(prefixCls)}`
|
||||
: `.${prefixCls}-dropdown`;
|
||||
const popup = holderRef.current?.querySelector(dropdownCls);
|
||||
|
||||
if (popup) {
|
||||
clearInterval(interval);
|
||||
resizeObserver.observe(popup);
|
||||
@ -83,6 +83,16 @@ const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
|
||||
if (postProps) {
|
||||
mergedProps = postProps(mergedProps);
|
||||
}
|
||||
if (alignPropName) {
|
||||
Object.assign(mergedProps, {
|
||||
[alignPropName]: {
|
||||
overflow: {
|
||||
adjustX: false,
|
||||
adjustY: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
const mergedStyle: React.CSSProperties = {
|
||||
paddingBottom: popupHeight,
|
||||
position: 'relative',
|
||||
|
@ -28,6 +28,18 @@ import { consumerBaseZIndexOffset, containerBaseZIndexOffset, useZIndex } from '
|
||||
import { resetWarned } from '../warning';
|
||||
import zIndexContext from '../zindexContext';
|
||||
|
||||
// TODO: Remove this. Mock for React 19
|
||||
jest.mock('react-dom', () => {
|
||||
const realReactDOM = jest.requireActual('react-dom');
|
||||
|
||||
if (realReactDOM.version.startsWith('19')) {
|
||||
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||
}
|
||||
|
||||
return realReactDOM;
|
||||
});
|
||||
|
||||
const WrapWithProvider: React.FC<PropsWithChildren<{ container: ZIndexContainer }>> = ({
|
||||
children,
|
||||
container,
|
||||
|
@ -9,6 +9,18 @@ import { TARGET_CLS } from '../wave/interface';
|
||||
|
||||
(global as any).isVisible = true;
|
||||
|
||||
// TODO: Remove this. Mock for React 19
|
||||
jest.mock('react-dom', () => {
|
||||
const realReactDOM = jest.requireActual('react-dom');
|
||||
|
||||
if (realReactDOM.version.startsWith('19')) {
|
||||
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||
}
|
||||
|
||||
return realReactDOM;
|
||||
});
|
||||
|
||||
jest.mock('rc-util/lib/Dom/isVisible', () => {
|
||||
const mockFn = () => (global as any).isVisible;
|
||||
return mockFn;
|
||||
@ -96,6 +108,7 @@ describe('Wave component', () => {
|
||||
expect(document.querySelector('.ant-wave')).toBeFalsy();
|
||||
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
errorSpy.mockRestore();
|
||||
|
||||
unmount();
|
||||
});
|
||||
|
3
components/_util/isPrimitive.ts
Normal file
3
components/_util/isPrimitive.ts
Normal file
@ -0,0 +1,3 @@
|
||||
const isPrimitive = (value: unknown) => (typeof value !== 'object' && typeof value !== 'function') || value === null;
|
||||
|
||||
export default isPrimitive;
|
@ -69,13 +69,13 @@ export default function useResponsiveObserver() {
|
||||
return React.useMemo(() => {
|
||||
const subscribers = new Map<number, SubscribeFunc>();
|
||||
let subUid = -1;
|
||||
let screens = {};
|
||||
let screens: Partial<Record<Breakpoint, boolean>> = {};
|
||||
|
||||
return {
|
||||
matchHandlers: {} as {
|
||||
[prop: string]: {
|
||||
mql: MediaQueryList;
|
||||
listener: ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | null;
|
||||
listener: (this: MediaQueryList, ev: MediaQueryListEvent) => void;
|
||||
};
|
||||
},
|
||||
dispatch(pointMap: ScreenMap) {
|
||||
@ -84,7 +84,9 @@ export default function useResponsiveObserver() {
|
||||
return subscribers.size >= 1;
|
||||
},
|
||||
subscribe(func: SubscribeFunc): number {
|
||||
if (!subscribers.size) this.register();
|
||||
if (!subscribers.size) {
|
||||
this.register();
|
||||
}
|
||||
subUid += 1;
|
||||
subscribers.set(subUid, func);
|
||||
func(screens);
|
||||
@ -92,7 +94,9 @@ export default function useResponsiveObserver() {
|
||||
},
|
||||
unsubscribe(paramToken: number) {
|
||||
subscribers.delete(paramToken);
|
||||
if (!subscribers.size) this.unregister();
|
||||
if (!subscribers.size) {
|
||||
this.unregister();
|
||||
}
|
||||
},
|
||||
unregister() {
|
||||
Object.keys(responsiveMap).forEach((screen) => {
|
||||
@ -117,7 +121,6 @@ export default function useResponsiveObserver() {
|
||||
mql,
|
||||
listener,
|
||||
};
|
||||
|
||||
listener(mql);
|
||||
});
|
||||
},
|
||||
@ -129,7 +132,7 @@ export default function useResponsiveObserver() {
|
||||
export const matchScreen = (screens: ScreenMap, screenSizes?: ScreenSizeMap) => {
|
||||
if (screenSizes && typeof screenSizes === 'object') {
|
||||
for (let i = 0; i < responsiveArray.length; i++) {
|
||||
const breakpoint: Breakpoint = responsiveArray[i];
|
||||
const breakpoint = responsiveArray[i];
|
||||
if (screens[breakpoint] && screenSizes[breakpoint] !== undefined) {
|
||||
return screenSizes[breakpoint];
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import CSSMotion from 'rc-motion';
|
||||
import raf from 'rc-util/lib/raf';
|
||||
import { render, unmount } from 'rc-util/lib/React/render';
|
||||
import { composeRef } from 'rc-util/lib/ref';
|
||||
|
||||
import { getReactRender, type UnmountType } from '../../config-provider/UnstableContext';
|
||||
import { TARGET_CLS } from './interface';
|
||||
import type { ShowWaveEffect } from './interface';
|
||||
import { getTargetWaveColor } from './util';
|
||||
@ -17,12 +17,21 @@ export interface WaveEffectProps {
|
||||
className: string;
|
||||
target: HTMLElement;
|
||||
component?: string;
|
||||
registerUnmount: () => UnmountType | null;
|
||||
}
|
||||
|
||||
const WaveEffect: React.FC<WaveEffectProps> = (props) => {
|
||||
const { className, target, component } = props;
|
||||
const WaveEffect = (props: WaveEffectProps) => {
|
||||
const { className, target, component, registerUnmount } = props;
|
||||
const divRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
// ====================== Refs ======================
|
||||
const unmountRef = React.useRef<UnmountType>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
unmountRef.current = registerUnmount();
|
||||
}, []);
|
||||
|
||||
// ===================== Effect =====================
|
||||
const [color, setWaveColor] = React.useState<string | null>(null);
|
||||
const [borderRadius, setBorderRadius] = React.useState<number[]>([]);
|
||||
const [left, setLeft] = React.useState(0);
|
||||
@ -119,7 +128,7 @@ const WaveEffect: React.FC<WaveEffectProps> = (props) => {
|
||||
onAppearEnd={(_, event) => {
|
||||
if (event.deadline || (event as TransitionEvent).propertyName === 'opacity') {
|
||||
const holder = divRef.current?.parentElement!;
|
||||
unmount(holder).then(() => {
|
||||
unmountRef.current?.().then(() => {
|
||||
holder?.remove();
|
||||
});
|
||||
}
|
||||
@ -152,7 +161,18 @@ const showWaveEffect: ShowWaveEffect = (target, info) => {
|
||||
holder.style.top = '0px';
|
||||
target?.insertBefore(holder, target?.firstChild);
|
||||
|
||||
render(<WaveEffect {...info} target={target} />, holder);
|
||||
const reactRender = getReactRender();
|
||||
|
||||
let unmountCallback: UnmountType | null = null;
|
||||
|
||||
function registerUnmount() {
|
||||
return unmountCallback;
|
||||
}
|
||||
|
||||
unmountCallback = reactRender(
|
||||
<WaveEffect {...info} target={target} registerUnmount={registerUnmount} />,
|
||||
holder,
|
||||
);
|
||||
};
|
||||
|
||||
export default showWaveEffect;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useContext, useRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import isVisible from 'rc-util/lib/Dom/isVisible';
|
||||
import { composeRef, supportRef } from 'rc-util/lib/ref';
|
||||
import { composeRef, getNodeRef, supportRef } from 'rc-util/lib/ref';
|
||||
|
||||
import type { ConfigConsumerProps } from '../../config-provider';
|
||||
import { ConfigContext } from '../../config-provider';
|
||||
@ -19,7 +19,7 @@ export interface WaveProps {
|
||||
const Wave: React.FC<WaveProps> = (props) => {
|
||||
const { children, disabled, component } = props;
|
||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||
const containerRef = useRef<HTMLElement>(null);
|
||||
const containerRef = useRef<HTMLElement>(null!);
|
||||
|
||||
// ============================== Style ===============================
|
||||
const prefixCls = getPrefixCls('wave');
|
||||
@ -64,7 +64,7 @@ const Wave: React.FC<WaveProps> = (props) => {
|
||||
return children ?? null;
|
||||
}
|
||||
|
||||
const ref = supportRef(children) ? composeRef((children as any).ref, containerRef) : containerRef;
|
||||
const ref = supportRef(children) ? composeRef(getNodeRef(children), containerRef) : containerRef;
|
||||
|
||||
return cloneElement(children, { ref });
|
||||
};
|
||||
|
@ -28,10 +28,16 @@ const useWave = (
|
||||
const { showEffect } = wave || {};
|
||||
|
||||
// Customize wave effect
|
||||
(showEffect || showWaveEffect)(targetNode, { className, token, component, event, hashId });
|
||||
(showEffect || showWaveEffect)(targetNode, {
|
||||
className,
|
||||
token,
|
||||
component,
|
||||
event,
|
||||
hashId,
|
||||
});
|
||||
});
|
||||
|
||||
const rafId = React.useRef<number>();
|
||||
const rafId = React.useRef<number>(null);
|
||||
|
||||
// Merge trigger event into one for each frame
|
||||
const showDebounceWave: ShowWave = (event) => {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||
|
||||
describe('Affix image', () => {
|
||||
imageDemoTest('affix');
|
||||
imageDemoTest('affix', {
|
||||
onlyViewport: ['debug.tsx'],
|
||||
});
|
||||
});
|
||||
|
@ -80,7 +80,7 @@ const Affix = React.forwardRef<AffixRef, AffixProps>((props, ref) => {
|
||||
const status = React.useRef<AffixStatus>(AFFIX_STATUS_NONE);
|
||||
|
||||
const prevTarget = React.useRef<Window | HTMLElement | null>(null);
|
||||
const prevListener = React.useRef<EventListener>();
|
||||
const prevListener = React.useRef<EventListener>(null);
|
||||
|
||||
const placeholderNodeRef = React.useRef<HTMLDivElement>(null);
|
||||
const fixedNodeRef = React.useRef<HTMLDivElement>(null);
|
||||
|
@ -76,9 +76,14 @@ const IconNode: React.FC<IconNodeProps> = (props) => {
|
||||
const iconType = iconMapFilled[type!] || null;
|
||||
if (icon) {
|
||||
return replaceElement(icon, <span className={`${prefixCls}-icon`}>{icon}</span>, () => ({
|
||||
className: classNames(`${prefixCls}-icon`, {
|
||||
[(icon as ReactElement).props.className]: (icon as ReactElement).props.className,
|
||||
}),
|
||||
className: classNames(
|
||||
`${prefixCls}-icon`,
|
||||
(
|
||||
icon as ReactElement<{
|
||||
className?: string;
|
||||
}>
|
||||
).props.className,
|
||||
),
|
||||
})) as ReactElement;
|
||||
}
|
||||
return React.createElement(iconType, { className: `${prefixCls}-icon` });
|
||||
|
@ -5,7 +5,7 @@ import { resetWarned } from 'rc-util/lib/warning';
|
||||
import Alert from '..';
|
||||
import { accessibilityTest } from '../../../tests/shared/accessibilityTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { act, render, screen, waitFakeTimer } from '../../../tests/utils';
|
||||
import { act, fireEvent, render, screen, waitFakeTimer } from '../../../tests/utils';
|
||||
import Button from '../../button';
|
||||
import Popconfirm from '../../popconfirm';
|
||||
import Tooltip from '../../tooltip';
|
||||
@ -28,7 +28,7 @@ describe('Alert', () => {
|
||||
it('should show close button and could be closed', async () => {
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const onClose = jest.fn();
|
||||
render(
|
||||
const { container } = render(
|
||||
<Alert
|
||||
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
|
||||
type="warning"
|
||||
@ -37,10 +37,7 @@ describe('Alert', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await userEvent.click(screen.getByRole('button', { name: /close/i }));
|
||||
jest.runAllTimers();
|
||||
});
|
||||
fireEvent.click(container.querySelector('.ant-alert-close-icon')!);
|
||||
|
||||
expect(onClose).toHaveBeenCalledTimes(1);
|
||||
expect(errSpy).not.toHaveBeenCalled();
|
||||
|
@ -381,8 +381,6 @@ describe('Anchor Render', () => {
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
// https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0
|
||||
{ legacyRoot: true },
|
||||
);
|
||||
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
@ -556,16 +554,14 @@ describe('Anchor Render', () => {
|
||||
{ key: hash2, href: `#${hash2}`, title: hash2 },
|
||||
]}
|
||||
/>,
|
||||
// https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0
|
||||
{ legacyRoot: true },
|
||||
);
|
||||
|
||||
// Should be 2 times:
|
||||
// 1. ''
|
||||
// 2. hash1 (Since `getCurrentAnchor` still return same hash)
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
const calledTimes = onChange.mock.calls.length;
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash2}"]`)!);
|
||||
expect(onChange).toHaveBeenCalledTimes(3);
|
||||
expect(onChange).toHaveBeenCalledTimes(calledTimes + 1);
|
||||
expect(onChange).toHaveBeenLastCalledWith(`#${hash2}`);
|
||||
});
|
||||
|
||||
|
@ -202,10 +202,12 @@ describe('App', () => {
|
||||
|
||||
expect(container.querySelector('.anticon')).toBeTruthy();
|
||||
const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]'));
|
||||
// Self-contained .anticon style
|
||||
const regex = /(?:^|\})\s*\.anticon\s*{[^}]*}/;
|
||||
expect(
|
||||
dynamicStyles.some((style) => {
|
||||
const { innerHTML } = style;
|
||||
return innerHTML.startsWith('.anticon');
|
||||
return regex.test(innerHTML);
|
||||
}),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
@ -2267,15 +2267,7 @@ exports[`renders components/auto-complete/demo/render-panel.tsx extend context c
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/render-panel.tsx extend context correctly 2`] = `
|
||||
[
|
||||
"Warning: Received \`%s\` for a non-boolean attribute \`%s\`.
|
||||
|
||||
If you want to write it to the DOM, pass a string instead: %s="%s" or %s={value.toString()}.
|
||||
|
||||
If you used to conditionally omit it with %s={condition && value}, pass %s={condition ? value : undefined} instead.%s",
|
||||
]
|
||||
`;
|
||||
exports[`renders components/auto-complete/demo/render-panel.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/status.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { extendTest } from '../../../tests/shared/demoTest';
|
||||
|
||||
extendTest('auto-complete');
|
||||
extendTest('auto-complete', {
|
||||
skip: ['row-selection-debug.tsx'],
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||
|
||||
describe('AutoComplete image', () => {
|
||||
imageDemoTest('auto-complete');
|
||||
imageDemoTest('auto-complete', {
|
||||
skip: ['row-selection-debug.tsx'],
|
||||
});
|
||||
});
|
||||
|
@ -170,7 +170,9 @@ const RefAutoComplete = React.forwardRef<RefSelectProps, AutoCompleteProps>(
|
||||
|
||||
// We don't care debug panel
|
||||
/* istanbul ignore next */
|
||||
const PurePanel = genPurePanel(RefAutoComplete);
|
||||
const PurePanel = genPurePanel(RefAutoComplete, 'dropdownAlign', (props: any) =>
|
||||
omit(props, ['visible']),
|
||||
);
|
||||
|
||||
RefAutoComplete.Option = Option;
|
||||
RefAutoComplete._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
||||
|
@ -271,8 +271,8 @@ describe('Avatar Render', () => {
|
||||
count: 2,
|
||||
popover: {
|
||||
placement: 'bottomRight',
|
||||
overlayClassName: 'wanpan-111',
|
||||
overlayStyle: { background: 'red' },
|
||||
classNames: { root: 'wanpan-111' },
|
||||
styles: { root: { background: 'red' } },
|
||||
content: 'Avatar.Group',
|
||||
open: true,
|
||||
},
|
||||
|
@ -441,6 +441,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="color: rgb(245, 106, 0); background-color: rgb(253, 227, 207);"
|
||||
>
|
||||
@ -464,12 +465,14 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner-content"
|
||||
>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
style="background-color: rgb(135, 208, 104);"
|
||||
>
|
||||
@ -506,6 +509,7 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
Ant User
|
||||
@ -731,6 +735,7 @@ Array [
|
||||
</span>
|
||||
</a>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
style="background-color: rgb(135, 208, 104);"
|
||||
>
|
||||
@ -767,6 +772,7 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
Ant User
|
||||
@ -824,6 +830,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="color: rgb(245, 106, 0); background-color: rgb(253, 227, 207);"
|
||||
>
|
||||
@ -847,12 +854,14 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner-content"
|
||||
>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
style="background-color: rgb(135, 208, 104);"
|
||||
>
|
||||
@ -889,6 +898,7 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
Ant User
|
||||
@ -950,6 +960,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle"
|
||||
style="color: rgb(245, 106, 0); background-color: rgb(253, 227, 207);"
|
||||
>
|
||||
@ -973,12 +984,14 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner-content"
|
||||
>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle ant-avatar-icon"
|
||||
style="background-color: rgb(135, 208, 104);"
|
||||
>
|
||||
@ -1015,6 +1028,7 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
Ant User
|
||||
@ -1076,6 +1090,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle"
|
||||
style="color: rgb(245, 106, 0); background-color: rgb(253, 227, 207); cursor: pointer;"
|
||||
>
|
||||
@ -1099,12 +1114,14 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-inner-content"
|
||||
>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle ant-avatar-icon"
|
||||
style="background-color: rgb(135, 208, 104);"
|
||||
>
|
||||
@ -1141,6 +1158,7 @@ Array [
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
Ant User
|
||||
|
@ -437,6 +437,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="color:#f56a00;background-color:#fde3cf"
|
||||
>
|
||||
@ -632,6 +633,7 @@ Array [
|
||||
</span>
|
||||
</a>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
style="background-color:#87d068"
|
||||
>
|
||||
@ -706,6 +708,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="color:#f56a00;background-color:#fde3cf"
|
||||
>
|
||||
@ -743,6 +746,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle"
|
||||
style="color:#f56a00;background-color:#fde3cf"
|
||||
>
|
||||
@ -780,6 +784,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle"
|
||||
style="color:#f56a00;background-color:#fde3cf;cursor:pointer"
|
||||
>
|
||||
|
@ -102,7 +102,10 @@ const Group: React.FC<GroupProps> = (props) => {
|
||||
);
|
||||
|
||||
const childrenWithProps = toArray(children).map((child, index) =>
|
||||
cloneElement(child, { key: `avatar-key-${index}` }),
|
||||
cloneElement(child, {
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key: `avatar-key-${index}`,
|
||||
}),
|
||||
);
|
||||
|
||||
const mergeCount = max?.count || maxCount;
|
||||
@ -118,7 +121,7 @@ const Group: React.FC<GroupProps> = (props) => {
|
||||
const mergeProps = {
|
||||
content: childrenHidden,
|
||||
...max?.popover,
|
||||
overlayClassName: classNames(`${groupPrefixCls}-popover`, max?.popover?.overlayClassName),
|
||||
classNames: { root: classNames(`${groupPrefixCls}-popover`, max?.popover?.classNames?.root) },
|
||||
placement: mergePopoverPlacement,
|
||||
trigger: mergePopoverTrigger,
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ export interface ScrollNumberProps {
|
||||
className?: string;
|
||||
motionClassName?: string;
|
||||
count?: string | number | null;
|
||||
children?: React.ReactElement<HTMLElement>;
|
||||
children?: React.ReactElement;
|
||||
component?: React.ComponentType<any>;
|
||||
style?: React.CSSProperties;
|
||||
title?: string | number | null;
|
||||
|
@ -79,23 +79,29 @@ const SingleNumber: React.FC<Readonly<SingleNumberProps>> = (props) => {
|
||||
unitNumberList.push(index);
|
||||
}
|
||||
|
||||
const unit = prevCount < count ? 1 : -1;
|
||||
|
||||
// Fill with number unit nodes
|
||||
const prevIndex = unitNumberList.findIndex((n) => n % 10 === prevValue);
|
||||
unitNodes = unitNumberList.map((n, index) => {
|
||||
|
||||
// Cut list
|
||||
const cutUnitNumberList =
|
||||
unit < 0 ? unitNumberList.slice(0, prevIndex + 1) : unitNumberList.slice(prevIndex);
|
||||
|
||||
unitNodes = cutUnitNumberList.map((n, index) => {
|
||||
const singleUnit = n % 10;
|
||||
return (
|
||||
<UnitNumber
|
||||
{...props}
|
||||
key={n}
|
||||
value={singleUnit}
|
||||
offset={index - prevIndex}
|
||||
offset={unit < 0 ? index - prevIndex : index}
|
||||
current={index === prevIndex}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
// Calculate container offset value
|
||||
const unit = prevCount < count ? 1 : -1;
|
||||
offsetStyle = {
|
||||
transform: `translateY(${-getOffset(prevValue, value, unit)}00%)`,
|
||||
};
|
||||
|
@ -305,60 +305,6 @@ exports[`Badge should render when count is changed 1`] = `
|
||||
>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -900%; left: 0px;"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -800%; left: 0px;"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -700%; left: 0px;"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -600%; left: 0px;"
|
||||
>
|
||||
3
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -500%; left: 0px;"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -400%; left: 0px;"
|
||||
>
|
||||
5
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -300%; left: 0px;"
|
||||
>
|
||||
6
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -200%; left: 0px;"
|
||||
>
|
||||
7
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -100%; left: 0px;"
|
||||
>
|
||||
8
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit current"
|
||||
>
|
||||
9
|
||||
</span>
|
||||
@ -400,60 +346,6 @@ exports[`Badge should render when count is changed 2`] = `
|
||||
>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -900%; left: 0px;"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -800%; left: 0px;"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -700%; left: 0px;"
|
||||
>
|
||||
3
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -600%; left: 0px;"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -500%; left: 0px;"
|
||||
>
|
||||
5
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -400%; left: 0px;"
|
||||
>
|
||||
6
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -300%; left: 0px;"
|
||||
>
|
||||
7
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -200%; left: 0px;"
|
||||
>
|
||||
8
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: -100%; left: 0px;"
|
||||
>
|
||||
9
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit current"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
@ -495,7 +387,6 @@ exports[`Badge should render when count is changed 3`] = `
|
||||
>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit current"
|
||||
style=""
|
||||
>
|
||||
1
|
||||
</span>
|
||||
@ -579,60 +470,6 @@ exports[`Badge should render when count is changed 6`] = `
|
||||
>
|
||||
0
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 100%; left: 0px;"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 200%; left: 0px;"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 300%; left: 0px;"
|
||||
>
|
||||
3
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 400%; left: 0px;"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 500%; left: 0px;"
|
||||
>
|
||||
5
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 600%; left: 0px;"
|
||||
>
|
||||
6
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 700%; left: 0px;"
|
||||
>
|
||||
7
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 800%; left: 0px;"
|
||||
>
|
||||
8
|
||||
</span>
|
||||
<span
|
||||
class="ant-scroll-number-only-unit"
|
||||
style="position: absolute; top: 900%; left: 0px;"
|
||||
>
|
||||
9
|
||||
</span>
|
||||
</span>
|
||||
</bdi>
|
||||
</sup>
|
||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||
import type { GetRef } from '../../_util/type';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||
import { act, fireEvent, render, waitFakeTimer19 } from '../../../tests/utils';
|
||||
import Tooltip from '../../tooltip';
|
||||
import Badge from '../index';
|
||||
|
||||
@ -50,7 +50,7 @@ describe('Badge', () => {
|
||||
const { container } = render(<Comp />);
|
||||
|
||||
fireEvent.click(container.querySelector('button')!);
|
||||
await waitFakeTimer();
|
||||
await waitFakeTimer19();
|
||||
|
||||
expect(errSpy).not.toHaveBeenCalled();
|
||||
errSpy.mockRestore();
|
||||
|
@ -26,7 +26,7 @@ export interface BreadcrumbItemType {
|
||||
*/
|
||||
path?: string;
|
||||
title?: React.ReactNode;
|
||||
/* @deprecated Please use `title` instead */
|
||||
/** @deprecated Please use `title` instead */
|
||||
breadcrumbName?: string;
|
||||
menu?: BreadcrumbItemProps['menu'];
|
||||
/** @deprecated Please use `menu` instead */
|
||||
@ -199,6 +199,7 @@ const Breadcrumb = <T extends AnyObject = AnyObject>(props: BreadcrumbProps<T>)
|
||||
const isLastItem = index === childrenLength - 1;
|
||||
return cloneElement(element, {
|
||||
separator: isLastItem ? '' : separator,
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key: index,
|
||||
});
|
||||
});
|
||||
|
@ -144,6 +144,7 @@ exports[`renders components/breadcrumb/demo/component-token.tsx extend context c
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-1"
|
||||
role="menuitem"
|
||||
@ -174,11 +175,13 @@ exports[`renders components/breadcrumb/demo/component-token.tsx extend context c
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-2"
|
||||
role="menuitem"
|
||||
@ -209,11 +212,13 @@ exports[`renders components/breadcrumb/demo/component-token.tsx extend context c
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-3"
|
||||
role="menuitem"
|
||||
@ -244,6 +249,7 @@ exports[`renders components/breadcrumb/demo/component-token.tsx extend context c
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
@ -402,6 +408,7 @@ exports[`renders components/breadcrumb/demo/debug-routes.tsx extend context corr
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-0"
|
||||
role="menuitem"
|
||||
@ -430,11 +437,13 @@ exports[`renders components/breadcrumb/demo/debug-routes.tsx extend context corr
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-1"
|
||||
role="menuitem"
|
||||
@ -463,6 +472,7 @@ exports[`renders components/breadcrumb/demo/debug-routes.tsx extend context corr
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
@ -563,6 +573,7 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-1"
|
||||
role="menuitem"
|
||||
@ -593,11 +604,13 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-2"
|
||||
role="menuitem"
|
||||
@ -628,11 +641,13 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
aria-describedby="test-id"
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
data-menu-id="rc-menu-uuid-test-3"
|
||||
role="menuitem"
|
||||
@ -663,6 +678,7 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`react router react router 3 1`] = `
|
||||
exports[`react router react router legacy 1`] = `
|
||||
<nav
|
||||
class="ant-breadcrumb"
|
||||
>
|
||||
|
@ -1,29 +1,10 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RouterProps } from 'react-router-dom';
|
||||
import { Link, MemoryRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
import { MemoryRouter, useLocation } from 'react-router-dom';
|
||||
import type { Location as ReactRouterLocation } from 'react-router-dom';
|
||||
|
||||
import { fireEvent, render } from '../../../tests/utils';
|
||||
import { render } from '../../../tests/utils';
|
||||
import Breadcrumb from '../index';
|
||||
|
||||
const Apps: React.FC = () => (
|
||||
<ul className="app-list">
|
||||
<li>
|
||||
<Link to="/apps/1">Application1</Link>:<Link to="/apps/1/detail">Detail</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/apps/2">Application2</Link>:<Link to="/apps/2/detail">Detail</Link>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
|
||||
const breadcrumbNameMap = {
|
||||
'/apps': 'Application List',
|
||||
'/apps/1': 'Application1',
|
||||
'/apps/2': 'Application2',
|
||||
'/apps/1/detail': 'Detail',
|
||||
'/apps/2/detail': 'Detail',
|
||||
};
|
||||
|
||||
describe('react router', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
@ -33,63 +14,37 @@ describe('react router', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('react router 6', () => {
|
||||
const Home: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const pathSnippets = location.pathname.split('/').filter((i) => i);
|
||||
const extraBreadcrumbItems = pathSnippets.map((_, index) => {
|
||||
const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
|
||||
return (
|
||||
<Breadcrumb.Item key={url}>
|
||||
<Link to={url}>{breadcrumbNameMap[url as keyof typeof breadcrumbNameMap]}</Link>
|
||||
</Breadcrumb.Item>
|
||||
);
|
||||
});
|
||||
const breadcrumbItems = [
|
||||
<Breadcrumb.Item key="home">
|
||||
<Link to="/">Home</Link>
|
||||
</Breadcrumb.Item>,
|
||||
].concat(extraBreadcrumbItems);
|
||||
const componentProps = useMemo<RouterProps>(
|
||||
() => ({ component: Apps }) as unknown as RouterProps,
|
||||
[],
|
||||
);
|
||||
const renderProps = useMemo<RouterProps>(
|
||||
() => ({ render: () => <span>Home Page</span> }) as unknown as RouterProps,
|
||||
[],
|
||||
);
|
||||
return (
|
||||
<div className="demo">
|
||||
<div className="demo-nav">
|
||||
<a onClick={() => navigate('/')}>Home</a>
|
||||
<a onClick={() => navigate('/apps')}>Application List</a>
|
||||
</div>
|
||||
<Routes>
|
||||
<Route path="/apps" {...componentProps} />
|
||||
<Route {...renderProps} />
|
||||
</Routes>
|
||||
<Breadcrumb>{breadcrumbItems}</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
it('memoizes the current location', () => {
|
||||
let location1: ReactRouterLocation | undefined;
|
||||
const CaptureLocation1: React.FC = () => {
|
||||
location1 = useLocation();
|
||||
return null;
|
||||
};
|
||||
const { container } = render(
|
||||
<MemoryRouter initialEntries={['/']} initialIndex={0}>
|
||||
<Home />
|
||||
const { container: container1 } = render(
|
||||
<MemoryRouter>
|
||||
<CaptureLocation1 />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-breadcrumb-link').length).toBe(1);
|
||||
expect(container.querySelectorAll('.ant-breadcrumb-link')[0].textContent).toBe('Home');
|
||||
expect(container1).toBeTruthy();
|
||||
expect(location1).toBeDefined();
|
||||
|
||||
fireEvent.click(container.querySelectorAll('.demo-nav a')[1]);
|
||||
|
||||
expect(container.querySelectorAll('.ant-breadcrumb-link').length).toBe(2);
|
||||
expect(container.querySelectorAll('.ant-breadcrumb-link')[1].textContent).toBe(
|
||||
'Application List',
|
||||
let location2: ReactRouterLocation | undefined;
|
||||
const CaptureLocation2: React.FC = () => {
|
||||
location2 = useLocation();
|
||||
return null;
|
||||
};
|
||||
const { container: container2 } = render(
|
||||
<MemoryRouter>
|
||||
<CaptureLocation2 />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
expect(container2).toBeTruthy();
|
||||
expect(location2).toBeDefined();
|
||||
|
||||
expect(location1).toEqual(location2);
|
||||
});
|
||||
|
||||
it('react router 3', () => {
|
||||
it('react router legacy', () => {
|
||||
const routes = [
|
||||
{
|
||||
name: 'home',
|
||||
|
@ -23,12 +23,13 @@ const InnerLoadingIcon = forwardRef<HTMLSpanElement, InnerLoadingIconProps>((pro
|
||||
);
|
||||
});
|
||||
|
||||
export type LoadingIconProps = {
|
||||
export type DefaultLoadingIconProps = {
|
||||
prefixCls: string;
|
||||
existIcon: boolean;
|
||||
loading?: boolean | object;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
mount: boolean;
|
||||
};
|
||||
|
||||
const getCollapsedWidth = (): React.CSSProperties => ({
|
||||
@ -43,8 +44,8 @@ const getRealWidth = (node: HTMLElement): React.CSSProperties => ({
|
||||
transform: 'scale(1)',
|
||||
});
|
||||
|
||||
const LoadingIcon: React.FC<LoadingIconProps> = (props) => {
|
||||
const { prefixCls, loading, existIcon, className, style } = props;
|
||||
const DefaultLoadingIcon: React.FC<DefaultLoadingIconProps> = (props) => {
|
||||
const { prefixCls, loading, existIcon, className, style, mount } = props;
|
||||
const visible = !!loading;
|
||||
|
||||
if (existIcon) {
|
||||
@ -54,9 +55,11 @@ const LoadingIcon: React.FC<LoadingIconProps> = (props) => {
|
||||
return (
|
||||
<CSSMotion
|
||||
visible={visible}
|
||||
// We do not really use this motionName
|
||||
// Used for minus flex gap style only
|
||||
motionName={`${prefixCls}-loading-icon-motion`}
|
||||
motionLeave={visible}
|
||||
motionAppear={!mount}
|
||||
motionEnter={!mount}
|
||||
motionLeave={!mount}
|
||||
removeOnLeave
|
||||
onAppearStart={getCollapsedWidth}
|
||||
onAppearActive={getRealWidth}
|
||||
@ -65,17 +68,20 @@ const LoadingIcon: React.FC<LoadingIconProps> = (props) => {
|
||||
onLeaveStart={getRealWidth}
|
||||
onLeaveActive={getCollapsedWidth}
|
||||
>
|
||||
{({ className: motionCls, style: motionStyle }, ref: React.Ref<HTMLSpanElement>) => (
|
||||
<InnerLoadingIcon
|
||||
prefixCls={prefixCls}
|
||||
className={className}
|
||||
style={{ ...style, ...motionStyle }}
|
||||
ref={ref}
|
||||
iconClassName={motionCls}
|
||||
/>
|
||||
)}
|
||||
{({ className: motionCls, style: motionStyle }, ref: React.Ref<HTMLSpanElement>) => {
|
||||
const mergedStyle = { ...style, ...motionStyle };
|
||||
|
||||
return (
|
||||
<InnerLoadingIcon
|
||||
prefixCls={prefixCls}
|
||||
className={classNames(className, motionCls)}
|
||||
style={mergedStyle}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</CSSMotion>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingIcon;
|
||||
export default DefaultLoadingIcon;
|
File diff suppressed because it is too large
Load Diff
@ -301,12 +301,35 @@ exports[`renders components/button/demo/chinese-chars-loading.tsx correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/button/demo/chinese-space.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
确定
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
确 定
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/button/demo/color-variant.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-small ant-flex-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-middle"
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-solid ant-btn-sm"
|
||||
@ -358,7 +381,7 @@ exports[`renders components/button/demo/color-variant.tsx correctly 1`] = `
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-middle"
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-primary ant-btn-variant-solid ant-btn-sm"
|
||||
@ -410,7 +433,7 @@ exports[`renders components/button/demo/color-variant.tsx correctly 1`] = `
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-middle"
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-dangerous ant-btn-variant-solid ant-btn-sm"
|
||||
@ -461,6 +484,162 @@ exports[`renders components/button/demo/color-variant.tsx correctly 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-pink ant-btn-variant-solid ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Solid
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-pink ant-btn-variant-outlined ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Outlined
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-pink ant-btn-variant-dashed ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Dashed
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-pink ant-btn-variant-filled ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Filled
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-pink ant-btn-variant-text ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Text
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-pink ant-btn-variant-link ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Link
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-purple ant-btn-variant-solid ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Solid
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-purple ant-btn-variant-outlined ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Outlined
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-purple ant-btn-variant-dashed ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Dashed
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-purple ant-btn-variant-filled ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Filled
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-purple ant-btn-variant-text ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Text
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-purple ant-btn-variant-link ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Link
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-cyan ant-btn-variant-solid ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Solid
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-cyan ant-btn-variant-outlined ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Outlined
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-cyan ant-btn-variant-dashed ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Dashed
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-cyan ant-btn-variant-filled ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Filled
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-cyan ant-btn-variant-text ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Text
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-cyan ant-btn-variant-link ant-btn-sm"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Link
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -577,7 +756,7 @@ exports[`renders components/button/demo/debug-block.tsx correctly 1`] = `
|
||||
|
||||
exports[`renders components/button/demo/debug-color-variant.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-small ant-flex-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-gap-small"
|
||||
@ -704,6 +883,7 @@ Array [
|
||||
<input
|
||||
checked=""
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="large"
|
||||
/>
|
||||
@ -711,7 +891,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
Large
|
||||
</span>
|
||||
</label>
|
||||
@ -723,6 +905,7 @@ Array [
|
||||
>
|
||||
<input
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="default"
|
||||
/>
|
||||
@ -730,7 +913,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
Default
|
||||
</span>
|
||||
</label>
|
||||
@ -742,6 +927,7 @@ Array [
|
||||
>
|
||||
<input
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="small"
|
||||
/>
|
||||
@ -749,7 +935,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
Small
|
||||
</span>
|
||||
</label>
|
||||
@ -771,6 +959,7 @@ Array [
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -838,6 +1027,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -901,6 +1091,7 @@ Array [
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -960,6 +1151,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-dashed ant-btn-color-default ant-btn-variant-dashed ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1022,6 +1214,7 @@ Array [
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg ant-btn-icon-only"
|
||||
href="https://www.google.com"
|
||||
tabindex="0"
|
||||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
@ -1075,6 +1268,297 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-center ant-divider-plain"
|
||||
role="separator"
|
||||
>
|
||||
<span
|
||||
class="ant-divider-inner-text"
|
||||
>
|
||||
👇🏻 https://github.com/ant-design/ant-design/issues/51811 👇🏻
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
without icon
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
with icon
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-center ant-divider-plain"
|
||||
role="separator"
|
||||
>
|
||||
<span
|
||||
class="ant-divider-inner-text"
|
||||
>
|
||||
👇🏻 https://github.com/ant-design/ant-design/issues/52124 👇🏻
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg"
|
||||
style="height:60px"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
without icon
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg"
|
||||
style="height:60px"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
with icon
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-center ant-divider-plain"
|
||||
role="separator"
|
||||
>
|
||||
<span
|
||||
class="ant-divider-inner-text"
|
||||
>
|
||||
👇🏻 https://github.com/ant-design/ant-design/issues/51380 👇🏻
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
class="my-class-name"
|
||||
fill="none"
|
||||
height="1em"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 3h7a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-7m0-18H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h7m0-18v18"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="1em"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 3h7a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-7m0-18H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h7m0-18v18"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span>
|
||||
custom icon
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
with icon
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
without icon
|
||||
</span>
|
||||
</button>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-group-wrapper-outlined ant-input-search ant-input-search-large"
|
||||
style="width:100px"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-lg ant-input-outlined"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg ant-btn-icon-only ant-input-search-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-center ant-divider-plain"
|
||||
role="separator"
|
||||
>
|
||||
<span
|
||||
class="ant-divider-inner-text"
|
||||
>
|
||||
👇🏻 https://github.com/ant-design/ant-design/issues/51380 👇🏻
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-gap-small"
|
||||
style="transform:scale(3);transform-origin:left top"
|
||||
@ -1415,6 +1899,7 @@ exports[`renders components/button/demo/icon.tsx correctly 1`] = `
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1482,6 +1967,7 @@ exports[`renders components/button/demo/icon.tsx correctly 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1545,6 +2031,7 @@ exports[`renders components/button/demo/icon.tsx correctly 1`] = `
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1604,6 +2091,7 @@ exports[`renders components/button/demo/icon.tsx correctly 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-dashed ant-btn-color-default ant-btn-variant-dashed ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1666,6 +2154,7 @@ exports[`renders components/button/demo/icon.tsx correctly 1`] = `
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-icon-only"
|
||||
href="https://www.google.com"
|
||||
tabindex="0"
|
||||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
@ -1714,6 +2203,7 @@ Array [
|
||||
>
|
||||
<input
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="start"
|
||||
/>
|
||||
@ -1721,7 +2211,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
start
|
||||
</span>
|
||||
</label>
|
||||
@ -1734,6 +2226,7 @@ Array [
|
||||
<input
|
||||
checked=""
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="end"
|
||||
/>
|
||||
@ -1741,7 +2234,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
end
|
||||
</span>
|
||||
</label>
|
||||
@ -1765,6 +2260,7 @@ Array [
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1832,6 +2328,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1895,6 +2392,7 @@ Array [
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -1954,6 +2452,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-circle ant-btn-dashed ant-btn-color-default ant-btn-variant-dashed ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -2016,6 +2515,7 @@ Array [
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-icon-only ant-btn-icon-end"
|
||||
href="https://www.google.com"
|
||||
tabindex="0"
|
||||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
@ -2099,6 +2599,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-sm ant-btn-icon-only"
|
||||
disabled=""
|
||||
type="button"
|
||||
@ -2128,6 +2629,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-sm ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -2177,6 +2679,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only"
|
||||
disabled=""
|
||||
type="button"
|
||||
@ -2206,6 +2709,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -2255,6 +2759,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-lg ant-btn-icon-only"
|
||||
disabled=""
|
||||
type="button"
|
||||
@ -2284,6 +2789,7 @@ Array [
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-describedby="test-id"
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
@ -2323,7 +2829,7 @@ exports[`renders components/button/demo/linear-gradient.tsx correctly 1`] = `
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-lg acss-9mi5l3"
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-lg acss-wkbm77"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
@ -2358,7 +2864,7 @@ exports[`renders components/button/demo/linear-gradient.tsx correctly 1`] = `
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg acss-9mi5l3"
|
||||
class="ant-btn ant-btn-default ant-btn-color-default ant-btn-variant-outlined ant-btn-lg acss-wkbm77"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
@ -2466,6 +2972,37 @@ exports[`renders components/button/demo/loading.tsx correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-loading"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="sync"
|
||||
class="anticon anticon-sync anticon-spin"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="sync"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M168 504.2c1-43.7 10-86.1 26.9-126 17.3-41 42.1-77.7 73.7-109.4S337 212.3 378 195c42.4-17.9 87.4-27 133.9-27s91.5 9.1 133.8 27A341.5 341.5 0 01755 268.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.7 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c0-6.7-7.7-10.5-12.9-6.3l-56.4 44.1C765.8 155.1 646.2 92 511.8 92 282.7 92 96.3 275.6 92 503.8a8 8 0 008 8.2h60c4.4 0 7.9-3.5 8-7.8zm756 7.8h-60c-4.4 0-7.9 3.5-8 7.8-1 43.7-10 86.1-26.9 126-17.3 41-42.1 77.8-73.7 109.4A342.45 342.45 0 01512.1 856a342.24 342.24 0 01-243.2-100.8c-9.9-9.9-19.2-20.4-27.8-31.4l60.2-47a8 8 0 00-3-14.1l-175.7-43c-5-1.2-9.9 2.6-9.9 7.7l-.7 181c0 6.7 7.7 10.5 12.9 6.3l56.4-44.1C258.2 868.9 377.8 932 512.2 932c229.2 0 415.5-183.7 419.8-411.8a8 8 0 00-8-8.2z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
Loading Icon
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"
|
||||
@ -2475,7 +3012,15 @@ exports[`renders components/button/demo/loading.tsx correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Click me!
|
||||
Icon Start
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-end"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Icon End
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
@ -2506,7 +3051,7 @@ exports[`renders components/button/demo/loading.tsx correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
Click me!
|
||||
Icon Replace
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
@ -2537,6 +3082,37 @@ exports[`renders components/button/demo/loading.tsx correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="poweroff"
|
||||
class="anticon anticon-poweroff"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="poweroff"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M705.6 124.9a8 8 0 00-11.6 7.2v64.2c0 5.5 2.9 10.6 7.5 13.6a352.2 352.2 0 0162.2 49.8c32.7 32.8 58.4 70.9 76.3 113.3a355 355 0 0127.9 138.7c0 48.1-9.4 94.8-27.9 138.7a355.92 355.92 0 01-76.3 113.3 353.06 353.06 0 01-113.2 76.4c-43.8 18.6-90.5 28-138.5 28s-94.7-9.4-138.5-28a353.06 353.06 0 01-113.2-76.4A355.92 355.92 0 01184 650.4a355 355 0 01-27.9-138.7c0-48.1 9.4-94.8 27.9-138.7 17.9-42.4 43.6-80.5 76.3-113.3 19-19 39.8-35.6 62.2-49.8 4.7-2.9 7.5-8.1 7.5-13.6V132c0-6-6.3-9.8-11.6-7.2C178.5 195.2 82 339.3 80 506.3 77.2 745.1 272.5 943.5 511.2 944c239 .5 432.8-193.3 432.8-432.4 0-169.2-97-315.7-238.4-386.7zM480 560h64c4.4 0 8-3.6 8-8V88c0-4.4-3.6-8-8-8h-64c-4.4 0-8 3.6-8 8v464c0 4.4 3.6 8 8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
Loading Icon
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -2604,29 +3180,6 @@ exports[`renders components/button/demo/multiple.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/button/demo/noSpace.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-middle"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
确定
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-color-primary ant-btn-variant-solid"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
确 定
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/button/demo/size.tsx correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
@ -2641,6 +3194,7 @@ Array [
|
||||
<input
|
||||
checked=""
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="large"
|
||||
/>
|
||||
@ -2648,7 +3202,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
Large
|
||||
</span>
|
||||
</label>
|
||||
@ -2660,6 +3216,7 @@ Array [
|
||||
>
|
||||
<input
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="default"
|
||||
/>
|
||||
@ -2667,7 +3224,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
Default
|
||||
</span>
|
||||
</label>
|
||||
@ -2679,6 +3238,7 @@ Array [
|
||||
>
|
||||
<input
|
||||
class="ant-radio-button-input"
|
||||
name="test-id"
|
||||
type="radio"
|
||||
value="small"
|
||||
/>
|
||||
@ -2686,7 +3246,9 @@ Array [
|
||||
class="ant-radio-button-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-radio-button-label"
|
||||
>
|
||||
Small
|
||||
</span>
|
||||
</label>
|
||||
|
@ -177,11 +177,10 @@ exports[`Button renders Chinese characters correctly 6`] = `
|
||||
>
|
||||
<span
|
||||
class="ant-btn-icon ant-btn-loading-icon"
|
||||
style="width: 0px; opacity: 0; transform: scale(0);"
|
||||
>
|
||||
<span
|
||||
aria-label="loading"
|
||||
class="anticon anticon-loading anticon-spin ant-btn-loading-icon-motion-appear ant-btn-loading-icon-motion-appear-start ant-btn-loading-icon-motion"
|
||||
class="anticon anticon-loading anticon-spin"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
|
@ -2,13 +2,14 @@ import React, { Suspense, useRef, useState } from 'react';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { resetWarned } from 'rc-util/lib/warning';
|
||||
|
||||
import Button from '..';
|
||||
import Button, { _ButtonVariantTypes } from '..';
|
||||
import type { GetRef } from '../../_util/type';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import theme from '../../theme';
|
||||
import { PresetColors } from '../../theme/interface';
|
||||
import type { BaseButtonProps } from '../button';
|
||||
|
||||
describe('Button', () => {
|
||||
@ -474,4 +475,24 @@ describe('Button', () => {
|
||||
'--ant-button-solid-text-color': '#000',
|
||||
});
|
||||
});
|
||||
|
||||
it('should render preset colors and variants correctly', () => {
|
||||
PresetColors.forEach((color) => {
|
||||
_ButtonVariantTypes.forEach((variant) => {
|
||||
const { container } = render(
|
||||
<Button color={color} variant={variant}>
|
||||
{color}
|
||||
</Button>,
|
||||
);
|
||||
expect(container.firstChild).toHaveClass(`ant-btn-color-${color}`);
|
||||
expect(container.firstChild).toHaveClass(`ant-btn-variant-${variant}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('autoFocus should work', () => {
|
||||
const { container } = render(<Button autoFocus>button</Button>);
|
||||
|
||||
expect(container.querySelector('button')).toBe(document.activeElement);
|
||||
});
|
||||
});
|
||||
|
@ -4,6 +4,18 @@ import userEvent from '@testing-library/user-event';
|
||||
import Button from '..';
|
||||
import { act, fireEvent, render } from '../../../tests/utils';
|
||||
|
||||
// TODO: Remove this. Mock for React 19
|
||||
jest.mock('react-dom', () => {
|
||||
const realReactDOM = jest.requireActual('react-dom');
|
||||
|
||||
if (realReactDOM.version.startsWith('19')) {
|
||||
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||
}
|
||||
|
||||
return realReactDOM;
|
||||
});
|
||||
|
||||
jest.mock('rc-util/lib/Dom/isVisible', () => {
|
||||
const mockFn = () => true;
|
||||
return mockFn;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { Children, createRef, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import React, { Children, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import { composeRef } from 'rc-util/lib/ref';
|
||||
import { useComposeRef } from 'rc-util/lib/ref';
|
||||
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import Wave from '../_util/wave';
|
||||
@ -20,9 +20,9 @@ import type {
|
||||
} from './buttonHelpers';
|
||||
import { isTwoCNChar, isUnBorderedButtonVariant, spaceChildren } from './buttonHelpers';
|
||||
import IconWrapper from './IconWrapper';
|
||||
import LoadingIcon from './LoadingIcon';
|
||||
import DefaultLoadingIcon from './DefaultLoadingIcon';
|
||||
import useStyle from './style';
|
||||
import CompactCmp from './style/compactCmp';
|
||||
import Compact from './style/compact';
|
||||
|
||||
export type LegacyButtonType = ButtonType | 'danger';
|
||||
|
||||
@ -35,7 +35,7 @@ export interface BaseButtonProps {
|
||||
shape?: ButtonShape;
|
||||
size?: SizeType;
|
||||
disabled?: boolean;
|
||||
loading?: boolean | { delay?: number };
|
||||
loading?: boolean | { delay?: number; icon?: React.ReactNode };
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
rootClassName?: string;
|
||||
@ -119,6 +119,7 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
classNames: customClassNames,
|
||||
style: customStyle = {},
|
||||
autoInsertSpace,
|
||||
autoFocus,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
@ -162,13 +163,26 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
|
||||
const [hasTwoCNChar, setHasTwoCNChar] = useState<boolean>(false);
|
||||
|
||||
const internalRef = createRef<HTMLButtonElement | HTMLAnchorElement>();
|
||||
const buttonRef = useRef<HTMLButtonElement | HTMLAnchorElement>(null);
|
||||
|
||||
const buttonRef = composeRef(ref, internalRef);
|
||||
const mergedRef = useComposeRef(ref, buttonRef);
|
||||
|
||||
const needInserted =
|
||||
Children.count(children) === 1 && !icon && !isUnBorderedButtonVariant(mergedVariant);
|
||||
|
||||
// ========================= Mount ==========================
|
||||
// Record for mount status.
|
||||
// This will help to no to show the animation of loading on the first mount.
|
||||
const isMountRef = useRef(true);
|
||||
React.useEffect(() => {
|
||||
isMountRef.current = false;
|
||||
return () => {
|
||||
isMountRef.current = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// ========================= Effect =========================
|
||||
// Loading
|
||||
useEffect(() => {
|
||||
let delayTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
if (loadingOrDelay.delay > 0) {
|
||||
@ -190,12 +204,13 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
return cleanupTimer;
|
||||
}, [loadingOrDelay]);
|
||||
|
||||
// Two chinese characters check
|
||||
useEffect(() => {
|
||||
// FIXME: for HOC usage like <FormatMessage />
|
||||
if (!buttonRef || !(buttonRef as any).current || !mergedInsertSpace) {
|
||||
if (!buttonRef.current || !mergedInsertSpace) {
|
||||
return;
|
||||
}
|
||||
const buttonText = (buttonRef as any).current.textContent;
|
||||
const buttonText = buttonRef.current.textContent || '';
|
||||
if (needInserted && isTwoCNChar(buttonText)) {
|
||||
if (!hasTwoCNChar) {
|
||||
setHasTwoCNChar(true);
|
||||
@ -203,8 +218,16 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
} else if (hasTwoCNChar) {
|
||||
setHasTwoCNChar(false);
|
||||
}
|
||||
}, [buttonRef]);
|
||||
});
|
||||
|
||||
// Auto focus
|
||||
useEffect(() => {
|
||||
if (autoFocus && buttonRef.current) {
|
||||
buttonRef.current.focus();
|
||||
}
|
||||
}, []);
|
||||
|
||||
// ========================= Events =========================
|
||||
const handleClick = React.useCallback(
|
||||
(e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => {
|
||||
// FIXME: https://github.com/ant-design/ant-design/issues/30207
|
||||
@ -217,6 +240,7 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
[props.onClick, innerLoading, mergedDisabled],
|
||||
);
|
||||
|
||||
// ========================== Warn ==========================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Button');
|
||||
|
||||
@ -233,6 +257,7 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
);
|
||||
}
|
||||
|
||||
// ========================== Size ==========================
|
||||
const { compactSize, compactItemClassnames } = useCompactItemContext(prefixCls, direction);
|
||||
|
||||
const sizeClassNameMap = { large: 'lg', small: 'sm', middle: undefined };
|
||||
@ -245,6 +270,7 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
|
||||
const linkButtonRestProps = omit(rest as ButtonProps & { navigate: any }, ['navigate']);
|
||||
|
||||
// ========================= Render =========================
|
||||
const classes = classNames(
|
||||
prefixCls,
|
||||
hashId,
|
||||
@ -284,8 +310,17 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
<IconWrapper prefixCls={prefixCls} className={iconClasses} style={iconStyle}>
|
||||
{icon}
|
||||
</IconWrapper>
|
||||
) : typeof loading === 'object' && loading.icon ? (
|
||||
<IconWrapper prefixCls={prefixCls} className={iconClasses} style={iconStyle}>
|
||||
{loading.icon}
|
||||
</IconWrapper>
|
||||
) : (
|
||||
<LoadingIcon existIcon={!!icon} prefixCls={prefixCls} loading={innerLoading} />
|
||||
<DefaultLoadingIcon
|
||||
existIcon={!!icon}
|
||||
prefixCls={prefixCls}
|
||||
loading={innerLoading}
|
||||
mount={isMountRef.current}
|
||||
/>
|
||||
);
|
||||
|
||||
const kids =
|
||||
@ -301,7 +336,7 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
href={mergedDisabled ? undefined : linkButtonRestProps.href}
|
||||
style={fullStyle}
|
||||
onClick={handleClick}
|
||||
ref={buttonRef as React.Ref<HTMLAnchorElement>}
|
||||
ref={mergedRef as React.Ref<HTMLAnchorElement>}
|
||||
tabIndex={mergedDisabled ? -1 : 0}
|
||||
>
|
||||
{iconNode}
|
||||
@ -318,12 +353,11 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
style={fullStyle}
|
||||
onClick={handleClick}
|
||||
disabled={mergedDisabled}
|
||||
ref={buttonRef as React.Ref<HTMLButtonElement>}
|
||||
ref={mergedRef as React.Ref<HTMLButtonElement>}
|
||||
>
|
||||
{iconNode}
|
||||
{kids}
|
||||
{/* Styles: compact */}
|
||||
{!!compactItemClassnames && <CompactCmp key="compact" prefixCls={prefixCls} />}
|
||||
{compactItemClassnames && <Compact prefixCls={prefixCls} />}
|
||||
</button>
|
||||
);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { cloneElement, isFragment } from '../_util/reactNode';
|
||||
import { PresetColors } from '../theme/interface';
|
||||
import type { BaseButtonProps, LegacyButtonType } from './button';
|
||||
|
||||
const rxTwoCNChar = /^[\u4E00-\u9FA5]{2}$/;
|
||||
@ -15,7 +16,7 @@ export function convertLegacyProps(
|
||||
return { type };
|
||||
}
|
||||
|
||||
export function isString(str: any): str is string {
|
||||
export function isString(str: unknown): str is string {
|
||||
return typeof str === 'string';
|
||||
}
|
||||
|
||||
@ -34,10 +35,22 @@ function splitCNCharsBySpace(child: React.ReactElement | string | number, needIn
|
||||
typeof child !== 'string' &&
|
||||
typeof child !== 'number' &&
|
||||
isString(child.type) &&
|
||||
isTwoCNChar(child.props.children)
|
||||
isTwoCNChar(
|
||||
(
|
||||
child as React.ReactElement<{
|
||||
children: string;
|
||||
}>
|
||||
).props.children,
|
||||
)
|
||||
) {
|
||||
return cloneElement(child, {
|
||||
children: child.props.children.split('').join(SPACE),
|
||||
children: (
|
||||
child as React.ReactElement<{
|
||||
children: string;
|
||||
}>
|
||||
).props.children
|
||||
.split('')
|
||||
.join(SPACE),
|
||||
});
|
||||
}
|
||||
|
||||
@ -94,5 +107,6 @@ export const _ButtonVariantTypes = [
|
||||
] as const;
|
||||
export type ButtonVariantType = (typeof _ButtonVariantTypes)[number];
|
||||
|
||||
export const _ButtonColorTypes = ['default', 'primary', 'danger'] as const;
|
||||
export const _ButtonColorTypes = ['default', 'primary', 'danger', ...PresetColors] as const;
|
||||
|
||||
export type ButtonColorType = (typeof _ButtonColorTypes)[number];
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { Button, Flex } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Flex gap="middle" wrap>
|
||||
<Flex gap="small" wrap>
|
||||
<Button type="primary" autoInsertSpace={false}>
|
||||
确定
|
||||
</Button>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user