mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 12:39:49 +08:00
commit
f3a4b6c429
@ -1,11 +1,11 @@
|
||||
export default function use<T>(promise: PromiseLike<T>): T {
|
||||
function use<T>(promise: PromiseLike<T>): T {
|
||||
const internal: PromiseLike<T> & {
|
||||
status?: 'pending' | 'fulfilled' | 'rejected';
|
||||
value?: T;
|
||||
reason?: any;
|
||||
} = promise;
|
||||
if (internal.status === 'fulfilled') {
|
||||
return internal.value;
|
||||
return internal.value as T;
|
||||
}
|
||||
if (internal.status === 'rejected') {
|
||||
throw internal.reason;
|
||||
@ -26,3 +26,5 @@ export default function use<T>(promise: PromiseLike<T>): T {
|
||||
throw internal;
|
||||
}
|
||||
}
|
||||
|
||||
export default use;
|
||||
|
@ -5,10 +5,12 @@ export interface LocaleMap<Key extends string> {
|
||||
en: Record<Key, string>;
|
||||
}
|
||||
|
||||
export default function useLocale<Key extends string>(
|
||||
function useLocale<Key extends string>(
|
||||
localeMap?: LocaleMap<Key>,
|
||||
): [Record<Key, string>, 'cn' | 'en'] {
|
||||
const { id } = useDumiLocale();
|
||||
const localeType = id === 'zh-CN' ? 'cn' : 'en';
|
||||
return [localeMap?.[localeType], localeType];
|
||||
const localeType = id === 'zh-CN' ? ('cn' as const) : ('en' as const);
|
||||
return [localeMap?.[localeType]!, localeType];
|
||||
}
|
||||
|
||||
export default useLocale;
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { useFullSidebarData, useSidebarData } from 'dumi';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Tag, version } from 'antd';
|
||||
import { useFullSidebarData, useSidebarData } from 'dumi';
|
||||
|
||||
import Link from '../theme/common/Link';
|
||||
import useLocation from './useLocation';
|
||||
|
||||
@ -136,7 +137,7 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
const list = group.children || [];
|
||||
// 如果有 date 字段,我们就对其进行排序
|
||||
if (list.every((info) => info?.frontmatter?.date)) {
|
||||
list.sort((a, b) => (a.frontmatter.date > b.frontmatter.date ? -1 : 1));
|
||||
list.sort((a, b) => (a.frontmatter?.date > b.frontmatter?.date ? -1 : 1));
|
||||
}
|
||||
|
||||
result.push(
|
||||
|
@ -32,11 +32,7 @@ const useThemeAnimation = () => {
|
||||
token: { colorBgElevated },
|
||||
} = theme.useToken();
|
||||
|
||||
const animateRef = useRef<{
|
||||
colorBgElevated: string;
|
||||
}>({
|
||||
colorBgElevated,
|
||||
});
|
||||
const animateRef = useRef<{ colorBgElevated: string }>({ colorBgElevated });
|
||||
|
||||
const startAnimationTheme = (clipPath: string[], isDark: boolean) => {
|
||||
updateCSS(
|
||||
@ -64,9 +60,14 @@ const useThemeAnimation = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const toggleAnimationTheme = (event: MouseEvent, isDark: boolean) => {
|
||||
const toggleAnimationTheme = (
|
||||
event: React.MouseEvent<HTMLElement, MouseEvent>,
|
||||
isDark: boolean,
|
||||
) => {
|
||||
// @ts-ignore
|
||||
if (!(event && typeof document.startViewTransition === 'function')) return;
|
||||
if (!(event && typeof document.startViewTransition === 'function')) {
|
||||
return;
|
||||
}
|
||||
const x = event.clientX;
|
||||
const y = event.clientY;
|
||||
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
|
||||
|
@ -83,8 +83,8 @@ const Group: React.FC<GroupProps> = (props) => {
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph
|
||||
style={{
|
||||
marginBottom: isMobile ? token.marginXXL : token.marginFarXS,
|
||||
color: titleColor,
|
||||
marginBottom: isMobile ? token.marginXXL : token.marginFarXS,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { CSSMotionList } from 'rc-motion';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import classNames from 'classnames';
|
||||
import { CSSMotionList } from 'rc-motion';
|
||||
|
||||
import { COLOR_IMAGES, getClosetColor } from './colorUtil';
|
||||
|
||||
export interface BackgroundImageProps {
|
||||
@ -36,7 +37,7 @@ const BackgroundImage: React.FC<BackgroundImageProps> = ({ colorPrimary, isLight
|
||||
const [keyList, setKeyList] = useState<string[]>([]);
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
setKeyList([activeColor]);
|
||||
setKeyList([activeColor as string]);
|
||||
}, [activeColor]);
|
||||
|
||||
return (
|
||||
@ -56,7 +57,7 @@ const BackgroundImage: React.FC<BackgroundImageProps> = ({ colorPrimary, isLight
|
||||
const entity = COLOR_IMAGES.find((ent) => ent.color === color);
|
||||
|
||||
if (!entity || !entity.url) {
|
||||
return null;
|
||||
return null as unknown as React.ReactElement;
|
||||
}
|
||||
|
||||
const { opacity } = style || {};
|
||||
|
@ -1,39 +1,47 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { ColorPicker, Input, Space } from 'antd';
|
||||
import type { Color, ColorPickerProps } from 'antd/es/color-picker';
|
||||
import { createStyles } from 'antd-style';
|
||||
import type { Color } from 'antd/es/color-picker';
|
||||
import { generateColor } from 'antd/es/color-picker/util';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { PRESET_COLORS } from './colorUtil';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => ({
|
||||
color: css`
|
||||
width: ${token.controlHeightLG / 2}px;
|
||||
height: ${token.controlHeightLG / 2}px;
|
||||
border-radius: 100%;
|
||||
cursor: pointer;
|
||||
transition: all ${token.motionDurationFast};
|
||||
display: inline-block;
|
||||
width: ${token.controlHeightLG / 2}px;
|
||||
height: ${token.controlHeightLG / 2}px;
|
||||
border-radius: 100%;
|
||||
cursor: pointer;
|
||||
transition: all ${token.motionDurationFast};
|
||||
display: inline-block;
|
||||
|
||||
& > input[type='radio'] {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
& > input[type='radio'] {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
// need ?
|
||||
}
|
||||
`,
|
||||
&:focus-within {
|
||||
// need ?
|
||||
}
|
||||
`,
|
||||
|
||||
colorActive: css`
|
||||
box-shadow: 0 0 0 1px ${token.colorBgContainer},
|
||||
0 0 0 ${token.controlOutlineWidth * 2 + 1}px ${token.colorPrimary};
|
||||
`,
|
||||
box-shadow:
|
||||
0 0 0 1px ${token.colorBgContainer},
|
||||
0 0 0 ${token.controlOutlineWidth * 2 + 1}px ${token.colorPrimary};
|
||||
`,
|
||||
}));
|
||||
|
||||
const DebouncedColorPicker: FC<ColorPickerProps> = ({ value: color, onChange, children }) => {
|
||||
export interface ColorPickerProps {
|
||||
children?: React.ReactNode;
|
||||
value?: string | Color;
|
||||
onChange?: (value?: Color | string) => void;
|
||||
}
|
||||
|
||||
const DebouncedColorPicker: React.FC<ColorPickerProps> = (props) => {
|
||||
const { value: color, children, onChange } = props;
|
||||
const [value, setValue] = useState(color);
|
||||
|
||||
useEffect(() => {
|
||||
@ -51,40 +59,24 @@ const DebouncedColorPicker: FC<ColorPickerProps> = ({ value: color, onChange, ch
|
||||
<ColorPicker
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
presets={[
|
||||
{
|
||||
label: 'PresetColors',
|
||||
colors: PRESET_COLORS,
|
||||
},
|
||||
]}
|
||||
presets={[{ label: 'PresetColors', colors: PRESET_COLORS }]}
|
||||
>
|
||||
{children}
|
||||
</ColorPicker>
|
||||
);
|
||||
};
|
||||
|
||||
export interface RadiusPickerProps {
|
||||
value?: string | Color;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
export default function ThemeColorPicker({ value, onChange }: RadiusPickerProps) {
|
||||
const ThemeColorPicker: React.FC<ColorPickerProps> = ({ value, onChange }) => {
|
||||
const { styles } = useStyle();
|
||||
|
||||
const matchColors = React.useMemo(() => {
|
||||
const valueStr = generateColor(value).toRgbString();
|
||||
const valueStr = generateColor(value || '').toRgbString();
|
||||
let existActive = false;
|
||||
|
||||
const colors = PRESET_COLORS.map((color) => {
|
||||
const colorStr = generateColor(color).toRgbString();
|
||||
const active = colorStr === valueStr;
|
||||
existActive = existActive || active;
|
||||
|
||||
return {
|
||||
color,
|
||||
active,
|
||||
picker: false,
|
||||
};
|
||||
return { color, active, picker: false };
|
||||
});
|
||||
|
||||
return [
|
||||
@ -100,10 +92,8 @@ export default function ThemeColorPicker({ value, onChange }: RadiusPickerProps)
|
||||
return (
|
||||
<Space size="large">
|
||||
<Input
|
||||
value={typeof value === 'string' ? value : value.toHexString()}
|
||||
onChange={(event) => {
|
||||
onChange?.(event.target.value);
|
||||
}}
|
||||
value={typeof value === 'string' ? value : value?.toHexString()}
|
||||
onChange={(event) => onChange?.(event.target.value)}
|
||||
style={{ width: 120 }}
|
||||
/>
|
||||
|
||||
@ -114,9 +104,7 @@ export default function ThemeColorPicker({ value, onChange }: RadiusPickerProps)
|
||||
<label
|
||||
key={color}
|
||||
className={classNames(styles.color, active && styles.colorActive)}
|
||||
style={{
|
||||
background: color,
|
||||
}}
|
||||
style={{ background: color }}
|
||||
onClick={() => {
|
||||
if (!picker) {
|
||||
onChange?.(color);
|
||||
@ -149,4 +137,6 @@ export default function ThemeColorPicker({ value, onChange }: RadiusPickerProps)
|
||||
</Space>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default ThemeColorPicker;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import type { Color } from 'antd/es/color-picker';
|
||||
import { generateColor } from 'antd/es/color-picker/util';
|
||||
|
||||
export const DEFAULT_COLOR = '#1677FF';
|
||||
@ -50,7 +51,8 @@ export const COLOR_IMAGES = [
|
||||
export const PRESET_COLORS = COLOR_IMAGES.map(({ color }) => color);
|
||||
|
||||
const DISTANCE = 33;
|
||||
export function getClosetColor(colorPrimary?: string | null) {
|
||||
|
||||
export function getClosetColor(colorPrimary?: Color | string | null) {
|
||||
if (!colorPrimary) {
|
||||
return null;
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ const useStyle = createStyles(({ token, cx }) => {
|
||||
});
|
||||
|
||||
// ========================== Menu Config ==========================
|
||||
const subMenuItems: MenuProps['items'] = [
|
||||
const subMenuItems = [
|
||||
{
|
||||
key: `Design Values`,
|
||||
label: `Design Values`,
|
||||
@ -287,11 +287,12 @@ const ThemesInfo: Record<THEME, Partial<ThemeData>> = {
|
||||
},
|
||||
};
|
||||
|
||||
const normalize = (value: number) => value / 255;
|
||||
|
||||
function rgbToColorMatrix(color: string) {
|
||||
const rgb = new TinyColor(color).toRgb();
|
||||
const { r, g, b } = rgb;
|
||||
|
||||
const normalize = (value) => value / 255;
|
||||
const invertValue = normalize(r) * 100;
|
||||
const sepiaValue = 100;
|
||||
const saturateValue = Math.max(normalize(r), normalize(g), normalize(b)) * 10000;
|
||||
@ -360,10 +361,7 @@ export default function Theme() {
|
||||
const isRootDark = useDark();
|
||||
|
||||
React.useEffect(() => {
|
||||
onThemeChange(null, {
|
||||
...themeData,
|
||||
themeType: isRootDark ? 'dark' : 'default',
|
||||
});
|
||||
onThemeChange({}, { ...themeData, themeType: isRootDark ? 'dark' : 'default' });
|
||||
}, [isRootDark]);
|
||||
|
||||
// ================================ Tokens ================================
|
||||
|
@ -62,12 +62,12 @@ function rehypeAntd(): UnifiedTransformer<HastRoot> {
|
||||
(node.properties.className as string[]).push('component-api-table');
|
||||
} else if (node.type === 'element' && (node.tagName === 'Link' || node.tagName === 'a')) {
|
||||
const { tagName } = node;
|
||||
node.properties.sourceType = tagName;
|
||||
node.properties!.sourceType = tagName;
|
||||
node.tagName = 'LocaleLink';
|
||||
} else if (node.type === 'element' && node.tagName === 'video') {
|
||||
node.tagName = 'VideoPlayer';
|
||||
} else if (node.tagName === 'SourceCode') {
|
||||
const { lang } = node.properties;
|
||||
const { lang } = node.properties!;
|
||||
|
||||
if (typeof lang === 'string' && lang.startsWith('sandpack')) {
|
||||
const code = (node.children[0] as any).value as string;
|
||||
|
@ -1,12 +1,15 @@
|
||||
import { unistUtilVisit } from 'dumi';
|
||||
import type { UnifiedTransformer } from 'dumi';
|
||||
|
||||
export default function remarkMeta() {
|
||||
function remarkMeta(): UnifiedTransformer<any> {
|
||||
return (tree, vFile) => {
|
||||
// read frontmatter
|
||||
unistUtilVisit.visit(tree, 'yaml', (node) => {
|
||||
if (!/(^|[\n\r])description:/.test(node.value)) {
|
||||
vFile.data.frontmatter.__autoDescription = true;
|
||||
(vFile.data.frontmatter as any).__autoDescription = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default remarkMeta;
|
||||
|
@ -1,10 +1,11 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { theme as antdTheme, ConfigProvider } from 'antd';
|
||||
import type { ThemeConfig } from 'antd';
|
||||
import type { ThemeProviderProps } from 'antd-style';
|
||||
import { ThemeProvider } from 'antd-style';
|
||||
import type { FC } from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { ConfigProvider, theme as antdTheme } from 'antd';
|
||||
|
||||
interface NewToken {
|
||||
bannerHeight: number;
|
||||
headerHeight: number;
|
||||
menuItemBorder: number;
|
||||
mobileMaxWidth: number;
|
||||
@ -24,15 +25,13 @@ declare module 'antd-style' {
|
||||
export interface CustomToken extends NewToken {}
|
||||
}
|
||||
|
||||
const SiteThemeProvider: FC<ThemeProviderProps> = ({ children, theme, ...rest }) => {
|
||||
const SiteThemeProvider: React.FC<ThemeProviderProps<any>> = ({ children, theme, ...rest }) => {
|
||||
const { getPrefixCls, iconPrefixCls } = useContext(ConfigProvider.ConfigContext);
|
||||
const rootPrefixCls = getPrefixCls();
|
||||
const { token } = antdTheme.useToken();
|
||||
|
||||
React.useEffect(() => {
|
||||
ConfigProvider.config({
|
||||
theme,
|
||||
});
|
||||
ConfigProvider.config({ theme: theme as ThemeConfig });
|
||||
}, [theme]);
|
||||
|
||||
return (
|
||||
|
@ -3,12 +3,12 @@ import React, { forwardRef, useLayoutEffect, useMemo, useTransition } from 'reac
|
||||
import { useLocation, useNavigate } from 'dumi';
|
||||
import nprogress from 'nprogress';
|
||||
|
||||
export type LinkProps = {
|
||||
export interface LinkProps {
|
||||
to?: string | { pathname?: string; search?: string; hash?: string };
|
||||
children?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
|
||||
const { to, children, ...rest } = props;
|
||||
@ -24,12 +24,14 @@ const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
|
||||
}, [to]);
|
||||
|
||||
const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {
|
||||
if (!href.startsWith('http')) {
|
||||
if (!href?.startsWith('http')) {
|
||||
// Should support open in new tab
|
||||
if (!e.metaKey && !e.ctrlKey && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
startTransition(() => {
|
||||
navigate(href);
|
||||
if (href) {
|
||||
navigate(href);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ import ThemeIcon from './ThemeIcon';
|
||||
|
||||
export type ThemeName = 'light' | 'dark' | 'compact' | 'motion-off' | 'happy-work';
|
||||
|
||||
export type ThemeSwitchProps = {
|
||||
export interface ThemeSwitchProps {
|
||||
value?: ThemeName[];
|
||||
onChange: (value: ThemeName[]) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const ThemeSwitch: React.FC<ThemeSwitchProps> = (props) => {
|
||||
const { value = ['light'], onChange } = props;
|
||||
@ -72,23 +72,6 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = (props) => {
|
||||
}}
|
||||
tooltip={<FormattedMessage id="app.theme.switch.compact" />}
|
||||
/>
|
||||
{/* Too many float button. Hide motion one */}
|
||||
{/* <FloatButton
|
||||
icon={<Motion />}
|
||||
type={!isMotionOff ? 'primary' : 'default'}
|
||||
onClick={() => {
|
||||
if (isMotionOff) {
|
||||
onChange(value.filter((theme) => theme !== 'motion-off'));
|
||||
} else {
|
||||
onChange([...value, 'motion-off']);
|
||||
}
|
||||
}}
|
||||
tooltip={
|
||||
<FormattedMessage
|
||||
id={isMotionOff ? 'app.theme.switch.motion.off' : 'app.theme.switch.motion.on'}
|
||||
/>
|
||||
}
|
||||
/> */}
|
||||
<FloatButton
|
||||
badge={{ dot: true }}
|
||||
icon={<SmileOutlined />}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { useCallback, useEffect, useMemo, startTransition } from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
createCache,
|
||||
extractStyle,
|
||||
@ -32,6 +33,7 @@ type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
|
||||
type SiteState = Partial<Omit<SiteContextProps, 'updateSiteContext'>>;
|
||||
|
||||
const RESPONSIVE_MOBILE = 768;
|
||||
export const ANT_DESIGN_NOT_SHOW_BANNER = 'ANT_DESIGN_NOT_SHOW_BANNER';
|
||||
|
||||
// const styleCache = createCache();
|
||||
// if (typeof global !== 'undefined') {
|
||||
@ -56,12 +58,12 @@ const GlobalLayout: React.FC = () => {
|
||||
const { pathname } = useLocation();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [, , setPrefersColor] = usePrefersColor();
|
||||
const [{ theme = [], direction, isMobile, bannerVisible = true }, setSiteState] =
|
||||
const [{ theme = [], direction, isMobile, bannerVisible = false }, setSiteState] =
|
||||
useLayoutState<SiteState>({
|
||||
isMobile: false,
|
||||
direction: 'ltr',
|
||||
theme: [],
|
||||
bannerVisible: true,
|
||||
bannerVisible: false,
|
||||
});
|
||||
|
||||
const updateSiteConfig = useCallback(
|
||||
@ -106,8 +108,16 @@ const GlobalLayout: React.FC = () => {
|
||||
useEffect(() => {
|
||||
const _theme = searchParams.getAll('theme') as ThemeName[];
|
||||
const _direction = searchParams.get('direction') as DirectionType;
|
||||
const storedBannerVisibleLastTime =
|
||||
localStorage && localStorage.getItem(ANT_DESIGN_NOT_SHOW_BANNER);
|
||||
const storedBannerVisible =
|
||||
storedBannerVisibleLastTime && dayjs().diff(dayjs(storedBannerVisibleLastTime), 'day') >= 1;
|
||||
|
||||
setSiteState({ theme: _theme, direction: _direction === 'rtl' ? 'rtl' : 'ltr' });
|
||||
setSiteState({
|
||||
theme: _theme,
|
||||
direction: _direction === 'rtl' ? 'rtl' : 'ltr',
|
||||
bannerVisible: storedBannerVisibleLastTime ? storedBannerVisible : true,
|
||||
});
|
||||
// Handle isMobile
|
||||
updateMobileMode();
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { GithubOutlined, MenuOutlined } from '@ant-design/icons';
|
||||
import { createStyles } from 'antd-style';
|
||||
import dayjs from 'dayjs';
|
||||
import classNames from 'classnames';
|
||||
import { useLocation, useSiteData } from 'dumi';
|
||||
import DumiSearchBar from 'dumi/theme-default/slots/SearchBar';
|
||||
@ -10,6 +11,7 @@ import DirectionIcon from '../../common/DirectionIcon';
|
||||
import * as utils from '../../utils';
|
||||
import { getThemeConfig } from '../../utils';
|
||||
import type { SiteContextProps } from '../SiteContext';
|
||||
import { ANT_DESIGN_NOT_SHOW_BANNER } from '../../layouts/GlobalLayout';
|
||||
import SiteContext from '../SiteContext';
|
||||
import Logo from './Logo';
|
||||
import More from './More';
|
||||
@ -154,7 +156,8 @@ const Header: React.FC = () => {
|
||||
windowWidth: 1400,
|
||||
searching: false,
|
||||
});
|
||||
const { direction, isMobile, updateSiteConfig } = useContext<SiteContextProps>(SiteContext);
|
||||
const { direction, isMobile, bannerVisible, updateSiteConfig } =
|
||||
useContext<SiteContextProps>(SiteContext);
|
||||
const pingTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const location = useLocation();
|
||||
const { pathname, search } = location;
|
||||
@ -178,6 +181,10 @@ const Header: React.FC = () => {
|
||||
};
|
||||
const onBannerClose = () => {
|
||||
updateSiteConfig({ bannerVisible: false });
|
||||
|
||||
if (utils.isLocalStorageNameSupported()) {
|
||||
localStorage.setItem(ANT_DESIGN_NOT_SHOW_BANNER, dayjs().toISOString());
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -352,7 +359,7 @@ const Header: React.FC = () => {
|
||||
<MenuOutlined className="nav-phone-icon" onClick={handleShowMenu} />
|
||||
</Popover>
|
||||
)}
|
||||
{isZhCN && (
|
||||
{isZhCN && bannerVisible && (
|
||||
<Alert
|
||||
className={styles.banner}
|
||||
message={
|
||||
|
@ -1,5 +1,6 @@
|
||||
import flatten from 'lodash/flatten';
|
||||
import flattenDeep from 'lodash/flattenDeep';
|
||||
|
||||
import themeConfig from './themeConfig';
|
||||
|
||||
interface Meta {
|
||||
|
@ -1,15 +1,7 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"baseUrl": "../",
|
||||
"paths": {
|
||||
"@@/*": [".dumi/tmp/*"],
|
||||
"antd": ["components/index.tsx"],
|
||||
"antd/es/*": ["components/*"],
|
||||
"dumi/theme/*": [".dumi/theme/*"]
|
||||
}
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["./**/*", "../site/theme/template/Content"]
|
||||
"include": ["**/*"]
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ const showInsetEffect: WaveConfig['showEffect'] = (node, { event, component }) =
|
||||
// Motion
|
||||
requestAnimationFrame(() => {
|
||||
dot.ontransitionend = () => {
|
||||
holder.parentElement?.removeChild(holder);
|
||||
holder.remove();
|
||||
};
|
||||
|
||||
dot.style.width = '200px';
|
||||
|
@ -289,6 +289,8 @@ describe('Theme', () => {
|
||||
expect(token2.colorLink).toEqual(token2.colorInfo);
|
||||
expect(token2.colorLinkHover).toEqual(token2.colorInfoHover);
|
||||
expect(token2.colorLinkActive).toEqual(token2.colorInfoActive);
|
||||
// colorInfo should not follow colorPrimary
|
||||
expect(token2.colorLink).not.toEqual('#189cff');
|
||||
|
||||
const token3 = getHookToken({ algorithm: [theme.darkAlgorithm] });
|
||||
expect(token3.colorLink).toEqual(token3.colorInfo);
|
||||
|
@ -211,6 +211,10 @@ Please ref document [Shadow Dom Usage](/docs/react/customize-theme#shadow-dom-us
|
||||
|
||||
Please ref dynamic theme document [SSR](/docs/react/customize-theme#server-side-render-ssr) part.
|
||||
|
||||
## What is the relationship between colorPrimary and colorInfo and colorLink in V5?
|
||||
|
||||
In the Ant Design Token system, `colorPrimary` and `colorInfo` are both [Seed Token](../react/customize-theme.en-US.md#seed-token), so they are independent of each other. `colorLink` is an [Alias Token](../react/customize-theme.en-US.md#alias-token), inherits `colorInfo` by default, and is independent of `colorPrimary`.
|
||||
|
||||
## How to spell Ant Design correctly?
|
||||
|
||||
- ✅ **Ant Design**: Capitalized with space, for the design language.
|
||||
|
@ -239,6 +239,10 @@ import { ConfigProvider } from 'antd';
|
||||
|
||||
请参考动态主题文档 [服务端渲染](/docs/react/customize-theme-cn#服务端渲染) 部分内容。
|
||||
|
||||
## V5 中 colorPrimary 和 colorInfo 及 colorLink 之间是什么关系?
|
||||
|
||||
在 Ant Design Token 系统中 `colorPrimary` 和 `colorInfo` 同属于 [基础变量(Seed Token)](../react/customize-theme.zh-CN.md#基础变量seed-token),所以两者是互相独立的。`colorLink` 则属于 [别名变量(Alias Token)](../react/customize-theme.zh-CN.md#别名变量alias-token), 默认继承 `colorInfo` 且和 `colorPrimary` 无关。
|
||||
|
||||
## 如何正确的拼写 Ant Design?
|
||||
|
||||
- ✅ **Ant Design**:用空格分隔的首字母大写单词,指代设计语言。
|
||||
|
@ -175,8 +175,8 @@ import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
|
||||
import type Entity from '@ant-design/cssinjs/es/Cache';
|
||||
import { useServerInsertedHTML } from 'next/navigation';
|
||||
|
||||
const StyledComponentsRegistry = ({ children }: { children: React.ReactNode }) => {
|
||||
const cache = React.useMemo<Entity>(() => createCache(), [createCache]);
|
||||
const StyledComponentsRegistry = ({ children }: React.PropsWithChildren) => {
|
||||
const cache = React.useMemo<Entity>(() => createCache(), []);
|
||||
useServerInsertedHTML(() => (
|
||||
<style id="antd" dangerouslySetInnerHTML={{ __html: extractStyle(cache, true) }} />
|
||||
));
|
||||
@ -203,7 +203,7 @@ export const metadata = {
|
||||
description: 'Generated by create next app',
|
||||
};
|
||||
|
||||
const RootLayout = ({ children }: { children: React.ReactNode }) => (
|
||||
const RootLayout = ({ children }: React.PropsWithChildren) => (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
|
||||
|
@ -175,8 +175,8 @@ import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
|
||||
import type Entity from '@ant-design/cssinjs/es/Cache';
|
||||
import { useServerInsertedHTML } from 'next/navigation';
|
||||
|
||||
const StyledComponentsRegistry = ({ children }: { children: React.ReactNode }) => {
|
||||
const cache = React.useMemo<Entity>(() => createCache(), [createCache]);
|
||||
const StyledComponentsRegistry = ({ children }: React.PropsWithChildren) => {
|
||||
const cache = React.useMemo<Entity>(() => createCache(), []);
|
||||
useServerInsertedHTML(() => (
|
||||
<style id="antd" dangerouslySetInnerHTML={{ __html: extractStyle(cache, true) }} />
|
||||
));
|
||||
@ -203,7 +203,7 @@ export const metadata = {
|
||||
description: 'Generated by create next app',
|
||||
};
|
||||
|
||||
const RootLayout = ({ children }: { children: React.ReactNode }) => (
|
||||
const RootLayout = ({ children }: React.PropsWithChildren) => (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
|
||||
|
@ -194,6 +194,7 @@
|
||||
"@types/jquery": "^3.5.14",
|
||||
"@types/lodash": "^4.14.139",
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/prismjs": "^1.26.0",
|
||||
"@types/progress": "^2.0.5",
|
||||
"@types/qs": "^6.9.7",
|
||||
@ -216,7 +217,7 @@
|
||||
"cross-fetch": "^4.0.0",
|
||||
"crypto": "^1.0.1",
|
||||
"dekko": "^0.2.1",
|
||||
"dumi": "^2.1.23",
|
||||
"dumi": "^2.2.10",
|
||||
"duplicate-package-checker-webpack-plugin": "^3.0.0",
|
||||
"esbuild-loader": "^4.0.0",
|
||||
"eslint": "^8.40.0",
|
||||
|
@ -7,6 +7,7 @@ import { globSync } from 'glob';
|
||||
import { configureToMatchImageSnapshot } from 'jest-image-snapshot';
|
||||
import MockDate from 'mockdate';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
|
||||
import { App, ConfigProvider, theme } from '../../components';
|
||||
|
||||
const toMatchImageSnapshot = configureToMatchImageSnapshot({
|
||||
@ -77,7 +78,6 @@ export default function imageTest(component: React.ReactElement, options: ImageT
|
||||
|
||||
const image = await page.screenshot({
|
||||
fullPage: !options.onlyViewport,
|
||||
optimizeForSpeed: true,
|
||||
});
|
||||
|
||||
expect(image).toMatchImageSnapshot();
|
||||
|
@ -2,6 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@@/*": [".dumi/tmp/*"],
|
||||
"antd": ["components/index.ts"],
|
||||
"antd/es/*": ["components/*"],
|
||||
"antd/lib/*": ["components/*"],
|
||||
@ -23,5 +24,6 @@
|
||||
"skipLibCheck": true,
|
||||
"stripInternal": true
|
||||
},
|
||||
"include": [".dumirc.ts", "**/*"],
|
||||
"exclude": ["node_modules", "lib", "es"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user