chore: auto merge branches (#38851)

chore: feature merge master
This commit is contained in:
github-actions[bot] 2022-11-22 09:05:37 +00:00 committed by GitHub
commit 9f2b9656d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
577 changed files with 2913 additions and 3509 deletions

View File

@ -1,23 +1,21 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const restCssPath = path.join(process.cwd(), 'components', 'style', 'reset.css');
function finalizeCompile() { function finalizeCompile() {
if (fs.existsSync(path.join(__dirname, './es'))) { if (fs.existsSync(path.join(__dirname, './es'))) {
// Build less entry file: dist/antd.less fs.copyFileSync(restCssPath, path.join(process.cwd(), 'es', 'style', 'reset.css'));
fs.copyFileSync( }
path.join(process.cwd(), 'components', 'style', 'reset.css'),
path.join(process.cwd(), 'es', 'style', 'reset.css'), if (fs.existsSync(path.join(__dirname, './lib'))) {
); fs.copyFileSync(restCssPath, path.join(process.cwd(), 'lib', 'style', 'reset.css'));
} }
} }
function finalizeDist() { function finalizeDist() {
if (fs.existsSync(path.join(__dirname, './dist'))) { if (fs.existsSync(path.join(__dirname, './dist'))) {
// Build less entry file: dist/antd.less fs.copyFileSync(restCssPath, path.join(process.cwd(), 'dist', 'reset.css'));
fs.copyFileSync(
path.join(process.cwd(), 'components', 'style', 'reset.css'),
path.join(process.cwd(), 'dist', 'reset.css'),
);
} }
} }

View File

@ -58,7 +58,7 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
}, {}); }, {});
const childItems = []; const childItems = [];
childItems.push( childItems.push(
...childrenGroup.default.map(item => ({ ...childrenGroup.default.map((item) => ({
label: ( label: (
<Link to={item.link}> <Link to={item.link}>
{before} {before}
@ -75,7 +75,7 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
type: 'group', type: 'group',
label: type, label: type,
key: type, key: type,
children: children?.map(item => ({ children: children?.map((item) => ({
label: ( label: (
<Link to={item.link}> <Link to={item.link}>
{before} {before}
@ -98,7 +98,7 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
type: 'group', type: 'group',
label: group.title, label: group.title,
key: group.title, key: group.title,
children: group.children?.map(item => ({ children: group.children?.map((item) => ({
label: ( label: (
<Link to={item.link}> <Link to={item.link}>
{before} {before}
@ -115,7 +115,7 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
} }
} else { } else {
result.push( result.push(
...group.children?.map(item => ({ ...group.children?.map((item) => ({
label: ( label: (
<Link to={item.link}> <Link to={item.link}>
{before} {before}

View File

@ -26,7 +26,7 @@ const useSiteToken = () => {
/** 80 */ /** 80 */
marginFarSM: (token.marginXXL / 3) * 5, marginFarSM: (token.marginXXL / 3) * 5,
/** 96 */ /** 96 */
marginFar: token.marginXXL * 1.8, marginFar: token.marginXXL * 2,
codeFamily: `'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace`, codeFamily: `'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace`,
}, },
}; };

View File

@ -8,14 +8,14 @@ import * as utils from '../../../theme/utils';
const locales = { const locales = {
cn: { cn: {
slogan: '助力设计开发者「更灵活」搭建出「更美」的产品,让用户「快乐工作」~', slogan: '助力设计开发者「更灵活」搭建出「更美」的产品,让用户「快乐工作」~',
start: '开始使用', start: '开始使用',
designLanguage: '设计语言', designLanguage: '设计语言',
}, },
en: { en: {
slogan: slogan:
'Help design developers "more flexible" to build "more beautiful" products, helping users to "work happily"~', 'Help designers/developers building beautiful products more flexible and working with happiness',
start: 'Get Start', start: 'Getting Started',
designLanguage: 'Design Language', designLanguage: 'Design Language',
}, },
}; };
@ -36,7 +36,7 @@ export default function Banner({ children }: BannerProps) {
{/* Banner Placeholder Motion */} {/* Banner Placeholder Motion */}
<div <div
style={{ style={{
height: 240, height: 320,
background: '#77C6FF', background: '#77C6FF',
display: 'flex', display: 'flex',
flexWrap: 'nowrap', flexWrap: 'nowrap',
@ -53,12 +53,7 @@ export default function Banner({ children }: BannerProps) {
}} }}
/> />
<video <video style={{ height: '100%', objectFit: 'contain' }} autoPlay muted loop>
style={{ height: '100%', objectFit: 'contain' }}
autoPlay
muted
loop
>
<source <source
src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*uYT7SZwhJnUAAAAAAAAAAAAADgCCAQ" src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*uYT7SZwhJnUAAAAAAAAAAAAADgCCAQ"
type="video/webm" type="video/webm"
@ -76,6 +71,7 @@ export default function Banner({ children }: BannerProps) {
backgroundRepeat: 'repeat-x', backgroundRepeat: 'repeat-x',
backgroundPosition: '0 0', backgroundPosition: '0 0',
backgroundSize: 'auto 100%', backgroundSize: 'auto 100%',
marginLeft: -1,
}} }}
/> />
</div> </div>
@ -91,7 +87,7 @@ export default function Banner({ children }: BannerProps) {
<GroupMask <GroupMask
style={{ style={{
textAlign: 'center', textAlign: 'center',
paddingTop: token.marginFar, paddingTop: token.marginFar - 16,
paddingBottom: token.marginFarSM, paddingBottom: token.marginFarSM,
}} }}
> >

View File

@ -54,7 +54,7 @@ export default function BannerRecommends({ extras = [], icons = [] }: BannerReco
> >
{first3.map((extra, index) => { {first3.map((extra, index) => {
if (!extra) { if (!extra) {
return <Skeleton />; return <Skeleton key={index} />;
} }
const icon = icons.find((icon) => icon.name === extra.source); const icon = icons.find((icon) => icon.name === extra.source);
return ( return (

View File

@ -10,7 +10,6 @@ import {
Modal, Modal,
FloatButton, FloatButton,
Progress, Progress,
ConfigProvider,
} from 'antd'; } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { CustomerServiceOutlined, QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons'; import { CustomerServiceOutlined, QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons';
@ -222,7 +221,7 @@ export default function ComponentsList() {
const tagText = type === 'new' ? locale.new : locale.update; const tagText = type === 'new' ? locale.new : locale.update;
return ( return (
<div key={index} css={styles.card} style={{ pointerEvents: 'none' }}> <div key={index} css={styles.card}>
{/* Decorator */} {/* Decorator */}
<div <div
css={styles.cardCircle} css={styles.cardCircle}

View File

@ -54,7 +54,7 @@ export default function ColorPicker({ value, onChange }: RadiusPickerProps) {
const valueStr = new TinyColor(value).toRgbString(); const valueStr = new TinyColor(value).toRgbString();
let existActive = false; let existActive = false;
const colors = PRESET_COLORS.map(color => { const colors = PRESET_COLORS.map((color) => {
const colorStr = new TinyColor(color).toRgbString(); const colorStr = new TinyColor(color).toRgbString();
const active = colorStr === valueStr; const active = colorStr === valueStr;
existActive = existActive || active; existActive = existActive || active;
@ -80,7 +80,7 @@ export default function ColorPicker({ value, onChange }: RadiusPickerProps) {
<Space size="large"> <Space size="large">
<Input <Input
value={value} value={value}
onChange={event => { onChange={(event) => {
onChange?.(event.target.value); onChange?.(event.target.value);
}} }}
style={{ width: 120 }} style={{ width: 120 }}
@ -109,7 +109,10 @@ export default function ColorPicker({ value, onChange }: RadiusPickerProps) {
key={color} key={color}
overlayInnerStyle={{ padding: 0 }} overlayInnerStyle={{ padding: 0 }}
content={ content={
<DebouncedColorPanel color={value || ''} onChange={color => onChange?.(color)} /> <DebouncedColorPanel
color={value || ''}
onChange={(color) => onChange?.(color)}
/>
} }
trigger="click" trigger="click"
showArrow={false} showArrow={false}

View File

@ -14,8 +14,8 @@ export default function RadiusPicker({ value, onChange }: RadiusPickerProps) {
onChange={onChange} onChange={onChange}
style={{ width: 120 }} style={{ width: 120 }}
min={0} min={0}
formatter={val => `${val}px`} formatter={(val) => `${val}px`}
parser={str => (str ? parseFloat(str) : (str as any))} parser={(str) => (str ? parseFloat(str) : (str as any))}
/> />
<Slider <Slider

View File

@ -74,7 +74,7 @@ export default function ThemePicker({ value, onChange }: ThemePickerProps) {
return ( return (
<Space size={token.paddingLG}> <Space size={token.paddingLG}>
{Object.keys(THEMES).map(theme => { {Object.keys(THEMES).map((theme) => {
const url = THEMES[theme as THEME]; const url = THEMES[theme as THEME];
return ( return (

View File

@ -73,7 +73,7 @@ export function getAvatarURL(color?: string | null) {
} }
return ( return (
COLOR_IMAGES.find(obj => obj.color === closestColor)?.url || COLOR_IMAGES.find((obj) => obj.color === closestColor)?.url ||
'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*CLp0Qqc11AkAAAAAAAAAAAAAARQnAQ' 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*CLp0Qqc11AkAAAAAAAAAAAAAARQnAQ'
); );
} }

View File

@ -72,7 +72,7 @@ export function preLoad(list: string[]) {
const div = document.createElement('div'); const div = document.createElement('div');
div.style.display = 'none'; div.style.display = 'none';
document.body.appendChild(div); document.body.appendChild(div);
list.forEach(src => { list.forEach((src) => {
const img = new Image(); const img = new Image();
img.src = src; img.src = src;
div.appendChild(img); div.appendChild(img);
@ -88,8 +88,8 @@ export function useSiteData(): [Partial<SiteData>, boolean] {
if (Object.keys(data ?? {}).length === 0 && typeof fetch !== 'undefined') { if (Object.keys(data ?? {}).length === 0 && typeof fetch !== 'undefined') {
setLoading(true); setLoading(true);
fetch(`https://render.alipay.com/p/h5data/antd4-config_website-h5data.json`) fetch(`https://render.alipay.com/p/h5data/antd4-config_website-h5data.json`)
.then(res => res.json()) .then((res) => res.json())
.then(result => { .then((result) => {
setData(result); setData(result);
setLoading(false); setLoading(false);
}); });

View File

@ -24,7 +24,7 @@ const CustomTheme = () => {
theme={{ name: 'test', key: 'test', config: theme }} theme={{ name: 'test', key: 'test', config: theme }}
simple simple
style={{ height: 'calc(100vh - 64px)' }} style={{ height: 'calc(100vh - 64px)' }}
onThemeChange={newTheme => { onThemeChange={(newTheme) => {
setTheme(newTheme.config); setTheme(newTheme.config);
}} }}
/> />

View File

@ -6,6 +6,8 @@ import { type HastRoot, type UnifiedTransformer, unistUtilVisit } from 'dumi';
*/ */
function rehypeAntd(): UnifiedTransformer<HastRoot> { function rehypeAntd(): UnifiedTransformer<HastRoot> {
return (tree, vFile) => { return (tree, vFile) => {
const filename = (vFile.data.frontmatter as any).filename;
unistUtilVisit.visit(tree, 'element', (node) => { unistUtilVisit.visit(tree, 'element', (node) => {
if (node.tagName === 'DumiDemoGrid') { if (node.tagName === 'DumiDemoGrid') {
// replace DumiDemoGrid to DemoWrapper, to implement demo toolbar // replace DumiDemoGrid to DemoWrapper, to implement demo toolbar
@ -16,9 +18,7 @@ function rehypeAntd(): UnifiedTransformer<HastRoot> {
assert( assert(
contentNode.type === 'text', contentNode.type === 'text',
`ResourceCards content must be plain text!\nat ${ `ResourceCards content must be plain text!\nat ${filename}`,
(vFile.data.frontmatter as any).filename
}`,
); );
// clear children // clear children
@ -52,6 +52,14 @@ function rehypeAntd(): UnifiedTransformer<HastRoot> {
), ),
}, },
]; ];
} else if (
node.type === 'element' &&
node.tagName === 'Table' &&
/^components/.test(filename)
) {
if (!node.properties) return;
node.properties.className ??= [];
(node.properties.className as string[]).push('component-api-table');
} }
}); });
}; };

View File

@ -29,7 +29,6 @@ const useStyle = () => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 152px; height: 152px;
background-color: ${token.colorBgElevated};
`, `,
componentsOverviewCard: css` componentsOverviewCard: css`
cursor: pointer; cursor: pointer;
@ -68,7 +67,7 @@ const onClickCard = (pathname: string) => {
} }
}; };
const reportSearch = debounce<(value: string) => void>(value => { const reportSearch = debounce<(value: string) => void>((value) => {
if (window.gtag) { if (window.gtag) {
window.gtag('event', '搜索', { window.gtag('event', '搜索', {
event_category: '组件总览卡片', event_category: '组件总览卡片',
@ -91,7 +90,7 @@ const Overview: React.FC = () => {
const sectionRef = React.useRef<HTMLElement>(null); const sectionRef = React.useRef<HTMLElement>(null);
const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = event => { const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {
if (event.keyCode === 13 && search.trim().length) { if (event.keyCode === 13 && search.trim().length) {
sectionRef.current?.querySelector<HTMLElement>('.components-overview-card')?.click(); sectionRef.current?.querySelector<HTMLElement>('.components-overview-card')?.click();
} }
@ -99,11 +98,11 @@ const Overview: React.FC = () => {
const groups = useMemo<{ title: string; children: Component[] }[]>(() => { const groups = useMemo<{ title: string; children: Component[] }[]>(() => {
return data return data
.filter(item => item.title) .filter((item) => item.title)
.map<{ title: string; children: Component[] }>(item => { .map<{ title: string; children: Component[] }>((item) => {
return { return {
title: item.title!, title: item.title!,
children: item.children.map(child => ({ children: item.children.map((child) => ({
title: child.frontmatter.title, title: child.frontmatter.title,
subtitle: child.frontmatter.subtitle, subtitle: child.frontmatter.subtitle,
cover: child.frontmatter.cover, cover: child.frontmatter.cover,
@ -114,7 +113,10 @@ const Overview: React.FC = () => {
.concat([ .concat([
{ {
title: locale === 'zh-CN' ? '重型组件' : 'Others', title: locale === 'zh-CN' ? '重型组件' : 'Others',
children: proComponentsList, children:
locale === 'zh-CN'
? proComponentsList
: proComponentsList.map((component) => ({ ...component, subtitle: '' })),
}, },
]); ]);
}, [data, locale]); }, [data, locale]);
@ -126,7 +128,7 @@ const Overview: React.FC = () => {
value={search} value={search}
placeholder={formatMessage({ id: 'app.components.overview.search' })} placeholder={formatMessage({ id: 'app.components.overview.search' })}
css={style.componentsOverviewSearch} css={style.componentsOverviewSearch}
onChange={e => { onChange={(e) => {
setSearch(e.target.value); setSearch(e.target.value);
reportSearch(e.target.value); reportSearch(e.target.value);
}} }}
@ -136,10 +138,10 @@ const Overview: React.FC = () => {
/> />
<Divider /> <Divider />
{groups {groups
.filter(i => i.title) .filter((i) => i.title)
.map(group => { .map((group) => {
const components = group?.children?.filter( const components = group?.children?.filter(
component => (component) =>
!search.trim() || !search.trim() ||
component.title.toLowerCase().includes(search.trim().toLowerCase()) || component.title.toLowerCase().includes(search.trim().toLowerCase()) ||
(component?.subtitle || '').toLowerCase().includes(search.trim().toLowerCase()), (component?.subtitle || '').toLowerCase().includes(search.trim().toLowerCase()),
@ -153,7 +155,7 @@ const Overview: React.FC = () => {
</Space> </Space>
</Title> </Title>
<Row gutter={[24, 24]}> <Row gutter={[24, 24]}>
{components.map(component => { {components.map((component) => {
const url = `${component.link}/`; const url = `${component.link}/`;
/** Link 不能跳转到外链 */ /** Link 不能跳转到外链 */

View File

@ -12,7 +12,7 @@ interface CategoryProps {
newIcons: string[]; newIcons: string[];
} }
const Category: React.FC<CategoryProps> = props => { const Category: React.FC<CategoryProps> = (props) => {
const { icons, title, newIcons, theme } = props; const { icons, title, newIcons, theme } = props;
const intl = useIntl(); const intl = useIntl();
const [justCopied, setJustCopied] = React.useState<string | null>(null); const [justCopied, setJustCopied] = React.useState<string | null>(null);
@ -40,7 +40,7 @@ const Category: React.FC<CategoryProps> = props => {
<div> <div>
<h3>{intl.formatMessage({ id: `app.docs.components.icon.category.${title}` })}</h3> <h3>{intl.formatMessage({ id: `app.docs.components.icon.category.${title}` })}</h3>
<ul className="anticons-list"> <ul className="anticons-list">
{icons.map(name => ( {icons.map((name) => (
<CopyableIcon <CopyableIcon
key={name} key={name}
name={name} name={name}

View File

@ -1,239 +0,0 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Upload, Tooltip, Popover, Modal, Progress, message, Spin, Result } from 'antd';
import CopyToClipboard from 'react-copy-to-clipboard';
import { useIntl } from 'dumi';
import * as AntdIcons from '@ant-design/icons';
const allIcons: { [key: string]: any } = AntdIcons;
const { Dragger } = Upload;
interface AntdIconClassifier {
load: Function;
predict: Function;
}
declare global {
interface Window {
antdIconClassifier: AntdIconClassifier;
}
}
interface PicSearcherState {
loading: boolean;
modalOpen: boolean;
popoverVisible: boolean;
icons: iconObject[];
fileList: any[];
error: boolean;
modelLoaded: boolean;
}
interface iconObject {
type: string;
score: number;
}
const PicSearcher: React.FC = () => {
const intl = useIntl();
const [state, setState] = useState<PicSearcherState>({
loading: false,
modalOpen: false,
popoverVisible: false,
icons: [],
fileList: [],
error: false,
modelLoaded: false,
});
const predict = (imgEl: HTMLImageElement) => {
try {
let icons: any[] = window.antdIconClassifier.predict(imgEl);
if (gtag && icons.length) {
gtag('event', 'icon', {
event_category: 'search-by-image',
event_label: icons[0].className,
});
}
icons = icons.map(i => ({ score: i.score, type: i.className.replace(/\s/g, '-') }));
setState(prev => ({ ...prev, loading: false, error: false, icons }));
} catch {
setState(prev => ({ ...prev, loading: false, error: true }));
}
};
// eslint-disable-next-line class-methods-use-this
const toImage = (url: string): Promise<HTMLImageElement> =>
new Promise(resolve => {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;
img.onload = () => {
resolve(img);
};
});
const uploadFile = useCallback((file: File) => {
setState(prev => ({ ...prev, loading: true }));
const reader = new FileReader();
reader.onload = () => {
toImage(reader.result as string).then(predict);
setState(prev => ({
...prev,
fileList: [{ uid: 1, name: file.name, status: 'done', url: reader.result }],
}));
};
reader.readAsDataURL(file);
}, []);
const onPaste = useCallback((event: ClipboardEvent) => {
const items = event.clipboardData && event.clipboardData.items;
let file = null;
if (items && items.length) {
for (let i = 0; i < items.length; i++) {
if (items[i].type.includes('image')) {
file = items[i].getAsFile();
break;
}
}
}
if (file) {
uploadFile(file);
}
}, []);
const toggleModal = useCallback(() => {
setState(prev => ({
...prev,
modalOpen: !prev.modalOpen,
popoverVisible: false,
fileList: [],
icons: [],
}));
if (!localStorage.getItem('disableIconTip')) {
localStorage.setItem('disableIconTip', 'true');
}
}, []);
// eslint-disable-next-line class-methods-use-this
const onCopied = useCallback((text: string) => {
message.success(
<span>
<code className="copied-code">{text}</code> copied 🎉
</span>,
);
}, []);
useEffect(() => {
const script = document.createElement('script');
script.onload = async () => {
await window.antdIconClassifier.load();
setState(prev => ({ ...prev, modelLoaded: true }));
document.addEventListener('paste', onPaste);
};
script.src = 'https://cdn.jsdelivr.net/gh/lewis617/antd-icon-classifier@0.0/dist/main.js';
document.head.appendChild(script);
setState(prev => ({ ...prev, popoverVisible: !localStorage.getItem('disableIconTip') }));
return () => {
document.removeEventListener('paste', onPaste);
};
}, []);
return (
<div className="icon-pic-searcher">
<Popover
content={intl.formatMessage({ id: `app.docs.components.icon.pic-searcher.intro` })}
open={state.popoverVisible}
>
<AntdIcons.CameraOutlined className="icon-pic-btn" onClick={toggleModal} />
</Popover>
<Modal
title={intl.formatMessage({ id: `app.docs.components.icon.pic-searcher.title` })}
open={state.modalOpen}
onCancel={toggleModal}
footer={null}
>
{state.modelLoaded || (
<Spin
spinning={!state.modelLoaded}
tip={intl.formatMessage({ id: 'app.docs.components.icon.pic-searcher.modelloading' })}
>
<div style={{ height: 100 }} />
</Spin>
)}
{state.modelLoaded && (
<Dragger
accept="image/jpeg, image/png"
listType="picture"
customRequest={o => uploadFile(o.file as File)}
fileList={state.fileList}
showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }}
>
<p className="ant-upload-drag-icon">
<AntdIcons.InboxOutlined />
</p>
<p className="ant-upload-text">
{intl.formatMessage({ id: 'app.docs.components.icon.pic-searcher.upload-text' })}
</p>
<p className="ant-upload-hint">
{intl.formatMessage({ id: 'app.docs.components.icon.pic-searcher.upload-hint' })}
</p>
</Dragger>
)}
<Spin
spinning={state.loading}
tip={intl.formatMessage({ id: 'app.docs.components.icon.pic-searcher.matching' })}
>
<div className="icon-pic-search-result">
{state.icons.length > 0 && (
<div className="result-tip">
{intl.formatMessage({ id: 'app.docs.components.icon.pic-searcher.result-tip' })}
</div>
)}
<table>
{state.icons.length > 0 && (
<thead>
<tr>
<th className="col-icon">
{intl.formatMessage({ id: 'app.docs.components.icon.pic-searcher.th-icon' })}
</th>
<th>
{intl.formatMessage({ id: 'app.docs.components.icon.pic-searcher.th-score' })}
</th>
</tr>
</thead>
)}
<tbody>
{state.icons.map(icon => {
const { type } = icon;
const iconName = `${type
.split('-')
.map(str => `${str[0].toUpperCase()}${str.slice(1)}`)
.join('')}Outlined`;
return (
<tr key={iconName}>
<td className="col-icon">
<CopyToClipboard text={`<${iconName} />`} onCopy={onCopied}>
<Tooltip title={icon.type} placement="right">
{React.createElement(allIcons[iconName])}
</Tooltip>
</CopyToClipboard>
</td>
<td>
<Progress percent={Math.ceil(icon.score * 100)} />
</td>
</tr>
);
})}
</tbody>
</table>
{state.error && (
<Result
status="500"
title="503"
subTitle={intl.formatMessage({
id: 'app.docs.components.icon.pic-searcher.server-error',
})}
/>
)}
</div>
</Spin>
</Modal>
</div>
);
};
export default PicSearcher;

View File

@ -1,7 +1,7 @@
import * as AntdIcons from '@ant-design/icons/lib/icons'; import * as AntdIcons from '@ant-design/icons/lib/icons';
const all = Object.keys(AntdIcons) const all = Object.keys(AntdIcons)
.map(n => n.replace(/(Outlined|Filled|TwoTone)$/, '')) .map((n) => n.replace(/(Outlined|Filled|TwoTone)$/, ''))
.filter((n, i, arr) => arr.indexOf(n) === i); .filter((n, i, arr) => arr.indexOf(n) === i);
const direction = [ const direction = [
@ -204,7 +204,7 @@ const logo = [
const datum = [...direction, ...suggestion, ...editor, ...data, ...logo]; const datum = [...direction, ...suggestion, ...editor, ...data, ...logo];
const other = all.filter(n => !datum.includes(n)); const other = all.filter((n) => !datum.includes(n));
export const categories = { export const categories = {
direction, direction,

View File

@ -5,7 +5,6 @@ import type { RadioChangeEvent } from 'antd/es/radio/interface';
import { useIntl } from 'dumi'; import { useIntl } from 'dumi';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import Category from './Category'; import Category from './Category';
import IconPicSearcher from './IconPicSearcher';
import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons'; import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons';
import type { CategoriesKeys } from './fields'; import type { CategoriesKeys } from './fields';
import { categories } from './fields'; import { categories } from './fields';
@ -34,20 +33,20 @@ const IconSearch: React.FC = () => {
const handleSearchIcon = React.useCallback( const handleSearchIcon = React.useCallback(
debounce((searchKey: string) => { debounce((searchKey: string) => {
setDisplayState(prevState => ({ ...prevState, searchKey })); setDisplayState((prevState) => ({ ...prevState, searchKey }));
}), }),
[], [],
); );
const handleChangeTheme = React.useCallback((e: RadioChangeEvent) => { const handleChangeTheme = React.useCallback((e: RadioChangeEvent) => {
setDisplayState(prevState => ({ ...prevState, theme: e.target.value as ThemeType })); setDisplayState((prevState) => ({ ...prevState, theme: e.target.value as ThemeType }));
}, []); }, []);
const renderCategories = React.useMemo<React.ReactNode | React.ReactNode[]>(() => { const renderCategories = React.useMemo<React.ReactNode | React.ReactNode[]>(() => {
const { searchKey = '', theme } = displayState; const { searchKey = '', theme } = displayState;
const categoriesResult = Object.keys(categories) const categoriesResult = Object.keys(categories)
.map(key => { .map((key) => {
let iconList = categories[key as CategoriesKeys]; let iconList = categories[key as CategoriesKeys];
if (searchKey) { if (searchKey) {
const matchKey = searchKey const matchKey = searchKey
@ -55,15 +54,17 @@ const IconSearch: React.FC = () => {
.replace(new RegExp(`^<([a-zA-Z]*)\\s/>$`, 'gi'), (_, name) => name) .replace(new RegExp(`^<([a-zA-Z]*)\\s/>$`, 'gi'), (_, name) => name)
.replace(/(Filled|Outlined|TwoTone)$/, '') .replace(/(Filled|Outlined|TwoTone)$/, '')
.toLowerCase(); .toLowerCase();
iconList = iconList.filter(iconName => iconName.toLowerCase().includes(matchKey)); iconList = iconList.filter((iconName) => iconName.toLowerCase().includes(matchKey));
} }
// CopyrightCircle is same as Copyright, don't show it // CopyrightCircle is same as Copyright, don't show it
iconList = iconList.filter(icon => icon !== 'CopyrightCircle'); iconList = iconList.filter((icon) => icon !== 'CopyrightCircle');
return { return {
category: key, category: key,
icons: iconList.map(iconName => iconName + theme).filter(iconName => allIcons[iconName]), icons: iconList
.map((iconName) => iconName + theme)
.filter((iconName) => allIcons[iconName]),
}; };
}) })
.filter(({ icons }) => !!icons.length) .filter(({ icons }) => !!icons.length)
@ -104,10 +105,9 @@ const IconSearch: React.FC = () => {
placeholder={intl.formatMessage({ id: 'app.docs.components.icon.search.placeholder' })} placeholder={intl.formatMessage({ id: 'app.docs.components.icon.search.placeholder' })}
style={{ margin: '0 10px', flex: 1 }} style={{ margin: '0 10px', flex: 1 }}
allowClear allowClear
onChange={e => handleSearchIcon(e.currentTarget.value)} onChange={(e) => handleSearchIcon(e.currentTarget.value)}
size="large" size="large"
autoFocus autoFocus
suffix={<IconPicSearcher />}
/> />
</div> </div>
{renderCategories} {renderCategories}

View File

@ -5,7 +5,7 @@ type CustomIconComponent = React.ComponentType<
CustomIconComponentProps | React.SVGProps<SVGSVGElement> CustomIconComponentProps | React.SVGProps<SVGSVGElement>
>; >;
export const FilledIcon: CustomIconComponent = props => { export const FilledIcon: CustomIconComponent = (props) => {
const path = const path =
'M864 64H160C107 64 64 107 64 160v' + 'M864 64H160C107 64 64 107 64 160v' +
'704c0 53 43 96 96 96h704c53 0 96-43 96-96V16' + '704c0 53 43 96 96 96h704c53 0 96-43 96-96V16' +
@ -17,7 +17,7 @@ export const FilledIcon: CustomIconComponent = props => {
); );
}; };
export const OutlinedIcon: CustomIconComponent = props => { export const OutlinedIcon: CustomIconComponent = (props) => {
const path = const path =
'M864 64H160C107 64 64 107 64 160v7' + 'M864 64H160C107 64 64 107 64 160v7' +
'04c0 53 43 96 96 96h704c53 0 96-43 96-96V160c' + '04c0 53 43 96 96 96h704c53 0 96-43 96-96V160c' +
@ -31,7 +31,7 @@ export const OutlinedIcon: CustomIconComponent = props => {
); );
}; };
export const TwoToneIcon: CustomIconComponent = props => { export const TwoToneIcon: CustomIconComponent = (props) => {
const path = const path =
'M16 512c0 273.932 222.066 496 496 49' + 'M16 512c0 273.932 222.066 496 496 49' +
'6s496-222.068 496-496S785.932 16 512 16 16 238.' + '6s496-222.068 496-496S785.932 16 512 16 16 238.' +

View File

@ -15,14 +15,14 @@ function isInline(className) {
} }
function PreviewImageBox({ function PreviewImageBox({
cover, cover,
coverMeta, coverMeta,
imgs, imgs,
style, style,
previewVisible, previewVisible,
comparable, comparable,
onClick, onClick,
onCancel, onCancel,
}) { }) {
const onlyOneImg = comparable || imgs.length === 1; const onlyOneImg = comparable || imgs.length === 1;
const imageWrapperClassName = classNames('preview-image-wrapper', { const imageWrapperClassName = classNames('preview-image-wrapper', {
@ -77,7 +77,7 @@ export default class ImagePreview extends React.Component {
}; };
} }
handleClick = index => { handleClick = (index) => {
this.setState({ this.setState({
previewVisible: { previewVisible: {
[index]: true, [index]: true,
@ -93,7 +93,7 @@ export default class ImagePreview extends React.Component {
render() { render() {
const { imgs } = this.props; const { imgs } = this.props;
const imgsMeta = imgs.map(img => { const imgsMeta = imgs.map((img) => {
const { alt, description, src } = img; const { alt, description, src } = img;
const imgClassName = img.class; const imgClassName = img.class;
return { return {

View File

@ -16,8 +16,8 @@ function useShowRiddleButton() {
const [showRiddleButton, setShowRiddleButton] = useState(false); const [showRiddleButton, setShowRiddleButton] = useState(false);
useEffect(() => { useEffect(() => {
pingDeferrer ??= new Promise<boolean>(resolve => { pingDeferrer ??= new Promise<boolean>((resolve) => {
ping(status => { ping((status) => {
if (status !== 'timeout' && status !== 'error') { if (status !== 'timeout' && status !== 'error') {
return resolve(true); return resolve(true);
} }

View File

@ -75,7 +75,7 @@ class Demo extends React.Component {
return ['', '']; return ['', ''];
} }
handleCodeExpand = demo => { handleCodeExpand = (demo) => {
const { codeExpand } = this.state; const { codeExpand } = this.state;
this.setState({ codeExpand: !codeExpand }); this.setState({ codeExpand: !codeExpand });
this.track({ this.track({
@ -84,11 +84,11 @@ class Demo extends React.Component {
}); });
}; };
saveAnchor = anchor => { saveAnchor = (anchor) => {
this.anchor = anchor; this.anchor = anchor;
}; };
handleCodeCopied = demo => { handleCodeCopied = (demo) => {
this.setState({ copied: true }); this.setState({ copied: true });
this.track({ this.track({
type: 'copy', type: 'copy',
@ -96,7 +96,7 @@ class Demo extends React.Component {
}); });
}; };
onCopyTooltipOpenChange = open => { onCopyTooltipOpenChange = (open) => {
if (open) { if (open) {
this.setState({ this.setState({
copyTooltipOpen: open, copyTooltipOpen: open,
@ -254,7 +254,7 @@ class Demo extends React.Component {
'react-router-dom/umd/react-router-dom.min.js', 'react-router-dom/umd/react-router-dom.min.js',
'react-router@3.x/umd/ReactRouter.min.js', 'react-router@3.x/umd/ReactRouter.min.js',
] ]
.map(url => `https://unpkg.com/${url}`) .map((url) => `https://unpkg.com/${url}`)
.join(';'), .join(';'),
js_pre_processor: 'typescript', js_pre_processor: 'typescript',
}; };
@ -495,7 +495,7 @@ createRoot(document.getElementById('container')).render(<Demo />);
<CodePreview <CodePreview
toReactComponent={props.utils.toReactComponent} toReactComponent={props.utils.toReactComponent}
codes={highlightedCodes} codes={highlightedCodes}
onCodeTypeChange={type => this.setState({ codeType: type })} onCodeTypeChange={(type) => this.setState({ codeType: type })}
/> />
{highlightedStyle ? ( {highlightedStyle ? (
<div key="style" className="highlight"> <div key="style" className="highlight">

View File

@ -76,7 +76,7 @@ const ArticleList: React.FC<ArticleListProps> = ({ name, data = [], authors = []
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
) : ( ) : (
data.map((article, index) => { data.map((article, index) => {
const author = authors.find(auth => auth.name === article.author); const author = authors.find((auth) => auth.name === article.author);
return ( return (
<li key={index}> <li key={index}>
<a href={author?.href} target="_blank" rel="noreferrer"> <a href={author?.href} target="_blank" rel="noreferrer">
@ -105,7 +105,7 @@ export default () => {
// ========================== Data ========================== // ========================== Data ==========================
const mergedData = React.useMemo(() => { const mergedData = React.useMemo(() => {
const yearData: Record<number | string, Record<string, Article[]>> = {}; const yearData: Record<number | string, Record<string, Article[]>> = {};
articles[isZhCN ? 'cn' : 'en']?.forEach(article => { articles[isZhCN ? 'cn' : 'en']?.forEach((article) => {
const year = dayjs(article.date).year(); const year = dayjs(article.date).year();
yearData[year] = yearData[year] || {}; yearData[year] = yearData[year] || {};
yearData[year][article.type] = [...(yearData[year][article.type] || []), article]; yearData[year][article.type] = [...(yearData[year][article.type] || []), article];
@ -122,7 +122,7 @@ export default () => {
const yearList = Object.keys(mergedData).sort((a, b) => Number(b) - Number(a)); const yearList = Object.keys(mergedData).sort((a, b) => Number(b) - Number(a));
content = yearList.length ? ( content = yearList.length ? (
<Tabs> <Tabs>
{yearList.map(year => ( {yearList.map((year) => (
<Tabs.TabPane tab={`${year}${isZhCN ? ' 年' : ''}`} key={year}> <Tabs.TabPane tab={`${year}${isZhCN ? ' 年' : ''}`} key={year}>
<table> <table>
<tbody> <tbody>

View File

@ -108,7 +108,7 @@ export type ResourceCardsProps = {
const ResourceCards: FC<ResourceCardsProps> = ({ resources }) => { const ResourceCards: FC<ResourceCardsProps> = ({ resources }) => {
return ( return (
<Row style={{ margin: '-12px -12px 0 -12px' }}> <Row style={{ margin: '-12px -12px 0 -12px' }}>
{resources.map(item => ( {resources.map((item) => (
<ResourceCard resource={item} key={item.title} /> <ResourceCard resource={item} key={item.title} />
))} ))}
</Row> </Row>

View File

@ -7,6 +7,6 @@ const SVGIcon = () => (
</svg> </svg>
); );
const CodePenIcon = props => <Icon component={SVGIcon} {...props} />; const CodePenIcon = (props) => <Icon component={SVGIcon} {...props} />;
export default CodePenIcon; export default CodePenIcon;

View File

@ -24,7 +24,7 @@ const CodePreview = ({ toReactComponent, codes, onCodeTypeChange }) => {
} else { } else {
content = ( content = (
<Tabs centered onChange={onCodeTypeChange}> <Tabs centered onChange={onCodeTypeChange}>
{langList.map(lang => ( {langList.map((lang) => (
<TabPane tab={LANGS[lang]} key={lang}> <TabPane tab={LANGS[lang]} key={lang}>
{toReactComponent([ {toReactComponent([
'pre', 'pre',

View File

@ -7,6 +7,6 @@ const SVGIcon = () => (
</svg> </svg>
); );
const CodeSandboxIcon = props => <Icon component={SVGIcon} {...props} />; const CodeSandboxIcon = (props) => <Icon component={SVGIcon} {...props} />;
export default CodeSandboxIcon; export default CodeSandboxIcon;

View File

@ -22,7 +22,7 @@ export default class ColorPaletteTool extends Component {
}); });
}; };
handleChangeBackgroundColor = e => { handleChangeBackgroundColor = (e) => {
const value = e.target ? e.target.value : e; const value = e.target ? e.target.value : e;
this.setState({ this.setState({
backgroundColor: value, backgroundColor: value,

View File

@ -2,7 +2,7 @@ import React from 'react';
import cls from 'classnames'; import cls from 'classnames';
import Palette from './Palette'; import Palette from './Palette';
const ColorPalettes = props => { const ColorPalettes = (props) => {
const { dark } = props; const { dark } = props;
const colors = [ const colors = [
@ -84,7 +84,7 @@ const ColorPalettes = props => {
}); });
return ( return (
<div className={colorCls}> <div className={colorCls}>
{colors.map(color => ( {colors.map((color) => (
<Palette key={color.name} color={color} dark={dark} showTitle /> <Palette key={color.name} color={color} dark={dark} showTitle />
))} ))}
</div> </div>

View File

@ -3,7 +3,7 @@ import { message } from 'antd';
import CopyToClipboard from 'react-copy-to-clipboard'; import CopyToClipboard from 'react-copy-to-clipboard';
import { presetDarkPalettes } from '@ant-design/colors'; import { presetDarkPalettes } from '@ant-design/colors';
const rgbToHex = rgbString => { const rgbToHex = (rgbString) => {
const rgb = rgbString.match(/\d+/g); const rgb = rgbString.match(/\d+/g);
let r = parseInt(rgb[0], 10).toString(16); let r = parseInt(rgb[0], 10).toString(16);
let g = parseInt(rgb[1], 10).toString(16); let g = parseInt(rgb[1], 10).toString(16);
@ -17,7 +17,7 @@ const rgbToHex = rgbString => {
export default class Palette extends React.Component { export default class Palette extends React.Component {
componentDidMount() { componentDidMount() {
this.hexColors = {}; this.hexColors = {};
Object.keys(this.colorNodes).forEach(key => { Object.keys(this.colorNodes).forEach((key) => {
const computedColor = getComputedStyle(this.colorNodes[key])['background-color']; const computedColor = getComputedStyle(this.colorNodes[key])['background-color'];
if (computedColor.includes('rgba')) { if (computedColor.includes('rgba')) {
this.hexColors[key] = computedColor; this.hexColors[key] = computedColor;
@ -55,7 +55,7 @@ export default class Palette extends React.Component {
> >
<div <div
key={i} key={i}
ref={node => { ref={(node) => {
this.colorNodes[`${name}-${i}`] = node; this.colorNodes[`${name}-${i}`] = node;
}} }}
className={`main-color-item palette-${name}-${i}`} className={`main-color-item palette-${name}-${i}`}
@ -90,4 +90,4 @@ export default class Palette extends React.Component {
Palette.defaultProps = { Palette.defaultProps = {
color: { name: 'gray', count: 13 }, color: { name: 'gray', count: 13 },
} };

View File

@ -21,8 +21,10 @@ const useStyle = () => {
a& { a& {
display: inline-block; display: inline-block;
text-decoration: none; text-decoration: none;
margin-inline-start: 4px; margin-inline-start: 6px;
vertical-align: -2px; vertical-align: middle;
position: relative;
top: -2px;
${iconCls} { ${iconCls} {
display: block; display: block;

View File

@ -8,6 +8,6 @@ const SVGIcon = ({ color = 'currentColor' }) => (
</svg> </svg>
); );
const ExternalLinkIcon = props => <Icon component={SVGIcon} {...props} />; const ExternalLinkIcon = (props) => <Icon component={SVGIcon} {...props} />;
export default ExternalLinkIcon; export default ExternalLinkIcon;

View File

@ -406,8 +406,50 @@ const GlobalStyles = () => {
} }
.markdown .dumi-default-table { .markdown .dumi-default-table {
table { .component-api-table {
display: block; display: block;
td {
&:first-child {
width: 18%;
color: #595959;
font-weight: 600;
white-space: nowrap;
}
&:nth-child(2) {
width: 55%;
}
&:nth-child(3) {
width: 22%;
color: ${token['magenta-7']};
font-size: ${Math.max(token.fontSize - 1, 12)}px;
}
&:nth-child(4) {
width: 15%;
font-size: ${Math.max(token.fontSize - 1, 12)}px;
}
&:nth-child(5) {
width: 8%;
font-size: ${Math.max(token.fontSize - 1, 12)}px;
}
&:nth-last-child(3):first-child {
width: 38%;
}
&:nth-last-child(3):first-child ~ td:nth-last-child(2) {
width: 70%;
}
}
}
}
.markdown .dumi-default-table {
table {
margin: 2em 0; margin: 2em 0;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
@ -447,38 +489,7 @@ const GlobalStyles = () => {
td { td {
&:first-child { &:first-child {
width: 18%; min-width: 58px;
color: #595959;
font-weight: 600;
white-space: nowrap;
}
&:nth-child(2) {
width: 55%;
}
&:nth-child(3) {
width: 22%;
color: ${token['magenta-7']};
font-size: ${Math.max(token.fontSize - 1, 12)}px;
}
&:nth-child(4) {
width: 15%;
font-size: ${Math.max(token.fontSize - 1, 12)}px;
}
&:nth-child(5) {
width: 8%;
font-size: ${Math.max(token.fontSize - 1, 12)}px;
}
&:nth-last-child(3):first-child {
width: 38%;
}
&:nth-last-child(3):first-child ~ td:nth-last-child(2) {
width: 70%;
} }
} }
} }
@ -1156,6 +1167,7 @@ const GlobalStyles = () => {
code { code {
background: ${token.colorBgContainer}; background: ${token.colorBgContainer};
border: none; border: none;
box-shadow: unset;
} }
} }
@ -1268,6 +1280,7 @@ const GlobalStyles = () => {
width: 100%; width: 100%;
height: 100%; height: 100%;
color: #fff; color: #fff;
background: #1677ff;
line-height: 110px; line-height: 110px;
text-align: center; text-align: center;
opacity: 0; opacity: 0;
@ -1276,7 +1289,6 @@ const GlobalStyles = () => {
} }
&.copied::after { &.copied::after {
top: -10px;
opacity: 1; opacity: 1;
} }
} }
@ -1768,236 +1780,237 @@ const GlobalStyles = () => {
{/* Preview Image */} {/* Preview Image */}
<Global <Global
styles={css` styles={css`
.preview-image-boxes { .preview-image-boxes {
display: flex; display: flex;
float: right; float: right;
clear: both; clear: both;
width: 496px; width: 496px;
margin: 0 0 70px 64px; margin: 0 0 70px 64px;
&-with-carousel { &-with-carousel {
width: 420px; width: 420px;
.preview-image-box img { .preview-image-box img {
padding: 0; padding: 0;
} }
} }
.ant-row-rtl & { .ant-row-rtl & {
float: left; float: left;
margin: 0 64px 70px 0; margin: 0 64px 70px 0;
} }
} }
.preview-image-boxes + .preview-image-boxes { .preview-image-boxes + .preview-image-boxes {
margin-top: -35px; margin-top: -35px;
} }
.preview-image-box { .preview-image-box {
float: left; float: left;
width: 100%; width: 100%;
} }
.preview-image-box + .preview-image-box { .preview-image-box + .preview-image-box {
margin-left: 24px; margin-left: 24px;
.ant-row-rtl & { .ant-row-rtl & {
margin-right: 24px; margin-right: 24px;
margin-left: 0; margin-left: 0;
} }
} }
.preview-image-wrapper { .preview-image-wrapper {
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 100%; width: 100%;
padding: 16px; padding: 16px;
text-align: center; text-align: center;
background: #f2f4f5; background: #f2f4f5;
} }
.preview-image-wrapper.video { .preview-image-wrapper.video {
display: block; display: block;
padding: 0; padding: 0;
background: 0; background: 0;
} }
.preview-image-wrapper video { .preview-image-wrapper video {
display: block; display: block;
width: 100%; width: 100%;
+ svg { + svg {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
} }
} }
.preview-image-wrapper.good::after { .preview-image-wrapper.good::after {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
display: block; display: block;
width: 100%; width: 100%;
height: 3px; height: 3px;
background: @primary-color; background: @primary-color;
content: ''; content: '';
} }
.preview-image-wrapper.bad::after { .preview-image-wrapper.bad::after {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
display: block; display: block;
width: 100%; width: 100%;
height: 3px; height: 3px;
background: @error-color; background: @error-color;
content: ''; content: '';
} }
.preview-image-title { .preview-image-title {
margin-top: 20px; margin-top: 20px;
color: @site-text-color; color: @site-text-color;
font-size: 12px; font-size: 12px;
} }
.preview-image-description { .preview-image-description {
margin-top: 2px; margin-top: 2px;
color: @site-text-color-secondary; color: @site-text-color-secondary;
font-size: 12px; font-size: 12px;
line-height: 1.5; line-height: 1.5;
} }
.preview-image-description hr { .preview-image-description hr {
margin: 2px 0; margin: 2px 0;
background: none; background: none;
border: 0; border: 0;
} }
.preview-image-box img { .preview-image-box img {
max-width: 100%; max-width: 100%;
padding: 12px; padding: 12px;
background: @body-background; background: @body-background;
border-radius: @border-radius-base; border-radius: @border-radius-base;
cursor: pointer; cursor: pointer;
transition: all 0.3s; transition: all 0.3s;
&.no-padding { &.no-padding {
padding: 0; padding: 0;
background: none; background: none;
} }
} }
.preview-image-boxes.preview-image-boxes-with-carousel img { .preview-image-boxes.preview-image-boxes-with-carousel img {
padding: 0; padding: 0;
box-shadow: 0 1px 0 0 #ddd, 0 3px 0 0 @body-background, 0 4px 0 0 #ddd, 0 6px 0 0 @body-background, box-shadow: 0 1px 0 0 #ddd, 0 3px 0 0 @body-background, 0 4px 0 0 #ddd,
0 7px 0 0 #ddd; 0 6px 0 0 @body-background, 0 7px 0 0 #ddd;
} }
.preview-image-box img:hover { .preview-image-box img:hover {
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3); box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3);
} }
.preview-img { .preview-img {
max-width: 496px !important; float: right;
clear: both; clear: both;
float: right; max-width: 496px !important;
margin: 0 0 70px 64px; margin: 0 0 70px 64px;
background-color: #f2f4f5; padding: 16px;
padding: 16px; background-color: #f2f4f5;
} }
.image-modal { .image-modal {
text-align: center; text-align: center;
&-container { &-container {
position: relative; position: relative;
text-align: center; text-align: center;
} }
.ant-carousel { .ant-carousel {
.slick-slider { .slick-slider {
padding-bottom: 24px; padding-bottom: 24px;
img { img {
display: inline; display: inline;
max-width: 100%; max-width: 100%;
} }
} }
.slick-dots { .slick-dots {
bottom: 4px; bottom: 4px;
li button { li button {
background: #888; background: #888;
} }
} }
} }
.image-modal-single.slick-slider { .image-modal-single.slick-slider {
padding-bottom: 0; padding-bottom: 0;
} }
.image-modal-single .slick-dots { .image-modal-single .slick-dots {
display: none !important; display: none !important;
} }
} }
.transition-video-player, .transition-video-player,
.motion-video-min { .motion-video-min {
float: right; float: right;
width: 600px; width: 600px;
padding: 0 0 70px 20px; padding: 0 0 70px 20px;
.preview-image-wrapper { .preview-image-wrapper {
padding: 0; padding: 0;
} }
.ant-row-rtl & { .ant-row-rtl & {
float: left; float: left;
} }
} }
.motion-video-min { .motion-video-min {
width: 390px; width: 390px;
} }
.motion-principle-wrapper { .motion-principle-wrapper {
width: 100%; width: 100%;
max-width: 900px; max-width: 900px;
margin: 48px 0 24px; margin: 48px 0 24px;
} }
.principle-wrapper { .principle-wrapper {
width: 100%; width: 100%;
.principle { .principle {
display: inline-block; display: inline-block;
width: 100%; box-sizing: border-box;
min-height: 180px; width: 100%;
margin-right: 12.5%; min-height: 180px;
margin-bottom: 24px; margin-right: 12.5%;
padding: 24px; margin-bottom: 24px;
font-size: 24px; padding: 24px;
text-align: center; font-size: 24px;
border: 1px solid #e8e8e8; text-align: center;
border-radius: 4px; border: 1px solid #e8e8e8;
box-sizing: border-box; border-radius: 4px;
&:last-child { &:last-child {
margin-right: 0; margin-right: 0;
} }
h4 { h4 {
margin: 16px 0 8px; margin: 16px 0 8px;
} }
p { p {
font-size: 12px; font-size: 12px;
line-height: 24px; line-height: 24px;
} }
} }
}`} }
`}
/> />
<ColorStyle /> <ColorStyle />

View File

@ -7,6 +7,6 @@ const SVGIcon = () => (
</svg> </svg>
); );
const RiddleIcon = props => <Icon component={SVGIcon} {...props} />; const RiddleIcon = (props) => <Icon component={SVGIcon} {...props} />;
export default RiddleIcon; export default RiddleIcon;

View File

@ -96,8 +96,8 @@ const DocLayout: FC = () => {
const content = useMemo(() => { const content = useMemo(() => {
if ( if (
['', '/'].some(path => path === pathname) || ['', '/'].some((path) => path === pathname) ||
['/index'].some(path => pathname.startsWith(path)) ['/index'].some((path) => pathname.startsWith(path))
) { ) {
return ( return (
<> <>

View File

@ -14,7 +14,7 @@ const GlobalLayout: FC = () => {
const contextValue = React.useMemo<ThemeContextProps>( const contextValue = React.useMemo<ThemeContextProps>(
() => ({ () => ({
theme, theme,
setTheme: newTheme => { setTheme: (newTheme) => {
setTheme(newTheme); setTheme(newTheme);
localStorage.setItem( localStorage.setItem(
ANT_DESIGN_SITE_THEME, ANT_DESIGN_SITE_THEME,

View File

@ -117,10 +117,10 @@ export default () => {
<div css={[styles.affixTabs, fixedId && styles.affixTabsFixed]} ref={containerRef}> <div css={[styles.affixTabs, fixedId && styles.affixTabsFixed]} ref={containerRef}>
<Tabs <Tabs
activeKey={fixedId || undefined} activeKey={fixedId || undefined}
onChange={key => { onChange={(key) => {
scrollToId(key); scrollToId(key);
}} }}
items={idsRef.current.map(id => ({ items={idsRef.current.map((id) => ({
key: id, key: id,
label: <span style={{ textTransform: 'capitalize' }}>{id.replace(/-/g, ' ')}</span>, label: <span style={{ textTransform: 'capitalize' }}>{id.replace(/-/g, ' ')}</span>,
}))} }))}

View File

@ -123,16 +123,6 @@
"app.docs.components.icon.category.data": "Data Icons", "app.docs.components.icon.category.data": "Data Icons",
"app.docs.components.icon.category.other": "Application Icons", "app.docs.components.icon.category.other": "Application Icons",
"app.docs.components.icon.category.logo": "Brand and Logos", "app.docs.components.icon.category.logo": "Brand and Logos",
"app.docs.components.icon.pic-searcher.intro": "AI Search by image is online, you are welcome to use it! 🎉",
"app.docs.components.icon.pic-searcher.title": "Search by image",
"app.docs.components.icon.pic-searcher.upload-text": "Click, drag, or paste file to this area to upload",
"app.docs.components.icon.pic-searcher.upload-hint": "We will find the best matching icon based on the image provided",
"app.docs.components.icon.pic-searcher.server-error": "Predict service is temporarily unavailable",
"app.docs.components.icon.pic-searcher.matching": "Matching...",
"app.docs.components.icon.pic-searcher.modelloading": "Model is loading...",
"app.docs.components.icon.pic-searcher.result-tip": "Matched the following icons for you:",
"app.docs.components.icon.pic-searcher.th-icon": "Icon",
"app.docs.components.icon.pic-searcher.th-score": "Probability",
"app.docs.resource.design": "Design", "app.docs.resource.design": "Design",
"app.docs.resource.develop": "Develop", "app.docs.resource.develop": "Develop",
"app.components.overview.search": "Search in components", "app.components.overview.search": "Search in components",

View File

@ -122,16 +122,6 @@
"app.docs.components.icon.category.data": "数据类图标", "app.docs.components.icon.category.data": "数据类图标",
"app.docs.components.icon.category.other": "网站通用图标", "app.docs.components.icon.category.other": "网站通用图标",
"app.docs.components.icon.category.logo": "品牌和标识", "app.docs.components.icon.category.logo": "品牌和标识",
"app.docs.components.icon.pic-searcher.intro": "AI 截图搜索上线了,快来体验吧!🎉",
"app.docs.components.icon.pic-searcher.title": "上传图片搜索图标",
"app.docs.components.icon.pic-searcher.upload-text": "点击/拖拽/粘贴上传图片",
"app.docs.components.icon.pic-searcher.upload-hint": "我们会通过上传的图片进行匹配,得到最相似的图标",
"app.docs.components.icon.pic-searcher.server-error": "识别服务暂不可用",
"app.docs.components.icon.pic-searcher.matching": "匹配中...",
"app.docs.components.icon.pic-searcher.modelloading": "神经网络模型加载中...",
"app.docs.components.icon.pic-searcher.result-tip": "为您匹配到以下图标:",
"app.docs.components.icon.pic-searcher.th-icon": "图标",
"app.docs.components.icon.pic-searcher.th-score": "匹配度",
"app.docs.resource.design": "设计", "app.docs.resource.design": "设计",
"app.docs.resource.develop": "开发", "app.docs.resource.develop": "开发",
"app.components.overview.search": "搜索组件", "app.components.overview.search": "搜索组件",

View File

@ -178,32 +178,36 @@ const Content: FC<{ children: ReactNode }> = ({ children }) => {
)} )}
</Typography.Title> </Typography.Title>
{children} {children}
<ContributorsList {meta.frontmatter.filename && (
css={styles.contributorsList} <ContributorsList
fileName={meta.frontmatter.filename ?? ''} css={styles.contributorsList}
renderItem={(item, loading) => fileName={meta.frontmatter.filename}
loading ? ( renderItem={(item, loading) =>
<Avatar style={{ opacity: 0.3 }} /> loading ? (
) : ( <Avatar style={{ opacity: 0.3 }} />
item && ( ) : (
<Tooltip item && (
title={`${formatMessage({ id: 'app.content.contributors' })}: ${item.username}`} <Tooltip
key={item.username} title={`${formatMessage({ id: 'app.content.contributors' })}: ${
> item.username
<a }`}
href={`https://github.com/${item.username}`} key={item.username}
target="_blank"
rel="noopener noreferrer"
> >
<Avatar src={item.url}>{item.username}</Avatar> <a
</a> href={`https://github.com/${item.username}`}
</Tooltip> target="_blank"
rel="noopener noreferrer"
>
<Avatar src={item.url}>{item.username}</Avatar>
</a>
</Tooltip>
)
) )
) }
} repo="ant-design"
repo="ant-design" owner="ant-design"
owner="ant-design" />
/> )}
</article> </article>
<PrevAndNext /> <PrevAndNext />
<Footer /> <Footer />

View File

@ -15,7 +15,7 @@ import {
TwitterOutlined, TwitterOutlined,
UsergroupAddOutlined, UsergroupAddOutlined,
ZhihuOutlined, ZhihuOutlined,
YuqueOutlined, YuqueFilled,
} from '@ant-design/icons'; } from '@ant-design/icons';
import useLocation from '../../../hooks/useLocation'; import useLocation from '../../../hooks/useLocation';
import { css } from '@emotion/react'; import { css } from '@emotion/react';
@ -129,7 +129,7 @@ const Footer = () => {
openExternal: true, openExternal: true,
}, },
{ {
title: 'Dumi', title: 'dumi',
description: <FormattedMessage id="app.footer.dumi" />, description: <FormattedMessage id="app.footer.dumi" />,
url: 'https://d.umijs.org', url: 'https://d.umijs.org',
openExternal: true, openExternal: true,
@ -181,7 +181,7 @@ const Footer = () => {
openExternal: true, openExternal: true,
}, },
{ {
icon: <YuqueOutlined style={{ color: '#00b96b' }} />, icon: <YuqueFilled style={{ color: '#00b96b' }} />,
title: <FormattedMessage id="app.footer.yuque.repo" />, title: <FormattedMessage id="app.footer.yuque.repo" />,
url: 'https://yuque.com/ant-design/ant-design', url: 'https://yuque.com/ant-design/ant-design',
openExternal: true, openExternal: true,
@ -189,7 +189,7 @@ const Footer = () => {
{ {
icon: <ZhihuOutlined style={{ color: '#0084ff' }} />, icon: <ZhihuOutlined style={{ color: '#0084ff' }} />,
title: <FormattedMessage id="app.footer.zhihu" />, title: <FormattedMessage id="app.footer.zhihu" />,
url: 'http://zhuanlan.zhihu.com/antdesign', url: 'https://www.zhihu.com/column/c_1564262000561106944',
openExternal: true, openExternal: true,
}, },
{ {

View File

@ -38,7 +38,8 @@ export function getEcosystemGroup(): Exclude<MenuProps['items'], undefined> {
<a href="http://ng.ant.design" target="_blank" rel="noopener noreferrer"> <a href="http://ng.ant.design" target="_blank" rel="noopener noreferrer">
Ant Design of Angular Ant Design of Angular
<span style={smallStyle}> <span style={smallStyle}>
(<FormattedMessage id="app.implementation.community" />) (
<FormattedMessage id="app.implementation.community" />)
</span> </span>
</a> </a>
), ),
@ -49,7 +50,8 @@ export function getEcosystemGroup(): Exclude<MenuProps['items'], undefined> {
<a href="http://antdv.com" target="_blank" rel="noopener noreferrer"> <a href="http://antdv.com" target="_blank" rel="noopener noreferrer">
Ant Design of Vue Ant Design of Vue
<span style={smallStyle}> <span style={smallStyle}>
(<FormattedMessage id="app.implementation.community" />) (
<FormattedMessage id="app.implementation.community" />)
</span> </span>
</a> </a>
), ),

View File

@ -1,3 +1,6 @@
const chineseMirror =
typeof location !== 'undefined' && location.hostname.includes('.antgroup.com');
export default { export default {
categoryOrder: { categoryOrder: {
'Ant Design': 0, 'Ant Design': 0,
@ -43,7 +46,7 @@ export default {
'Template Document': 3, 'Template Document': 3,
}, },
docVersions: { docVersions: {
'4.x': 'https://4x.ant.design', '4.x': chineseMirror ? 'https://4x-ant-design.antgroup.com/' : 'https://4x.ant.design',
'3.x': 'https://3x.ant.design', '3.x': 'https://3x.ant.design',
'2.x': 'https://2x.ant.design', '2.x': 'https://2x.ant.design',
'1.x': 'https://1x.ant.design', '1.x': 'https://1x.ant.design',

View File

@ -29,11 +29,11 @@ export function getMenuItems(
categoryOrder: Orders, categoryOrder: Orders,
typeOrder: Orders, typeOrder: Orders,
) { ) {
const menuMeta = moduleData.map(item => item.meta).filter(meta => !meta.skip); const menuMeta = moduleData.map((item) => item.meta).filter((meta) => !meta.skip);
const menuItems: Meta[] = []; const menuItems: Meta[] = [];
const sortFn = (a: Meta, b: Meta) => (a.order || 0) - (b.order || 0); const sortFn = (a: Meta, b: Meta) => (a.order || 0) - (b.order || 0);
menuMeta.sort(sortFn).forEach(meta => { menuMeta.sort(sortFn).forEach((meta) => {
// Format // Format
if (meta.category) { if (meta.category) {
meta.category = meta.category[locale] || meta.category; meta.category = meta.category[locale] || meta.category;
@ -52,7 +52,7 @@ export function getMenuItems(
// Component // Component
if (meta.category === 'Components' && meta.type) { if (meta.category === 'Components' && meta.type) {
let type = menuItems.find(i => i.title === meta.type); let type = menuItems.find((i) => i.title === meta.type);
if (!type) { if (!type) {
type = { type = {
type: 'type', type: 'type',
@ -67,7 +67,7 @@ export function getMenuItems(
return; return;
} }
let group = menuItems.find(i => i.title === meta.category); let group = menuItems.find((i) => i.title === meta.category);
if (!group) { if (!group) {
group = { group = {
@ -82,7 +82,7 @@ export function getMenuItems(
group.children = group.children || []; group.children = group.children || [];
if (meta.type) { if (meta.type) {
let type = group.children.filter(i => i.title === meta.type)[0]; let type = group.children.filter((i) => i.title === meta.type)[0];
if (!type) { if (!type) {
type = { type = {
type: 'type', type: 'type',
@ -100,7 +100,7 @@ export function getMenuItems(
}); });
function nestSort(list: Meta[]): Meta[] { function nestSort(list: Meta[]): Meta[] {
return list.sort(sortFn).map(item => { return list.sort(sortFn).map((item) => {
if (item.children) { if (item.children) {
return { return {
...item, ...item,
@ -201,7 +201,7 @@ export function getMetaDescription(jml?: any[] | null) {
} }
const paragraph = flattenDeep( const paragraph = flattenDeep(
jml jml
.filter(item => { .filter((item) => {
if (Array.isArray(item)) { if (Array.isArray(item)) {
const [tag] = item; const [tag] = item;
return tag === 'p'; return tag === 'p';
@ -209,14 +209,14 @@ export function getMetaDescription(jml?: any[] | null) {
return false; return false;
}) })
// ['p', ['code', 'aa'], 'bb'] => ['p', 'aabb'] // ['p', ['code', 'aa'], 'bb'] => ['p', 'aabb']
.map(item => { .map((item) => {
const [tag, ...others] = flatten(item); const [tag, ...others] = flatten(item);
const content = others const content = others
.filter(other => typeof other === 'string' && !COMMON_TAGS.includes(other)) .filter((other) => typeof other === 'string' && !COMMON_TAGS.includes(other))
.join(''); .join('');
return [tag, content]; return [tag, content];
}), }),
).find(p => p && typeof p === 'string' && !COMMON_TAGS.includes(p)) as string; ).find((p) => p && typeof p === 'string' && !COMMON_TAGS.includes(p)) as string;
return paragraph; return paragraph;
} }

View File

@ -5,7 +5,7 @@ on:
create create
permissions: permissions:
contents: read contents: write
jobs: jobs:
setup: setup:
@ -66,5 +66,6 @@ jobs:
- name: deploy - name: deploy
uses: peaceiris/actions-gh-pages@v3 uses: peaceiris/actions-gh-pages@v3
with: with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_site publish_dir: ./_site
force_orphan: true

View File

@ -8,6 +8,7 @@ on:
- feature - feature
- 2.x-stable - 2.x-stable
- 3.x-stable - 3.x-stable
- 4.x-stable
create: create:
permissions: permissions:

View File

@ -250,6 +250,12 @@ jobs:
path: node_modules path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }} key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: cache lib
uses: actions/cache@v3
with:
path: lib
key: lib-${{ github.sha }}
- name: cache es - name: cache es
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
@ -258,6 +264,9 @@ jobs:
- name: compile - name: compile
run: npm run compile run: npm run compile
- name: check
run: node ./tests/dekko/lib.test.js
needs: setup needs: setup
compiled-module-test: compiled-module-test:
@ -266,7 +275,7 @@ jobs:
strategy: strategy:
matrix: matrix:
react: ['16', '17', '18'] react: ['16', '17', '18']
module: [es] module: [lib, es]
shard: ['1/2', '2/2'] shard: ['1/2', '2/2']
env: env:
REACT: ${{ matrix.react }} REACT: ${{ matrix.react }}

View File

@ -3,7 +3,6 @@
"trailingComma": "all", "trailingComma": "all",
"printWidth": 100, "printWidth": 100,
"proseWrap": "never", "proseWrap": "never",
"arrowParens": "avoid",
"overrides": [ "overrides": [
{ {
"files": ".prettierrc", "files": ".prettierrc",

View File

@ -19,13 +19,13 @@ timeline: true
`2022-11-18` `2022-11-18`
- 🏆 Ant Design 5.0.0 is out! 🏆 Ant Design 5.0.0 is released, see our [release note](https://github.com/ant-design/ant-design/issues/38671) for more details.
**Read it before migration** #### Read it before migration
- 🌟 If you want to migrate to Ant Design 5.0, please check [V4 to V5](/docs/react/migration-v5). 🌟 If you want to migrate to Ant Design 5.0, please check [V4 to V5](/docs/react/migration-v5).
**Major Changes** #### Major Changes
- 🔥 New Components - 🔥 New Components
- 🔥 FloatButton component, and refactor BackTop as child component of FloatButton. [#37520](https://github.com/ant-design/ant-design/pull/37520) [@li-jia-nan](https://github.com/li-jia-nan) - 🔥 FloatButton component, and refactor BackTop as child component of FloatButton. [#37520](https://github.com/ant-design/ant-design/pull/37520) [@li-jia-nan](https://github.com/li-jia-nan)

View File

@ -19,13 +19,13 @@ timeline: true
`2022-11-18` `2022-11-18`
- 🏆 Ant Design 5.0.0 已发布!欢迎阅读我们的 [发布文档](https://www.yuque.com/ant-design/ant-design/cy5nfvdo8oidvwmz)。 🏆 Ant Design 5.0.0 已发布!欢迎阅读我们的 [发布文档](https://www.yuque.com/ant-design/ant-design/cy5nfvdo8oidvwmz)。
**升级必读** #### 升级必读
- 🌟 如果你想升级到 Ant Design 5.0,请仔细查阅我们的[迁移文档](/docs/react/migration-v5-cn)。 🌟 如果你想升级到 Ant Design 5.0,请仔细查阅我们的[迁移文档](/docs/react/migration-v5-cn)。
**主要变化** #### 主要变化
- 🔥 新增组件 - 🔥 新增组件
- 🔥 FloatButton 悬浮按钮,原 BackTop 移至 FloatButton 子组件。[#37520](https://github.com/ant-design/ant-design/pull/37520) [@li-jia-nan](https://github.com/li-jia-nan) - 🔥 FloatButton 悬浮按钮,原 BackTop 移至 FloatButton 子组件。[#37520](https://github.com/ant-design/ant-design/pull/37520) [@li-jia-nan](https://github.com/li-jia-nan)

View File

@ -62,7 +62,7 @@
- サーバーサイド レンダリング - サーバーサイド レンダリング
- [Electron](https://www.electronjs.org/) - [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / 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" />](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 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Edge | 直近の 2 バージョン | 直近の 2 バージョン | 直近の 2 バージョン | 直近の 2 バージョン | | Edge | 直近の 2 バージョン | 直近の 2 バージョン | 直近の 2 バージョン | 直近の 2 バージョン |

View File

@ -62,7 +62,7 @@ Uma solução empresarial de design e biblioteca UI para React.
- Renderização no lado do servidor (server-side) - Renderização no lado do servidor (server-side)
- [Electron](https://www.electronjs.org/) - [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / 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/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<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" />](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/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<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 |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| Edge | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões | | Edge | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões |

View File

@ -62,7 +62,7 @@ Un lenguaje de diseño de interfaz de usuario de clase empresarial y una bibliot
- Representación del lado del servidor - Representación del lado del servidor
- [Electron](https://www.electronjs.org/) - [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / 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" />](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 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Edge | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones | | Edge | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones |

View File

@ -62,7 +62,7 @@
- Рендеринг на стороні сервера (SSR) - Рендеринг на стороні сервера (SSR)
- [Electron](https://www.electronjs.org/) - [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / 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" />](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 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Edge | 2 останні версії | 2 останні версії | 2 останні версії | 2 останні версії | | Edge | 2 останні версії | 2 останні версії | 2 останні версії | 2 останні версії |

View File

@ -62,7 +62,7 @@
- 支持服务端渲染。 - 支持服务端渲染。
- [Electron](https://www.electronjs.org/) - [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / 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" />](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 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | | Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |

View File

@ -12,9 +12,9 @@ An enterprise-class UI design language and React UI library.
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url] [![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
[![Renovate status][renovate-image]][renovate-dashboard-url] [![Total alerts][lgtm-image]][lgtm-url] [![][bundlesize-js-image]][unpkg-js-url] [![Total alerts][lgtm-image]][lgtm-url] [![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
[![Follow Twitter][twitter-image]][twitter-url] [![FOSSA Status][fossa-image]][fossa-url] [![Discussions][discussions-image]][discussions-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url] [![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square [npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
[npm-url]: http://npmjs.org/package/antd [npm-url]: http://npmjs.org/package/antd
@ -30,12 +30,12 @@ An enterprise-class UI design language and React UI library.
[fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield [fossa-url]: https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield
[help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open [help-wanted-image]: https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22 [help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social [twitter-image]: https://badgen.net/twitter/follow/antdesignui?style=flat-square
[twitter-url]: https://twitter.com/AntDesignUI [twitter-url]: https://twitter.com/AntDesignUI
[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue?style=flat-square
[discussions-url]: https://github.com/ant-design/ant-design/discussions
[bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square [bundlesize-js-image]: https://img.badgesize.io/https:/unpkg.com/antd/dist/antd.min.js?label=antd.min.js&compression=gzip&style=flat-square
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js [unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
[bundlephobia-url]: https://bundlephobia.com/package/antd
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square [issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
[issues-helper-url]: https://github.com/actions-cool/issues-helper [issues-helper-url]: https://github.com/actions-cool/issues-helper
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square [renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
@ -62,7 +62,7 @@ English | [Português](./README-pt_BR.md) | [简体中文](./README-zh_CN.md) |
- Server-side Rendering - Server-side Rendering
- [Electron](https://www.electronjs.org/) - [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / 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" />](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 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | | Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |

View File

@ -21,7 +21,7 @@ describe('node', () => {
// Find the component exist demo test file // Find the component exist demo test file
const files = glob.sync(`./components/*/__tests__/demo.test.@(j|t)s?(x)`); const files = glob.sync(`./components/*/__tests__/demo.test.@(j|t)s?(x)`);
files.forEach(componentTestFile => { files.forEach((componentTestFile) => {
const componentName = componentTestFile.match(/components\/([^/]*)\//)![1]; const componentName = componentTestFile.match(/components\/([^/]*)\//)![1];
// Test for ssr // Test for ssr
@ -32,9 +32,9 @@ describe('node', () => {
require(`../../${componentTestFile}`); // eslint-disable-line global-require, import/no-dynamic-require require(`../../${componentTestFile}`); // eslint-disable-line global-require, import/no-dynamic-require
const option = (global as any).testConfig?.[componentName]; const option = (global as any).testConfig?.[componentName];
demoList.forEach(demoFile => { demoList.forEach((demoFile) => {
const skip: string[] = option?.skip || []; const skip: string[] = option?.skip || [];
const test = skip.some(skipMarkdown => demoFile.includes(skipMarkdown)) ? it.skip : it; const test = skip.some((skipMarkdown) => demoFile.includes(skipMarkdown)) ? it.skip : it;
test(demoFile, () => { test(demoFile, () => {
const Demo = require(`../../${demoFile}`).default; // eslint-disable-line global-require, import/no-dynamic-require const Demo = require(`../../${demoFile}`).default; // eslint-disable-line global-require, import/no-dynamic-require

View File

@ -20,7 +20,7 @@ function isThenable(thing?: PromiseLike<any>): boolean {
return !!(thing && !!thing.then); return !!(thing && !!thing.then);
} }
const ActionButton: React.FC<ActionButtonProps> = props => { const ActionButton: React.FC<ActionButtonProps> = (props) => {
const clickedRef = React.useRef<boolean>(false); const clickedRef = React.useRef<boolean>(false);
const ref = React.useRef<HTMLInputElement>(null); const ref = React.useRef<HTMLInputElement>(null);
const [loading, setLoading] = useState<ButtonProps['loading']>(false); const [loading, setLoading] = useState<ButtonProps['loading']>(false);

View File

@ -31,7 +31,7 @@ export default function genPurePanel<ComponentProps extends BaseProps>(
setOpen(true); setOpen(true);
if (typeof ResizeObserver !== 'undefined') { if (typeof ResizeObserver !== 'undefined') {
const resizeObserver = new ResizeObserver(entries => { const resizeObserver = new ResizeObserver((entries) => {
const element: HTMLDivElement = entries[0].target as any; const element: HTMLDivElement = entries[0].target as any;
setPopupHeight(element.offsetHeight + 8); setPopupHeight(element.offsetHeight + 8);
setPopupWidth(element.offsetWidth); setPopupWidth(element.offsetWidth);

View File

@ -6,10 +6,7 @@ import { waitFakeTimer, render, fireEvent } from '../../../tests/utils';
import getDataOrAriaProps from '../getDataOrAriaProps'; import getDataOrAriaProps from '../getDataOrAriaProps';
import delayRaf from '../raf'; import delayRaf from '../raf';
import { isStyleSupport } from '../styleChecker'; import { isStyleSupport } from '../styleChecker';
import { import throttleByAnimationFrame from '../throttleByAnimationFrame';
throttleByAnimationFrame,
throttleByAnimationFrameDecorator,
} from '../throttleByAnimationFrame';
import TransButton from '../transButton'; import TransButton from '../transButton';
describe('Test utils function', () => { describe('Test utils function', () => {
@ -49,22 +46,6 @@ describe('Test utils function', () => {
expect(callback).not.toHaveBeenCalled(); expect(callback).not.toHaveBeenCalled();
}); });
it('throttleByAnimationFrameDecorator should works', async () => {
const callbackFn = jest.fn();
class Test {
@throttleByAnimationFrameDecorator()
callback() {
callbackFn();
}
}
const test = new Test();
test.callback();
test.callback();
test.callback();
await waitFakeTimer();
expect(callbackFn).toHaveBeenCalledTimes(1);
});
}); });
describe('getDataOrAriaProps', () => { describe('getDataOrAriaProps', () => {

View File

@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
export default function useForceUpdate() { export default function useForceUpdate() {
const [, forceUpdate] = React.useReducer(x => x + 1, 0); const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
return forceUpdate; return forceUpdate;
} }

View File

@ -8,12 +8,12 @@ export default function usePatchElement(): [
const patchElement = React.useCallback((element: React.ReactElement) => { const patchElement = React.useCallback((element: React.ReactElement) => {
// append a new element to elements (and create a new ref) // append a new element to elements (and create a new ref)
setElements(originElements => [...originElements, element]); setElements((originElements) => [...originElements, element]);
// return a function that removes the new element out of elements (and create a new ref) // return a function that removes the new element out of elements (and create a new ref)
// it works a little like useEffect // it works a little like useEffect
return () => { return () => {
setElements(originElements => originElements.filter(ele => ele !== element)); setElements((originElements) => originElements.filter((ele) => ele !== element));
}; };
}, []); }, []);

View File

@ -4,11 +4,11 @@ import { tuple } from './type';
// ================== Collapse Motion ================== // ================== Collapse Motion ==================
const getCollapsedHeight: MotionEventHandler = () => ({ height: 0, opacity: 0 }); const getCollapsedHeight: MotionEventHandler = () => ({ height: 0, opacity: 0 });
const getRealHeight: MotionEventHandler = node => { const getRealHeight: MotionEventHandler = (node) => {
const { scrollHeight } = node; const { scrollHeight } = node;
return { height: scrollHeight, opacity: 1 }; return { height: scrollHeight, opacity: 1 };
}; };
const getCurrentHeight: MotionEventHandler = node => ({ height: node ? node.offsetHeight : 0 }); const getCurrentHeight: MotionEventHandler = (node) => ({ height: node ? node.offsetHeight : 0 });
const skipOpacityTransition: MotionEndEventHandler = (_, event: MotionEvent) => const skipOpacityTransition: MotionEndEventHandler = (_, event: MotionEvent) =>
event?.deadline === true || (event as TransitionEvent).propertyName === 'height'; event?.deadline === true || (event as TransitionEvent).propertyName === 'height';

View File

@ -94,7 +94,7 @@ export default function getPlacements(config: PlacementsConfig) {
offset: [-4, verticalArrowShift + arrowWidth], offset: [-4, verticalArrowShift + arrowWidth],
}, },
}; };
Object.keys(placementMap).forEach(key => { Object.keys(placementMap).forEach((key) => {
placementMap[key] = arrowPointAtCenter placementMap[key] = arrowPointAtCenter
? { ? {
...placementMap[key], ...placementMap[key],

View File

@ -28,7 +28,7 @@ const responsiveObserve = {
}, },
dispatch(pointMap: ScreenMap) { dispatch(pointMap: ScreenMap) {
screens = pointMap; screens = pointMap;
subscribers.forEach(func => func(screens)); subscribers.forEach((func) => func(screens));
return subscribers.size >= 1; return subscribers.size >= 1;
}, },
subscribe(func: SubscribeFunc): number { subscribe(func: SubscribeFunc): number {

View File

@ -1,6 +1,10 @@
import raf from 'rc-util/lib/raf'; import raf from 'rc-util/lib/raf';
export function throttleByAnimationFrame<T extends unknown[]>(fn: (...args: T) => void) { type throttledFn = (...args: any[]) => void;
type throttledCancelFn = { cancel: () => void };
function throttleByAnimationFrame<T extends any[]>(fn: (...args: T) => void) {
let requestId: number | null; let requestId: number | null;
const later = (args: T) => () => { const later = (args: T) => () => {
@ -8,10 +12,7 @@ export function throttleByAnimationFrame<T extends unknown[]>(fn: (...args: T) =
fn(...args); fn(...args);
}; };
const throttled: { const throttled: throttledFn & throttledCancelFn = (...args: T) => {
(...args: T): void;
cancel: () => void;
} = (...args: T) => {
if (requestId == null) { if (requestId == null) {
requestId = raf(later(args)); requestId = raf(later(args));
} }
@ -25,32 +26,4 @@ export function throttleByAnimationFrame<T extends unknown[]>(fn: (...args: T) =
return throttled; return throttled;
} }
export function throttleByAnimationFrameDecorator() { export default throttleByAnimationFrame;
return function throttle(target: any, key: string, descriptor: any) {
const fn = descriptor.value;
let definingProperty = false;
return {
configurable: true,
get() {
// In IE11 calling Object.defineProperty has a side-effect of evaluating the
// getter for the property which is being replaced. This causes infinite
// recursion and an "Out of stack space" error.
// eslint-disable-next-line no-prototype-builtins
if (definingProperty || this === target.prototype || this.hasOwnProperty(key)) {
/* istanbul ignore next */
return fn;
}
const boundFn = throttleByAnimationFrame(fn.bind(this));
definingProperty = true;
Object.defineProperty(this, key, {
value: boundFn,
configurable: true,
writable: true,
});
definingProperty = false;
return boundFn;
},
};
};
}

View File

@ -22,14 +22,14 @@ const inlineStyle: React.CSSProperties = {
}; };
const TransButton = React.forwardRef<HTMLDivElement, TransButtonProps>((props, ref) => { const TransButton = React.forwardRef<HTMLDivElement, TransButtonProps>((props, ref) => {
const onKeyDown: React.KeyboardEventHandler<HTMLDivElement> = event => { const onKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
const { keyCode } = event; const { keyCode } = event;
if (keyCode === KeyCode.ENTER) { if (keyCode === KeyCode.ENTER) {
event.preventDefault(); event.preventDefault();
} }
}; };
const onKeyUp: React.KeyboardEventHandler<HTMLDivElement> = event => { const onKeyUp: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
const { keyCode } = event; const { keyCode } = event;
const { onClick } = props; const { onClick } = props;
if (keyCode === KeyCode.ENTER && onClick) { if (keyCode === KeyCode.ENTER && onClick) {

View File

@ -12,7 +12,7 @@ interface WaveToken extends AliasToken {
clickAnimatingWithoutExtraNodeTrueAfter: string; clickAnimatingWithoutExtraNodeTrueAfter: string;
} }
const genWaveStyle: GenerateStyle<WaveToken> = token => { const genWaveStyle: GenerateStyle<WaveToken> = (token) => {
const waveEffect = new Keyframes('waveEffect', { const waveEffect = new Keyframes('waveEffect', {
'100%': { '100%': {
boxShadow: `0 0 0 6px var(--antd-wave-shadow-color)`, boxShadow: `0 0 0 6px var(--antd-wave-shadow-color)`,

View File

@ -33,7 +33,7 @@ class AffixMounter extends React.Component<{
const { getInstance, ...restProps } = this.props; const { getInstance, ...restProps } = this.props;
return ( return (
<div <div
ref={node => { ref={(node) => {
this.container = node!; this.container = node!;
}} }}
className="container" className="container"
@ -41,7 +41,7 @@ class AffixMounter extends React.Component<{
<Affix <Affix
className="fixed" className="fixed"
target={this.getTarget} target={this.getTarget}
ref={ele => { ref={(ele) => {
getInstance?.(ele!); getInstance?.(ele!);
}} }}
{...restProps} {...restProps}
@ -163,7 +163,7 @@ describe('Affix Render', () => {
let affixInstance: InternalAffixClass; let affixInstance: InternalAffixClass;
const { rerender } = render( const { rerender } = render(
<Affix <Affix
ref={node => { ref={(node) => {
affixInstance = node as InternalAffixClass; affixInstance = node as InternalAffixClass;
}} }}
target={getTarget} target={getTarget}
@ -173,7 +173,7 @@ describe('Affix Render', () => {
); );
rerender( rerender(
<Affix <Affix
ref={node => { ref={(node) => {
affixInstance = node as InternalAffixClass; affixInstance = node as InternalAffixClass;
}} }}
target={() => null} target={() => null}
@ -224,7 +224,7 @@ describe('Affix Render', () => {
const { rerender } = render( const { rerender } = render(
<AffixMounter <AffixMounter
getInstance={inst => { getInstance={(inst) => {
affixInstance = inst; affixInstance = inst;
}} }}
offsetBottom={0} offsetBottom={0}
@ -235,7 +235,7 @@ describe('Affix Render', () => {
rerender( rerender(
<AffixMounter <AffixMounter
getInstance={inst => { getInstance={(inst) => {
affixInstance = inst; affixInstance = inst;
}} }}
offsetBottom={0} offsetBottom={0}
@ -256,7 +256,7 @@ describe('Affix Render', () => {
let affixInstance: InternalAffixClass | null = null; let affixInstance: InternalAffixClass | null = null;
render( render(
<AffixMounter <AffixMounter
getInstance={inst => { getInstance={(inst) => {
affixInstance = inst; affixInstance = inst;
}} }}
offsetBottom={0} offsetBottom={0}
@ -275,7 +275,7 @@ describe('Affix Render', () => {
[ [
'.ant-btn', // inner '.ant-btn', // inner
'.fixed', // outer '.fixed', // outer
].forEach(selector => { ].forEach((selector) => {
it(`trigger listener when size change: ${selector}`, async () => { it(`trigger listener when size change: ${selector}`, async () => {
const updateCalled = jest.fn(); const updateCalled = jest.fn();
const { container } = render( const { container } = render(

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Affix, Button } from 'antd'; import { Affix, Button } from 'antd';
const App: React.FC = () => ( const App: React.FC = () => (
<Affix offsetTop={120} onChange={affixed => console.log(affixed)}> <Affix offsetTop={120} onChange={(affixed) => console.log(affixed)}>
<Button>120px to affix top</Button> <Button>120px to affix top</Button>
</Affix> </Affix>
); );

View File

@ -4,7 +4,7 @@ import omit from 'rc-util/lib/omit';
import * as React from 'react'; import * as React from 'react';
import type { ConfigConsumerProps } from '../config-provider'; import type { ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider'; import { ConfigContext } from '../config-provider';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame'; import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
import useStyle from './style'; import useStyle from './style';
import { import {
@ -126,9 +126,9 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
componentWillUnmount() { componentWillUnmount() {
clearTimeout(this.timeout); clearTimeout(this.timeout);
removeObserveTarget(this); removeObserveTarget(this);
(this.updatePosition as any).cancel(); this.updatePosition.cancel();
// https://github.com/ant-design/ant-design/issues/22683 // https://github.com/ant-design/ant-design/issues/22683
(this.lazyUpdatePosition as any).cancel(); this.lazyUpdatePosition.cancel();
} }
getOffsetTop = () => { getOffsetTop = () => {
@ -228,14 +228,11 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
} }
}; };
// Handle realign logic updatePosition = throttleByAnimationFrame(() => {
@throttleByAnimationFrameDecorator()
updatePosition() {
this.prepareMeasure(); this.prepareMeasure();
} });
@throttleByAnimationFrameDecorator() lazyUpdatePosition = throttleByAnimationFrame(() => {
lazyUpdatePosition() {
const targetFunc = this.getTargetFunc(); const targetFunc = this.getTargetFunc();
const { affixStyle } = this.state; const { affixStyle } = this.state;
@ -262,7 +259,7 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
// Directly call prepare measure since it's already throttled. // Directly call prepare measure since it's already throttled.
this.prepareMeasure(); this.prepareMeasure();
} });
// =================== Render =================== // =================== Render ===================
render() { render() {
@ -288,21 +285,11 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
} }
return ( return (
<ResizeObserver <ResizeObserver onResize={this.updatePosition}>
onResize={() => {
this.updatePosition();
}}
>
<div {...props} ref={this.savePlaceholderNode}> <div {...props} ref={this.savePlaceholderNode}>
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />} {affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
<div className={className} ref={this.saveFixedNode} style={affixStyle}> <div className={className} ref={this.saveFixedNode} style={affixStyle}>
<ResizeObserver <ResizeObserver onResize={this.updatePosition}>{children}</ResizeObserver>
onResize={() => {
this.updatePosition();
}}
>
{children}
</ResizeObserver>
</div> </div>
</div> </div>
</ResizeObserver> </ResizeObserver>
@ -321,7 +308,6 @@ const AffixFC = React.forwardRef<Affix, AffixProps>((props, ref) => {
const AffixProps: InternalAffixProps = { const AffixProps: InternalAffixProps = {
...props, ...props,
affixPrefixCls, affixPrefixCls,
rootClassName: hashId, rootClassName: hashId,
}; };

View File

@ -19,7 +19,7 @@ const genSharedAffixStyle: GenerateStyle<AffixToken> = (token): CSSObject => {
}; };
// ============================== Export ============================== // ============================== Export ==============================
export default genComponentStyleHook('Affix', token => { export default genComponentStyleHook('Affix', (token) => {
const affixToken = mergeToken<AffixToken>(token, { const affixToken = mergeToken<AffixToken>(token, {
zIndexPopup: token.zIndexBase + 10, zIndexPopup: token.zIndexBase + 10,
}); });

View File

@ -56,7 +56,7 @@ export function addObserveTarget<T>(target: HTMLElement | Window | null, affix?:
return; return;
} }
let entity: ObserverEntity | undefined = observerEntities.find(item => item.target === target); let entity: ObserverEntity | undefined = observerEntities.find((item) => item.target === target);
if (entity) { if (entity) {
entity.affixList.push(affix); entity.affixList.push(affix);
@ -69,9 +69,9 @@ export function addObserveTarget<T>(target: HTMLElement | Window | null, affix?:
observerEntities.push(entity); observerEntities.push(entity);
// Add listener // Add listener
TRIGGER_EVENTS.forEach(eventName => { TRIGGER_EVENTS.forEach((eventName) => {
entity!.eventHandlers[eventName] = addEventListener(target, eventName, () => { entity!.eventHandlers[eventName] = addEventListener(target, eventName, () => {
entity!.affixList.forEach(targetAffix => { entity!.affixList.forEach((targetAffix) => {
targetAffix.lazyUpdatePosition(); targetAffix.lazyUpdatePosition();
}); });
}); });
@ -80,19 +80,19 @@ export function addObserveTarget<T>(target: HTMLElement | Window | null, affix?:
} }
export function removeObserveTarget<T>(affix: T): void { export function removeObserveTarget<T>(affix: T): void {
const observerEntity = observerEntities.find(oriObserverEntity => { const observerEntity = observerEntities.find((oriObserverEntity) => {
const hasAffix = oriObserverEntity.affixList.some(item => item === affix); const hasAffix = oriObserverEntity.affixList.some((item) => item === affix);
if (hasAffix) { if (hasAffix) {
oriObserverEntity.affixList = oriObserverEntity.affixList.filter(item => item !== affix); oriObserverEntity.affixList = oriObserverEntity.affixList.filter((item) => item !== affix);
} }
return hasAffix; return hasAffix;
}); });
if (observerEntity && observerEntity.affixList.length === 0) { if (observerEntity && observerEntity.affixList.length === 0) {
observerEntities = observerEntities.filter(item => item !== observerEntity); observerEntities = observerEntities.filter((item) => item !== observerEntity);
// Remove listener // Remove listener
TRIGGER_EVENTS.forEach(eventName => { TRIGGER_EVENTS.forEach((eventName) => {
const handler = observerEntity.eventHandlers[eventName]; const handler = observerEntity.eventHandlers[eventName];
if (handler && handler.remove) { if (handler && handler.remove) {
handler.remove(); handler.remove();

View File

@ -61,7 +61,7 @@ interface IconNodeProps {
description: AlertProps['description']; description: AlertProps['description'];
} }
const IconNode: React.FC<IconNodeProps> = props => { const IconNode: React.FC<IconNodeProps> = (props) => {
const { icon, prefixCls, type } = props; const { icon, prefixCls, type } = props;
const iconType = iconMapFilled[type!] || null; const iconType = iconMapFilled[type!] || null;
if (icon) { if (icon) {
@ -82,7 +82,7 @@ interface CloseIconProps {
handleClose: AlertProps['onClose']; handleClose: AlertProps['onClose'];
} }
const CloseIcon: React.FC<CloseIconProps> = props => { const CloseIcon: React.FC<CloseIconProps> = (props) => {
const { isClosable, closeText, prefixCls, closeIcon, handleClose } = props; const { isClosable, closeText, prefixCls, closeIcon, handleClose } = props;
return isClosable ? ( return isClosable ? (
<button type="button" onClick={handleClose} className={`${prefixCls}-close-icon`} tabIndex={0}> <button type="button" onClick={handleClose} className={`${prefixCls}-close-icon`} tabIndex={0}>
@ -91,11 +91,11 @@ const CloseIcon: React.FC<CloseIconProps> = props => {
) : null; ) : null;
}; };
interface AlertInterface extends React.FC<AlertProps> { type CompoundedComponent = React.FC<AlertProps> & {
ErrorBoundary: typeof ErrorBoundary; ErrorBoundary: typeof ErrorBoundary;
} };
const Alert: AlertInterface = ({ const Alert: CompoundedComponent = ({
description, description,
prefixCls: customizePrefixCls, prefixCls: customizePrefixCls,
message, message,
@ -162,7 +162,7 @@ const Alert: AlertInterface = ({
motionName={`${prefixCls}-motion`} motionName={`${prefixCls}-motion`}
motionAppear={false} motionAppear={false}
motionEnter={false} motionEnter={false}
onLeaveStart={node => ({ onLeaveStart={(node) => ({
maxHeight: node.offsetHeight, maxHeight: node.offsetHeight,
})} })}
onLeaveEnd={afterClose} onLeaveEnd={afterClose}

View File

@ -14,7 +14,7 @@ export interface AnchorLinkProps {
className?: string; className?: string;
} }
const AnchorLink: React.FC<AnchorLinkProps> = props => { const AnchorLink: React.FC<AnchorLinkProps> = (props) => {
const { href = '#', title, prefixCls: customizePrefixCls, children, className, target } = props; const { href = '#', title, prefixCls: customizePrefixCls, children, className, target } = props;
const context = React.useContext<AntAnchor | undefined>(AnchorContext); const context = React.useContext<AntAnchor | undefined>(AnchorContext);

View File

@ -6,11 +6,11 @@ export type { AnchorLinkProps } from './AnchorLink';
type InternalAnchorType = typeof InternalAnchor; type InternalAnchorType = typeof InternalAnchor;
interface AnchorInterface extends InternalAnchorType { type CompoundedComponent = InternalAnchorType & {
Link: typeof AnchorLink; Link: typeof AnchorLink;
} };
const Anchor = InternalAnchor as AnchorInterface; const Anchor = InternalAnchor as CompoundedComponent;
Anchor.Link = AnchorLink; Anchor.Link = AnchorLink;
export default Anchor; export default Anchor;

View File

@ -679,20 +679,20 @@ exports[`renders ./components/auto-complete/demo/form-debug.tsx extend context c
<ellipse <ellipse
cx="32" cx="32"
cy="33" cy="33"
fill="#F5F5F5" fill="#f5f5f5"
rx="32" rx="32"
ry="7" ry="7"
/> />
<g <g
fill-rule="nonzero" fill-rule="nonzero"
stroke="#D9D9D9" stroke="#d9d9d9"
> >
<path <path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z" d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/> />
<path <path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA" fill="#fafafa"
/> />
</g> </g>
</g> </g>
@ -827,20 +827,20 @@ exports[`renders ./components/auto-complete/demo/form-debug.tsx extend context c
<ellipse <ellipse
cx="32" cx="32"
cy="33" cy="33"
fill="#F5F5F5" fill="#f5f5f5"
rx="32" rx="32"
ry="7" ry="7"
/> />
<g <g
fill-rule="nonzero" fill-rule="nonzero"
stroke="#D9D9D9" stroke="#d9d9d9"
> >
<path <path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z" d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/> />
<path <path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA" fill="#fafafa"
/> />
</g> </g>
</g> </g>
@ -1115,20 +1115,20 @@ exports[`renders ./components/auto-complete/demo/form-debug.tsx extend context c
<ellipse <ellipse
cx="32" cx="32"
cy="33" cy="33"
fill="#F5F5F5" fill="#f5f5f5"
rx="32" rx="32"
ry="7" ry="7"
/> />
<g <g
fill-rule="nonzero" fill-rule="nonzero"
stroke="#D9D9D9" stroke="#d9d9d9"
> >
<path <path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z" d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/> />
<path <path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA" fill="#fafafa"
/> />
</g> </g>
</g> </g>
@ -1332,20 +1332,20 @@ exports[`renders ./components/auto-complete/demo/form-debug.tsx extend context c
<ellipse <ellipse
cx="32" cx="32"
cy="33" cy="33"
fill="#F5F5F5" fill="#f5f5f5"
rx="32" rx="32"
ry="7" ry="7"
/> />
<g <g
fill-rule="nonzero" fill-rule="nonzero"
stroke="#D9D9D9" stroke="#d9d9d9"
> >
<path <path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z" d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/> />
<path <path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA" fill="#fafafa"
/> />
</g> </g>
</g> </g>
@ -1558,20 +1558,20 @@ exports[`renders ./components/auto-complete/demo/form-debug.tsx extend context c
<ellipse <ellipse
cx="32" cx="32"
cy="33" cy="33"
fill="#F5F5F5" fill="#f5f5f5"
rx="32" rx="32"
ry="7" ry="7"
/> />
<g <g
fill-rule="nonzero" fill-rule="nonzero"
stroke="#D9D9D9" stroke="#d9d9d9"
> >
<path <path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z" d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/> />
<path <path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA" fill="#fafafa"
/> />
</g> </g>
</g> </g>

View File

@ -9,7 +9,7 @@ const App: React.FC = () => {
if (!value || value.indexOf('@') >= 0) { if (!value || value.indexOf('@') >= 0) {
res = []; res = [];
} else { } else {
res = ['gmail.com', '163.com', 'qq.com'].map(domain => ({ res = ['gmail.com', '163.com', 'qq.com'].map((domain) => ({
value, value,
label: `${value}@${domain}`, label: `${value}@${domain}`,
})); }));

View File

@ -86,7 +86,7 @@ const AutoComplete: React.ForwardRefRenderFunction<RefSelectProps, AutoCompleteP
optionChildren = children; optionChildren = children;
} else { } else {
optionChildren = dataSource optionChildren = dataSource
? dataSource.map(item => { ? dataSource.map((item) => {
if (isValidElement(item)) { if (isValidElement(item)) {
return item; return item;
} }

View File

@ -12,7 +12,7 @@ export interface SizeContextProps {
export const SizeContextProvider: React.FC<SizeContextProps> = ({ children, size }) => ( export const SizeContextProvider: React.FC<SizeContextProps> = ({ children, size }) => (
<SizeContext.Consumer> <SizeContext.Consumer>
{originSize => ( {(originSize) => (
<SizeContext.Provider value={size || originSize}>{children}</SizeContext.Provider> <SizeContext.Provider value={size || originSize}>{children}</SizeContext.Provider>
)} )}
</SizeContext.Consumer> </SizeContext.Consumer>

View File

@ -108,7 +108,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
const size = customSize === 'default' ? groupSize : customSize; const size = customSize === 'default' ? groupSize : customSize;
const needResponsive = Object.keys(typeof size === 'object' ? size || {} : {}).some(key => const needResponsive = Object.keys(typeof size === 'object' ? size || {} : {}).some((key) =>
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].includes(key), ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].includes(key),
); );
const screens = useBreakpoint(needResponsive); const screens = useBreakpoint(needResponsive);
@ -117,7 +117,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
return {}; return {};
} }
const currentBreakpoint: Breakpoint = responsiveArray.find(screen => screens[screen])!; const currentBreakpoint: Breakpoint = responsiveArray.find((screen) => screens[screen])!;
const currentSize = size[currentBreakpoint]; const currentSize = size[currentBreakpoint];
return currentSize return currentSize

View File

@ -25,7 +25,7 @@ export interface GroupProps {
size?: AvatarSize; size?: AvatarSize;
} }
const Group: React.FC<GroupProps> = props => { const Group: React.FC<GroupProps> = (props) => {
const { getPrefixCls, direction } = React.useContext(ConfigContext); const { getPrefixCls, direction } = React.useContext(ConfigContext);
const { prefixCls: customizePrefixCls, className = '', maxCount, maxStyle, size } = props; const { prefixCls: customizePrefixCls, className = '', maxCount, maxStyle, size } = props;

View File

@ -20,7 +20,7 @@ type AvatarToken = FullToken<'Avatar'> & {
avatarBgColor: string; avatarBgColor: string;
}; };
const genBaseStyle: GenerateStyle<AvatarToken> = token => { const genBaseStyle: GenerateStyle<AvatarToken> = (token) => {
const { const {
antCls, antCls,
componentCls, componentCls,
@ -109,7 +109,7 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
}; };
}; };
const genGroupStyle: GenerateStyle<AvatarToken> = token => { const genGroupStyle: GenerateStyle<AvatarToken> = (token) => {
const { componentCls, avatarGroupBorderColor, avatarGroupOverlapping, avatarGroupSpace } = token; const { componentCls, avatarGroupBorderColor, avatarGroupOverlapping, avatarGroupSpace } = token;
return { return {
@ -133,7 +133,7 @@ const genGroupStyle: GenerateStyle<AvatarToken> = token => {
}; };
}; };
export default genComponentStyleHook('Avatar', token => { export default genComponentStyleHook('Avatar', (token) => {
const { const {
colorTextLightSolid, colorTextLightSolid,

View File

@ -9,7 +9,7 @@ import { ConfigContext } from '../config-provider';
import getScroll from '../_util/getScroll'; import getScroll from '../_util/getScroll';
import { cloneElement } from '../_util/reactNode'; import { cloneElement } from '../_util/reactNode';
import scrollTo from '../_util/scrollTo'; import scrollTo from '../_util/scrollTo';
import { throttleByAnimationFrame } from '../_util/throttleByAnimationFrame'; import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
import warning from '../_util/warning'; import warning from '../_util/warning';
import useStyle from './style'; import useStyle from './style';
@ -32,7 +32,7 @@ interface ChildrenProps {
visible?: boolean; // Only for test. Don't use it. visible?: boolean; // Only for test. Don't use it.
} }
const BackTopContent: React.FC<ChildrenProps> = props => { const BackTopContent: React.FC<ChildrenProps> = (props) => {
const { prefixCls, rootPrefixCls, children, visible } = props; const { prefixCls, rootPrefixCls, children, visible } = props;
const defaultElement = ( const defaultElement = (
<div className={`${prefixCls}-content`}> <div className={`${prefixCls}-content`}>
@ -52,7 +52,7 @@ const BackTopContent: React.FC<ChildrenProps> = props => {
); );
}; };
const BackTop: React.FC<BackTopProps> = props => { const BackTop: React.FC<BackTopProps> = (props) => {
const [visible, setVisible] = useMergedState(false, { const [visible, setVisible] = useMergedState(false, {
value: props.visible, value: props.visible,
}); });

View File

@ -95,7 +95,7 @@ export default function SingleNumber(props: SingleNumberProps) {
} }
// Fill with number unit nodes // Fill with number unit nodes
const prevIndex = unitNumberList.findIndex(n => n % 10 === prevValue); const prevIndex = unitNumberList.findIndex((n) => n % 10 === prevValue);
unitNodes = unitNumberList.map((n, index) => { unitNodes = unitNumberList.map((n, index) => {
const singleUnit = n % 10; const singleUnit = n % 10;
return ( return (

View File

@ -1727,7 +1727,7 @@ exports[`renders ./components/badge/demo/overflow.tsx extend context correctly 1
</div> </div>
`; `;
exports[`renders ./components/badge/demo/ribbbon.tsx extend context correctly 1`] = ` exports[`renders ./components/badge/demo/ribbon.tsx extend context correctly 1`] = `
<div <div
class="ant-space ant-space-vertical" class="ant-space ant-space-vertical"
style="width:100%" style="width:100%"

View File

@ -1727,7 +1727,7 @@ exports[`renders ./components/badge/demo/overflow.tsx correctly 1`] = `
</div> </div>
`; `;
exports[`renders ./components/badge/demo/ribbbon.tsx correctly 1`] = ` exports[`renders ./components/badge/demo/ribbon.tsx correctly 1`] = `
<div <div
class="ant-space ant-space-vertical" class="ant-space ant-space-vertical"
style="width:100%" style="width:100%"

View File

@ -21,7 +21,7 @@ const App: React.FC = () => (
<> <>
<Divider orientation="left">Presets</Divider> <Divider orientation="left">Presets</Divider>
<Space direction="vertical"> <Space direction="vertical">
{colors.map(color => ( {colors.map((color) => (
<Badge key={color} color={color} text={color} /> <Badge key={color} color={color} text={color} />
))} ))}
</Space> </Space>

View File

@ -26,7 +26,7 @@ Badge normally appears in proximity to notifications or user avatars with eye-ca
<code src="./demo/size.tsx">Size</code> <code src="./demo/size.tsx">Size</code>
<code src="./demo/status.tsx">Status</code> <code src="./demo/status.tsx">Status</code>
<code src="./demo/colorful.tsx">Colorful Badge</code> <code src="./demo/colorful.tsx">Colorful Badge</code>
<code src="./demo/ribbbon.tsx">Ribbon</code> <code src="./demo/ribbon.tsx">Ribbon</code>
<code src="./demo/ribbon-debug.tsx" debug>Ribbon Debug</code> <code src="./demo/ribbon-debug.tsx" debug>Ribbon Debug</code>
<code src="./demo/mix.tsx" debug>Mixed usage</code> <code src="./demo/mix.tsx" debug>Mixed usage</code>
<code src="./demo/title.tsx" debug>Title</code> <code src="./demo/title.tsx" debug>Title</code>

View File

@ -13,9 +13,9 @@ import { isPresetColor } from './utils';
export type { ScrollNumberProps } from './ScrollNumber'; export type { ScrollNumberProps } from './ScrollNumber';
interface CompoundedComponent extends React.FC<BadgeProps> { type CompoundedComponent = React.FC<BadgeProps> & {
Ribbon: typeof Ribbon; Ribbon: typeof Ribbon;
} };
export interface BadgeProps { export interface BadgeProps {
/** Number to show in badge */ /** Number to show in badge */
@ -137,7 +137,7 @@ const Badge: CompoundedComponent = ({
const displayNode = const displayNode =
!livingCount || typeof livingCount !== 'object' !livingCount || typeof livingCount !== 'object'
? undefined ? undefined
: cloneElement(livingCount, oriProps => ({ : cloneElement(livingCount, (oriProps) => ({
style: { style: {
...mergedStyle, ...mergedStyle,
...oriProps.style, ...oriProps.style,

View File

@ -27,7 +27,7 @@ group: 数据展示
<code src="./demo/size.tsx">大小</code> <code src="./demo/size.tsx">大小</code>
<code src="./demo/status.tsx">状态点</code> <code src="./demo/status.tsx">状态点</code>
<code src="./demo/colorful.tsx">多彩徽标</code> <code src="./demo/colorful.tsx">多彩徽标</code>
<code src="./demo/ribbbon.tsx">缎带</code> <code src="./demo/ribbon.tsx">缎带</code>
<code src="./demo/ribbon-debug.tsx" debug>Ribbon Debug</code> <code src="./demo/ribbon-debug.tsx" debug>Ribbon Debug</code>
<code src="./demo/mix.tsx" debug>各种混用的情况</code> <code src="./demo/mix.tsx" debug>各种混用的情况</code>
<code src="./demo/title.tsx" debug>自定义标题</code> <code src="./demo/title.tsx" debug>自定义标题</code>

View File

@ -69,12 +69,12 @@ const addChildPath = (paths: string[], childPath: string, params: any) => {
return originalPaths; return originalPaths;
}; };
interface BreadcrumbInterface extends React.FC<BreadcrumbProps> { type CompoundedComponent = React.FC<BreadcrumbProps> & {
Item: typeof BreadcrumbItem; Item: typeof BreadcrumbItem;
Separator: typeof BreadcrumbSeparator; Separator: typeof BreadcrumbSeparator;
} };
const Breadcrumb: BreadcrumbInterface = ({ const Breadcrumb: CompoundedComponent = ({
prefixCls: customizePrefixCls, prefixCls: customizePrefixCls,
separator = '/', separator = '/',
style, style,

View File

@ -36,7 +36,7 @@ describe('react router', () => {
const Home: React.FC = () => { const Home: React.FC = () => {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const pathSnippets = location.pathname.split('/').filter(i => i); const pathSnippets = location.pathname.split('/').filter((i) => i);
const extraBreadcrumbItems = pathSnippets.map((_, index) => { const extraBreadcrumbItems = pathSnippets.map((_, index) => {
const url = `/${pathSnippets.slice(0, index + 1).join('/')}`; const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
return ( return (
@ -51,11 +51,11 @@ describe('react router', () => {
</Breadcrumb.Item>, </Breadcrumb.Item>,
].concat(extraBreadcrumbItems); ].concat(extraBreadcrumbItems);
const componentProps = useMemo<RouterProps>( const componentProps = useMemo<RouterProps>(
() => ({ component: Apps } as unknown as RouterProps), () => ({ component: Apps }) as unknown as RouterProps,
[], [],
); );
const renderProps = useMemo<RouterProps>( const renderProps = useMemo<RouterProps>(
() => ({ render: () => <span>Home Page</span> } as unknown as RouterProps), () => ({ render: () => <span>Home Page</span> }) as unknown as RouterProps,
[], [],
); );
return ( return (

View File

@ -23,7 +23,7 @@ const breadcrumbNameMap: Record<string, string> = {
const Home = () => { const Home = () => {
const location = useLocation(); const location = useLocation();
const pathSnippets = location.pathname.split('/').filter(i => i); const pathSnippets = location.pathname.split('/').filter((i) => i);
const extraBreadcrumbItems = pathSnippets.map((_, index) => { const extraBreadcrumbItems = pathSnippets.map((_, index) => {
const url = `/${pathSnippets.slice(0, index + 1).join('/')}`; const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;

View File

@ -43,11 +43,11 @@ it('Delay loading timer in Button component', () => {
// other component may call setTimeout or clearTimeout // other component may call setTimeout or clearTimeout
const setTimeoutCount = () => { const setTimeoutCount = () => {
const items = setTimeoutMock.mock.calls.filter(item => item[1] === specialDelay); const items = setTimeoutMock.mock.calls.filter((item) => item[1] === specialDelay);
return items.length; return items.length;
}; };
const clearTimeoutCount = () => { const clearTimeoutCount = () => {
const items = clearTimeoutMock.mock.calls.filter(item => item[0] === btnTimer); const items = clearTimeoutMock.mock.calls.filter((item) => item[0] === btnTimer);
return items.length; return items.length;
}; };

View File

@ -5,7 +5,7 @@ import { act } from 'react-dom/test-utils';
import Button from '..'; import Button from '..';
import mountTest from '../../../tests/shared/mountTest'; import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest'; import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render, sleep } from '../../../tests/utils'; import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import ConfigProvider from '../../config-provider'; import ConfigProvider from '../../config-provider';
describe('Button', () => { describe('Button', () => {
@ -242,6 +242,7 @@ describe('Button', () => {
}); });
it('should support to change loading', async () => { it('should support to change loading', async () => {
jest.useFakeTimers();
const { container, rerender, unmount } = render(<Button>Button</Button>); const { container, rerender, unmount } = render(<Button>Button</Button>);
rerender(<Button loading />); rerender(<Button loading />);
expect(container.querySelectorAll('.ant-btn-loading').length).toBe(1); expect(container.querySelectorAll('.ant-btn-loading').length).toBe(1);
@ -249,12 +250,13 @@ describe('Button', () => {
expect(container.querySelectorAll('.ant-btn-loading').length).toBe(0); expect(container.querySelectorAll('.ant-btn-loading').length).toBe(0);
rerender(<Button loading={{ delay: 50 }} />); rerender(<Button loading={{ delay: 50 }} />);
expect(container.querySelectorAll('.ant-btn-loading').length).toBe(0); expect(container.querySelectorAll('.ant-btn-loading').length).toBe(0);
await sleep(50); await waitFakeTimer();
expect(container.querySelectorAll('.ant-btn-loading').length).toBe(1); expect(container.querySelectorAll('.ant-btn-loading').length).toBe(1);
rerender(<Button loading={false} />); rerender(<Button loading={false} />);
await sleep(50); await waitFakeTimer();
expect(container.querySelectorAll('.ant-btn-loading').length).toBe(0); expect(container.querySelectorAll('.ant-btn-loading').length).toBe(0);
expect(unmount).not.toThrow(); expect(unmount).not.toThrow();
jest.useRealTimers();
}); });
it('should warning when pass a string as icon props', () => { it('should warning when pass a string as icon props', () => {
@ -297,7 +299,7 @@ describe('Button', () => {
render( render(
<ConfigProvider autoInsertSpaceInButton={false}> <ConfigProvider autoInsertSpaceInButton={false}>
<Button <Button
ref={node => { ref={(node) => {
buttonInstance = node; buttonInstance = node;
}} }}
> >

View File

@ -1,6 +1,7 @@
import userEvent from '@testing-library/user-event';
import React from 'react'; import React from 'react';
import Button from '..'; import Button from '..';
import { fireEvent, render, sleep, assertsExist } from '../../../tests/utils'; import { fireEvent, render, assertsExist } from '../../../tests/utils';
// Mock Wave ref // Mock Wave ref
let waveInstanceMock: any; let waveInstanceMock: any;
@ -13,7 +14,7 @@ jest.mock('../../_util/wave', () => {
__esModule: true, __esModule: true,
default: (props: import('../../_util/wave').WaveProps) => ( default: (props: import('../../_util/wave').WaveProps) => (
<WaveComponent <WaveComponent
ref={node => { ref={(node) => {
waveInstanceMock = node; waveInstanceMock = node;
}} }}
{...props} {...props}
@ -23,13 +24,21 @@ jest.mock('../../_util/wave', () => {
}); });
describe('click wave effect', () => { describe('click wave effect', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});
async function clickButton(wrapper: any) { async function clickButton(wrapper: any) {
const element = wrapper.container.firstChild; const element = wrapper.container.firstChild;
fireEvent.click(element); // https://github.com/testing-library/user-event/issues/833
await userEvent.setup({ advanceTimers: jest.advanceTimersByTime }).click(element);
fireEvent(element, new Event('transitionstart')); fireEvent(element, new Event('transitionstart'));
await sleep(20);
fireEvent(element, new Event('animationend')); fireEvent(element, new Event('animationend'));
await sleep(20);
} }
it('should have click wave effect for primary button', async () => { it('should have click wave effect for primary button', async () => {
@ -82,8 +91,9 @@ describe('click wave effect', () => {
const resetEffect = jest.spyOn(waveInstanceMock, 'resetEffect'); const resetEffect = jest.spyOn(waveInstanceMock, 'resetEffect');
await clickButton(wrapper); await clickButton(wrapper);
expect(resetEffect).toHaveBeenCalledTimes(1); expect(resetEffect).toHaveBeenCalledTimes(1);
fireEvent.click(wrapper.container.querySelector('.ant-btn')!); await userEvent
await sleep(10); .setup({ advanceTimers: jest.advanceTimersByTime })
.click(wrapper.container.querySelector('.ant-btn')!);
expect(resetEffect).toHaveBeenCalledTimes(2); expect(resetEffect).toHaveBeenCalledTimes(2);
waveInstanceMock.animationStart = false; waveInstanceMock.animationStart = false;
fireEvent(wrapper.container.querySelector('.ant-btn')!, new Event('transitionstart')); fireEvent(wrapper.container.querySelector('.ant-btn')!, new Event('transitionstart'));

View File

@ -15,7 +15,7 @@ export interface ButtonGroupProps {
export const GroupSizeContext = React.createContext<SizeType | undefined>(undefined); export const GroupSizeContext = React.createContext<SizeType | undefined>(undefined);
const ButtonGroup: React.FC<ButtonGroupProps> = props => { const ButtonGroup: React.FC<ButtonGroupProps> = (props) => {
const { getPrefixCls, direction } = React.useContext(ConfigContext); const { getPrefixCls, direction } = React.useContext(ConfigContext);
const { prefixCls: customizePrefixCls, size, className, ...others } = props; const { prefixCls: customizePrefixCls, size, className, ...others } = props;

View File

@ -58,7 +58,7 @@ function insertSpace(child: React.ReactElement | string | number, needInserted:
function spaceChildren(children: React.ReactNode, needInserted: boolean) { function spaceChildren(children: React.ReactNode, needInserted: boolean) {
let isPrevChildPure: boolean = false; let isPrevChildPure: boolean = false;
const childList: React.ReactNode[] = []; const childList: React.ReactNode[] = [];
React.Children.forEach(children, child => { React.Children.forEach(children, (child) => {
const type = typeof child; const type = typeof child;
const isCurrentChildPure = type === 'string' || type === 'number'; const isCurrentChildPure = type === 'string' || type === 'number';
if (isPrevChildPure && isCurrentChildPure) { if (isPrevChildPure && isCurrentChildPure) {
@ -73,7 +73,7 @@ function spaceChildren(children: React.ReactNode, needInserted: boolean) {
}); });
// Pass to React.Children.map to auto fill key // Pass to React.Children.map to auto fill key
return React.Children.map(childList, child => return React.Children.map(childList, (child) =>
insertSpace(child as React.ReactElement | string | number, needInserted), insertSpace(child as React.ReactElement | string | number, needInserted),
); );
} }
@ -131,12 +131,13 @@ export type NativeButtonProps = {
export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>; export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>;
interface CompoundedComponent type CompoundedComponent = React.ForwardRefExoticComponent<
extends React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLElement>> { ButtonProps & React.RefAttributes<HTMLElement>
> & {
Group: typeof Group; Group: typeof Group;
/** @internal */ /** @internal */
__ANT_BUTTON: boolean; __ANT_BUTTON: boolean;
} };
type Loading = number | boolean; type Loading = number | boolean;

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