diff --git a/.dumi/theme/builtins/ComponentOverview/index.tsx b/.dumi/theme/builtins/ComponentOverview/index.tsx index 49cb8f1369..308ed135c5 100644 --- a/.dumi/theme/builtins/ComponentOverview/index.tsx +++ b/.dumi/theme/builtins/ComponentOverview/index.tsx @@ -1,8 +1,9 @@ -import React, { memo, useMemo, useState } from 'react'; +import React, { memo, useMemo, useRef, useState } from 'react'; +import type { CSSProperties } from 'react'; import { Link, useIntl, useSidebarData, useLocation } from 'dumi'; import { css } from '@emotion/react'; import debounce from 'lodash/debounce'; -import { Card, Col, Divider, Input, Row, Space, Tag, Typography } from 'antd'; +import { Card, Col, Divider, Input, Row, Space, Tag, Typography, Affix } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; import type { Component } from './ProComponentsList'; import proComponentsList from './ProComponentsList'; @@ -10,7 +11,6 @@ import useSiteToken from '../../../hooks/useSiteToken'; const useStyle = () => { const { token } = useSiteToken(); - return { componentsOverviewGroupTitle: css` margin-bottom: 24px !important; @@ -33,22 +33,25 @@ const useStyle = () => { box-shadow: 0 6px 16px -8px #00000014, 0 9px 28px #0000000d, 0 12px 48px 16px #00000008; } `, + componentsOverviewAffix: css` + display: flex; + transition: all 0.3s; + justify-content: space-between; + `, componentsOverviewSearch: css` - font-size: ${token.fontSizeXL}px; padding: 0; - .anticon-search { color: ${token.colorTextDisabled}; } `, componentsOverviewContent: css` &:empty:after { - content: 'Not Found'; - text-align: center; - padding: 16px 0 40px; display: block; + padding: 16px 0 40px; color: ${token.colorTextDisabled}; + text-align: center; border-bottom: 1px solid ${token.colorSplit}; + content: 'Not Found'; } `, }; @@ -76,13 +79,27 @@ const { Title } = Typography; const Overview: React.FC = () => { const style = useStyle(); + const data = useSidebarData(); + const [searchBarAffixed, setSearchBarAffixed] = useState(false); + + const { token } = useSiteToken(); + const { borderRadius, colorBgContainer, fontSizeXL } = token; + + const affixedStyle: CSSProperties = { + boxShadow: 'rgba(50, 50, 93, 0.25) 0 6px 12px -2px, rgba(0, 0, 0, 0.3) 0 3px 7px -3px', + padding: 8, + margin: -8, + borderRadius, + backgroundColor: colorBgContainer, + }; + const { search: urlSearch } = useLocation(); const { locale, formatMessage } = useIntl(); const [search, setSearch] = useState(''); - const sectionRef = React.useRef(null); + const sectionRef = useRef(null); const onKeyDown: React.KeyboardEventHandler = (event) => { if (event.keyCode === 13 && search.trim().length) { @@ -114,23 +131,27 @@ const Overview: React.FC = () => { ]), [data, locale], ); - return (
- { - setSearch(e.target.value); - reportSearch(e.target.value); - }} - onKeyDown={onKeyDown} - bordered={false} - autoFocus - suffix={} - /> + +
+ { + setSearch(e.target.value); + reportSearch(e.target.value); + }} + onKeyDown={onKeyDown} + bordered={false} + suffix={} + style={{ fontSize: searchBarAffixed ? fontSizeXL - 2 : fontSizeXL }} + /> +
+
{groups diff --git a/.dumi/theme/builtins/IconSearch/index.tsx b/.dumi/theme/builtins/IconSearch/index.tsx index 96a1da38c1..0dc425a380 100644 --- a/.dumi/theme/builtins/IconSearch/index.tsx +++ b/.dumi/theme/builtins/IconSearch/index.tsx @@ -1,6 +1,10 @@ -import * as React from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; +import type { CSSProperties } from 'react'; import Icon, * as AntdIcons from '@ant-design/icons'; +import type { SegmentedProps } from 'antd'; +import type { IntlShape } from 'react-intl'; import { Segmented, Input, Empty, Affix } from 'antd'; +import { css } from '@emotion/react'; import { useIntl } from 'dumi'; import debounce from 'lodash/debounce'; import Category from './Category'; @@ -17,6 +21,32 @@ export enum ThemeType { const allIcons: { [key: string]: any } = AntdIcons; +const useStyle = () => ({ + iconSearchAffix: css` + display: flex; + transition: all 0.3s; + justify-content: space-between; + `, +}); + +const options = (intl: IntlShape): SegmentedProps['options'] => [ + { + value: ThemeType.Outlined, + icon: , + label: intl.formatMessage({ id: 'app.docs.components.icon.outlined' }), + }, + { + value: ThemeType.Filled, + icon: , + label: intl.formatMessage({ id: 'app.docs.components.icon.filled' }), + }, + { + value: ThemeType.TwoTone, + icon: , + label: intl.formatMessage({ id: 'app.docs.components.icon.two-tone' }), + }, +]; + interface IconSearchState { theme: ThemeType; searchKey: string; @@ -24,25 +54,23 @@ interface IconSearchState { const IconSearch: React.FC = () => { const intl = useIntl(); - const [displayState, setDisplayState] = React.useState({ - theme: ThemeType.Outlined, + const { iconSearchAffix } = useStyle(); + const [displayState, setDisplayState] = useState({ searchKey: '', + theme: ThemeType.Outlined, }); const newIconNames: string[] = []; - const handleSearchIcon = React.useCallback( - debounce((searchKey: string) => { - setDisplayState((prevState) => ({ ...prevState, searchKey })); - }), - [], - ); + const handleSearchIcon = debounce((e: React.ChangeEvent) => { + setDisplayState((prevState) => ({ ...prevState, searchKey: e.target.value })); + }, 300); - const handleChangeTheme = React.useCallback((value) => { + const handleChangeTheme = useCallback((value) => { setDisplayState((prevState) => ({ ...prevState, theme: value as ThemeType })); }, []); - const renderCategories = React.useMemo(() => { + const renderCategories = useMemo(() => { const { searchKey = '', theme } = displayState; const categoriesResult = Object.keys(categories) @@ -77,62 +105,38 @@ const IconSearch: React.FC = () => { newIcons={newIconNames} /> )); - return categoriesResult.length === 0 ? : categoriesResult; + return categoriesResult.length ? categoriesResult : ; }, [displayState.searchKey, displayState.theme]); - const [searchBarAffixed, setSearchBarAffixed] = React.useState(false); + const [searchBarAffixed, setSearchBarAffixed] = useState(false); const { token } = useSiteToken(); const { borderRadius, colorBgContainer } = token; - const affixedStyle = searchBarAffixed - ? { - boxShadow: 'rgba(50, 50, 93, 0.25) 0px 6px 12px -2px, rgba(0, 0, 0, 0.3) 0px 3px 7px -3px', - padding: 8, - margin: -8, - borderRadius, - background: colorBgContainer, - } - : {}; + + const affixedStyle: CSSProperties = { + boxShadow: 'rgba(50, 50, 93, 0.25) 0 6px 12px -2px, rgba(0, 0, 0, 0.3) 0 3px 7px -3px', + padding: 8, + margin: -8, + borderRadius, + backgroundColor: colorBgContainer, + }; return (
- setSearchBarAffixed(affixed)}> -
+ +
, - label: intl.formatMessage({ id: 'app.docs.components.icon.outlined' }), - value: ThemeType.Outlined, - }, - { - icon: , - label: intl.formatMessage({ id: 'app.docs.components.icon.filled' }), - value: ThemeType.Filled, - }, - { - icon: , - label: intl.formatMessage({ id: 'app.docs.components.icon.two-tone' }), - value: ThemeType.TwoTone, - }, - ]} + value={displayState.theme} + options={options(intl)} + onChange={handleChangeTheme} /> handleSearchIcon(e.currentTarget.value)} - size="large" autoFocus + size="large" + onChange={handleSearchIcon} />
diff --git a/.dumi/theme/slots/Sidebar/index.tsx b/.dumi/theme/slots/Sidebar/index.tsx index cecd67cb9b..8d1c219dd7 100644 --- a/.dumi/theme/slots/Sidebar/index.tsx +++ b/.dumi/theme/slots/Sidebar/index.tsx @@ -1,6 +1,6 @@ import React, { useContext } from 'react'; import { useSidebarData } from 'dumi'; -import { Affix, Col, ConfigProvider, Menu } from 'antd'; +import { Col, ConfigProvider, Menu } from 'antd'; import MobileMenu from 'rc-drawer'; import { css } from '@emotion/react'; import SiteContext from '../SiteContext'; @@ -107,6 +107,9 @@ const useStyle = () => { z-index: 1; .main-menu-inner { + position: sticky; + top: 0; + width: 100%; height: 100%; max-height: 100vh; overflow: hidden; @@ -115,11 +118,6 @@ const useStyle = () => { &:hover .main-menu-inner { overflow-y: auto; } - - > div, - > div > div { - height: 100%; - } `, }; }; @@ -153,11 +151,7 @@ const Sidebar: React.FC = () => { {menuChild} ) : ( - -
- {menuChild} -
-
+
{menuChild}
); }; diff --git a/components/button/LoadingIcon.tsx b/components/button/LoadingIcon.tsx index 2f361c293c..7c760147f1 100644 --- a/components/button/LoadingIcon.tsx +++ b/components/button/LoadingIcon.tsx @@ -7,8 +7,14 @@ export interface LoadingIconProps { existIcon: boolean; loading?: boolean | object; } -const getCollapsedWidth = () => ({ width: 0, opacity: 0, transform: 'scale(0)' }); -const getRealWidth = (node: HTMLElement) => ({ + +const getCollapsedWidth = (): React.CSSProperties => ({ + width: 0, + opacity: 0, + transform: 'scale(0)', +}); + +const getRealWidth = (node: HTMLElement): React.CSSProperties => ({ width: node.scrollWidth, opacity: 1, transform: 'scale(1)',