;
@@ -36,7 +36,6 @@ export default function fromDumiProps(
const hoc = function DumiPropsAntdPreviewer(props: IPreviewerProps) {
const showRiddleButton = useShowRiddleButton();
const location = useLocation();
- const [searchParams] = useSearchParams();
const { asset, children, demoUrl, expand, description = '', ...meta } = props;
const intl = useIntl();
const entryCode = asset.dependencies['index.tsx'].value;
@@ -89,7 +88,6 @@ export default function fromDumiProps
(
expand,
// FIXME: confirm is there has any case?
highlightedStyle: '',
- theme: searchParams.get('theme'),
} as P;
return ;
diff --git a/.dumi/theme/builtins/Previewer/index.tsx b/.dumi/theme/builtins/Previewer/index.tsx
index 0a5aa6b80b..9cc5a642d6 100644
--- a/.dumi/theme/builtins/Previewer/index.tsx
+++ b/.dumi/theme/builtins/Previewer/index.tsx
@@ -17,6 +17,8 @@ import CodeSandboxIcon from '../../common/CodeSandboxIcon';
import RiddleIcon from '../../common/RiddleIcon';
import ExternalLinkIcon from '../../common/ExternalLinkIcon';
import fromDumiProps from './fromDumiProps';
+import type { SiteContextProps } from '../../slots/SiteContext';
+import SiteContext from '../../slots/SiteContext';
import { version } from '../../../../package.json';
const { ErrorBoundary } = Alert;
@@ -38,7 +40,6 @@ interface DemoProps {
highlightedStyle: string;
expand: boolean;
intl: any;
- theme: string;
sourceCodes: Record<'jsx' | 'tsx', string>;
location: Location;
showRiddleButton: boolean;
@@ -53,6 +54,8 @@ interface DemoState {
}
class Demo extends React.Component {
+ static contextType = SiteContext;
+
liveDemo: any;
iframeRef = React.createRef();
@@ -81,13 +84,12 @@ class Demo extends React.Component {
shouldComponentUpdate(nextProps: DemoProps, nextState: DemoState) {
const { codeExpand, copied, copyTooltipOpen, codeType } = this.state;
- const { expand, theme, showRiddleButton } = this.props;
+ const { expand, showRiddleButton } = this.props;
return (
(codeExpand || expand) !== (nextState.codeExpand || nextProps.expand) ||
copied !== nextState.copied ||
copyTooltipOpen !== nextState.copyTooltipOpen ||
codeType !== nextState.copyTooltipOpen ||
- nextProps.theme !== theme ||
nextProps.showRiddleButton !== showRiddleButton
);
}
@@ -129,6 +131,7 @@ class Demo extends React.Component {
render() {
const { state } = this;
const { props } = this;
+ const site: SiteContextProps = this.context;
const {
meta,
src,
@@ -139,7 +142,6 @@ class Demo extends React.Component {
highlightedStyle,
expand,
intl: { locale },
- theme,
showRiddleButton,
} = props;
const { copied, copyTooltipOpen, codeType } = state;
@@ -465,7 +467,7 @@ createRoot(document.getElementById('container')).render();
);
void;
};
-const ThemeSwitch: React.FC = ({ value, onChange }) => {
+const ThemeSwitch: React.FC = (props: ThemeSwitchProps) => {
+ const { value = ['light'], onChange } = props;
const { token } = useSiteToken();
const { pathname, search } = useLocation();
return (
diff --git a/.dumi/theme/layouts/DocLayout/index.tsx b/.dumi/theme/layouts/DocLayout/index.tsx
index f0a754dac9..a9f5efe9e0 100644
--- a/.dumi/theme/layouts/DocLayout/index.tsx
+++ b/.dumi/theme/layouts/DocLayout/index.tsx
@@ -1,16 +1,15 @@
-import React, { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
+import React, { useContext, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
import 'dayjs/locale/zh-cn';
import dayjs from 'dayjs';
-import { Helmet, useOutlet, useSearchParams } from 'dumi';
+import { Helmet, useOutlet } from 'dumi';
import '../../static/style';
-import type { DirectionType } from 'antd/es/config-provider';
import ConfigProvider from 'antd/es/config-provider';
import classNames from 'classnames';
import zhCN from 'antd/es/locale/zh_CN';
+import SiteContext from '../../slots/SiteContext';
import Header from '../../slots/Header';
import Footer from '../../slots/Footer';
import useLocale from '../../../hooks/useLocale';
-import SiteContext from '../../slots/SiteContext';
import useLocation from '../../../hooks/useLocation';
import ResourceLayout from '../ResourceLayout';
import GlobalStyles from '../../common/GlobalStyles';
@@ -28,26 +27,13 @@ const locales = {
},
};
-const RESPONSIVE_MOBILE = 768;
-
const DocLayout: React.FC = () => {
const outlet = useOutlet();
const location = useLocation();
const { pathname, search } = location;
- const [searchParams, setSearchParams] = useSearchParams();
const [locale, lang] = useLocale(locales);
-
- // TODO: place doc layout here, apply for all docs route paths
- // migrate from: https://github.com/ant-design/ant-design/blob/eb9179464b9c4a93c856e1e70ddbdbaaf3f3371f/site/theme/template/Layout/index.tsx
-
- const [isMobile, setIsMobile] = React.useState(false);
- const [direction, setDirection] = React.useState('ltr');
-
const timerRef = useRef(null);
-
- const updateMobileMode = () => {
- setIsMobile(window.innerWidth < RESPONSIVE_MOBILE);
- };
+ const { direction } = useContext(SiteContext);
useLayoutEffect(() => {
if (lang === 'cn') {
@@ -64,20 +50,6 @@ const DocLayout: React.FC = () => {
nprogressHiddenStyle.parentNode?.removeChild(nprogressHiddenStyle);
}, 0);
}
-
- // Handle direction
- const queryDirection = searchParams.get('direction');
- setDirection(queryDirection === 'rtl' ? 'rtl' : 'ltr');
-
- // Handle mobile mode
- updateMobileMode();
- window.addEventListener('resize', updateMobileMode);
- return () => {
- window.removeEventListener('resize', updateMobileMode);
- if (timerRef.current) {
- clearTimeout(timerRef.current);
- }
- };
}, []);
React.useEffect(() => {
@@ -89,16 +61,6 @@ const DocLayout: React.FC = () => {
}
}, [location]);
- const changeDirection = (dir: DirectionType): void => {
- setDirection(dir);
- if (dir === 'ltr') {
- searchParams.delete('direction');
- } else {
- searchParams.set('direction', 'rtl');
- }
- setSearchParams(searchParams);
- };
-
const content = useMemo(() => {
if (
['', '/'].some((path) => path === pathname) ||
@@ -120,16 +82,8 @@ const DocLayout: React.FC = () => {
return {outlet};
}, [pathname, outlet]);
- const siteContextValue = useMemo(
- () => ({
- isMobile,
- direction,
- }),
- [isMobile, direction],
- );
-
return (
-
+ <>
{
content="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
/>
-
+
-
+
{content}
-
+ >
);
};
diff --git a/.dumi/theme/layouts/GlobalLayout.tsx b/.dumi/theme/layouts/GlobalLayout.tsx
index ca71a4b772..035287fee8 100644
--- a/.dumi/theme/layouts/GlobalLayout.tsx
+++ b/.dumi/theme/layouts/GlobalLayout.tsx
@@ -1,18 +1,26 @@
-import React from 'react';
-import { useOutlet, useSearchParams } from 'dumi';
+import React, { useCallback, useEffect, useMemo } from 'react';
+import { createSearchParams, useOutlet, useSearchParams } from 'dumi';
import { ConfigProvider, theme as antdTheme } from 'antd';
import { createCache, StyleProvider } from '@ant-design/cssinjs';
+import type { DirectionType } from 'antd/es/config-provider';
import ThemeSwitch from '../common/ThemeSwitch';
import type { ThemeName } from '../common/ThemeSwitch';
import useLocation from '../../hooks/useLocation';
+import type { SiteContextProps } from '../slots/SiteContext';
+import SiteContext from '../slots/SiteContext';
+
+type Entries = { [K in keyof T]: [K, T[K]] }[keyof T][];
+type SiteState = Partial>;
+
+const RESPONSIVE_MOBILE = 768;
const styleCache = createCache();
if (typeof global !== 'undefined') {
(global as any).styleCache = styleCache;
}
-const getAlgorithm = (themes: ThemeName[]) =>
- (themes || []).map((theme) => {
+const getAlgorithm = (themes: ThemeName[] = []) =>
+ themes.map((theme) => {
if (theme === 'dark') {
return antdTheme.darkAlgorithm;
}
@@ -26,26 +34,87 @@ const GlobalLayout: React.FC = () => {
const outlet = useOutlet();
const { pathname } = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
- const theme = searchParams.getAll('theme') as unknown as ThemeName[];
- const handleThemeChange = (value: ThemeName[]) => {
- setSearchParams({
- ...searchParams,
- theme: value,
- });
+ const [{ theme, direction, isMobile }, setSiteState] = React.useState({
+ isMobile: false,
+ direction: 'ltr',
+ theme: ['light'],
+ });
+
+ const updateSiteConfig = useCallback(
+ (props: SiteState) => {
+ setSiteState((prev) => ({ ...prev, ...props }));
+
+ // updating `searchParams` will clear the hash
+ const oldSearchStr = searchParams.toString();
+
+ let nextSearchParams: URLSearchParams = searchParams;
+ (Object.entries(props) as Entries).forEach(([key, value]) => {
+ if (key === 'direction') {
+ if (value === 'rtl') {
+ nextSearchParams.set('direction', 'rtl');
+ } else {
+ nextSearchParams.delete('direction');
+ }
+ }
+ if (key === 'theme') {
+ nextSearchParams = createSearchParams({
+ ...nextSearchParams,
+ theme: value.filter((t) => t !== 'light'),
+ });
+ }
+ });
+
+ if (nextSearchParams.toString() !== oldSearchStr) {
+ setSearchParams(nextSearchParams);
+ }
+ },
+ [searchParams, setSearchParams],
+ );
+
+ const updateMobileMode = () => {
+ updateSiteConfig({ isMobile: window.innerWidth < RESPONSIVE_MOBILE });
};
+ useEffect(() => {
+ const _theme = searchParams.getAll('theme') as ThemeName[];
+ const _direction = searchParams.get('direction') as DirectionType;
+ setSiteState({ theme: _theme, direction: _direction === 'rtl' ? 'rtl' : 'ltr' });
+
+ // Handle isMobile
+ updateMobileMode();
+ window.addEventListener('resize', updateMobileMode);
+ return () => {
+ window.removeEventListener('resize', updateMobileMode);
+ };
+ }, []);
+
+ const siteContextValue = useMemo(
+ () => ({
+ direction,
+ updateSiteConfig,
+ theme: theme!,
+ isMobile: isMobile!,
+ }),
+ [isMobile, direction, updateSiteConfig, theme],
+ );
+
return (
-
- {outlet}
- {!pathname.startsWith('/~demos') && (
-
- )}
-
+
+
+ {outlet}
+ {!pathname.startsWith('/~demos') && (
+ updateSiteConfig({ theme: nextTheme })}
+ />
+ )}
+
+
);
};
diff --git a/.dumi/theme/slots/Header/SwitchBtn.tsx b/.dumi/theme/slots/Header/SwitchBtn.tsx
index b532b03ea4..799392a65a 100644
--- a/.dumi/theme/slots/Header/SwitchBtn.tsx
+++ b/.dumi/theme/slots/Header/SwitchBtn.tsx
@@ -83,7 +83,7 @@ export default function LangBtn({
top: 0,
zIndex: 1,
background: token.colorText,
- color: token.colorTextLightSolid,
+ color: token.colorBgContainer,
transformOrigin: '0 0',
transform: `scale(0.7)`,
};
diff --git a/.dumi/theme/slots/Header/index.tsx b/.dumi/theme/slots/Header/index.tsx
index 9dc42060fb..95704a4ba8 100644
--- a/.dumi/theme/slots/Header/index.tsx
+++ b/.dumi/theme/slots/Header/index.tsx
@@ -4,7 +4,6 @@ import DumiSearchBar from 'dumi/theme-default/slots/SearchBar';
import classNames from 'classnames';
import { Col, Modal, Popover, Row, Select, Typography } from 'antd';
import { GithubOutlined, MenuOutlined } from '@ant-design/icons';
-import type { DirectionType } from 'antd/es/config-provider';
import { ClassNames, css } from '@emotion/react';
import * as utils from '../../utils';
import { getThemeConfig, ping } from '../../utils';
@@ -129,10 +128,6 @@ const useStyle = () => {
};
};
-export interface HeaderProps {
- changeDirection: (direction: DirectionType) => void;
-}
-
const V5_NOTIFICATION = 'antd@4.0.0-notification-sent';
const SHOULD_OPEN_ANT_DESIGN_MIRROR_MODAL = 'ANT_DESIGN_DO_NOT_OPEN_MIRROR_MODAL';
@@ -151,8 +146,7 @@ interface HeaderState {
}
// ================================= Header =================================
-const Header: React.FC = (props) => {
- const { changeDirection } = props;
+const Header: React.FC = () => {
const [isClient, setIsClient] = React.useState(false);
const [locale, lang] = useLocale(locales);
const { token } = useSiteToken();
@@ -188,7 +182,7 @@ const Header: React.FC = (props) => {
windowWidth: 1400,
searching: false,
});
- const { direction, isMobile } = useContext(SiteContext);
+ const { direction, isMobile, updateSiteConfig } = useContext(SiteContext);
const pingTimer = useRef(null);
const location = useLocation();
const { pathname, search } = location;
@@ -208,7 +202,7 @@ const Header: React.FC = (props) => {
setHeaderState((prev) => ({ ...prev, menuVisible: visible }));
}, []);
const onDirectionChange = () => {
- changeDirection?.(direction !== 'rtl' ? 'rtl' : 'ltr');
+ updateSiteConfig({ direction: direction !== 'rtl' ? 'rtl' : 'ltr' });
};
useEffect(() => {
diff --git a/.dumi/theme/slots/Sidebar/index.tsx b/.dumi/theme/slots/Sidebar/index.tsx
index d8da6ecfaf..996a77b1cb 100644
--- a/.dumi/theme/slots/Sidebar/index.tsx
+++ b/.dumi/theme/slots/Sidebar/index.tsx
@@ -126,10 +126,11 @@ const useStyle = () => {
const Sidebar: React.FC = () => {
const sidebarData = useSidebarData();
- const { isMobile } = useContext(SiteContext);
+ const { isMobile, theme } = useContext(SiteContext);
const styles = useStyle();
const [menuItems, selectedKey] = useMenu();
+ const isDark = theme.includes('dark');
const menuChild = (