mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 10:59:19 +08:00
Compare commits
145 Commits
chore/scri
...
5.28.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a4a4abe1a | ||
|
|
2037fa7834 | ||
|
|
f3d75842fa | ||
|
|
a4b8185a74 | ||
|
|
ce9a5dc2fd | ||
|
|
2b12ef528d | ||
|
|
44526a56a7 | ||
|
|
2f6846d2a5 | ||
|
|
8471922710 | ||
|
|
3966a9fcc8 | ||
|
|
dee2365bed | ||
|
|
39843ae9b2 | ||
|
|
51949965ce | ||
|
|
be0d352579 | ||
|
|
bf1a3393fc | ||
|
|
d11b6c7807 | ||
|
|
d928c9b2fb | ||
|
|
15a17dee7c | ||
|
|
fbfc09901e | ||
|
|
0db00b0886 | ||
|
|
041f6d6692 | ||
|
|
45b929dfd7 | ||
|
|
d33d8cf959 | ||
|
|
0bd374b94e | ||
|
|
352f6c6c78 | ||
|
|
ec658c9842 | ||
|
|
134a474ed4 | ||
|
|
9e792c72c2 | ||
|
|
1ff663afa8 | ||
|
|
1c0f1cdc06 | ||
|
|
259e533757 | ||
|
|
7f921b0ad4 | ||
|
|
cf34c4a1eb | ||
|
|
2ee85ee240 | ||
|
|
d29f4721b6 | ||
|
|
e1ff71744e | ||
|
|
26c3b09eeb | ||
|
|
682c460673 | ||
|
|
6e958871c4 | ||
|
|
27a9c8a57c | ||
|
|
8a81accfaf | ||
|
|
41b5dce953 | ||
|
|
80a1f69588 | ||
|
|
40531626c1 | ||
|
|
d7ee8cc377 | ||
|
|
246c14b442 | ||
|
|
bf7cd94b89 | ||
|
|
d3ac9eddd0 | ||
|
|
5a69863ac1 | ||
|
|
00e392e66d | ||
|
|
1d0b0a440c | ||
|
|
8ab7fa52d4 | ||
|
|
c6bff1aca6 | ||
|
|
c13ac86af2 | ||
|
|
db2b6c93f6 | ||
|
|
da7c8192a3 | ||
|
|
94a2574e4a | ||
|
|
384646768d | ||
|
|
addf5ba2f7 | ||
|
|
1592b9c4df | ||
|
|
2933bd66ce | ||
|
|
60000bc14e | ||
|
|
1c30401023 | ||
|
|
553ac801d3 | ||
|
|
34297362a3 | ||
|
|
44223967ae | ||
|
|
f187eeafb3 | ||
|
|
5fe4cff30d | ||
|
|
8095b8c467 | ||
|
|
4aeb941bec | ||
|
|
ec44482a1b | ||
|
|
2131d9f7e2 | ||
|
|
2bceb47f3a | ||
|
|
70cba6b961 | ||
|
|
4c6f5d965b | ||
|
|
5c122a805d | ||
|
|
d792286afe | ||
|
|
6d879793fd | ||
|
|
e06b9533c0 | ||
|
|
4195a736e2 | ||
|
|
563e855dec | ||
|
|
a31d11d8a7 | ||
|
|
2367a516c4 | ||
|
|
af1a78a83f | ||
|
|
9e2ca60497 | ||
|
|
072c9fa707 | ||
|
|
a0a32ff450 | ||
|
|
25001647a7 | ||
|
|
3b47ac3630 | ||
|
|
7a70bafe42 | ||
|
|
c0408b70aa | ||
|
|
90696b1632 | ||
|
|
1252e72856 | ||
|
|
f442fa2518 | ||
|
|
b447d9c22a | ||
|
|
f981a12895 | ||
|
|
474245dd7b | ||
|
|
62bd8e367d | ||
|
|
cea58dc907 | ||
|
|
479963ccbc | ||
|
|
a534480899 | ||
|
|
785f7fd8a3 | ||
|
|
d82c775248 | ||
|
|
76fe1be8a6 | ||
|
|
de674acfc9 | ||
|
|
5bbb3726b8 | ||
|
|
eef4faa527 | ||
|
|
4760c2af89 | ||
|
|
c61c5abd69 | ||
|
|
dd3de44261 | ||
|
|
b16183b209 | ||
|
|
8a77e20d93 | ||
|
|
6647881b09 | ||
|
|
631610433d | ||
|
|
247b95a89e | ||
|
|
b7dc1324b1 | ||
|
|
4b2364bde0 | ||
|
|
fc649c4a44 | ||
|
|
f73f6063d7 | ||
|
|
7dccd7a449 | ||
|
|
568f8074a4 | ||
|
|
f81e47a0b4 | ||
|
|
a983e79481 | ||
|
|
ba93683692 | ||
|
|
7d4bd5bd8c | ||
|
|
e0683bbd41 | ||
|
|
fbc8cc03a7 | ||
|
|
7d2860e4f4 | ||
|
|
827b22bf55 | ||
|
|
5facf03416 | ||
|
|
48c5ed40f2 | ||
|
|
864b177fdd | ||
|
|
8838b8f178 | ||
|
|
9244e8039e | ||
|
|
c579e2fd8e | ||
|
|
a1c2f3b4d2 | ||
|
|
f98c8f9617 | ||
|
|
9bf6ba06c8 | ||
|
|
da30965089 | ||
|
|
e01b76c4a4 | ||
|
|
6a302f1133 | ||
|
|
f40cedc3bb | ||
|
|
410d38921d | ||
|
|
a06e74ebb3 | ||
|
|
b1702668bf |
@@ -20,6 +20,9 @@
|
||||
html {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #eaeaea transparent;
|
||||
@supports (text-autospace: normal) {
|
||||
text-autospace: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.rc-footer {
|
||||
|
||||
107
.dumi/hooks/useLocalStorage.ts
Normal file
107
.dumi/hooks/useLocalStorage.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
|
||||
const ANT_SYNC_STORAGE_EVENT_KEY = 'ANT_SYNC_STORAGE_EVENT_KEY';
|
||||
|
||||
const isFunction = (val: any): val is (...args: any[]) => any => {
|
||||
return typeof val === 'function';
|
||||
};
|
||||
|
||||
interface Options<T> {
|
||||
defaultValue?: T;
|
||||
serializer?: (value: T) => string;
|
||||
deserializer?: (value: string) => T;
|
||||
onError?: (error: unknown) => void;
|
||||
}
|
||||
|
||||
const useLocalStorage = <T>(key: string, options: Options<T> = {}) => {
|
||||
const storage = typeof window !== 'undefined' ? localStorage : null;
|
||||
|
||||
const { serializer, deserializer, onError, defaultValue } = options;
|
||||
|
||||
const mergedSerializer = typeof serializer === 'function' ? serializer : JSON.stringify;
|
||||
|
||||
const mergedDeserializer = typeof deserializer === 'function' ? deserializer : JSON.parse;
|
||||
|
||||
const handleError = typeof onError === 'function' ? onError : console.error;
|
||||
|
||||
const getStoredValue = () => {
|
||||
try {
|
||||
const rawData = storage?.getItem(key);
|
||||
if (rawData) {
|
||||
return mergedDeserializer(rawData);
|
||||
}
|
||||
} catch (e) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
handleError(e);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
const [state, setState] = React.useState<T>(getStoredValue);
|
||||
|
||||
useEffect(() => {
|
||||
setState(getStoredValue());
|
||||
}, [key]);
|
||||
|
||||
const updateState: React.Dispatch<React.SetStateAction<T>> = (value) => {
|
||||
const currentState = isFunction(value) ? value(state) : value;
|
||||
setState(currentState);
|
||||
try {
|
||||
let newValue: string | null;
|
||||
const oldValue = storage?.getItem(key);
|
||||
if (typeof currentState === 'undefined') {
|
||||
newValue = null;
|
||||
storage?.removeItem(key);
|
||||
} else {
|
||||
newValue = mergedSerializer(currentState);
|
||||
storage?.setItem(key, newValue);
|
||||
}
|
||||
dispatchEvent(
|
||||
new CustomEvent(ANT_SYNC_STORAGE_EVENT_KEY, {
|
||||
detail: { key, newValue, oldValue, storageArea: storage },
|
||||
}),
|
||||
);
|
||||
} catch (e) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
handleError(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const shouldSync = (ev: StorageEvent) => {
|
||||
return ev && ev.key === key && ev.storageArea === storage;
|
||||
};
|
||||
|
||||
const onNativeStorage = useCallback(
|
||||
(event: StorageEvent) => {
|
||||
if (shouldSync(event)) {
|
||||
setState(getStoredValue());
|
||||
}
|
||||
},
|
||||
[key],
|
||||
);
|
||||
|
||||
const onCustomStorage = useCallback(
|
||||
(event: Event) => {
|
||||
if (shouldSync(event as StorageEvent)) {
|
||||
setState(getStoredValue());
|
||||
}
|
||||
},
|
||||
[key],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window?.addEventListener('storage', onNativeStorage);
|
||||
window?.addEventListener(ANT_SYNC_STORAGE_EVENT_KEY, onCustomStorage);
|
||||
return () => {
|
||||
window?.removeEventListener('storage', onNativeStorage);
|
||||
window?.removeEventListener(ANT_SYNC_STORAGE_EVENT_KEY, onCustomStorage);
|
||||
};
|
||||
}, [key, onNativeStorage, onCustomStorage]);
|
||||
|
||||
return [state, updateState] as const;
|
||||
};
|
||||
|
||||
export default useLocalStorage;
|
||||
@@ -85,10 +85,6 @@ const useThemeAnimation = () => {
|
||||
);
|
||||
document
|
||||
.startViewTransition(async () => {
|
||||
// wait for theme change end
|
||||
while (colorBgElevated === animateRef.current.colorBgElevated) {
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 1000 / 60));
|
||||
}
|
||||
const root = document.documentElement;
|
||||
root.classList.remove(isDark ? 'dark' : 'light');
|
||||
root.classList.add(isDark ? 'light' : 'dark');
|
||||
|
||||
@@ -31,15 +31,17 @@ const locales = {
|
||||
|
||||
const useStyle = createStyles(({ token, css, cx }, siteConfig: SiteContextProps) => {
|
||||
const textShadow = `0 0 4px ${token.colorBgContainer}`;
|
||||
const isDark = siteConfig.theme.includes('dark');
|
||||
const mask = cx(css`
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
backdrop-filter: blur(2px);
|
||||
opacity: 1;
|
||||
background-color: ${isDark ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.2)'};
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
transition: all 1s ease;
|
||||
pointer-events: none;
|
||||
[data-prefers-color='dark'] & {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
`);
|
||||
|
||||
const block = cx(css`
|
||||
|
||||
@@ -389,10 +389,9 @@ const Theme: React.FC = () => {
|
||||
themeType,
|
||||
...ThemesInfo[themeType],
|
||||
};
|
||||
|
||||
setThemeData(mergedData);
|
||||
form.setFieldsValue(mergedData);
|
||||
}, [themeType]);
|
||||
}, [form, themeType]);
|
||||
|
||||
const isDark = React.use(DarkContext);
|
||||
|
||||
@@ -433,23 +432,14 @@ const Theme: React.FC = () => {
|
||||
token: { ...themeToken, colorPrimary: colorPrimaryValue },
|
||||
algorithm: algorithmFn,
|
||||
components: {
|
||||
Layout: isLight
|
||||
? {
|
||||
headerBg: 'transparent',
|
||||
bodyBg: 'transparent',
|
||||
}
|
||||
: {},
|
||||
Layout: isLight ? { headerBg: 'transparent', bodyBg: 'transparent' } : {},
|
||||
Menu: isLight
|
||||
? {
|
||||
itemBg: 'transparent',
|
||||
subMenuItemBg: 'transparent',
|
||||
activeBarBorderWidth: 0,
|
||||
}
|
||||
? { itemBg: 'transparent', subMenuItemBg: 'transparent', activeBarBorderWidth: 0 }
|
||||
: {},
|
||||
...(themeType === 'v4' ? defaultTheme.components : {}),
|
||||
},
|
||||
}),
|
||||
[themeToken, colorPrimaryValue, algorithmFn, themeType],
|
||||
[themeToken, colorPrimaryValue, algorithmFn, isLight, themeType],
|
||||
);
|
||||
|
||||
// ================================ Render ================================
|
||||
|
||||
@@ -60,7 +60,15 @@ export type Extras = {
|
||||
|
||||
export type Icons = Icon[];
|
||||
|
||||
export type HeadingBanner = {
|
||||
[key in 'cn' | 'en']: {
|
||||
title?: string;
|
||||
href?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type SiteData = {
|
||||
headingBanner: HeadingBanner;
|
||||
articles: Articles;
|
||||
authors: Authors;
|
||||
recommendations: Recommendations;
|
||||
@@ -82,10 +90,27 @@ export function preLoad(list: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Banner 硬编码,以防止页面闪烁问题
|
||||
export const getBannerData = (): null | {
|
||||
title: string;
|
||||
href: string;
|
||||
} => {
|
||||
return {
|
||||
title: 'See Conf 2025 震撼来袭 - 探索 AI 时代的用户体验与工程实践',
|
||||
href: 'https://seeconf.antfin.com/',
|
||||
};
|
||||
};
|
||||
|
||||
export const useAntdSiteConfig = () => {
|
||||
const { data, error, isLoading } = useSWR<Partial<SiteData>, Error>(
|
||||
`https://render.alipay.com/p/h5data/antd4-config_website-h5data.json`,
|
||||
(url: string) => fetch(url).then((res) => res.json()),
|
||||
{
|
||||
suspense: false,
|
||||
// revalidateOnMount: false,
|
||||
revalidateIfStale: false,
|
||||
revalidateOnFocus: false,
|
||||
},
|
||||
);
|
||||
return { data, error, isLoading };
|
||||
};
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React, { Suspense, useEffect } from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import { App, Button, ConfigProvider, Skeleton } from 'antd';
|
||||
import { enUS, zhCN } from 'antd-token-previewer';
|
||||
import type { ThemeConfig } from 'antd/es/config-provider/context';
|
||||
import { Helmet } from 'dumi';
|
||||
|
||||
import useLocale from '../../hooks/useLocale';
|
||||
import useLocalStorage from '../../hooks/useLocalStorage';
|
||||
|
||||
const ThemeEditor = React.lazy(() => import('antd-token-previewer/lib/ThemeEditor'));
|
||||
|
||||
@@ -33,24 +34,18 @@ const locales = {
|
||||
},
|
||||
};
|
||||
|
||||
const ANT_DESIGN_V5_THEME_EDITOR_THEME = 'ant-design-v5-theme-editor-theme';
|
||||
const ANT_THEME_EDITOR_THEME = 'ant-theme-editor-theme';
|
||||
|
||||
const CustomTheme: React.FC = () => {
|
||||
const { message } = App.useApp();
|
||||
const [locale, lang] = useLocale(locales);
|
||||
|
||||
const [theme, setTheme] = React.useState<ThemeConfig>({});
|
||||
|
||||
useEffect(() => {
|
||||
const storedConfig = localStorage.getItem(ANT_DESIGN_V5_THEME_EDITOR_THEME);
|
||||
if (storedConfig) {
|
||||
const themeConfig = JSON.parse(storedConfig);
|
||||
setTheme(themeConfig);
|
||||
}
|
||||
}, []);
|
||||
const [themeConfig, setThemeConfig] = useLocalStorage<ThemeConfig>(ANT_THEME_EDITOR_THEME, {
|
||||
defaultValue: {},
|
||||
});
|
||||
|
||||
const handleSave = () => {
|
||||
localStorage.setItem(ANT_DESIGN_V5_THEME_EDITOR_THEME, JSON.stringify(theme));
|
||||
setThemeConfig(themeConfig);
|
||||
message.success(locale.saveSuccessfully);
|
||||
};
|
||||
|
||||
@@ -65,11 +60,9 @@ const CustomTheme: React.FC = () => {
|
||||
<ThemeEditor
|
||||
advanced
|
||||
hideAdvancedSwitcher
|
||||
theme={{ name: 'Custom Theme', key: 'test', config: theme }}
|
||||
theme={{ name: 'Custom Theme', key: 'test', config: themeConfig }}
|
||||
style={{ height: 'calc(100vh - 64px)' }}
|
||||
onThemeChange={(newTheme) => {
|
||||
setTheme(newTheme.config);
|
||||
}}
|
||||
onThemeChange={(newTheme) => setThemeConfig(newTheme.config)}
|
||||
locale={lang === 'cn' ? zhCN : enUS}
|
||||
actions={
|
||||
<Button type="primary" onClick={handleSave}>
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
|
||||
const isEnabled = always || enabledCondition.every(Boolean);
|
||||
|
||||
if (!isEnabled) return;
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prefixCls = 'antd-mirror-notify';
|
||||
const primaryColor = '#1677ff';
|
||||
|
||||
@@ -139,7 +139,10 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
|
||||
}, [component, repo, source]);
|
||||
|
||||
// ======================== Render ========================
|
||||
const importList = `import { ${transformComponentName(component)} } from "antd";`;
|
||||
const importCode =
|
||||
component === 'Icon'
|
||||
? `import { AntDesignOutlined } from '@ant-design/icons';`
|
||||
: `import { ${transformComponentName(component)} } from 'antd';`;
|
||||
|
||||
return (
|
||||
<Descriptions
|
||||
@@ -153,14 +156,14 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
|
||||
{
|
||||
label: locale.import,
|
||||
children: (
|
||||
<CopyToClipboard text={`import { ${component} } from "antd";`} onCopy={onCopy}>
|
||||
<CopyToClipboard text={importCode} onCopy={onCopy}>
|
||||
<Tooltip
|
||||
placement="right"
|
||||
title={copied ? locale.copied : locale.copy}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<Typography.Text className={styles.code} onClick={onCopy}>
|
||||
{importList}
|
||||
{importCode}
|
||||
</Typography.Text>
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
|
||||
@@ -7,8 +7,8 @@ import classNames from 'classnames';
|
||||
import ImagePreview from '../ImagePreview';
|
||||
import type { ImagePreviewProps } from '../ImagePreview';
|
||||
|
||||
const isNotEmpty = (val: any) => {
|
||||
return typeof val !== 'undefined' && val !== null && val !== '';
|
||||
const isNonNullable = <T,>(val: T): val is NonNullable<T> => {
|
||||
return val !== undefined && val !== null;
|
||||
};
|
||||
|
||||
const useStyle = createStyles(({ css, token }) => {
|
||||
@@ -51,8 +51,8 @@ const FlexWithImagePreview: React.FC<
|
||||
return (
|
||||
<Flex className={classNames(styles.wrapper, className)} style={style} {...rest}>
|
||||
<Flex align="flex-start" justify="flex-start" vertical>
|
||||
{isNotEmpty(title) && <div className={styles.title}>{title}</div>}
|
||||
{isNotEmpty(description) && <div className={styles.description}>{description}</div>}
|
||||
{isNonNullable(title) && <div className={styles.title}>{title}</div>}
|
||||
{isNonNullable(description) && <div className={styles.description}>{description}</div>}
|
||||
</Flex>
|
||||
<ImagePreview {...imagePreviewProps}>{children}</ImagePreview>
|
||||
</Flex>
|
||||
|
||||
@@ -48,6 +48,8 @@ const IconSearch: React.FC = () => {
|
||||
|
||||
const handleSearchIcon = debounce((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDisplayState((prevState) => ({ ...prevState, searchKey: e.target.value }));
|
||||
|
||||
document.getElementById('list-of-icons')?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, 300);
|
||||
|
||||
const handleChangeTheme = useCallback((value: ThemeType) => {
|
||||
|
||||
@@ -164,7 +164,6 @@ const CodePreview: React.FC<CodePreviewProps> = ({
|
||||
</div>
|
||||
),
|
||||
})),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[
|
||||
entryName,
|
||||
error,
|
||||
|
||||
@@ -72,10 +72,10 @@ const Palette: React.FC<PaletteProps> = (props) => {
|
||||
key={i}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
colorNodesRef.current[`${name}-${i}`] = node;
|
||||
colorNodesRef.current[`${name}-${i + 1}`] = node;
|
||||
}
|
||||
}}
|
||||
className={`main-color-item palette-${name}-${i}`}
|
||||
className={`main-color-item palette-${name}-${i + 1}`}
|
||||
style={{
|
||||
color: (name === 'yellow' ? i > 6 : i > 5) ? firstColor : lastColor,
|
||||
fontWeight: i === 6 ? 'bold' : 'normal',
|
||||
|
||||
@@ -11,17 +11,17 @@ import type { MenuProps } from 'antd';
|
||||
import { CompactTheme, DarkTheme } from 'antd-token-previewer/es/icons';
|
||||
import { FormattedMessage, useLocation } from 'dumi';
|
||||
|
||||
import useLocalStorage from '../../../hooks/useLocalStorage';
|
||||
import useThemeAnimation from '../../../hooks/useThemeAnimation';
|
||||
import type { SiteContextProps } from '../../slots/SiteContext';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import { getLocalizedPathname, isZhCN, isLocalStorageNameSupported } from '../../utils';
|
||||
import { getLocalizedPathname, isZhCN } from '../../utils';
|
||||
import Link from '../Link';
|
||||
import ThemeIcon from './ThemeIcon';
|
||||
|
||||
export type ThemeName = 'light' | 'dark' | 'auto' | 'compact' | 'motion-off' | 'happy-work';
|
||||
|
||||
// 主题持久化存储键名
|
||||
const ANT_DESIGN_SITE_THEME = 'ant-design-site-theme';
|
||||
export const ANT_DESIGN_SITE_THEME = 'ant-design-site-theme';
|
||||
|
||||
export interface ThemeSwitchProps {
|
||||
value?: ThemeName[];
|
||||
@@ -33,6 +33,10 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = () => {
|
||||
const toggleAnimationTheme = useThemeAnimation();
|
||||
const lastThemeKey = useRef<string>(theme.includes('dark') ? 'dark' : 'light');
|
||||
|
||||
const [, setTheme] = useLocalStorage<ThemeName>(ANT_DESIGN_SITE_THEME, {
|
||||
defaultValue: undefined,
|
||||
});
|
||||
|
||||
const badge = <Badge color="blue" style={{ marginTop: -1 }} />;
|
||||
|
||||
// 主题选项配置
|
||||
@@ -133,14 +137,9 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = () => {
|
||||
const filteredTheme = theme.filter((t) => !['light', 'dark', 'auto'].includes(t));
|
||||
const newTheme = [...filteredTheme, themeKey];
|
||||
|
||||
updateSiteConfig({
|
||||
theme: newTheme,
|
||||
});
|
||||
setTheme(themeKey);
|
||||
|
||||
// 持久化到 localStorage
|
||||
if (isLocalStorageNameSupported()) {
|
||||
localStorage.setItem(ANT_DESIGN_SITE_THEME, themeKey);
|
||||
}
|
||||
updateSiteConfig({ theme: newTheme });
|
||||
} else {
|
||||
// 其他主题选项是开关式的
|
||||
const hasTheme = theme.includes(themeKey);
|
||||
|
||||
@@ -12,15 +12,18 @@ import { getSandpackCssText } from '@codesandbox/sandpack-react';
|
||||
import { theme as antdTheme, App } from 'antd';
|
||||
import type { MappingAlgorithm } from 'antd';
|
||||
import type { DirectionType, ThemeConfig } from 'antd/es/config-provider';
|
||||
import dayjs from 'dayjs';
|
||||
import { createSearchParams, useOutlet, useSearchParams, useServerInsertedHTML } from 'dumi';
|
||||
|
||||
import { DarkContext } from '../../hooks/useDark';
|
||||
import useLayoutState from '../../hooks/useLayoutState';
|
||||
import useLocalStorage from '../../hooks/useLocalStorage';
|
||||
import { getBannerData } from '../../pages/index/components/util';
|
||||
import { ANT_DESIGN_SITE_THEME } from '../common/ThemeSwitch';
|
||||
import type { ThemeName } from '../common/ThemeSwitch';
|
||||
import SiteThemeProvider from '../SiteThemeProvider';
|
||||
import type { SiteContextProps } from '../slots/SiteContext';
|
||||
import SiteContext from '../slots/SiteContext';
|
||||
import { isLocalStorageNameSupported } from '../utils';
|
||||
|
||||
import '@ant-design/v5-patch-for-react-19';
|
||||
|
||||
@@ -28,10 +31,8 @@ type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
|
||||
type SiteState = Partial<Omit<SiteContextProps, 'updateSiteConfig'>>;
|
||||
|
||||
const RESPONSIVE_MOBILE = 768;
|
||||
export const ANT_DESIGN_NOT_SHOW_BANNER = 'ANT_DESIGN_NOT_SHOW_BANNER';
|
||||
|
||||
// 主题持久化存储键名
|
||||
const ANT_DESIGN_SITE_THEME = 'ant-design-site-theme';
|
||||
export const ANT_DESIGN_NOT_SHOW_BANNER = 'ANT_DESIGN_NOT_SHOW_BANNER';
|
||||
|
||||
// Compatible with old anchors
|
||||
if (typeof window !== 'undefined') {
|
||||
@@ -43,9 +44,13 @@ if (typeof window !== 'undefined') {
|
||||
}
|
||||
}
|
||||
|
||||
const getAlgorithm = (themes: ThemeName[] = []) =>
|
||||
const getAlgorithm = (themes: ThemeName[] = [], systemTheme: 'dark' | 'light') =>
|
||||
themes
|
||||
.map((theme) => {
|
||||
// auto 模式下根据系统主题切换
|
||||
if (theme === 'auto' && systemTheme === 'dark') {
|
||||
return antdTheme.darkAlgorithm;
|
||||
}
|
||||
if (theme === 'dark') {
|
||||
return antdTheme.darkAlgorithm;
|
||||
}
|
||||
@@ -56,21 +61,11 @@ const getAlgorithm = (themes: ThemeName[] = []) =>
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
// 获取最终主题(优先级:URL Query > Local Storage > Site (Memory))
|
||||
const getFinalTheme = (urlTheme: ThemeName[]): ThemeName[] => {
|
||||
// 只认 light/dark
|
||||
const baseTheme = urlTheme.filter((t) => !['light', 'dark', 'auto'].includes(t));
|
||||
const urlColor = urlTheme.find((t) => t === 'light' || t === 'dark');
|
||||
if (urlColor) return [...baseTheme, urlColor];
|
||||
|
||||
if (isLocalStorageNameSupported()) {
|
||||
const stored = localStorage.getItem(ANT_DESIGN_SITE_THEME) as ThemeName;
|
||||
if (stored && ['light', 'dark', 'auto'].includes(stored)) {
|
||||
return [...baseTheme, stored];
|
||||
}
|
||||
const getSystemTheme = (): 'light' | 'dark' => {
|
||||
if (typeof window === 'undefined') {
|
||||
return 'light';
|
||||
}
|
||||
// 默认 auto
|
||||
return [...baseTheme, 'auto'];
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
};
|
||||
|
||||
const GlobalLayout: React.FC = () => {
|
||||
@@ -84,6 +79,32 @@ const GlobalLayout: React.FC = () => {
|
||||
bannerVisible: false,
|
||||
});
|
||||
|
||||
const [storedTheme] = useLocalStorage<ThemeName>(ANT_DESIGN_SITE_THEME, {
|
||||
defaultValue: undefined,
|
||||
});
|
||||
|
||||
const [bannerLastTime] = useLocalStorage<string>(ANT_DESIGN_NOT_SHOW_BANNER, {
|
||||
defaultValue: undefined,
|
||||
});
|
||||
|
||||
// 获取最终主题(优先级:URL Query > Local Storage > Site (Memory))
|
||||
const getFinalTheme = (urlTheme: ThemeName[]): ThemeName[] => {
|
||||
// 只认 light/dark
|
||||
const baseTheme = urlTheme.filter((t) => !['light', 'dark', 'auto'].includes(t));
|
||||
const urlColor = urlTheme.find((t) => t === 'light' || t === 'dark');
|
||||
if (urlColor) {
|
||||
return [...baseTheme, urlColor];
|
||||
}
|
||||
if (['light', 'dark', 'auto'].includes(storedTheme)) {
|
||||
return [...baseTheme, storedTheme];
|
||||
}
|
||||
return [...baseTheme, 'auto'];
|
||||
};
|
||||
|
||||
const [systemTheme, setSystemTheme] = React.useState<'light' | 'dark'>(() => getSystemTheme());
|
||||
|
||||
const bannerData = getBannerData();
|
||||
|
||||
// TODO: This can be remove in v6
|
||||
const useCssVar = searchParams.get('cssVar') !== 'false';
|
||||
|
||||
@@ -111,10 +132,6 @@ const GlobalLayout: React.FC = () => {
|
||||
} else {
|
||||
nextSearchParams.delete('theme');
|
||||
}
|
||||
// 设置 data-prefers-color
|
||||
if (color) {
|
||||
document.querySelector('html')?.setAttribute('data-prefers-color', color);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -122,7 +139,6 @@ const GlobalLayout: React.FC = () => {
|
||||
setSearchParams(nextSearchParams);
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[searchParams, setSearchParams],
|
||||
);
|
||||
|
||||
@@ -130,6 +146,17 @@ const GlobalLayout: React.FC = () => {
|
||||
updateSiteConfig({ isMobile: window.innerWidth < RESPONSIVE_MOBILE });
|
||||
}, [updateSiteConfig]);
|
||||
|
||||
// 设置 data-prefers-color 属性
|
||||
useEffect(() => {
|
||||
const color = theme.find((t) => t === 'light' || t === 'dark');
|
||||
const html = document.querySelector<HTMLHtmlElement>('html');
|
||||
if (theme.includes('auto') && systemTheme) {
|
||||
html?.setAttribute('data-prefers-color', systemTheme);
|
||||
} else if (color) {
|
||||
html?.setAttribute('data-prefers-color', color);
|
||||
}
|
||||
}, [systemTheme, theme]);
|
||||
|
||||
// 监听系统主题变化
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') {
|
||||
@@ -138,7 +165,10 @@ const GlobalLayout: React.FC = () => {
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
const handleSystemThemeChange = () => {};
|
||||
const handleSystemThemeChange = (e: MediaQueryListEvent) => {
|
||||
const newSystemTheme = e.matches ? 'dark' : 'light';
|
||||
setSystemTheme(newSystemTheme);
|
||||
};
|
||||
|
||||
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
||||
|
||||
@@ -153,17 +183,18 @@ const GlobalLayout: React.FC = () => {
|
||||
const finalTheme = getFinalTheme(urlTheme);
|
||||
const _direction = searchParams.get('direction') as DirectionType;
|
||||
|
||||
const storedBannerVisible = bannerLastTime && dayjs().diff(dayjs(bannerLastTime), 'day') >= 1;
|
||||
|
||||
const isZhCN = typeof window !== 'undefined' && window.location.pathname.includes('-cn');
|
||||
|
||||
const hasBannerContent = isZhCN && !!bannerData;
|
||||
|
||||
setSiteState({
|
||||
theme: finalTheme,
|
||||
direction: _direction === 'rtl' ? 'rtl' : 'ltr',
|
||||
bannerVisible: hasBannerContent && (bannerLastTime ? !!storedBannerVisible : true),
|
||||
});
|
||||
|
||||
// 设置 data-prefers-color 属性
|
||||
const colorTheme = finalTheme.find((t) => ['light', 'dark'].includes(t));
|
||||
if (colorTheme) {
|
||||
document.documentElement.setAttribute('data-prefers-color', colorTheme);
|
||||
}
|
||||
|
||||
// Handle isMobile
|
||||
updateMobileMode();
|
||||
|
||||
@@ -177,7 +208,6 @@ const GlobalLayout: React.FC = () => {
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateMobileMode);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchParams, updateMobileMode]);
|
||||
|
||||
const siteContextValue = React.useMemo<SiteContextProps>(
|
||||
@@ -195,12 +225,12 @@ const GlobalLayout: React.FC = () => {
|
||||
// 算法优先级:auto 时用系统主题算法
|
||||
const themeForAlgorithm = theme;
|
||||
return {
|
||||
algorithm: getAlgorithm(themeForAlgorithm),
|
||||
algorithm: getAlgorithm(themeForAlgorithm, systemTheme),
|
||||
token: { motion: !theme.includes('motion-off') },
|
||||
cssVar: useCssVar,
|
||||
hashed: !useCssVar,
|
||||
};
|
||||
}, [theme, useCssVar]);
|
||||
}, [theme, useCssVar, systemTheme]);
|
||||
|
||||
const styleCache = React.useMemo(() => createCache(), []);
|
||||
|
||||
@@ -239,7 +269,9 @@ const GlobalLayout: React.FC = () => {
|
||||
));
|
||||
|
||||
return (
|
||||
<DarkContext value={theme.includes('dark')}>
|
||||
<DarkContext
|
||||
value={theme.includes('dark') || (theme.includes('auto') && systemTheme === 'dark')}
|
||||
>
|
||||
<StyleProvider
|
||||
cache={styleCache}
|
||||
linters={[legacyNotSelectorLinter, parentSelectorLinter, NaNLinter]}
|
||||
|
||||
@@ -40,12 +40,10 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setShowDebug(process.env.NODE_ENV === 'development' || isDebugDemo);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isDebugDemo]);
|
||||
|
||||
const contextValue = useMemo<DemoContextProps>(
|
||||
() => ({ showDebug, setShowDebug, codeType, setCodeType }),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[showDebug, codeType],
|
||||
);
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import { useLocation, useSiteData } from 'dumi';
|
||||
import DumiSearchBar from 'dumi/theme-default/slots/SearchBar';
|
||||
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useLocalStorage from '../../../hooks/useLocalStorage';
|
||||
import { getBannerData } from '../../../pages/index/components/util';
|
||||
import ThemeSwitch from '../../common/ThemeSwitch';
|
||||
import DirectionIcon from '../../icons/DirectionIcon';
|
||||
import { ANT_DESIGN_NOT_SHOW_BANNER } from '../../layouts/GlobalLayout';
|
||||
@@ -22,20 +24,7 @@ import SwitchBtn from './SwitchBtn';
|
||||
const RESPONSIVE_XS = 1120;
|
||||
const RESPONSIVE_SM = 1200;
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
message: '语雀征文 · 说说你和开源的故事,赢取 Ant Design 精美周边 🎁',
|
||||
shortMessage: '语雀征文 · 说说你和开源的故事,赢取 Ant Design 精美周边 🎁',
|
||||
more: '前往了解',
|
||||
link: 'https://www.yuque.com/opensource2023',
|
||||
},
|
||||
en: {
|
||||
message: '',
|
||||
shortMessage: '',
|
||||
more: '',
|
||||
link: '',
|
||||
},
|
||||
};
|
||||
export const ANT_LOCAL_TYPE_KEY = 'ANT_LOCAL_TYPE_KEY';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => {
|
||||
const searchIconColor = '#ced4d9';
|
||||
@@ -162,11 +151,12 @@ interface HeaderState {
|
||||
|
||||
// ================================= Header =================================
|
||||
const Header: React.FC = () => {
|
||||
const [locale, lang] = useLocale(locales);
|
||||
const [, lang] = useLocale();
|
||||
|
||||
const { pkg } = useSiteData();
|
||||
|
||||
const themeConfig = getThemeConfig();
|
||||
|
||||
const [headerState, setHeaderState] = useState<HeaderState>({
|
||||
menuVisible: false,
|
||||
windowWidth: 1400,
|
||||
@@ -179,24 +169,33 @@ const Header: React.FC = () => {
|
||||
|
||||
const { styles } = useStyle();
|
||||
|
||||
const [, setTopBannerDay] = useLocalStorage<string>(ANT_DESIGN_NOT_SHOW_BANNER, {
|
||||
defaultValue: undefined,
|
||||
});
|
||||
|
||||
const [, setLocalType] = useLocalStorage<string>(ANT_LOCAL_TYPE_KEY, {
|
||||
defaultValue: undefined,
|
||||
});
|
||||
|
||||
const handleHideMenu = useCallback(() => {
|
||||
setHeaderState((prev) => ({ ...prev, menuVisible: false }));
|
||||
}, []);
|
||||
|
||||
const onWindowResize = useCallback(() => {
|
||||
setHeaderState((prev) => ({ ...prev, windowWidth: window.innerWidth }));
|
||||
}, []);
|
||||
|
||||
const onMenuVisibleChange = useCallback((visible: boolean) => {
|
||||
setHeaderState((prev) => ({ ...prev, menuVisible: visible }));
|
||||
}, []);
|
||||
|
||||
const onDirectionChange = () => {
|
||||
updateSiteConfig({ direction: direction !== 'rtl' ? 'rtl' : 'ltr' });
|
||||
};
|
||||
|
||||
const onBannerClose = () => {
|
||||
updateSiteConfig({ bannerVisible: false });
|
||||
|
||||
if (utils.isLocalStorageNameSupported()) {
|
||||
localStorage.setItem(ANT_DESIGN_NOT_SHOW_BANNER, dayjs().toISOString());
|
||||
}
|
||||
setTopBannerDay(dayjs().toISOString());
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -238,9 +237,8 @@ const Header: React.FC = () => {
|
||||
const currentProtocol = `${window.location.protocol}//`;
|
||||
const currentHref = window.location.href.slice(currentProtocol.length);
|
||||
|
||||
if (utils.isLocalStorageNameSupported()) {
|
||||
localStorage.setItem('locale', utils.isZhCN(pathname) ? 'en-US' : 'zh-CN');
|
||||
}
|
||||
setLocalType(utils.isZhCN(pathname) ? 'en-US' : 'zh-CN');
|
||||
|
||||
window.location.href =
|
||||
currentProtocol +
|
||||
currentHref.replace(
|
||||
@@ -272,6 +270,12 @@ const Header: React.FC = () => {
|
||||
const isHome = ['', 'index', 'index-cn'].includes(pathname);
|
||||
const isZhCN = lang === 'cn';
|
||||
const isRTL = direction === 'rtl';
|
||||
|
||||
// Get banner data from site config
|
||||
const bannerData = getBannerData();
|
||||
const bannerTitle = bannerData?.title || '';
|
||||
const bannerHref = bannerData?.href || '';
|
||||
|
||||
let responsive: null | 'narrow' | 'crowded' = null;
|
||||
if (windowWidth < RESPONSIVE_XS) {
|
||||
responsive = 'crowded';
|
||||
@@ -375,7 +379,7 @@ const Header: React.FC = () => {
|
||||
<MenuOutlined className="nav-phone-icon" />
|
||||
</Popover>
|
||||
)}
|
||||
{isZhCN && bannerVisible && (
|
||||
{isZhCN && bannerVisible && bannerTitle && bannerHref && (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
@@ -387,23 +391,25 @@ const Header: React.FC = () => {
|
||||
<Alert
|
||||
className={styles.banner}
|
||||
message={
|
||||
<>
|
||||
<span>{isMobile ? locale.shortMessage : locale.message}</span>
|
||||
<a
|
||||
className={styles.link}
|
||||
href={locale.link}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={() => {
|
||||
window.gtag?.('event', '点击', {
|
||||
event_category: 'top_banner',
|
||||
event_label: locale.link,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{locale.more}
|
||||
</a>
|
||||
</>
|
||||
bannerTitle && bannerHref ? (
|
||||
<>
|
||||
<span>{bannerTitle}</span>
|
||||
<a
|
||||
className={styles.link}
|
||||
href={bannerHref}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={() => {
|
||||
window.gtag?.('event', '点击', {
|
||||
event_category: 'top_banner',
|
||||
event_label: bannerHref,
|
||||
});
|
||||
}}
|
||||
>
|
||||
前往了解
|
||||
</a>
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
type="info"
|
||||
banner
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import type { DirectionType } from 'antd/es/config-provider';
|
||||
|
||||
import type { ThemeName } from '../common/ThemeSwitch';
|
||||
import { getBannerData } from '../../pages/index/components/util';
|
||||
|
||||
export interface SiteContextProps {
|
||||
isMobile: boolean;
|
||||
@@ -13,7 +14,7 @@ export interface SiteContextProps {
|
||||
|
||||
const SiteContext = React.createContext<SiteContextProps>({
|
||||
isMobile: false,
|
||||
bannerVisible: false,
|
||||
bannerVisible: !!getBannerData(),
|
||||
direction: 'ltr',
|
||||
theme: ['light'],
|
||||
updateSiteConfig: () => {},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import semver from 'semver';
|
||||
import flatten from 'lodash/flatten';
|
||||
import flattenDeep from 'lodash/flattenDeep';
|
||||
import semver from 'semver';
|
||||
|
||||
import deprecatedVersions from '../../../BUG_VERSIONS.json';
|
||||
import themeConfig from '../themeConfig';
|
||||
|
||||
@@ -157,19 +158,6 @@ export function getLocalizedPathname(
|
||||
return { pathname: fullPath, search };
|
||||
}
|
||||
|
||||
export function isLocalStorageNameSupported() {
|
||||
const testKey = 'test';
|
||||
const storage = window.localStorage;
|
||||
try {
|
||||
storage.setItem(testKey, '1');
|
||||
storage.removeItem(testKey);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Your web browser does not support storing settings locally.', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function loadScript(src: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
@@ -177,7 +165,7 @@ export function loadScript(src: string) {
|
||||
script.src = src;
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.head!.appendChild(script);
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
13
.dumirc.ts
13
.dumirc.ts
@@ -131,17 +131,6 @@ export default defineConfig({
|
||||
headScripts: [
|
||||
`
|
||||
(function () {
|
||||
function isLocalStorageNameSupported() {
|
||||
const testKey = 'test';
|
||||
const storage = window.localStorage;
|
||||
try {
|
||||
storage.setItem(testKey, '1');
|
||||
storage.removeItem(testKey);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 优先级提高到所有静态资源的前面,语言不对,加载其他静态资源没意义
|
||||
const pathname = location.pathname;
|
||||
|
||||
@@ -171,7 +160,7 @@ export default defineConfig({
|
||||
}
|
||||
|
||||
// 首页无视链接里面的语言设置 https://github.com/ant-design/ant-design/issues/4552
|
||||
if (isLocalStorageNameSupported() && (pathname === '/' || pathname === '/index-cn')) {
|
||||
if (pathname === '/' || pathname === '/index-cn') {
|
||||
const lang =
|
||||
(window.localStorage && localStorage.getItem('locale')) ||
|
||||
((navigator.language || navigator.browserLanguage).toLowerCase() === 'zh-cn'
|
||||
|
||||
@@ -39,7 +39,9 @@ jobs:
|
||||
const now = new Date();
|
||||
|
||||
for (const issue of issues) {
|
||||
if (issue.pull_request) continue;
|
||||
if (issue.pull_request) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const updatedAt = new Date(issue.updated_at);
|
||||
const daysInactive = (now - updatedAt) / (1000 * 60 * 60 * 24);
|
||||
|
||||
4
.github/workflows/preview-build.yml
vendored
4
.github/workflows/preview-build.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: run e2e test
|
||||
run: bun run test:site
|
||||
- name: upload site artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: site
|
||||
path: _site/
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
- name: Upload PR number
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: pr
|
||||
path: ./pr-id.txt
|
||||
|
||||
4
.github/workflows/preview-deploy.yml
vendored
4
.github/workflows/preview-deploy.yml
vendored
@@ -41,7 +41,9 @@ jobs:
|
||||
}, {});
|
||||
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
if (total === 0) {
|
||||
core.setFailed('no jobs found');
|
||||
}
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}` in preview-build.yml
|
||||
// set output
|
||||
|
||||
8
.github/workflows/site-deploy.yml
vendored
8
.github/workflows/site-deploy.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: upload site artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: real-site
|
||||
path: _site/
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v5
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
needs: build-site
|
||||
steps:
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v5
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
cd ..
|
||||
|
||||
- name: Upload to Release
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
|
||||
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
files: website.tar.gz
|
||||
|
||||
6
.github/workflows/test-v6.yml
vendored
6
.github/workflows/test-v6.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
mkdir persist-coverage
|
||||
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
name: upload coverages
|
||||
with:
|
||||
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
|
||||
@@ -123,7 +123,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -179,7 +179,7 @@ jobs:
|
||||
run: bun run test:dekko
|
||||
|
||||
# Artifact build files
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
with:
|
||||
name: build artifacts
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
||||
mkdir persist-coverage
|
||||
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
name: upload coverages
|
||||
with:
|
||||
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -182,7 +182,7 @@ jobs:
|
||||
run: bun run test:dekko
|
||||
|
||||
# Artifact build files
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
with:
|
||||
name: build artifacts
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
name: artifact snapshot
|
||||
with:
|
||||
name: snapshot-artifacts-${{ strategy.job-index }}
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: snapshot-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
|
||||
# Upload report in `visualRegressionReport`
|
||||
- name: upload report artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: visual-regression-report
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
|
||||
- name: Upload persist key
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: visual-regression-diff-ref
|
||||
path: ./visual-regression-pr-id.txt
|
||||
|
||||
@@ -43,7 +43,9 @@ jobs:
|
||||
}, {});
|
||||
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
if (total === 0) {
|
||||
core.setFailed('no jobs found');
|
||||
}
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}`
|
||||
console.log('visual-diff report job status: %s', jobs['visual-diff report'].status);
|
||||
|
||||
@@ -40,7 +40,9 @@ jobs:
|
||||
}, {});
|
||||
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
if (total === 0) {
|
||||
core.setFailed('no jobs found');
|
||||
}
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}`
|
||||
console.log('visual-diff report job status: %s', jobs['test image']);
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
# Upload `imageSnapshots` on master
|
||||
- name: upload report artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: image-snapshots
|
||||
path: imageSnapshots.tar.gz
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
|
||||
- name: Upload persist key
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: visual-regression-ref
|
||||
path: ./visual-regression-ref.txt
|
||||
|
||||
@@ -15,6 +15,56 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.28.1
|
||||
|
||||
`2025-11-10`
|
||||
|
||||
- Carousel
|
||||
- 🐞 Fix Carousel style issue in vertical mode. [#55615](https://github.com/ant-design/ant-design/pull/55615) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 Fix Carousel dots animation missing when first render. [#55589](https://github.com/ant-design/ant-design/pull/55589) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 Fix Descriptions where content style wrongly used `labelStyle`. [#55572](https://github.com/ant-design/ant-design/pull/55572) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 💄 Adjust the height of the Select component to 32px when `variant="underlined"`. [#55607](https://github.com/ant-design/ant-design/pull/55607) [@ustcfury](https://github.com/ustcfury)
|
||||
- 💄 When the `underlined` property is enabled for the Input component, the border color changes on mouse hover. [#55609](https://github.com/ant-design/ant-design/pull/55609) [@ustcfury](https://github.com/ustcfury)
|
||||
- 🛠 Flex `gap` prop support number type. [#55591](https://github.com/ant-design/ant-design/pull/55591) [@ayangweb](https://github.com/ayangweb)
|
||||
- 🌐 Add missing TimePicker translations for locales: ar_EG, en_GB, gl_ES, bg_BG, ca_ES, cs_CZ, el_GR, es_ES, eu_ES, fi_FI, he_IL, hu_HU, is_IS, kn_IN, kmr_IQ, lv_LV, mk_MK, mn_MN, ms_MY, pl_PL, pt_BR, pt_PT, ro_RO, sk_SK, sl_SI, sv_SE, ta_IN, th_TH, zh_TW, et_EE. [#55656](https://github.com/ant-design/ant-design/pull/55656) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
|
||||
## 5.28.0
|
||||
|
||||
`2025-11-01`
|
||||
|
||||
- 🆕 Drawer supports `closable.placement` prop to specify the position of the close button. [#54067](https://github.com/ant-design/ant-design/pull/54067) [@davidhsing](https://github.com/davidhsing)
|
||||
- 🆕 Image component supports `fallback` global configuration. [#54702](https://github.com/ant-design/ant-design/pull/54702) [@Jiyur](https://github.com/Jiyur)
|
||||
- 🆕 QRCode component supports `boostLevel` prop. [#55063](https://github.com/ant-design/ant-design/pull/55063) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🆕 Splitter supports `onCollapse` prop. [#54673](https://github.com/ant-design/ant-design/pull/54673) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🆕 Statistic displays animation effect by default when set to `loading`. [#55398](https://github.com/ant-design/ant-design/pull/55398) [@afc163](https://github.com/afc163)
|
||||
- 🆕 TreeSelect supports global configuration for switcher icon. [#54821](https://github.com/ant-design/ant-design/pull/54821) [@Jiyur](https://github.com/Jiyur)
|
||||
- Segmented
|
||||
- 💄 Segmented theme variable `itemSelectedBg` supports background gradient. [#55391](https://github.com/ant-design/ant-design/pull/55391) [@zancheng](https://github.com/zancheng)
|
||||
- 🐞 Fix Segmented abnormal animation after React DevTools upgrade. [#55438](https://github.com/ant-design/ant-design/pull/55438) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix Tree and Transfer components `disabled` inheritance issue. [#54831](https://github.com/ant-design/ant-design/pull/54831) [@cactuser-Lu](https://github.com/cactuser-Lu)
|
||||
- 🐞 Fix Tree.DirectoryTree `defaultExpandAll` not working when `fieldNames` is defined. [#55420](https://github.com/ant-design/ant-design/pull/55420) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- Upload
|
||||
- 🆕 Upload component adds `info.defaultRequest` in `customRequest` parameters. [#55146](https://github.com/ant-design/ant-design/pull/55146) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 💄 Upload component supports `pictureCardSize` token. [#54756](https://github.com/ant-design/ant-design/pull/54756) [@wanpan11](https://github.com/wanpan11)
|
||||
- 💄 Notification supports configuring background color token. [#54802](https://github.com/ant-design/ant-design/pull/54802) [@thinkasany](https://github.com/thinkasany)
|
||||
- 💄 Pagination supports modifying the text color of active items through `itemActiveColor` and `itemActiveColorHover` tokens. [#55195](https://github.com/ant-design/ant-design/pull/55195) [@Renderz](https://github.com/Renderz)
|
||||
- 🐞 Fix Select, DatePicker, TreeSelect, Cascader and other components not showing default suffix icon when `suffixIcon` is configured as undefined. [#54790](https://github.com/ant-design/ant-design/pull/54790) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 Fix Mentions component not inheriting `disabled` from external Form. [#54829](https://github.com/ant-design/ant-design/pull/54829) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 Fix Watermark component crashing when wrapping Modal with `modalRender`. [#55435](https://github.com/ant-design/ant-design/pull/55435) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🗑 Input component deprecates `addonAfter` and `addonBefore` props, use Space.Compact instead. [#55315](https://github.com/ant-design/ant-design/pull/55315) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🤖 Row component `gutter` prop supports string type definition. [#54628](https://github.com/ant-design/ant-design/pull/54628) [@ug-hero](https://github.com/ug-hero)
|
||||
|
||||
## 5.27.6
|
||||
|
||||
`2025-10-20`
|
||||
|
||||
- 🐞 Fix Table `pagination.align` is not working. [#55316](https://github.com/ant-design/ant-design/pull/55316)
|
||||
- 🛠 Refactor Modal useMemo of ConfirmDialog to resolve useMemo invalid where Object.values generates a new array. [#55376](https://github.com/ant-design/ant-design/pull/55376)
|
||||
- TypeScript
|
||||
- 🤖 Add ConfigProvider the `Window` type definition in `getTargetContainer` of . [#55313](https://github.com/ant-design/ant-design/pull/55313)
|
||||
- 🤖 Add ConfigProvider the `ShadowRoot` type definition in `getTargetContainer` and `getPopupContainer`. [#55278](https://github.com/ant-design/ant-design/pull/55278) [@leshalv](https://github.com/leshalv)
|
||||
- 🤖 Improve Modal type definition. [#55371](https://github.com/ant-design/ant-design/pull/55371)
|
||||
|
||||
## 5.27.5
|
||||
|
||||
`2025-10-14`
|
||||
|
||||
@@ -15,6 +15,57 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.28.1
|
||||
|
||||
`2025-11-10`
|
||||
|
||||
- Carousel
|
||||
- 🐞 修复 Carousel 组件纵向样式问题。[#55615](https://github.com/ant-design/ant-design/pull/55615) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 修复 Carousel 首次渲染时指示点动画丢失。[#55589](https://github.com/ant-design/ant-design/pull/55589) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 修复 Popconfirm 在 `actionFn` 出错时未重置 ref 的问题。[#55519](https://github.com/ant-design/ant-design/pull/55519) [@Taoister39](https://github.com/Taoister39)
|
||||
- 🐞 修复 Descriptions 组件内容样式错误使用 `labelStyle` 的问题。[#55572](https://github.com/ant-design/ant-design/pull/55572) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 💄 修正 `underlined` 变体的 Select 组件高度为 32px。[#55607](https://github.com/ant-design/ant-design/pull/55607) [@ustcfury](https://github.com/ustcfury)
|
||||
- 💄 为 `underlined` 变体的 Input 组件补全 hover 边框颜色样式。[#55609](https://github.com/ant-design/ant-design/pull/55609) [@ustcfury](https://github.com/ustcfury)
|
||||
- 🛠 Flex `gap` 属性支持 number 类型。[#55591](https://github.com/ant-design/ant-design/pull/55591) [@ayangweb](https://github.com/ayangweb)
|
||||
- 🌐 补充 TimePicker 多语言翻译,覆盖以下语言:ar_EG、en_GB、gl_ES、bg_BG、ca_ES、cs_CZ、el_GR、es_ES、eu_ES、fi_FI、he_IL、hu_HU、is_IS、kn_IN、kmr_IQ、lv_LV、mk_MK、mn_MN、ms_MY、pl_PL、pt_BR、pt_PT、ro_RO、sk_SK、sl_SI、sv_SE、ta_IN、th_TH、zh_TW、et_EE。[#55656](https://github.com/ant-design/ant-design/pull/55656) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
|
||||
## 5.28.0
|
||||
|
||||
`2025-11-01`
|
||||
|
||||
- 🆕 Drawer 支持 `closable.placement` 属性,用于指定关闭按钮的位置。[#54067](https://github.com/ant-design/ant-design/pull/54067) [@davidhsing](https://github.com/davidhsing)
|
||||
- 🆕 Image 组件支持 `fallback` 全局配置。[#54702](https://github.com/ant-design/ant-design/pull/54702) [@Jiyur](https://github.com/Jiyur)
|
||||
- 🆕 QRCode 组件支持 `boostLevel` 属性。[#55063](https://github.com/ant-design/ant-design/pull/55063) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🆕 Splitter 支持 `onCollapse` 属性。[#54673](https://github.com/ant-design/ant-design/pull/54673) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🆕 Statistic 设置为 `loading` 时默认展现动画效果。[#55398](https://github.com/ant-design/ant-design/pull/55398) [@afc163](https://github.com/afc163)
|
||||
- 🆕 TreeSelect 支持切换器图标的全局配置。[#54821](https://github.com/ant-design/ant-design/pull/54821) [@Jiyur](https://github.com/Jiyur)
|
||||
- Segmented
|
||||
- 💄 Segmented 的主题变量 `itemSelectedBg` 支持背景渐变。[#55391](https://github.com/ant-design/ant-design/pull/55391) [@zancheng](https://github.com/zancheng)
|
||||
- 🐞 修复 Segmented 切换动画总是从第一项移动闪烁的问题。[#55438](https://github.com/ant-design/ant-design/pull/55438) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Tree 和 Transfer 组件的 `disabled` 继承问题。[#54831](https://github.com/ant-design/ant-design/pull/54831) [@cactuser-Lu](https://github.com/cactuser-Lu)
|
||||
- 🐞 修复 Tree.DirectoryTree 定义 `fieldNames` 时 `defaultExpandAll` 不生效的问题。[#55420](https://github.com/ant-design/ant-design/pull/55420) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- Upload
|
||||
- 🆕 Upload 组件 `customRequest` 参数中增加 `info.defaultRequest`。[#55146](https://github.com/ant-design/ant-design/pull/55146) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 💄 Upload 组件支持 `pictureCardSize` token。[#54756](https://github.com/ant-design/ant-design/pull/54756) [@wanpan11](https://github.com/wanpan11)
|
||||
- 💄 Notification 支持配置背景颜色的 token。[#54802](https://github.com/ant-design/ant-design/pull/54802) [@thinkasany](https://github.com/thinkasany)
|
||||
- 💄 Pagination 支持通过 `itemActiveColor` 和 `itemActiveColorHover` token 修改高亮项的文字颜色。[#55195](https://github.com/ant-design/ant-design/pull/55195) [@Renderz](https://github.com/Renderz)
|
||||
- 🐞 修复 Select、DatePicker、TreeSelect、Cascader 等组件 `suffixIcon` 配置值为 undefined 时没有默认后缀图标的问题。[#54790](https://github.com/ant-design/ant-design/pull/54790) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 修复 Mentions 组件没有继承外部 Form 的 `disabled` 的问题。[#54829](https://github.com/ant-design/ant-design/pull/54829) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 修复 Watermark 组件内包裹 Modal 使用 `modalRender` 会导致崩溃的问题。[#55435](https://github.com/ant-design/ant-design/pull/55435) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🗑 Input 组件废弃 `addonAfter` 和 `addonBefore` 属性,使用 Space.Compact 替换。[#55315](https://github.com/ant-design/ant-design/pull/55315) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🤖 Row 组件 `gutter` 属性支持 string 类型定义。[#54628](https://github.com/ant-design/ant-design/pull/54628) [@ug-hero](https://github.com/ug-hero)
|
||||
|
||||
## 5.27.6
|
||||
|
||||
`2025-10-20`
|
||||
|
||||
- 🐞 修复 Table `pagination.align` 属性失效的问题。[#55316](https://github.com/ant-design/ant-design/pull/55316)
|
||||
- 🛠 重构 Modal 中 ConfirmDialog 的 useMemo,以解决 Object.values 生成新数组导致 useMemo 失效的问题。[#55376](https://github.com/ant-design/ant-design/pull/55376)
|
||||
- TypeScript
|
||||
- 🤖 补充 ConfigProvider `getTargetContainer` 中 `Window` 类型定义。[#55313](https://github.com/ant-design/ant-design/pull/55313)
|
||||
- 🤖 补充 ConfigProvider 的 `getTargetContainer` 和 `getPopupContainer` 中 `ShadowRoot` 类型定义。[#55278](https://github.com/ant-design/ant-design/pull/55278) [@leshalv](https://github.com/leshalv)
|
||||
- 🤖 优化 Modal 中类型定义。[#55371](https://github.com/ant-design/ant-design/pull/55371)
|
||||
|
||||
## 5.27.5
|
||||
|
||||
`2025-10-14`
|
||||
@@ -36,7 +87,7 @@ tag: vVERSION
|
||||
- 🐞 修复 Table 在使 `sticky` 表头或设置 `scroll.y` 时,筛选下拉与 Tooltip 重复显示的问题。[#54910](https://github.com/ant-design/ant-design/pull/54910) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Table 表头在首次加载时未正确渲染的问题。[#54910](https://github.com/ant-design/ant-design/pull/54910) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Table 在启用 `scroll.x` 时,固定列的对齐问题。[#54899](https://github.com/ant-design/ant-design/pull/54899) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Button 仅图标(icon-only)按钮的内边距受主题影响的问题。 [#54970](https://github.com/ant-design/ant-design/pull/54970) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 Button 仅图标(icon-only)按钮的内边距受主题影响的问题。[#54970](https://github.com/ant-design/ant-design/pull/54970) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 Splitter 在非受控模式下初次挂载时,`minSize` 和 `maxSize` 未生效的问题。[#54939](https://github.com/ant-design/ant-design/pull/54939) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Switch 波纹效果与 Tailwind CSS disabled 变体的兼容性问题。[#54933](https://github.com/ant-design/ant-design/pull/54933) [@Jiyur](https://github.com/Jiyur)
|
||||
- 🐞 修复 Input.Search 在搜索按钮为 `disabled` 时,悬停仍会导致边框和图标变色的问题。[#54892](https://github.com/ant-design/ant-design/pull/54892) [@Jiyur](https://github.com/Jiyur)
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"!scripts/previewEditor/**/*",
|
||||
"!**/*.tmp",
|
||||
"!package.json",
|
||||
"!components/style/antd.css"
|
||||
"!components/style/antd.css",
|
||||
"!scripts/visual-regression/report-template.html"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
@@ -57,6 +58,7 @@
|
||||
"noExplicitAny": "off",
|
||||
"noArrayIndexKey": "off",
|
||||
"noConfusingVoidType": "off",
|
||||
"noNonNullAssertedOptionalChain": "off",
|
||||
"noThenProperty": "off",
|
||||
"noTemplateCurlyInString": "off",
|
||||
"useIterableCallbackReturn": "off",
|
||||
|
||||
@@ -67,7 +67,7 @@ const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
}, [prefixCls]);
|
||||
|
||||
let mergedProps: WrapProps = {
|
||||
...props,
|
||||
|
||||
@@ -2,8 +2,8 @@ import React, { useEffect } from 'react';
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { useClosable } from '../hooks';
|
||||
import type { UseClosableParams } from '../hooks/useClosable';
|
||||
import useClosable from '../hooks/useClosable';
|
||||
|
||||
type ParamsOfUseClosable = [
|
||||
closable: UseClosableParams['closable'],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { fireEvent, render } from '../../../tests/utils';
|
||||
import useSyncState from '../hooks/useSyncState';
|
||||
import { useSyncState } from '../hooks';
|
||||
|
||||
describe('Table', () => {
|
||||
it('useSyncState', () => {
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { act, render } from '../../../tests/utils';
|
||||
import useUniqueMemo from '../hooks/useUniqueMemo';
|
||||
|
||||
describe('Table', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('useSyncState', () => {
|
||||
const sharedObjDeps1 = {};
|
||||
const sharedObjDeps2 = {};
|
||||
|
||||
let calledTimes = 0;
|
||||
|
||||
const Test: React.FC<{ depName?: string }> = ({ depName }) => {
|
||||
useUniqueMemo(() => {
|
||||
calledTimes += 1;
|
||||
return depName;
|
||||
}, [depName, sharedObjDeps1, 'bamboo', sharedObjDeps2]);
|
||||
return null;
|
||||
};
|
||||
|
||||
// Reuse the same memo
|
||||
const { rerender } = render(
|
||||
<>
|
||||
<Test depName="light" />
|
||||
<Test depName="light" />
|
||||
<Test depName="light" />
|
||||
</>,
|
||||
);
|
||||
|
||||
expect(calledTimes).toBe(1);
|
||||
|
||||
// Different deps should clean up the cache
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(1000 * 60 * 20);
|
||||
});
|
||||
|
||||
for (let i = 0; i < 20000; i += 1) {
|
||||
rerender(<Test depName="diff" key={i} />);
|
||||
}
|
||||
rerender(<Test depName="clear" />);
|
||||
calledTimes = 0;
|
||||
|
||||
// Back should recompute
|
||||
rerender(<Test depName="light" />);
|
||||
expect(calledTimes).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -300,7 +300,7 @@ describe('Test useZIndex hooks', () => {
|
||||
if (['SelectLike', 'DatePicker', 'ImagePreview'].includes(key)) {
|
||||
let comps = document.querySelectorAll<HTMLElement>(selector1);
|
||||
comps.forEach((comp) => {
|
||||
expect(comp?.style.zIndex).toBeFalsy();
|
||||
expect(comp).toHaveStyle({ zIndex: '' });
|
||||
});
|
||||
comps = document.querySelectorAll<HTMLElement>(selector2);
|
||||
comps.forEach((comp) => {
|
||||
@@ -311,9 +311,9 @@ describe('Test useZIndex hooks', () => {
|
||||
const operOffset = comp.classList.contains('ant-image-preview-operations-wrapper')
|
||||
? 1
|
||||
: 0;
|
||||
expect(comp?.style.zIndex).toBe(
|
||||
String(1000 + containerZIndexValue + consumerOffset + operOffset),
|
||||
);
|
||||
expect(comp).toHaveStyle({
|
||||
zIndex: 1000 + containerZIndexValue + consumerOffset + operOffset,
|
||||
});
|
||||
});
|
||||
|
||||
comps = document.querySelectorAll<HTMLElement>(selector3);
|
||||
@@ -325,21 +325,21 @@ describe('Test useZIndex hooks', () => {
|
||||
const operOffset = comp.classList.contains('ant-image-preview-operations-wrapper')
|
||||
? 1
|
||||
: 0;
|
||||
expect(comp?.style.zIndex).toBe(
|
||||
String(1000 + containerZIndexValue * 2 + consumerOffset + operOffset),
|
||||
);
|
||||
expect(comp).toHaveStyle({
|
||||
zIndex: 1000 + containerZIndexValue * 2 + consumerOffset + operOffset,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const element1 = document.querySelector<HTMLElement>(selector1);
|
||||
const element2 = document.querySelector<HTMLElement>(selector2);
|
||||
const element3 = document.querySelector<HTMLElement>(selector3);
|
||||
expect(element1?.style.zIndex).toBe(key === 'Tour' ? '1001' : '');
|
||||
expect(element2?.style.zIndex).toBe(
|
||||
String(1000 + containerZIndexValue + consumerZIndexValue),
|
||||
);
|
||||
expect(element3?.style.zIndex).toBe(
|
||||
String(1000 + containerZIndexValue * 2 + consumerZIndexValue),
|
||||
);
|
||||
expect(element1).toHaveStyle({ zIndex: key === 'Tour' ? 1001 : '' });
|
||||
expect(element2).toHaveStyle({
|
||||
zIndex: 1000 + containerZIndexValue + consumerZIndexValue,
|
||||
});
|
||||
expect(element3).toHaveStyle({
|
||||
zIndex: 1000 + containerZIndexValue * 2 + consumerZIndexValue,
|
||||
});
|
||||
}
|
||||
unmount();
|
||||
}, 20000);
|
||||
@@ -399,16 +399,14 @@ describe('Test useZIndex hooks', () => {
|
||||
<FloatButton />
|
||||
</WrapWithProvider>,
|
||||
);
|
||||
expect(container.querySelector<HTMLElement>('.ant-float-btn')?.style.zIndex).toBe(
|
||||
// parentZIndex + containerBaseZIndexOffset["FloatButton"]
|
||||
String(1100 + containerBaseZIndexOffset.FloatButton),
|
||||
);
|
||||
const ele = container.querySelector<HTMLElement>('.ant-float-btn');
|
||||
expect(ele).toHaveStyle({ zIndex: 1100 + containerBaseZIndexOffset.FloatButton });
|
||||
rerender(
|
||||
<WrapWithProvider container="FloatButton">
|
||||
<FloatButton style={{ zIndex: 666 }} />
|
||||
</WrapWithProvider>,
|
||||
);
|
||||
expect(container.querySelector<HTMLElement>('.ant-float-btn')?.style.zIndex).toBe(String(666));
|
||||
expect(ele).toHaveStyle({ zIndex: 666 });
|
||||
});
|
||||
|
||||
it('not warning for static func', () => {
|
||||
|
||||
8
components/_util/hooks/index.ts
Normal file
8
components/_util/hooks/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export * from './useClosable';
|
||||
export * from './useForceUpdate';
|
||||
export * from './useMergeSemantic';
|
||||
export * from './useMultipleSelect';
|
||||
export * from './usePatchElement';
|
||||
export * from './useProxyImperativeHandle';
|
||||
export * from './useSyncState';
|
||||
export * from './useZIndex';
|
||||
@@ -56,10 +56,7 @@ function useClosableConfig(closableCollection?: ClosableCollection | null) {
|
||||
closeIcon: typeof closeIcon !== 'boolean' && closeIcon !== null ? closeIcon : undefined,
|
||||
};
|
||||
if (closable && typeof closable === 'object') {
|
||||
closableConfig = {
|
||||
...closableConfig,
|
||||
...closable,
|
||||
};
|
||||
closableConfig = { ...closableConfig, ...closable };
|
||||
}
|
||||
return closableConfig;
|
||||
}, [closable, closeIcon]);
|
||||
@@ -82,7 +79,7 @@ interface FallbackCloseCollection extends ClosableCollection {
|
||||
/** Use same object to support `useMemo` optimization */
|
||||
const EmptyFallbackCloseCollection: FallbackCloseCollection = {};
|
||||
|
||||
export default function useClosable(
|
||||
export const useClosable = (
|
||||
propCloseCollection?: ClosableCollection,
|
||||
contextCloseCollection?: ClosableCollection | null,
|
||||
fallbackCloseCollection: FallbackCloseCollection = EmptyFallbackCloseCollection,
|
||||
@@ -91,7 +88,7 @@ export default function useClosable(
|
||||
closeIcon: React.ReactNode,
|
||||
closeBtnIsDisabled: boolean,
|
||||
ariaOrDataProps?: HTMLAriaDataAttributes,
|
||||
] {
|
||||
] => {
|
||||
// Align the `props`, `context` `fallback` to config object first
|
||||
const propCloseConfig = useClosableConfig(propCloseCollection);
|
||||
const contextCloseConfig = useClosableConfig(contextCloseCollection);
|
||||
@@ -172,4 +169,4 @@ export default function useClosable(
|
||||
mergedClosableConfig,
|
||||
mergedFallbackCloseCollection,
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export default function useForceUpdate() {
|
||||
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
|
||||
return forceUpdate;
|
||||
}
|
||||
export const useForceUpdate = () => {
|
||||
return React.useReducer((ori) => ori + 1, 0);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import type { ValidChar } from './interface';
|
||||
import type { ValidChar } from '../type';
|
||||
|
||||
type TemplateSemanticClassNames<T extends string> = Partial<Record<T, string>>;
|
||||
|
||||
export type SemanticSchema = {
|
||||
_default?: string;
|
||||
} & {
|
||||
export type SemanticSchema = { _default?: string } & {
|
||||
[key: `${ValidChar}${string}`]: SemanticSchema;
|
||||
};
|
||||
|
||||
@@ -15,7 +13,7 @@ export type SemanticSchema = {
|
||||
export function mergeClassNames<
|
||||
T extends string,
|
||||
SemanticClassNames extends Partial<Record<T, any>> = TemplateSemanticClassNames<T>,
|
||||
>(schema: SemanticSchema | undefined, ...classNames: (SemanticClassNames | undefined)[]) {
|
||||
>(schema?: SemanticSchema, ...classNames: (SemanticClassNames | undefined)[]) {
|
||||
const mergedSchema = schema || {};
|
||||
|
||||
return classNames.reduce((acc: any, cur) => {
|
||||
@@ -31,8 +29,10 @@ export function mergeClassNames<
|
||||
} else {
|
||||
// Covert string to object structure
|
||||
const { _default: defaultField } = keySchema;
|
||||
acc[key] = acc[key] || {};
|
||||
acc[key][defaultField!] = classnames(acc[key][defaultField!], curVal);
|
||||
if (defaultField) {
|
||||
acc[key] = acc[key] || {};
|
||||
acc[key][defaultField] = classnames(acc[key][defaultField], curVal);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Flatten fill
|
||||
@@ -40,16 +40,16 @@ export function mergeClassNames<
|
||||
}
|
||||
});
|
||||
return acc;
|
||||
}, {} as SemanticClassNames) as SemanticClassNames;
|
||||
}, {} as SemanticClassNames);
|
||||
}
|
||||
|
||||
function useSemanticClassNames<ClassNamesType extends object>(
|
||||
schema: SemanticSchema | undefined,
|
||||
schema?: SemanticSchema,
|
||||
...classNames: (Partial<ClassNamesType> | undefined)[]
|
||||
): Partial<ClassNamesType> {
|
||||
return React.useMemo(
|
||||
() => mergeClassNames(schema, ...classNames),
|
||||
[classNames],
|
||||
[classNames, schema],
|
||||
) as ClassNamesType;
|
||||
}
|
||||
|
||||
@@ -58,31 +58,25 @@ function useSemanticStyles<StylesType extends object>(
|
||||
...styles: (Partial<StylesType> | undefined)[]
|
||||
) {
|
||||
return React.useMemo(() => {
|
||||
return styles.reduce(
|
||||
(acc, cur = {}) => {
|
||||
Object.keys(cur).forEach((key) => {
|
||||
acc[key] = { ...acc[key], ...(cur as Record<string, React.CSSProperties>)[key] };
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, React.CSSProperties>,
|
||||
);
|
||||
return styles.reduce<Record<string, React.CSSProperties>>((acc, cur = {}) => {
|
||||
Object.keys(cur).forEach((key) => {
|
||||
acc[key] = { ...acc[key], ...(cur as Record<string, React.CSSProperties>)[key] };
|
||||
});
|
||||
return acc;
|
||||
}, {});
|
||||
}, [styles]) as StylesType;
|
||||
}
|
||||
|
||||
// =========================== Export ===========================
|
||||
function fillObjectBySchema<T extends object>(obj: T, schema: SemanticSchema): T {
|
||||
const newObj: any = { ...obj };
|
||||
|
||||
Object.keys(schema).forEach((key) => {
|
||||
if (key !== '_default') {
|
||||
const nestSchema = (schema as any)[key] as SemanticSchema;
|
||||
const nextValue = newObj[key] || {};
|
||||
|
||||
newObj[key] = nestSchema ? fillObjectBySchema(nextValue, nestSchema) : nextValue;
|
||||
}
|
||||
});
|
||||
|
||||
return newObj;
|
||||
}
|
||||
|
||||
@@ -90,18 +84,17 @@ function fillObjectBySchema<T extends object>(obj: T, schema: SemanticSchema): T
|
||||
* Merge classNames and styles from multiple sources.
|
||||
* When `schema` is provided, it will **must** provide the nest object structure.
|
||||
*/
|
||||
export default function useMergeSemantic<ClassNamesType extends object, StylesType extends object>(
|
||||
export const useMergeSemantic = <ClassNamesType extends object, StylesType extends object>(
|
||||
classNamesList: (ClassNamesType | undefined)[],
|
||||
stylesList: (StylesType | undefined)[],
|
||||
schema?: SemanticSchema,
|
||||
) {
|
||||
) => {
|
||||
const mergedClassNames = useSemanticClassNames(schema, ...classNamesList) as ClassNamesType;
|
||||
const mergedStyles = useSemanticStyles(...stylesList) as StylesType;
|
||||
|
||||
return React.useMemo(() => {
|
||||
return [
|
||||
fillObjectBySchema(mergedClassNames, schema!) as ClassNamesType,
|
||||
fillObjectBySchema(mergedStyles, schema!) as StylesType,
|
||||
] as const;
|
||||
}, [mergedClassNames, mergedStyles]);
|
||||
}
|
||||
}, [mergedClassNames, mergedStyles, schema]);
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
export type ValidChar =
|
||||
| 'a'
|
||||
| 'b'
|
||||
| 'c'
|
||||
| 'd'
|
||||
| 'e'
|
||||
| 'f'
|
||||
| 'g'
|
||||
| 'h'
|
||||
| 'i'
|
||||
| 'j'
|
||||
| 'k'
|
||||
| 'l'
|
||||
| 'm'
|
||||
| 'n'
|
||||
| 'o'
|
||||
| 'p'
|
||||
| 'q'
|
||||
| 'r'
|
||||
| 's'
|
||||
| 't'
|
||||
| 'u'
|
||||
| 'v'
|
||||
| 'w'
|
||||
| 'x'
|
||||
| 'y'
|
||||
| 'z';
|
||||
@@ -6,7 +6,7 @@ export type PrevSelectedIndex = null | number;
|
||||
* @title multipleSelect hooks
|
||||
* @description multipleSelect by hold down shift key
|
||||
*/
|
||||
export default function useMultipleSelect<T, K>(getKey: (item: T) => K) {
|
||||
export const useMultipleSelect = <T, K>(getKey: (item: T, index: number, array: T[]) => K) => {
|
||||
const [prevSelectedIndex, setPrevSelectedIndex] = useState<PrevSelectedIndex>(null);
|
||||
|
||||
const multipleSelect = useCallback(
|
||||
@@ -16,7 +16,7 @@ export default function useMultipleSelect<T, K>(getKey: (item: T) => K) {
|
||||
// add/delete the selected range
|
||||
const startIndex = Math.min(configPrevSelectedIndex || 0, currentSelectedIndex);
|
||||
const endIndex = Math.max(configPrevSelectedIndex || 0, currentSelectedIndex);
|
||||
const rangeKeys = data.slice(startIndex, endIndex + 1).map((item) => getKey(item));
|
||||
const rangeKeys = data.slice(startIndex, endIndex + 1).map<K>(getKey);
|
||||
const shouldSelected = rangeKeys.some((rangeKey) => !selectedKeys.has(rangeKey));
|
||||
const changedKeys: K[] = [];
|
||||
|
||||
@@ -39,9 +39,5 @@ export default function useMultipleSelect<T, K>(getKey: (item: T) => K) {
|
||||
[prevSelectedIndex],
|
||||
);
|
||||
|
||||
const updatePrevSelectedIndex = (val: PrevSelectedIndex) => {
|
||||
setPrevSelectedIndex(val);
|
||||
};
|
||||
|
||||
return [multipleSelect, updatePrevSelectedIndex] as const;
|
||||
}
|
||||
return [multipleSelect, setPrevSelectedIndex] as const;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export default function usePatchElement(): [
|
||||
export const usePatchElement = (): [
|
||||
React.ReactElement[],
|
||||
(element: React.ReactElement) => () => void,
|
||||
] {
|
||||
] => {
|
||||
const [elements, setElements] = React.useState<React.ReactElement[]>([]);
|
||||
|
||||
const patchElement = React.useCallback((element: React.ReactElement) => {
|
||||
@@ -18,4 +18,4 @@ export default function usePatchElement(): [
|
||||
}, []);
|
||||
|
||||
return [elements, patchElement];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,10 +22,13 @@ function fillProxy(
|
||||
return element;
|
||||
}
|
||||
|
||||
export default function useProxyImperativeHandle<
|
||||
export const useProxyImperativeHandle = <
|
||||
NativeELementType extends HTMLElement,
|
||||
ReturnRefType extends { nativeElement: NativeELementType },
|
||||
>(ref: Ref<any> | undefined, init: () => ReturnRefType) {
|
||||
>(
|
||||
ref: Ref<any> | undefined,
|
||||
init: () => ReturnRefType,
|
||||
) => {
|
||||
return useImperativeHandle(ref, () => {
|
||||
const refObj = init();
|
||||
const { nativeElement } = refObj;
|
||||
@@ -45,4 +48,4 @@ export default function useProxyImperativeHandle<
|
||||
// Fallback of IE
|
||||
return fillProxy(nativeElement, refObj);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import useForceUpdate from './useForceUpdate';
|
||||
import { useForceUpdate } from './useForceUpdate';
|
||||
|
||||
type UseSyncStateProps<T> = readonly [() => T, (newValue: T) => void];
|
||||
|
||||
export default function useSyncState<T>(initialValue: T): UseSyncStateProps<T> {
|
||||
export const useSyncState = <T>(initialValue: T): UseSyncStateProps<T> => {
|
||||
const ref = React.useRef<T>(initialValue);
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
const [, forceUpdate] = useForceUpdate();
|
||||
return [
|
||||
() => ref.current,
|
||||
(newValue: T) => {
|
||||
@@ -16,4 +15,4 @@ export default function useSyncState<T>(initialValue: T): UseSyncStateProps<T> {
|
||||
forceUpdate();
|
||||
},
|
||||
] as const;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const BEAT_LIMIT = 1000 * 60 * 10;
|
||||
|
||||
/**
|
||||
* A helper class to map keys to values.
|
||||
* It supports both primitive keys and object keys.
|
||||
*/
|
||||
class ArrayKeyMap<T> {
|
||||
map = new Map<string, T>();
|
||||
|
||||
// Use WeakMap to avoid memory leak
|
||||
objectIDMap = new WeakMap<object, number>();
|
||||
|
||||
nextID = 0;
|
||||
|
||||
lastAccessBeat = new Map<string, number>();
|
||||
|
||||
// We will clean up the cache when reach the limit
|
||||
accessBeat = 0;
|
||||
|
||||
set(keys: React.DependencyList, value: any) {
|
||||
// New set will trigger clear
|
||||
this.clear();
|
||||
|
||||
// Set logic
|
||||
const compositeKey = this.getCompositeKey(keys);
|
||||
this.map.set(compositeKey, value);
|
||||
this.lastAccessBeat.set(compositeKey, Date.now());
|
||||
}
|
||||
|
||||
get(keys: React.DependencyList) {
|
||||
const compositeKey = this.getCompositeKey(keys);
|
||||
|
||||
const cache = this.map.get(compositeKey);
|
||||
this.lastAccessBeat.set(compositeKey, Date.now());
|
||||
this.accessBeat += 1;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
getCompositeKey(keys: React.DependencyList) {
|
||||
const ids = keys.map<string>((key) => {
|
||||
if (key && typeof key === 'object') {
|
||||
return `obj_${this.getObjectID(key)}`;
|
||||
}
|
||||
return `${typeof key}_${key}`;
|
||||
});
|
||||
return ids.join('|');
|
||||
}
|
||||
|
||||
getObjectID(obj: object) {
|
||||
if (this.objectIDMap.has(obj)) {
|
||||
return this.objectIDMap.get(obj);
|
||||
}
|
||||
const id = this.nextID;
|
||||
this.objectIDMap.set(obj, id);
|
||||
|
||||
this.nextID += 1;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.accessBeat > 10000) {
|
||||
const now = Date.now();
|
||||
|
||||
this.lastAccessBeat.forEach((beat, key) => {
|
||||
if (now - beat > BEAT_LIMIT) {
|
||||
this.map.delete(key);
|
||||
this.lastAccessBeat.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
this.accessBeat = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueMap = new ArrayKeyMap();
|
||||
|
||||
/**
|
||||
* Like `useMemo`, but this hook result will be shared across all instances.
|
||||
*/
|
||||
function useUniqueMemo<T>(memoFn: () => T, deps: React.DependencyList) {
|
||||
return React.useMemo<T>(() => {
|
||||
const cachedValue = uniqueMap.get(deps);
|
||||
if (cachedValue) {
|
||||
return cachedValue as T;
|
||||
}
|
||||
const newValue = memoFn();
|
||||
uniqueMap.set(deps, newValue);
|
||||
return newValue;
|
||||
}, deps);
|
||||
}
|
||||
|
||||
export default useUniqueMemo;
|
||||
@@ -140,7 +140,7 @@ const useResponsiveObserver = () => {
|
||||
subscribers.clear();
|
||||
},
|
||||
};
|
||||
}, [token]);
|
||||
}, [responsiveMap]);
|
||||
};
|
||||
|
||||
export default useResponsiveObserver;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import type React from 'react';
|
||||
|
||||
export type Primitive = null | undefined | string | number | boolean | symbol | bigint;
|
||||
|
||||
/** https://github.com/Microsoft/TypeScript/issues/29729 */
|
||||
export type LiteralUnion<T extends string> = T | (string & {});
|
||||
export type LiteralUnion<T, U extends Primitive = string> = T | (U & Record<never, never>);
|
||||
|
||||
export type AnyObject = Record<PropertyKey, any>;
|
||||
|
||||
export type EmptyObject = Record<never, never>;
|
||||
|
||||
export type CustomComponent<P = AnyObject> = React.ComponentType<P> | string;
|
||||
|
||||
/**
|
||||
@@ -78,3 +82,31 @@ export type GetContextProp<
|
||||
T extends React.Context<any>,
|
||||
PropName extends keyof GetContextProps<T>,
|
||||
> = NonNullable<GetContextProps<T>[PropName]>;
|
||||
|
||||
export type ValidChar =
|
||||
| 'a'
|
||||
| 'b'
|
||||
| 'c'
|
||||
| 'd'
|
||||
| 'e'
|
||||
| 'f'
|
||||
| 'g'
|
||||
| 'h'
|
||||
| 'i'
|
||||
| 'j'
|
||||
| 'k'
|
||||
| 'l'
|
||||
| 'm'
|
||||
| 'n'
|
||||
| 'o'
|
||||
| 'p'
|
||||
| 'q'
|
||||
| 'r'
|
||||
| 's'
|
||||
| 't'
|
||||
| 'u'
|
||||
| 'v'
|
||||
| 'w'
|
||||
| 'x'
|
||||
| 'y'
|
||||
| 'z';
|
||||
|
||||
@@ -55,7 +55,10 @@ export interface AffixRef {
|
||||
updatePosition: ReturnType<typeof throttleByAnimationFrame>;
|
||||
}
|
||||
|
||||
type InternalAffixProps = AffixProps & { onTestUpdatePosition?: any };
|
||||
interface InternalAffixProps extends AffixProps {
|
||||
onTestUpdatePosition?: () => void;
|
||||
}
|
||||
|
||||
const Affix = React.forwardRef<AffixRef, InternalAffixProps>((props, ref) => {
|
||||
const {
|
||||
style,
|
||||
|
||||
@@ -10,7 +10,7 @@ import CSSMotion from 'rc-motion';
|
||||
import pickAttrs from 'rc-util/lib/pickAttrs';
|
||||
import { composeRef } from 'rc-util/lib/ref';
|
||||
|
||||
import type { ClosableType } from '../_util/hooks/useClosable';
|
||||
import type { ClosableType } from '../_util/hooks';
|
||||
import { replaceElement } from '../_util/reactNode';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
@@ -176,7 +176,9 @@ const Alert = React.forwardRef<AlertRef, AlertProps>((props, ref) => {
|
||||
|
||||
// closeable when closeText or closeIcon is assigned
|
||||
const isClosable = React.useMemo<boolean>(() => {
|
||||
if (typeof closable === 'object' && closable.closeIcon) return true;
|
||||
if (typeof closable === 'object' && closable.closeIcon) {
|
||||
return true;
|
||||
}
|
||||
if (closeText) {
|
||||
return true;
|
||||
}
|
||||
@@ -226,7 +228,7 @@ const Alert = React.forwardRef<AlertRef, AlertProps>((props, ref) => {
|
||||
return contextClosable.closeIcon;
|
||||
}
|
||||
return contextCloseIcon;
|
||||
}, [closeIcon, closable, closeText, contextCloseIcon]);
|
||||
}, [closeIcon, closable, contextClosable, closeText, contextCloseIcon]);
|
||||
|
||||
const mergedAriaProps = React.useMemo<React.AriaAttributes>(() => {
|
||||
const merged = closable ?? contextClosable;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
友好的 [React 错误处理](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html) 包裹组件。
|
||||
友好的 [React 错误处理](https://zh-hans.react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) 包裹组件。
|
||||
|
||||
## en-US
|
||||
|
||||
ErrorBoundary Component for making error handling easier in [React](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html).
|
||||
ErrorBoundary Component for making error handling easier in [React](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary).
|
||||
|
||||
@@ -246,7 +246,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
|
||||
);
|
||||
|
||||
setCurrentActiveLink(currentActiveLink);
|
||||
}, [dependencyListItem, targetOffset, offsetTop]);
|
||||
}, [links, targetOffset, offsetTop, bounds]);
|
||||
|
||||
const handleScrollTo = React.useCallback<(link: string) => void>(
|
||||
(link) => {
|
||||
|
||||
@@ -185,7 +185,7 @@ describe('Anchor Render', () => {
|
||||
const link = container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!;
|
||||
fireEvent.click(link);
|
||||
await waitFakeTimer();
|
||||
expect(link.classList).toContain('ant-anchor-link-title-active');
|
||||
expect(link).toHaveClass('ant-anchor-link-title-active');
|
||||
});
|
||||
|
||||
it('scrolls the page when clicking a link', async () => {
|
||||
@@ -737,11 +737,9 @@ describe('Anchor Render', () => {
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-anchor-ink').length).toBe(1);
|
||||
expect(
|
||||
container
|
||||
.querySelector('.ant-anchor-wrapper')
|
||||
?.classList.contains('ant-anchor-wrapper-horizontal'),
|
||||
).toBeTruthy();
|
||||
expect(container.querySelector('.ant-anchor-wrapper')).toHaveClass(
|
||||
'ant-anchor-wrapper-horizontal',
|
||||
);
|
||||
});
|
||||
|
||||
it('nested children via items should be filtered out when direction is horizontal', () => {
|
||||
@@ -818,7 +816,7 @@ describe('Anchor Render', () => {
|
||||
const link = container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!;
|
||||
fireEvent.click(link);
|
||||
await waitFakeTimer();
|
||||
expect(link.classList).toContain('ant-anchor-link-title-active');
|
||||
expect(link).toHaveClass('ant-anchor-link-title-active');
|
||||
});
|
||||
|
||||
it('scrolls the page when clicking a link', async () => {
|
||||
@@ -1026,25 +1024,29 @@ describe('Anchor Render', () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const wrapper = await render(<Foo />);
|
||||
(await wrapper.findByText('part-1')).click();
|
||||
const { container, findByText } = await render(<Foo />);
|
||||
(await findByText('part-1')).click();
|
||||
await waitFakeTimer();
|
||||
const ink = wrapper.container.querySelector<HTMLSpanElement>('.ant-anchor-ink')!;
|
||||
const toggleButton = wrapper.container.querySelector('button')!;
|
||||
const inkElement = container.querySelector<HTMLSpanElement>('.ant-anchor-ink');
|
||||
const toggleButton = container.querySelector<HTMLElement>('button');
|
||||
|
||||
fireEvent.click(toggleButton);
|
||||
act(() => jest.runAllTimers());
|
||||
expect(!!ink.style.left).toBe(true);
|
||||
expect(!!ink.style.width).toBe(true);
|
||||
expect(ink.style.top).toBe('');
|
||||
expect(ink.style.height).toBe('');
|
||||
expect(toggleButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(toggleButton);
|
||||
fireEvent.click(toggleButton!);
|
||||
act(() => jest.runAllTimers());
|
||||
expect(!!ink.style.top).toBe(true);
|
||||
expect(!!ink.style.height).toBe(true);
|
||||
expect(ink.style.left).toBe('');
|
||||
expect(ink.style.width).toBe('');
|
||||
|
||||
expect(inkElement).toHaveStyle({
|
||||
left: '0px',
|
||||
width: '0px',
|
||||
});
|
||||
|
||||
fireEvent.click(toggleButton!);
|
||||
act(() => jest.runAllTimers());
|
||||
|
||||
expect(inkElement).toHaveStyle({
|
||||
top: '0px',
|
||||
height: '0px',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { BaseSelectRef } from 'rc-select';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
|
||||
import { useZIndex } from '../_util/hooks/useZIndex';
|
||||
import { useZIndex } from '../_util/hooks';
|
||||
import type { InputStatus } from '../_util/statusUtils';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import type { ConfigConsumerProps } from '../config-provider';
|
||||
@@ -24,6 +24,7 @@ export interface DataSourceItemObject {
|
||||
value: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export type DataSourceItemType = DataSourceItemObject | React.ReactNode;
|
||||
|
||||
export interface AutoCompleteProps<
|
||||
|
||||
@@ -1096,7 +1096,11 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 2`] = `[]`;
|
||||
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 2`] = `
|
||||
[
|
||||
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/custom.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
@@ -2424,6 +2428,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
exports[`renders components/auto-complete/demo/form-debug.tsx extend context correctly 2`] = `
|
||||
[
|
||||
"Warning: [antd: Input.Group] \`Input.Group\` is deprecated. Please use \`Space.Compact\` instead.",
|
||||
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -2982,7 +2987,11 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx extend con
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 2`] = `[]`;
|
||||
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 2`] = `
|
||||
[
|
||||
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/variant.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
|
||||
@@ -46,8 +46,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
| allowClear | Show clear button | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: Support Object type |
|
||||
| autoFocus | If get focus when component mounted | boolean | false | |
|
||||
| backfill | If backfill selected item the input when using keyboard | boolean | false | |
|
||||
| children (for customize input element) | Customize input element | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| children (for dataSource) | Data source to auto complete | React.ReactElement<OptionProps> \| Array<React.ReactElement<OptionProps>> | - | |
|
||||
| children | Customize input element | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| classNames | Semantic DOM class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
|
||||
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
|
||||
| defaultOpen | Initial open state of dropdown | boolean | - | |
|
||||
|
||||
@@ -47,8 +47,7 @@ demo:
|
||||
| allowClear | 支持清除 | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: 支持对象形式 |
|
||||
| autoFocus | 自动获取焦点 | boolean | false | |
|
||||
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
|
||||
| children (自动完成的数据源) | 自动完成的数据源,不能和自定义输入框同时配置 | React.ReactElement<OptionProps> \| Array<React.ReactElement<OptionProps>> | - | |
|
||||
| children (自定义输入框) | 自定义输入框,不能和自动完成的数据源同时配置 | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| children | 自定义输入框 | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| classNames | 语义化结构 class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
|
||||
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
|
||||
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
|
||||
|
||||
@@ -129,7 +129,7 @@ const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
|
||||
fontSize: currentSize && (icon || children) ? currentSize / 2 : 18,
|
||||
}
|
||||
: {};
|
||||
}, [screens, size]);
|
||||
}, [screens, size, icon, children]);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Avatar');
|
||||
@@ -205,11 +205,7 @@ const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
|
||||
|
||||
childrenToRender = (
|
||||
<ResizeObserver onResize={setScaleParam}>
|
||||
<span
|
||||
className={`${prefixCls}-string`}
|
||||
ref={avatarChildrenRef}
|
||||
style={{ ...childrenStyle }}
|
||||
>
|
||||
<span className={`${prefixCls}-string`} ref={avatarChildrenRef} style={childrenStyle}>
|
||||
{children}
|
||||
</span>
|
||||
</ResizeObserver>
|
||||
|
||||
@@ -146,11 +146,11 @@ describe('Badge', () => {
|
||||
// https://github.com/ant-design/ant-design/issues/15349
|
||||
it('should color style works on Badge', () => {
|
||||
const { container } = render(
|
||||
<Badge style={{ color: 'red' }} status="success" text="Success" />,
|
||||
);
|
||||
expect((container.querySelector('.ant-badge-status-text')! as HTMLElement).style.color).toEqual(
|
||||
'red',
|
||||
<Badge style={{ color: 'rgb(255, 0, 0)' }} status="success" text="Success" />,
|
||||
);
|
||||
expect(container.querySelector<HTMLElement>('.ant-badge-status-text')).toHaveStyle({
|
||||
color: 'rgb(255, 0, 0)',
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/15799
|
||||
@@ -247,14 +247,8 @@ describe('Badge', () => {
|
||||
const { container } = render(
|
||||
<Badge
|
||||
count={10}
|
||||
classNames={{
|
||||
root: 'test-root',
|
||||
indicator: 'test-indicator',
|
||||
}}
|
||||
styles={{
|
||||
root: { backgroundColor: 'yellow' },
|
||||
indicator: { backgroundColor: 'blue' },
|
||||
}}
|
||||
classNames={{ root: 'test-root', indicator: 'test-indicator' }}
|
||||
styles={{ root: { padding: 10 }, indicator: { padding: 20 } }}
|
||||
>
|
||||
test
|
||||
</Badge>,
|
||||
@@ -267,9 +261,7 @@ describe('Badge', () => {
|
||||
expect(element?.querySelector<HTMLElement>('sup')).toHaveClass('test-indicator');
|
||||
|
||||
// styles
|
||||
expect(element).toHaveStyle({ backgroundColor: 'rgb(255, 255, 0)' });
|
||||
expect(element?.querySelector<HTMLElement>('sup')).toHaveStyle({
|
||||
backgroundColor: 'rgb(0, 0, 255)',
|
||||
});
|
||||
expect(element).toHaveStyle({ padding: '10px' });
|
||||
expect(element?.querySelector<HTMLElement>('sup')).toHaveStyle({ padding: '20px' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,28 +37,28 @@ describe('Ribbon', () => {
|
||||
expect(container.querySelectorAll('.ant-ribbon-color-green').length).toEqual(1);
|
||||
});
|
||||
it('works with custom color', () => {
|
||||
const { container: wrapperLeft } = render(
|
||||
<Badge.Ribbon color="#888" placement="start">
|
||||
const { container, rerender } = render(
|
||||
<Badge.Ribbon color="rgb(136, 136, 136)" placement="start">
|
||||
<div />
|
||||
</Badge.Ribbon>,
|
||||
);
|
||||
expect((wrapperLeft.querySelector('.ant-ribbon')! as HTMLElement).style.background).toEqual(
|
||||
'rgb(136, 136, 136)',
|
||||
);
|
||||
expect((wrapperLeft.querySelector('.ant-ribbon-corner')! as HTMLElement).style.color).toEqual(
|
||||
'rgb(136, 136, 136)',
|
||||
);
|
||||
const { container: wrapperRight } = render(
|
||||
<Badge.Ribbon color="#888" placement="end">
|
||||
expect(container.querySelector<HTMLElement>('.ant-ribbon')).toHaveStyle({
|
||||
backgroundColor: 'rgb(136, 136, 136)',
|
||||
});
|
||||
expect(container.querySelector<HTMLElement>('.ant-ribbon-corner')).toHaveStyle({
|
||||
color: 'rgb(136, 136, 136)',
|
||||
});
|
||||
rerender(
|
||||
<Badge.Ribbon color="rgb(136, 136, 136)" placement="end">
|
||||
<div />
|
||||
</Badge.Ribbon>,
|
||||
);
|
||||
expect((wrapperRight.querySelector('.ant-ribbon')! as HTMLElement).style.background).toEqual(
|
||||
'rgb(136, 136, 136)',
|
||||
);
|
||||
expect(
|
||||
(wrapperRight.querySelector('.ant-ribbon-corner')! as HTMLElement).style.color,
|
||||
).toEqual('rgb(136, 136, 136)');
|
||||
expect(container.querySelector<HTMLElement>('.ant-ribbon')).toHaveStyle({
|
||||
backgroundColor: 'rgb(136, 136, 136)',
|
||||
});
|
||||
expect(container.querySelector<HTMLElement>('.ant-ribbon-corner')).toHaveStyle({
|
||||
color: 'rgb(136, 136, 136)',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2014,7 +2014,11 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/button/demo/debug-icon.tsx extend context correctly 2`] = `[]`;
|
||||
exports[`renders components/button/demo/debug-icon.tsx extend context correctly 2`] = `
|
||||
[
|
||||
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/button/demo/disabled.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { Children, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import { useComposeRef } from 'rc-util/lib/ref';
|
||||
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
|
||||
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import Wave from '../_util/wave';
|
||||
@@ -154,7 +154,7 @@ const InternalCompoundedButton = React.forwardRef<
|
||||
}
|
||||
|
||||
return ['default', 'outlined'];
|
||||
}, [type, color, variant, danger, button?.variant, button?.color]);
|
||||
}, [color, variant, type, danger, button?.color, button?.variant, mergedType]);
|
||||
|
||||
const isDanger = mergedColor === 'danger';
|
||||
const mergedColorText = isDanger ? 'dangerous' : mergedColor;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import Dayjs from 'dayjs';
|
||||
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
import React from 'react';
|
||||
import Dayjs from 'dayjs';
|
||||
import MockDate from 'mockdate';
|
||||
import type { PickerPanelProps } from 'rc-picker';
|
||||
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
|
||||
@@ -17,9 +14,12 @@ import ConfigProvider from '../../config-provider';
|
||||
import Group from '../../radio/group';
|
||||
import Button from '../../radio/radioButton';
|
||||
import Select from '../../select';
|
||||
import type { DefaultOptionType } from '../../select';
|
||||
import Header from '../Header';
|
||||
import type { CalendarHeaderProps } from '../Header';
|
||||
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
const ref: {
|
||||
calendarProps?: PickerPanelProps;
|
||||
calendarHeaderProps?: CalendarHeaderProps<unknown>;
|
||||
@@ -375,15 +375,10 @@ describe('Calendar', () => {
|
||||
// Year
|
||||
const headerRender = jest.fn(({ value }) => {
|
||||
const year = value.year();
|
||||
const options = [];
|
||||
const options: DefaultOptionType[] = [];
|
||||
for (let i = year - 100; i < year + 100; i += 1) {
|
||||
options.push(
|
||||
<Select.Option className="year-item" key={i} value={i}>
|
||||
{i}
|
||||
</Select.Option>,
|
||||
);
|
||||
options.push({ label: i, value: i });
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
size="small"
|
||||
@@ -391,9 +386,8 @@ describe('Calendar', () => {
|
||||
className="my-year-select"
|
||||
onChange={onYearChange}
|
||||
value={String(year)}
|
||||
>
|
||||
{options}
|
||||
</Select>
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const uiWithYear = <Calendar fullscreen={false} headerRender={headerRender} />;
|
||||
@@ -412,23 +406,17 @@ describe('Calendar', () => {
|
||||
const headerRenderWithMonth = jest.fn(({ value }) => {
|
||||
const start = 0;
|
||||
const end = 12;
|
||||
const monthOptions = [];
|
||||
const months: string[] = [];
|
||||
const monthOptions: DefaultOptionType[] = [];
|
||||
const current = value.clone();
|
||||
const localeData = value.localeData();
|
||||
const months = [];
|
||||
for (let i = 0; i < 12; i += 1) {
|
||||
current.month(i);
|
||||
months.push(localeData.monthsShort(current));
|
||||
}
|
||||
|
||||
for (let index = start; index < end; index += 1) {
|
||||
monthOptions.push(
|
||||
<Select.Option className="month-item" key={index} value={index}>
|
||||
{months[index]}
|
||||
</Select.Option>,
|
||||
);
|
||||
monthOptions.push({ label: months[index], value: index });
|
||||
}
|
||||
|
||||
const month = value.month();
|
||||
return (
|
||||
<Select
|
||||
@@ -437,9 +425,8 @@ describe('Calendar', () => {
|
||||
className="my-month-select"
|
||||
onChange={onMonthChange}
|
||||
value={String(month)}
|
||||
>
|
||||
{monthOptions}
|
||||
</Select>
|
||||
options={monthOptions}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const uiWithMonth = <Calendar fullscreen={false} headerRender={headerRenderWithMonth} />;
|
||||
|
||||
@@ -65,8 +65,12 @@ const App: React.FC = () => {
|
||||
};
|
||||
|
||||
const cellRender: CalendarProps<Dayjs>['cellRender'] = (current, info) => {
|
||||
if (info.type === 'date') return dateCellRender(current);
|
||||
if (info.type === 'month') return monthCellRender(current);
|
||||
if (info.type === 'date') {
|
||||
return dateCellRender(current);
|
||||
}
|
||||
if (info.type === 'month') {
|
||||
return monthCellRender(current);
|
||||
}
|
||||
return info.originNode;
|
||||
};
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -347,7 +347,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -367,7 +367,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -387,7 +387,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -407,7 +407,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -427,7 +427,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -447,7 +447,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -467,7 +467,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -487,7 +487,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1036,7 +1036,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1056,7 +1056,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1076,7 +1076,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1096,7 +1096,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1116,7 +1116,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1136,7 +1136,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1156,7 +1156,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1176,7 +1176,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1196,7 +1196,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1272,7 +1272,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1292,7 +1292,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1312,7 +1312,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1332,7 +1332,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1503,7 +1503,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1523,7 +1523,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1543,7 +1543,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1563,7 +1563,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1583,7 +1583,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1603,7 +1603,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1623,7 +1623,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1643,7 +1643,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1663,7 +1663,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
|
||||
@@ -324,7 +324,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -344,7 +344,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -364,7 +364,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -384,7 +384,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -404,7 +404,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -424,7 +424,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -444,7 +444,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -464,7 +464,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -484,7 +484,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1027,7 +1027,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1047,7 +1047,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1067,7 +1067,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1087,7 +1087,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1107,7 +1107,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1127,7 +1127,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1147,7 +1147,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1167,7 +1167,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1187,7 +1187,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1261,7 +1261,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1281,7 +1281,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1301,7 +1301,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1321,7 +1321,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1490,7 +1490,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1510,7 +1510,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1530,7 +1530,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1550,7 +1550,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1570,7 +1570,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
@@ -1590,7 +1590,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
1
|
||||
</h3>
|
||||
@@ -1610,7 +1610,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
2
|
||||
</h3>
|
||||
@@ -1630,7 +1630,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
3
|
||||
</h3>
|
||||
@@ -1650,7 +1650,7 @@ Array [
|
||||
tabindex="-1"
|
||||
>
|
||||
<h3
|
||||
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
|
||||
>
|
||||
4
|
||||
</h3>
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { Carousel } from 'antd';
|
||||
|
||||
const contentStyle: React.CSSProperties = {
|
||||
margin: 0,
|
||||
height: '160px',
|
||||
color: '#fff',
|
||||
lineHeight: '160px',
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { Carousel } from 'antd';
|
||||
|
||||
const contentStyle: React.CSSProperties = {
|
||||
margin: 0,
|
||||
height: '160px',
|
||||
color: '#fff',
|
||||
lineHeight: '160px',
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { Carousel } from 'antd';
|
||||
|
||||
const contentStyle: React.CSSProperties = {
|
||||
margin: 0,
|
||||
height: '160px',
|
||||
color: '#fff',
|
||||
lineHeight: '160px',
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Carousel, Radio } from 'antd';
|
||||
type DotPosition = CarouselProps['dotPosition'];
|
||||
|
||||
const contentStyle: React.CSSProperties = {
|
||||
margin: 0,
|
||||
height: '160px',
|
||||
color: '#fff',
|
||||
lineHeight: '160px',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { unit } from '@ant-design/cssinjs';
|
||||
import { Keyframes, unit } from '@ant-design/cssinjs';
|
||||
|
||||
import { resetComponent } from '../../style';
|
||||
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
|
||||
@@ -230,6 +230,16 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
|
||||
colorBgContainer,
|
||||
motionDurationSlow,
|
||||
} = token;
|
||||
|
||||
const animation = new Keyframes(`${token.prefixCls}-dot-animation`, {
|
||||
from: {
|
||||
transform: `translate3d(-100%, 0, 0)`,
|
||||
},
|
||||
to: {
|
||||
transform: `translate3d(0%, 0, 0)`,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
'.slick-dots': {
|
||||
@@ -283,7 +293,6 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
|
||||
outline: 'none',
|
||||
cursor: 'pointer',
|
||||
overflow: 'hidden',
|
||||
transform: 'translate3d(-100%, 0, 0)',
|
||||
},
|
||||
|
||||
button: {
|
||||
@@ -322,8 +331,10 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
|
||||
},
|
||||
'&::after': {
|
||||
background: colorBgContainer,
|
||||
transform: 'translate3d(0, 0, 0)',
|
||||
transition: `transform var(${DotDuration}) ease-out`,
|
||||
animationName: animation,
|
||||
animationDuration: `var(${DotDuration})`,
|
||||
animationTimingFunction: 'ease-out',
|
||||
animationFillMode: 'forwards',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -335,6 +346,15 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
|
||||
const genCarouselVerticalStyle: GenerateStyle<CarouselToken> = (token) => {
|
||||
const { componentCls, dotOffset, arrowOffset, marginXXS } = token;
|
||||
|
||||
const animation = new Keyframes(`${token.prefixCls}-dot-vertical-animation`, {
|
||||
from: {
|
||||
height: 0,
|
||||
},
|
||||
to: {
|
||||
height: token.dotActiveWidth,
|
||||
},
|
||||
});
|
||||
|
||||
const reverseSizeOfDot = {
|
||||
width: token.dotHeight,
|
||||
height: token.dotWidth,
|
||||
@@ -396,12 +416,19 @@ const genCarouselVerticalStyle: GenerateStyle<CarouselToken> = (token) => {
|
||||
|
||||
'&.slick-active': {
|
||||
...reverseSizeOfDot,
|
||||
height: token.dotActiveWidth,
|
||||
|
||||
button: reverseSizeOfDot,
|
||||
button: {
|
||||
...reverseSizeOfDot,
|
||||
height: token.dotActiveWidth,
|
||||
},
|
||||
|
||||
'&::after': {
|
||||
...reverseSizeOfDot,
|
||||
transition: `height var(${DotDuration}) ease-out`,
|
||||
animationName: animation,
|
||||
animationDuration: `var(${DotDuration})`,
|
||||
animationTimingFunction: 'ease-out',
|
||||
animationFillMode: 'forwards',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -558,14 +558,14 @@ describe('Cascader', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const customStyle = { background: 'red' };
|
||||
const { container } = render(<Cascader dropdownStyle={customStyle} open />);
|
||||
|
||||
const { container } = render(<Cascader dropdownStyle={{ padding: 10 }} open />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Cascader] `dropdownStyle` is deprecated. Please use `styles.popup.root` instead.',
|
||||
);
|
||||
expect(container.querySelector('.ant-select-dropdown')?.getAttribute('style')).toContain(
|
||||
'background: red',
|
||||
);
|
||||
expect(container.querySelector<HTMLElement>('.ant-select-dropdown')).toHaveStyle({
|
||||
padding: '10px',
|
||||
});
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
@@ -595,11 +595,11 @@ describe('Cascader', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const columnStyle = { background: 'red' };
|
||||
|
||||
const { getByRole } = render(
|
||||
<Cascader
|
||||
options={[{ label: 'test', value: 1 }]}
|
||||
dropdownMenuColumnStyle={columnStyle}
|
||||
dropdownMenuColumnStyle={{ padding: 10 }}
|
||||
open
|
||||
/>,
|
||||
);
|
||||
@@ -607,7 +607,7 @@ describe('Cascader', () => {
|
||||
'Warning: [antd: Cascader] `dropdownMenuColumnStyle` is deprecated. Please use `popupMenuColumnStyle` instead.',
|
||||
);
|
||||
const menuColumn = getByRole('menuitemcheckbox');
|
||||
expect(menuColumn.style.background).toBe('red');
|
||||
expect(menuColumn).toHaveStyle({ padding: '10px' });
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import RcCascader from 'rc-cascader';
|
||||
import type { Placement } from 'rc-select/lib/BaseSelect';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
|
||||
import { useZIndex } from '../_util/hooks/useZIndex';
|
||||
import { useZIndex } from '../_util/hooks';
|
||||
import type { SelectCommonPlacement } from '../_util/motion';
|
||||
import { getTransitionName } from '../_util/motion';
|
||||
import genPurePanel from '../_util/PurePanel';
|
||||
|
||||
@@ -82,14 +82,12 @@ describe('Collapse', () => {
|
||||
</Collapse.Panel>
|
||||
</Collapse>,
|
||||
);
|
||||
expect(
|
||||
container.querySelector('.ant-collapse-item')?.classList.contains('ant-collapse-item-active'),
|
||||
).toBe(false);
|
||||
expect(container.querySelector('.ant-collapse-item')).not.toHaveClass(
|
||||
'ant-collapse-item-active',
|
||||
);
|
||||
fireEvent.click(container.querySelector('.ant-collapse-header')!);
|
||||
await waitFakeTimer();
|
||||
expect(
|
||||
container.querySelector('.ant-collapse-item')?.classList.contains('ant-collapse-item-active'),
|
||||
).toBe(true);
|
||||
expect(container.querySelector('.ant-collapse-item')).toHaveClass('ant-collapse-item-active');
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ import { SettingOutlined } from '@ant-design/icons';
|
||||
import type { CollapseProps } from 'antd';
|
||||
import { Collapse, Select } from 'antd';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const text = `
|
||||
A dog is a type of domesticated animal.
|
||||
Known for its loyalty and faithfulness,
|
||||
@@ -64,10 +62,15 @@ const App: React.FC = () => {
|
||||
/>
|
||||
<br />
|
||||
<span>Expand Icon Position: </span>
|
||||
<Select value={expandIconPosition} style={{ margin: '0 8px' }} onChange={onPositionChange}>
|
||||
<Option value="start">start</Option>
|
||||
<Option value="end">end</Option>
|
||||
</Select>
|
||||
<Select
|
||||
value={expandIconPosition}
|
||||
style={{ margin: '0 8px' }}
|
||||
onChange={onPositionChange}
|
||||
options={[
|
||||
{ label: 'start', value: 'start' },
|
||||
{ label: 'end', value: 'end' },
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -205,7 +205,7 @@ describe('ColorPicker', () => {
|
||||
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
|
||||
await waitFakeTimer();
|
||||
const presetsColors = container
|
||||
.querySelector('.ant-collapse-content')
|
||||
?.querySelector('.ant-collapse-content')
|
||||
?.querySelectorAll('.ant-color-picker-presets-color')!;
|
||||
|
||||
expect(container.querySelector('.ant-color-picker-presets')).toBeTruthy();
|
||||
@@ -217,9 +217,7 @@ describe('ColorPicker', () => {
|
||||
).toBeTruthy();
|
||||
|
||||
fireEvent.click(presetsColors[0]);
|
||||
expect(
|
||||
presetsColors[0].classList.contains('ant-color-picker-presets-color-bright'),
|
||||
).toBeFalsy();
|
||||
expect(presetsColors[0]).not.toHaveClass('ant-color-picker-presets-color-bright');
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-hex-input input')?.getAttribute('value'),
|
||||
).toEqual('000000');
|
||||
@@ -228,9 +226,7 @@ describe('ColorPicker', () => {
|
||||
);
|
||||
|
||||
fireEvent.click(presetsColors[9]);
|
||||
expect(
|
||||
presetsColors[9].classList.contains('ant-color-picker-presets-color-bright'),
|
||||
).toBeTruthy();
|
||||
expect(presetsColors[9]).toHaveClass('ant-color-picker-presets-color-bright');
|
||||
expect(
|
||||
container.querySelector('.ant-color-picker-hex-input input')?.getAttribute('value'),
|
||||
).toEqual('000000');
|
||||
|
||||
@@ -79,7 +79,7 @@ const ColorTrigger = forwardRef<HTMLDivElement, ColorTriggerProps>((props, ref)
|
||||
default:
|
||||
return alpha < 100 ? `${hexString.slice(0, 7)},${alpha}%` : hexString;
|
||||
}
|
||||
}, [color, format, showText, activeIndex]);
|
||||
}, [color, format, showText, activeIndex, locale.transparent, colorTextCellPrefixCls]);
|
||||
|
||||
// ============================= Render =============================
|
||||
const containerNode = useMemo<React.ReactNode>(
|
||||
|
||||
@@ -4,6 +4,7 @@ import RcColorPicker from '@rc-component/color-picker';
|
||||
import type { Color } from '@rc-component/color-picker';
|
||||
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
|
||||
|
||||
import { useForceUpdate } from '../../../_util/hooks';
|
||||
import Segmented from '../../../segmented';
|
||||
import { AggregationColor } from '../../color';
|
||||
import { PanelPickerContext } from '../../context';
|
||||
@@ -70,7 +71,7 @@ const PanelPicker: FC = () => {
|
||||
if (!isSingle) {
|
||||
setLockedColor(colors[activeIndex]?.color);
|
||||
}
|
||||
}, [gradientDragging, activeIndex]);
|
||||
}, [isSingle, colors, gradientDragging, activeIndex]);
|
||||
|
||||
const activeColor = React.useMemo(() => {
|
||||
if (isSingle) {
|
||||
@@ -83,11 +84,12 @@ const PanelPicker: FC = () => {
|
||||
}
|
||||
|
||||
return colors[activeIndex]?.color;
|
||||
}, [value, activeIndex, isSingle, lockedColor, gradientDragging]);
|
||||
}, [colors, value, activeIndex, isSingle, lockedColor, gradientDragging]);
|
||||
|
||||
// ========================= Picker Color =========================
|
||||
const [pickerColor, setPickerColor] = React.useState<AggregationColor | null>(activeColor);
|
||||
const [forceSync, setForceSync] = React.useState(0);
|
||||
|
||||
const [forceSync, setForceSync] = useForceUpdate();
|
||||
|
||||
const mergedPickerColor = pickerColor?.equals(activeColor) ? activeColor : pickerColor;
|
||||
|
||||
@@ -148,7 +150,7 @@ const PanelPicker: FC = () => {
|
||||
// Back of origin color in case in controlled
|
||||
// This will set after `onChangeComplete` to avoid `setState` trigger rerender
|
||||
// which will make `fillColor` get wrong `color.cleared` state
|
||||
setForceSync((ori) => ori + 1);
|
||||
setForceSync();
|
||||
};
|
||||
|
||||
const onInputChange = (colorValue: AggregationColor) => {
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function useModeColor(
|
||||
pushOption('gradient', locale.gradientColor);
|
||||
|
||||
return [optionList, modes];
|
||||
}, [mode]);
|
||||
}, [mode, locale.singleColor, locale.gradientColor]);
|
||||
|
||||
// ======================== Post ========================
|
||||
// We need align `mode` with `color` state
|
||||
|
||||
@@ -24801,7 +24801,7 @@ exports[`ConfigProvider components Select configProvider 1`] = `
|
||||
class="config-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
@@ -24819,8 +24819,11 @@ exports[`ConfigProvider components Select configProvider 1`] = `
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
class="config-select-selection-item"
|
||||
title="Light"
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -24833,18 +24836,13 @@ exports[`ConfigProvider components Select configProvider 1`] = `
|
||||
role="listbox"
|
||||
style="height: 0px; width: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="presentation"
|
||||
/>
|
||||
<div
|
||||
aria-label="Light"
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-selected="true"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="option"
|
||||
>
|
||||
Bamboo
|
||||
light
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -24861,14 +24859,8 @@ exports[`ConfigProvider components Select configProvider 1`] = `
|
||||
style="display: flex; flex-direction: column;"
|
||||
>
|
||||
<div
|
||||
class="config-select-item config-select-item-group"
|
||||
title="grp"
|
||||
>
|
||||
grp
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
|
||||
aria-selected="true"
|
||||
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
|
||||
title="Light"
|
||||
>
|
||||
<div
|
||||
@@ -24950,8 +24942,11 @@ exports[`ConfigProvider components Select configProvider componentDisabled 1`] =
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
class="config-select-selection-item"
|
||||
title="Light"
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
@@ -24997,7 +24992,7 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
|
||||
class="config-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
@@ -25015,8 +25010,11 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
class="config-select-selection-item"
|
||||
title="Light"
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -25029,18 +25027,13 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
|
||||
role="listbox"
|
||||
style="height: 0px; width: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="presentation"
|
||||
/>
|
||||
<div
|
||||
aria-label="Light"
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-selected="true"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="option"
|
||||
>
|
||||
Bamboo
|
||||
light
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -25057,14 +25050,8 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
|
||||
style="display: flex; flex-direction: column;"
|
||||
>
|
||||
<div
|
||||
class="config-select-item config-select-item-group"
|
||||
title="grp"
|
||||
>
|
||||
grp
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
|
||||
aria-selected="true"
|
||||
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
|
||||
title="Light"
|
||||
>
|
||||
<div
|
||||
@@ -25128,7 +25115,7 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
|
||||
class="config-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
@@ -25146,8 +25133,11 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
class="config-select-selection-item"
|
||||
title="Light"
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -25160,18 +25150,13 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
|
||||
role="listbox"
|
||||
style="height: 0px; width: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="presentation"
|
||||
/>
|
||||
<div
|
||||
aria-label="Light"
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-selected="true"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="option"
|
||||
>
|
||||
Bamboo
|
||||
light
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -25188,14 +25173,8 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
|
||||
style="display: flex; flex-direction: column;"
|
||||
>
|
||||
<div
|
||||
class="config-select-item config-select-item-group"
|
||||
title="grp"
|
||||
>
|
||||
grp
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
|
||||
aria-selected="true"
|
||||
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
|
||||
title="Light"
|
||||
>
|
||||
<div
|
||||
@@ -25259,7 +25238,7 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
|
||||
class="config-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
@@ -25277,8 +25256,11 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
class="config-select-selection-item"
|
||||
title="Light"
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -25291,18 +25273,13 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
|
||||
role="listbox"
|
||||
style="height: 0px; width: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="presentation"
|
||||
/>
|
||||
<div
|
||||
aria-label="Light"
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-selected="true"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="option"
|
||||
>
|
||||
Bamboo
|
||||
light
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -25319,14 +25296,8 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
|
||||
style="display: flex; flex-direction: column;"
|
||||
>
|
||||
<div
|
||||
class="config-select-item config-select-item-group"
|
||||
title="grp"
|
||||
>
|
||||
grp
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
|
||||
aria-selected="true"
|
||||
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
|
||||
title="Light"
|
||||
>
|
||||
<div
|
||||
@@ -25390,7 +25361,7 @@ exports[`ConfigProvider components Select normal 1`] = `
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
@@ -25408,8 +25379,11 @@ exports[`ConfigProvider components Select normal 1`] = `
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
class="ant-select-selection-item"
|
||||
title="Light"
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -25422,18 +25396,13 @@ exports[`ConfigProvider components Select normal 1`] = `
|
||||
role="listbox"
|
||||
style="height: 0px; width: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="presentation"
|
||||
/>
|
||||
<div
|
||||
aria-label="Light"
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-selected="true"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="option"
|
||||
>
|
||||
Bamboo
|
||||
light
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -25450,14 +25419,8 @@ exports[`ConfigProvider components Select normal 1`] = `
|
||||
style="display: flex; flex-direction: column;"
|
||||
>
|
||||
<div
|
||||
class="ant-select-item ant-select-item-group"
|
||||
title="grp"
|
||||
>
|
||||
grp
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="ant-select-item ant-select-item-option ant-select-item-option-grouped ant-select-item-option-active"
|
||||
aria-selected="true"
|
||||
class="ant-select-item ant-select-item-option ant-select-item-option-active ant-select-item-option-selected"
|
||||
title="Light"
|
||||
>
|
||||
<div
|
||||
@@ -25521,7 +25484,7 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
|
||||
class="prefix-Select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_TEST_OR_SSR_list"
|
||||
aria-expanded="true"
|
||||
@@ -25539,8 +25502,11 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="prefix-Select-selection-placeholder"
|
||||
/>
|
||||
class="prefix-Select-selection-item"
|
||||
title="Light"
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -25553,18 +25519,13 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
|
||||
role="listbox"
|
||||
style="height: 0px; width: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="presentation"
|
||||
/>
|
||||
<div
|
||||
aria-label="Light"
|
||||
aria-selected="false"
|
||||
id="rc_select_TEST_OR_SSR_list_1"
|
||||
aria-selected="true"
|
||||
id="rc_select_TEST_OR_SSR_list_0"
|
||||
role="option"
|
||||
>
|
||||
Bamboo
|
||||
light
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -25581,14 +25542,8 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
|
||||
style="display: flex; flex-direction: column;"
|
||||
>
|
||||
<div
|
||||
class="prefix-Select-item prefix-Select-item-group"
|
||||
title="grp"
|
||||
>
|
||||
grp
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="prefix-Select-item prefix-Select-item-option prefix-Select-item-option-grouped prefix-Select-item-option-active"
|
||||
aria-selected="true"
|
||||
class="prefix-Select-item prefix-Select-item-option prefix-Select-item-option-active prefix-Select-item-option-selected"
|
||||
title="Light"
|
||||
>
|
||||
<div
|
||||
@@ -39939,7 +39894,7 @@ exports[`ConfigProvider components Transfer configProvider 1`] = `
|
||||
|
||||
exports[`ConfigProvider components Transfer configProvider componentDisabled 1`] = `
|
||||
<div
|
||||
class="config-transfer"
|
||||
class="config-transfer config-transfer-disabled"
|
||||
>
|
||||
<div
|
||||
class="config-transfer-list"
|
||||
@@ -39966,6 +39921,7 @@ exports[`ConfigProvider components Transfer configProvider componentDisabled 1`]
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-dropdown-trigger config-transfer-list-header-dropdown"
|
||||
disabled=""
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
@@ -40136,6 +40092,7 @@ exports[`ConfigProvider components Transfer configProvider componentDisabled 1`]
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-dropdown-trigger config-transfer-list-header-dropdown"
|
||||
disabled=""
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
@@ -41810,11 +41767,12 @@ exports[`ConfigProvider components Tree configProvider 1`] = `
|
||||
exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-tree config-tree-icon-hide"
|
||||
class="config-tree config-tree-icon-hide config-tree-disabled"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
disabled=""
|
||||
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@@ -41848,7 +41806,7 @@ exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
|
||||
>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
class="config-tree-treenode config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
|
||||
class="config-tree-treenode config-tree-treenode-disabled config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
|
||||
draggable="false"
|
||||
role="treeitem"
|
||||
>
|
||||
@@ -41876,11 +41834,12 @@ exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="config-tree config-tree-block-node config-tree-directory"
|
||||
class="config-tree config-tree-block-node config-tree-disabled config-tree-directory"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
disabled=""
|
||||
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@@ -41914,7 +41873,7 @@ exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
|
||||
>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
class="config-tree-treenode config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
|
||||
class="config-tree-treenode config-tree-treenode-disabled config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
|
||||
draggable="false"
|
||||
role="treeitem"
|
||||
>
|
||||
|
||||
@@ -59,11 +59,12 @@ import TreeSelect from '../../tree-select';
|
||||
import Upload from '../../upload';
|
||||
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
jest.mock('rc-util/lib/Portal');
|
||||
|
||||
describe('ConfigProvider', () => {
|
||||
describe('components', () => {
|
||||
function testPair(name: string, renderComponent: (props?: any) => React.ReactElement): void {
|
||||
const testPair = (name: string, renderComponent: (props?: any) => React.ReactElement<any>) => {
|
||||
const isArray = ['Menu', 'TimePicker', 'Tooltip'].includes(name);
|
||||
describe(`${name}`, () => {
|
||||
// normal
|
||||
@@ -122,7 +123,7 @@ describe('ConfigProvider', () => {
|
||||
expect(isArray ? container.children : container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Alert
|
||||
testPair('Alert', (props) => (
|
||||
@@ -430,11 +431,12 @@ describe('ConfigProvider', () => {
|
||||
|
||||
// Select
|
||||
testPair('Select', (props) => (
|
||||
<Select {...props} open>
|
||||
<Select.OptGroup key="grp">
|
||||
<Select.Option key="Bamboo">Light</Select.Option>
|
||||
</Select.OptGroup>
|
||||
</Select>
|
||||
<Select
|
||||
open
|
||||
defaultValue={'light'}
|
||||
options={[{ label: 'Light', value: 'light' }]}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
// Skeleton
|
||||
|
||||
@@ -82,7 +82,8 @@ describe('ConfigProvider.Locale', () => {
|
||||
const datepicke = wrapper.container.querySelector<HTMLInputElement>('.ant-picker-input input');
|
||||
expect(datepicke?.value).toBe('');
|
||||
expect(datepicke?.placeholder).toBe('请选择日期');
|
||||
expect(wrapper.container.querySelector('.ant-pagination-item-1')?.className).toContain(
|
||||
|
||||
expect(wrapper.container.querySelector<HTMLElement>('.ant-pagination-item-1')).toHaveClass(
|
||||
'ant-pagination-item-active',
|
||||
);
|
||||
|
||||
@@ -93,6 +94,7 @@ describe('ConfigProvider.Locale', () => {
|
||||
expect(
|
||||
wrapper.container.querySelector<HTMLInputElement>('.ant-picker-input input')?.value,
|
||||
).not.toBe('');
|
||||
|
||||
wrapper.rerender(
|
||||
<ConfigProvider locale={{} as Locale}>
|
||||
<DatePicker />
|
||||
@@ -108,7 +110,7 @@ describe('ConfigProvider.Locale', () => {
|
||||
expect(datepicker?.value).not.toBe('');
|
||||
expect(datepicker?.value).toContain('-10');
|
||||
|
||||
expect(wrapper.container.querySelector('.ant-pagination-item-3')?.className).toContain(
|
||||
expect(wrapper.container.querySelector('.ant-pagination-item-3')).toHaveClass(
|
||||
'ant-pagination-item-active',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -132,6 +132,7 @@ export interface TableConfig extends ComponentStyleConfig {
|
||||
|
||||
export interface ImageConfig extends ComponentStyleConfig {
|
||||
preview?: Partial<Record<'closeIcon', React.ReactNode>>;
|
||||
fallback?: string;
|
||||
}
|
||||
|
||||
export type CollapseConfig = ComponentStyleConfig & Pick<CollapseProps, 'expandIcon'>;
|
||||
@@ -214,7 +215,7 @@ export type CascaderConfig = ComponentStyleConfig &
|
||||
Pick<CascaderProps, 'variant' | 'styles' | 'classNames'>;
|
||||
|
||||
export type TreeSelectConfig = ComponentStyleConfig &
|
||||
Pick<TreeSelectProps, 'variant' | 'styles' | 'classNames'>;
|
||||
Pick<TreeSelectProps, 'variant' | 'styles' | 'classNames' | 'switcherIcon'>;
|
||||
|
||||
export type DatePickerConfig = ComponentStyleConfig &
|
||||
Pick<DatePickerProps, 'variant' | 'styles' | 'classNames'>;
|
||||
|
||||
@@ -36,7 +36,6 @@ type DirectionType = ConfigProviderProps['direction'];
|
||||
const InputGroup = Input.Group;
|
||||
const ButtonGroup = Button.Group;
|
||||
|
||||
const { Option } = Select;
|
||||
const { TreeNode } = Tree;
|
||||
const { Search } = Input;
|
||||
|
||||
@@ -100,19 +99,27 @@ const Page: React.FC<{ placement: Placement }> = ({ placement }) => {
|
||||
const [showBadge, setShowBadge] = useState(true);
|
||||
|
||||
const selectBefore = (
|
||||
<Select defaultValue="Http://" style={{ width: 90 }}>
|
||||
<Option value="Http://">Http://</Option>
|
||||
<Option value="Https://">Https://</Option>
|
||||
</Select>
|
||||
<Select
|
||||
defaultValue="Http://"
|
||||
style={{ width: 90 }}
|
||||
options={[
|
||||
{ label: 'Http://', value: 'Http://' },
|
||||
{ label: 'Https://', value: 'Https://' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const selectAfter = (
|
||||
<Select defaultValue=".com" style={{ width: 80 }}>
|
||||
<Option value=".com">.com</Option>
|
||||
<Option value=".jp">.jp</Option>
|
||||
<Option value=".cn">.cn</Option>
|
||||
<Option value=".org">.org</Option>
|
||||
</Select>
|
||||
<Select
|
||||
defaultValue=".com"
|
||||
style={{ width: 80 }}
|
||||
options={[
|
||||
{ label: '.com', value: '.com' },
|
||||
{ label: '.jp', value: '.jp' },
|
||||
{ label: '.cn', value: '.cn' },
|
||||
{ label: '.org', value: '.org' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
// ==== Cascader ====
|
||||
@@ -280,10 +287,13 @@ const Page: React.FC<{ placement: Placement }> = ({ placement }) => {
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Select defaultValue="Option1">
|
||||
<Option value="Option1">Option1</Option>
|
||||
<Option value="Option2">Option2</Option>
|
||||
</Select>
|
||||
<Select
|
||||
defaultValue="Option1"
|
||||
options={[
|
||||
{ label: 'Option1', value: 'Option1' },
|
||||
{ label: 'Option2', value: 'Option2' },
|
||||
]}
|
||||
/>
|
||||
<Input style={{ width: '50%' }} defaultValue="input content" />
|
||||
<InputNumber />
|
||||
</InputGroup>
|
||||
@@ -297,27 +307,41 @@ const Page: React.FC<{ placement: Placement }> = ({ placement }) => {
|
||||
<br />
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<Divider orientation="left">Select example</Divider>
|
||||
<Divider orientation="start">Select example</Divider>
|
||||
<Space wrap>
|
||||
<Select mode="multiple" defaultValue="مورچه" style={{ width: 120 }}>
|
||||
<Option value="jack">Jack</Option>
|
||||
<Option value="مورچه">مورچه</Option>
|
||||
<Option value="disabled" disabled>
|
||||
Disabled
|
||||
</Option>
|
||||
<Option value="Yiminghe">yiminghe</Option>
|
||||
</Select>
|
||||
<Select defaultValue="مورچه" style={{ width: 120 }} disabled>
|
||||
<Option value="مورچه">مورچه</Option>
|
||||
</Select>
|
||||
<Select defaultValue="مورچه" style={{ width: 120 }} loading>
|
||||
<Option value="مورچه">مورچه</Option>
|
||||
</Select>
|
||||
<Select showSearch style={{ width: 200 }} placeholder="Select a person">
|
||||
<Option value="jack">Jack</Option>
|
||||
<Option value="سعید">سعید</Option>
|
||||
<Option value="tom">Tom</Option>
|
||||
</Select>
|
||||
<Select
|
||||
mode="multiple"
|
||||
defaultValue="مورچه"
|
||||
style={{ width: 120 }}
|
||||
options={[
|
||||
{ label: 'jack', value: 'jack' },
|
||||
{ label: 'مورچه', value: 'مورچه' },
|
||||
{ label: 'disabled', value: 'disabled', disabled: true },
|
||||
{ label: 'yiminghe', value: 'Yiminghe' },
|
||||
]}
|
||||
/>
|
||||
<Select
|
||||
disabled
|
||||
defaultValue="مورچه"
|
||||
style={{ width: 120 }}
|
||||
options={[{ label: 'مورچه', value: 'مورچه' }]}
|
||||
/>
|
||||
<Select
|
||||
loading
|
||||
defaultValue="مورچه"
|
||||
style={{ width: 120 }}
|
||||
options={[{ label: 'مورچه', value: 'مورچه' }]}
|
||||
/>
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: 200 }}
|
||||
placeholder="Select a person"
|
||||
options={[
|
||||
{ label: 'jack', value: 'jack' },
|
||||
{ label: 'سعید', value: 'سعید' },
|
||||
{ label: 'Tom', value: 'tom' },
|
||||
]}
|
||||
/>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
|
||||
@@ -41,7 +41,6 @@ type Locale = ConfigProviderProps['locale'];
|
||||
|
||||
dayjs.locale('en');
|
||||
|
||||
const { Option } = Select;
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const columns: TableProps['columns'] = [
|
||||
@@ -132,10 +131,14 @@ const Page: React.FC = () => {
|
||||
>
|
||||
<Pagination defaultCurrent={1} total={50} showSizeChanger />
|
||||
<Space wrap>
|
||||
<Select showSearch style={{ width: 200 }}>
|
||||
<Option value="jack">jack</Option>
|
||||
<Option value="lucy">lucy</Option>
|
||||
</Select>
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: 200 }}
|
||||
options={[
|
||||
{ label: 'jack', value: 'jack' },
|
||||
{ label: 'lucy', value: 'lucy' },
|
||||
]}
|
||||
/>
|
||||
<DatePicker />
|
||||
<TimePicker />
|
||||
<RangePicker />
|
||||
|
||||
@@ -132,7 +132,7 @@ const {
|
||||
| floatButton | Set FloatButton common props | { backTopIcon?: React.ReactNode } | - | 5.27.0 |
|
||||
| floatButtonGroup | Set FloatButton.Group common props | { closeIcon?: React.ReactNode } | - | 5.16.0 |
|
||||
| form | Set Form common props | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) } | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className` and `style`: 5.7.0 |
|
||||
| image | Set Image common props | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode } } | - | 5.7.0, `closeIcon`: 5.14.0 |
|
||||
| image | Set Image common props | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode }, fallback?: string } | - | 5.7.0, `closeIcon`: 5.14.0, `fallback`: 5.28.0 |
|
||||
| input | Set Input common props | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 4.2.0, `allowClear`: 5.15.0 |
|
||||
| textArea | Set TextArea common props | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.15.0 |
|
||||
| layout | Set Layout common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
@@ -168,7 +168,7 @@ const {
|
||||
| popconfirm | Set Popconfirm common props | { className?: string, style?: React.CSSProperties, classNames?:[Popconfirm\["classNames"\]](/components/popconfirm#api), styles?: [Popconfirm\["styles"\]](/components/popconfirm#api) } | - | 5.23.0 |
|
||||
| transfer | Set Transfer common props | { className?: string, style?: React.CSSProperties, selectionsIcon?: React.ReactNode } | - | 5.7.0, `selectionsIcon`: 5.14.0 |
|
||||
| tree | Set Tree common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| treeSelect | Set TreeSelect common props | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select#api), styles?: [TreeSelect\["styles"\]](/components/tree-select#api) } | - | 5.25.0 |
|
||||
| treeSelect | Set TreeSelect common props | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select#api), styles?: [TreeSelect\["styles"\]](/components/tree-select#api), switcherIcon?: [TreeSelect\["switcherIcon"\]](/components/tree-select#api) } | - | 5.25.0, `switcherIcon`: 5.28.0 |
|
||||
| typography | Set Typography common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| upload | Set Upload common props | { className?: string, style?: React.CSSProperties, customRequest?: [Upload\["customRequest"\]](/components/upload#api) } | - | 5.7.0, `customRequest`: 5.27.0 |
|
||||
| wave | Config wave effect | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |
|
||||
|
||||
@@ -134,7 +134,7 @@ const {
|
||||
| floatButton | 设置 FloatButton 组件的通用属性 | { backTopIcon?: React.ReactNode } | - | 5.27.0 |
|
||||
| floatButtonGroup | 设置 FloatButton.Group 组件的通用属性 | { closeIcon?: React.ReactNode } | - | 5.16.0 |
|
||||
| form | 设置 Form 组件的通用属性 | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form-cn#validatemessages), `requiredMark`?: boolean \| `optional`, colon?: boolean, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)} | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className` 和 `style`: 5.7.0 |
|
||||
| image | 设置 Image 组件的通用属性 | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode } } | - | 5.7.0, `closeIcon`: 5.14.0 |
|
||||
| image | 设置 Image 组件的通用属性 | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode }, fallback?: string } | - | 5.7.0, `closeIcon`: 5.14.0, `fallback`: 5.28.0 |
|
||||
| input | 设置 Input 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.7.0, `allowClear`: 5.15.0 |
|
||||
| textArea | 设置 TextArea 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.15.0 |
|
||||
| layout | 设置 Layout 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
@@ -170,7 +170,7 @@ const {
|
||||
| popconfirm | 设置 Popconfirm 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?:[Popconfirm\["classNames"\]](/components/popconfirm-cn#api), styles?: [Popconfirm\["styles"\]](/components/popconfirm-cn#api) } | - | 5.23.0 |
|
||||
| transfer | 设置 Transfer 组件的通用属性 | { className?: string, style?: React.CSSProperties, selectionsIcon?: React.ReactNode } | - | 5.7.0, `selectionsIcon`: 5.14.0 |
|
||||
| tree | 设置 Tree 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| treeSelect | 设置 TreeSelect 组件的通用属性 | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select-cn#api), styles?: [TreeSelect\["styles"\]](/components/tree-select-cn#api) } | - | 5.25.0 |
|
||||
| treeSelect | 设置 TreeSelect 组件的通用属性 | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select-cn#api), styles?: [TreeSelect\["styles"\]](/components/tree-select-cn#api), switcherIcon?: [TreeSelect\["switcherIcon"\]](/components/tree-select-cn#api) } | - | 5.25.0, `switcherIcon`: 5.28.0 |
|
||||
| typography | 设置 Typography 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| upload | 设置 Upload 组件的通用属性 | { className?: string, style?: React.CSSProperties, customRequest?: [Upload\["customRequest"\]](/components/upload-cn#api) } | - | 5.7.0, `customRequest`: 5.27.0 |
|
||||
| wave | 设置水波纹特效 | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |
|
||||
|
||||
@@ -480,4 +480,22 @@ describe('DatePicker', () => {
|
||||
rerender(<DatePicker value={somePoint} allowClear={{}} />);
|
||||
expect(getClearButton()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('suffixIcon', () => {
|
||||
const { rerender, container } = render(<DatePicker />);
|
||||
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeTruthy();
|
||||
|
||||
rerender(<DatePicker suffixIcon />);
|
||||
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeTruthy();
|
||||
|
||||
rerender(<DatePicker suffixIcon={false} />);
|
||||
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeFalsy();
|
||||
|
||||
rerender(<DatePicker suffixIcon={null} />);
|
||||
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeFalsy();
|
||||
|
||||
rerender(<DatePicker suffixIcon={'123'} />);
|
||||
expect(container.querySelector('.ant-picker-suffix')?.textContent).toBe('123');
|
||||
expect(container.children).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -643,6 +643,31 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`DatePicker suffixIcon 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-picker ant-picker-outlined"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-input"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
autocomplete="off"
|
||||
placeholder="Select date"
|
||||
size="12"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-picker-suffix"
|
||||
>
|
||||
123
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`DatePicker support DatePicker.generatePicker 1`] = `
|
||||
<div
|
||||
class="ant-picker ant-picker-outlined"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7414,6 +7414,165 @@ exports[`renders components/date-picker/demo/suffix.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/date-picker/demo/suffixIcon-debug.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-picker ant-picker-outlined"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-input"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
autocomplete="off"
|
||||
placeholder="Select date"
|
||||
size="12"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-picker-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="calendar"
|
||||
class="anticon anticon-calendar"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="calendar"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-picker ant-picker-outlined"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-input"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
autocomplete="off"
|
||||
placeholder="Select date"
|
||||
size="12"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-picker-suffix"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-picker ant-picker-outlined"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-input"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
autocomplete="off"
|
||||
placeholder="Select date"
|
||||
size="12"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-picker-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="calendar"
|
||||
class="anticon anticon-calendar"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="calendar"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-picker ant-picker-outlined"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-input"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
autocomplete="off"
|
||||
placeholder="Select date"
|
||||
size="12"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-picker-suffix"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-picker ant-picker-outlined"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-input"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
autocomplete="off"
|
||||
placeholder="Select date"
|
||||
size="12"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-picker-suffix"
|
||||
>
|
||||
123
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/date-picker/demo/switchable.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
|
||||
|
||||
@@ -2,14 +2,14 @@ import type { render } from '../../../tests/utils';
|
||||
import { fireEvent } from '../../../tests/utils';
|
||||
|
||||
export function openPicker(wrapper: ReturnType<typeof render>, index = 0) {
|
||||
const inputEle = wrapper.container?.querySelectorAll<HTMLInputElement>('input')?.[index]!;
|
||||
const inputEle = wrapper.container?.querySelectorAll<HTMLInputElement>('input')?.[index];
|
||||
fireEvent.mouseDown(inputEle);
|
||||
fireEvent.focus(inputEle);
|
||||
fireEvent.click(inputEle);
|
||||
}
|
||||
|
||||
export function closePicker(wrapper: ReturnType<typeof render>, index = 0) {
|
||||
fireEvent.blur(wrapper.container?.querySelectorAll('input')[index]!);
|
||||
fireEvent.blur(wrapper.container?.querySelectorAll('input')[index]);
|
||||
}
|
||||
|
||||
export function selectCell(wrapper: ReturnType<typeof render>, text: string | number, index = 0) {
|
||||
|
||||
7
components/date-picker/demo/suffixIcon-debug.md
Normal file
7
components/date-picker/demo/suffixIcon-debug.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
suffixIcon 测试。
|
||||
|
||||
## en-US
|
||||
|
||||
suffixIcon test.
|
||||
14
components/date-picker/demo/suffixIcon-debug.tsx
Normal file
14
components/date-picker/demo/suffixIcon-debug.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { DatePicker, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Space direction="vertical">
|
||||
<DatePicker suffixIcon />
|
||||
<DatePicker suffixIcon={false} />
|
||||
<DatePicker />
|
||||
<DatePicker suffixIcon={null} />
|
||||
<DatePicker suffixIcon={'123'} />
|
||||
</Space>
|
||||
);
|
||||
|
||||
export default App;
|
||||
@@ -2,19 +2,20 @@ import React, { useState } from 'react';
|
||||
import type { DatePickerProps, TimePickerProps } from 'antd';
|
||||
import { DatePicker, Select, Space, TimePicker } from 'antd';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
type PickerType = 'time' | 'date';
|
||||
|
||||
const PickerWithType = ({
|
||||
type,
|
||||
onChange,
|
||||
}: {
|
||||
interface PickerWithTypeProps {
|
||||
type: PickerType;
|
||||
onChange: TimePickerProps['onChange'] | DatePickerProps['onChange'];
|
||||
}) => {
|
||||
if (type === 'time') return <TimePicker onChange={onChange} />;
|
||||
if (type === 'date') return <DatePicker onChange={onChange} />;
|
||||
}
|
||||
|
||||
const PickerWithType: React.FC<PickerWithTypeProps> = ({ type, onChange }) => {
|
||||
if (type === 'time') {
|
||||
return <TimePicker onChange={onChange} />;
|
||||
}
|
||||
if (type === 'date') {
|
||||
return <DatePicker onChange={onChange} />;
|
||||
}
|
||||
return <DatePicker picker={type} onChange={onChange} />;
|
||||
};
|
||||
|
||||
@@ -23,14 +24,19 @@ const App: React.FC = () => {
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Select aria-label="Picker Type" value={type} onChange={setType}>
|
||||
<Option value="time">Time</Option>
|
||||
<Option value="date">Date</Option>
|
||||
<Option value="week">Week</Option>
|
||||
<Option value="month">Month</Option>
|
||||
<Option value="quarter">Quarter</Option>
|
||||
<Option value="year">Year</Option>
|
||||
</Select>
|
||||
<Select
|
||||
aria-label="Picker Type"
|
||||
value={type}
|
||||
onChange={setType}
|
||||
options={[
|
||||
{ label: 'Time', value: 'time' },
|
||||
{ label: 'Date', value: 'date' },
|
||||
{ label: 'Week', value: 'week' },
|
||||
{ label: 'Month', value: 'month' },
|
||||
{ label: 'Quarter', value: 'quarter' },
|
||||
{ label: 'Year', value: 'year' },
|
||||
]}
|
||||
/>
|
||||
<PickerWithType type={type} onChange={(value) => console.log(value)} />
|
||||
</Space>
|
||||
);
|
||||
|
||||
36
components/date-picker/generatePicker/SuffixIcon.tsx
Normal file
36
components/date-picker/generatePicker/SuffixIcon.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
|
||||
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
|
||||
import type { PickerMode } from 'rc-picker/lib/interface';
|
||||
|
||||
import { TIME } from '../generatePicker/constant';
|
||||
|
||||
interface SuffixIconProps {
|
||||
picker?: PickerMode;
|
||||
hasFeedback?: boolean;
|
||||
feedbackIcon?: React.ReactNode;
|
||||
suffixIcon?: React.ReactNode;
|
||||
}
|
||||
|
||||
const SuffixIcon: React.FC<SuffixIconProps> = ({
|
||||
picker,
|
||||
hasFeedback,
|
||||
feedbackIcon,
|
||||
suffixIcon,
|
||||
}) => {
|
||||
if (suffixIcon === null || suffixIcon === false) {
|
||||
return null;
|
||||
}
|
||||
if (suffixIcon === true || suffixIcon === undefined) {
|
||||
return (
|
||||
<>
|
||||
{picker === TIME ? <ClockCircleOutlined /> : <CalendarOutlined />}
|
||||
{hasFeedback && feedbackIcon}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return suffixIcon;
|
||||
};
|
||||
|
||||
export default SuffixIcon;
|
||||
@@ -1,7 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { forwardRef, useContext, useImperativeHandle } from 'react';
|
||||
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
|
||||
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
|
||||
import SwapRightOutlined from '@ant-design/icons/SwapRightOutlined';
|
||||
import cls from 'classnames';
|
||||
import { RangePicker as RCRangePicker } from 'rc-picker';
|
||||
@@ -9,7 +7,7 @@ import type { PickerRef } from 'rc-picker';
|
||||
import type { GenerateConfig } from 'rc-picker/lib/generate/index';
|
||||
|
||||
import ContextIsolator from '../../_util/ContextIsolator';
|
||||
import { useZIndex } from '../../_util/hooks/useZIndex';
|
||||
import { useZIndex } from '../../_util/hooks';
|
||||
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
|
||||
import type { AnyObject } from '../../_util/type';
|
||||
import { devUseWarning } from '../../_util/warning';
|
||||
@@ -21,13 +19,14 @@ import { FormItemInputContext } from '../../form/context';
|
||||
import useVariant from '../../form/hooks/useVariants';
|
||||
import { useLocale } from '../../locale';
|
||||
import { useCompactItemContext } from '../../space/Compact';
|
||||
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
|
||||
import enUS from '../locale/en_US';
|
||||
import useStyle from '../style';
|
||||
import { getRangePlaceholder, useIcons } from '../util';
|
||||
import { TIME } from './constant';
|
||||
import type { RangePickerProps } from './interface';
|
||||
import SuffixIcon from './SuffixIcon';
|
||||
import useComponents from './useComponents';
|
||||
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
|
||||
|
||||
const generateRangePicker = <DateType extends AnyObject = AnyObject>(
|
||||
generateConfig: GenerateConfig<DateType>,
|
||||
@@ -55,6 +54,7 @@ const generateRangePicker = <DateType extends AnyObject = AnyObject>(
|
||||
picker,
|
||||
styles,
|
||||
classNames,
|
||||
suffixIcon,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@@ -112,14 +112,7 @@ const generateRangePicker = <DateType extends AnyObject = AnyObject>(
|
||||
// ===================== FormItemInput =====================
|
||||
const formItemContext = useContext(FormItemInputContext);
|
||||
const { hasFeedback, status: contextStatus, feedbackIcon } = formItemContext;
|
||||
|
||||
const suffixNode = (
|
||||
<>
|
||||
{picker === TIME ? <ClockCircleOutlined /> : <CalendarOutlined />}
|
||||
{hasFeedback && feedbackIcon}
|
||||
</>
|
||||
);
|
||||
|
||||
const mergedSuffixIcon = <SuffixIcon {...{ picker, hasFeedback, feedbackIcon, suffixIcon }} />;
|
||||
useImperativeHandle(ref, () => innerRef.current!);
|
||||
|
||||
const [contextLocale] = useLocale('Calendar', enUS);
|
||||
@@ -141,7 +134,7 @@ const generateRangePicker = <DateType extends AnyObject = AnyObject>(
|
||||
ref={innerRef as any} // Need to modify PickerRef
|
||||
placement={placement}
|
||||
placeholder={getRangePlaceholder(locale, picker, placeholder)}
|
||||
suffixIcon={suffixNode}
|
||||
suffixIcon={mergedSuffixIcon}
|
||||
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
|
||||
nextIcon={<span className={`${prefixCls}-next-icon`} />}
|
||||
superPrevIcon={<span className={`${prefixCls}-super-prev-icon`} />}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { forwardRef, useContext, useImperativeHandle } from 'react';
|
||||
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
|
||||
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
|
||||
import cls from 'classnames';
|
||||
import RCPicker from 'rc-picker';
|
||||
import type { PickerRef } from 'rc-picker';
|
||||
@@ -9,7 +7,7 @@ import type { GenerateConfig } from 'rc-picker/lib/generate/index';
|
||||
import type { PickerMode } from 'rc-picker/lib/interface';
|
||||
|
||||
import ContextIsolator from '../../_util/ContextIsolator';
|
||||
import { useZIndex } from '../../_util/hooks/useZIndex';
|
||||
import { useZIndex } from '../../_util/hooks';
|
||||
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
|
||||
import type { AnyObject } from '../../_util/type';
|
||||
import { devUseWarning } from '../../_util/warning';
|
||||
@@ -21,6 +19,7 @@ import { FormItemInputContext } from '../../form/context';
|
||||
import useVariant from '../../form/hooks/useVariants';
|
||||
import { useLocale } from '../../locale';
|
||||
import { useCompactItemContext } from '../../space/Compact';
|
||||
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
|
||||
import enUS from '../locale/en_US';
|
||||
import useStyle from '../style';
|
||||
import { getPlaceholder, useIcons } from '../util';
|
||||
@@ -37,8 +36,8 @@ import {
|
||||
YEARPICKER,
|
||||
} from './constant';
|
||||
import type { GenericTimePickerProps, PickerProps, PickerPropsWithMultiple } from './interface';
|
||||
import SuffixIcon from './SuffixIcon';
|
||||
import useComponents from './useComponents';
|
||||
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
|
||||
|
||||
const generatePicker = <DateType extends AnyObject = AnyObject>(
|
||||
generateConfig: GenerateConfig<DateType>,
|
||||
@@ -69,6 +68,7 @@ const generatePicker = <DateType extends AnyObject = AnyObject>(
|
||||
onCalendarChange,
|
||||
styles,
|
||||
classNames,
|
||||
suffixIcon,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@@ -159,13 +159,9 @@ const generatePicker = <DateType extends AnyObject = AnyObject>(
|
||||
const formItemContext = useContext(FormItemInputContext);
|
||||
const { hasFeedback, status: contextStatus, feedbackIcon } = formItemContext;
|
||||
|
||||
const suffixNode = (
|
||||
<>
|
||||
{mergedPicker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
|
||||
{hasFeedback && feedbackIcon}
|
||||
</>
|
||||
const mergedSuffixIcon = (
|
||||
<SuffixIcon {...{ picker: mergedPicker, hasFeedback, feedbackIcon, suffixIcon }} />
|
||||
);
|
||||
|
||||
const [contextLocale] = useLocale('DatePicker', enUS);
|
||||
|
||||
const locale = { ...contextLocale, ...props.locale! };
|
||||
@@ -177,7 +173,7 @@ const generatePicker = <DateType extends AnyObject = AnyObject>(
|
||||
<RCPicker<DateType>
|
||||
ref={innerRef}
|
||||
placeholder={getPlaceholder(locale, mergedPicker, placeholder)}
|
||||
suffixIcon={suffixNode}
|
||||
suffixIcon={mergedSuffixIcon}
|
||||
placement={placement}
|
||||
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
|
||||
nextIcon={<span className={`${prefixCls}-next-icon`} />}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user