Selaa lähdekoodia

feat: nav add getpopupcontainer, #1277 (#1282)

pointhalo 2 vuotta sitten
vanhempi
sitoutus
6c4a85883d

+ 1 - 0
content/navigation/navigation/index-en-US.md

@@ -736,6 +736,7 @@ function NavApp (props = {}) {
 | defaultOpenKeys     | Initially open sub navigation `itemKey` array, valid only `mode = "vertical"`and the sidebar is in an expanded state                                                                       | string[]                                                                                                                         | []         |
 | defaultSelectedKeys | Originally selected navigation item `itemKey` array                                                                                                                                        | string[]                                                                                                                         | []         |
 | footer              | The bottom area configure objects or elements, see [Nav.Footer](#Nav.Footer)                                                                                                               | object\|ReactNode                                                                                                                |            |
+| getPopupContainer   | Dropdown's getPopupContainer config of vertical collapsed Nav or horizontal Nav. >= v2.24     | Function |                      |
 | header              | Head area configuration objects or elements, see [Nav.Header](#Nav.Header)                                                                                                                 | object\|ReactNode                                                                                                                |            |
 | isCollapsed         | A controlled attribute of whether it is in a put-away state, valid only when `mode = "vertical"`                                                                                           | boolean                                                                                                                          |            |
 | items               | Navigate the list of items, each item can continue with the items property. If it is a string array, each item is taken as text and itemKey                                                | object\|string[]\|[Item](#Nav.Item)[]\|[Sub](#Nav.Sub)[]                                                                         |            |

+ 53 - 49
content/navigation/navigation/index.md

@@ -113,7 +113,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -133,7 +133,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -154,7 +154,7 @@ Navigation 目前提供了个两个参数用于定义导航样式:`style` 和
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting, IconFolder } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconFolder, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -181,7 +181,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -200,7 +200,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -211,7 +211,7 @@ class NavApp extends React.Component {
                 onSelect={data => console.log('trigger onSelect: ', data)}
                 onClick={data => console.log('trigger onClick: ', data)}
             >
-                <Nav.Header logo={<img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />} text={'Semi 运营后台'} />
+                <Nav.Header logo={<IconSemiLogo style={{ height: '36px', fontSize: 36 }} />} text={'Semi 运营后台'} />
                 <Nav.Item itemKey={'union'} text={'活动管理'} icon={<IconStar />} />
                 <Nav.Sub itemKey={'user'} text="用户管理" icon={<IconUser />}>
                     <Nav.Item itemKey={'active'} text={'活跃用户'} />
@@ -238,36 +238,39 @@ class NavApp extends React.Component {
 
 ```jsx
 import { Link } from "react-router-dom";
+import React from 'react';
+import { Nav } from '@douyinfe/semi-ui';
 
-()=>{
-    return <Nav
-        renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
-            const routerMap = {
-                Home: "/",
-                About: "/about",
-                Dashboard: "/dashboard",
-                "Nothing Here": "/nothing-here"
-            };
-            return (
-                <Link
-                    style={{ textDecoration: "none" }}
-                    to={routerMap[props.itemKey]}
-                >
-                    {itemElement}
-                </Link>
-            );
-        }}
-        items={[
-            { itemKey: "Home", text: "Home" },
-            { itemKey: "About", text: "About" },
-            {
-                text: "Sub",
-
-                itemKey: "Sub",
-                items: ["Dashboard", "Nothing Here"]
-            }
-        ]}
-    ></Nav>
+() => {
+    return (
+        <Nav
+            renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
+                const routerMap = {
+                    Home: "/",
+                    About: "/about",
+                    Dashboard: "/dashboard",
+                    "Nothing Here": "/nothing-here"
+                };
+                return (
+                    <Link
+                        style={{ textDecoration: "none" }}
+                        to={routerMap[props.itemKey]}
+                    >
+                        {itemElement}
+                    </Link>
+                );
+            }}
+            items={[
+                { itemKey: "Home", text: "Home" },
+                { itemKey: "About", text: "About" },
+                {
+                    text: "Sub",
+                    itemKey: "Sub",
+                    items: ["Dashboard", "Nothing Here"]
+                }
+            ]}
+        ></Nav>
+    );
 }
 ```
 
@@ -292,7 +295,7 @@ Navigation 目前提供两种方向的导航:
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup, IconSetting } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -318,7 +321,7 @@ class NavApp extends React.Component {
                     ]}
                     onSelect={key => console.log(key)}
                     header={{
-                        logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                        logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                         text: 'Semi 运营后台'
                     }}
                     footer={{
@@ -336,7 +339,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav, Avatar, Dropdown } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -372,7 +375,7 @@ class NavApp extends React.Component {
                     ]}
                     onSelect={key => console.log(key)}
                     header={{
-                        logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                        logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                         text: 'Semi 运营后台'
                     }}
                     footer={
@@ -403,7 +406,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav, Avatar, Dropdown, Select, Button } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit, IconLanguage } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit, IconLanguage, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     constructor() {
@@ -450,7 +453,7 @@ class NavApp extends React.Component {
                 mode={'horizontal'}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={
@@ -511,7 +514,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir=column
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -532,7 +535,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -556,7 +559,7 @@ limitIndent 只在 竖直方向生效
 ```jsx live=true dir=column
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -588,7 +591,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -612,7 +615,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconUserGroup, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconUserGroup, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -639,7 +642,7 @@ class NavApp extends React.Component {
                     },
                 ]}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -671,7 +674,7 @@ Navigation 组件提供了几个受控属性,配合各种回调,可以很轻
 ```jsx live=true dir="column"
 import React, { useMemo, useState } from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconUserGroup, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconUserGroup, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 function NavApp (props = {}) {
     const [openKeys, setOpenKeys] = useState(['union-management', 'job']);
@@ -716,7 +719,7 @@ function NavApp (props = {}) {
             bodyStyle={{ height: 360 }}
             items={items}
             header={{
-                logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                 text: 'Semi 运营后台'
             }}
             footer={{
@@ -742,6 +745,7 @@ function NavApp (props = {}) {
 | defaultOpenKeys     | 初始打开的子导航 `itemKey` 数组,仅 `mode = "vertical"` 且侧边栏处于展开状态时有效                               | string[]                                                                                                                                                            | []                      |
 | defaultSelectedKeys | 初始选中的导航项 `itemKey` 数组                                                                   | string[]                                                                                                                                                            | []                      |
 | footer              | 底部区域配置对象或元素,详见 [Nav.Footer](#Nav.Footer)                                                | object\                                                                                                                                                             | ReactNode               |                      |
+| getPopupContainer   | 垂直 Nav 折叠或 水平 Nav中 Dropdown 的 getPopupContainer 配置,可指定弹出层容器, >=2.24.0                        | Function |                      |
 | header              | 头部区域配置对象或元素,详见 [Nav.Header](#Nav.Header)                                                | object\                                                                                                                                                             | ReactNode               |                      |
 | isCollapsed         | 是否处于收起状态的受控属性,仅 `mode = "vertical"` 时有效                                                 | boolean                                                                                                                                                             |                         |
 | items               | 导航项目列表,每一项可以继续带有 items 属性。如果为 string 数组,则会取每一项作为 text 和 itemKey                         | object\                                                                                                                                                             | string[] \              | [Item](#Nav.Item)[] \| [Sub](#Nav.Sub)[] |  |

+ 7 - 6
content/start/dark-mode/index-en-US.md

@@ -53,7 +53,7 @@ function Demo() {
             // Notify our site to update current mode
             window.setMode('dark');
         }
-    }
+    };
 
     return (
         <Button
@@ -100,9 +100,8 @@ Semi 2.0 natively supports block dark/bright color mode, and you can add `.semi-
 
 ```jsx live=true dir="column" hideInDSM
 import React from 'react';
-import { Layout, Nav, Button, Breadcrumb, Skeleton, Avatar } from '@douyinfe/semi-ui';
-import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting } from '@douyinfe/semi-icons';
-
+import { Layout, Nav, Button, Breadcrumb, Avatar, Steps, Pagination, Row, Badge, Tag, Rating, Tooltip, Timeline, Popover } from '@douyinfe/semi-ui';
+import { IconSemiLogo, IconCamera, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting, IconEdit, IconList } from '@douyinfe/semi-icons';
 () => {
     const { Header, Footer, Sider, Content } = Layout;
     const [mode, setMode] = useState('semi-always-dark');
@@ -210,8 +209,10 @@ import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, Ic
                             }}
                         >
                             <Row style={rowStyle}>
+                                <div id='popup-layer'></div>
                                 <Nav
                                     mode={'horizontal'}
+                                    getPopupContainer={() => document.querySelector('#popup-layer')}
                                     items={[
                                         { itemKey: 'user', text: 'Option1', icon: <IconEdit /> },
                                         { itemKey: 'union', text: 'Option2', icon: <IconCamera /> },
@@ -330,6 +331,6 @@ import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, Ic
                 </Footer>
             </Layout>
         </>
-    )
-}
+    );
+};
 ```

+ 5 - 3
content/start/dark-mode/index.md

@@ -51,7 +51,7 @@ function Demo() {
             body.setAttribute('theme-mode', 'dark');
             window.setMode('dark');
         }
-    }
+    };
 
     return (
         <Button
@@ -99,8 +99,8 @@ Semi 2.0 原生支持局部暗色/亮色模式。使用时,在顶级元素上
 
 ```jsx live=true dir="column" hideInDSM
 import React from 'react';
-import { Layout, Nav, Button, Breadcrumb, Avatar } from '@douyinfe/semi-ui';
-import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting } from '@douyinfe/semi-icons';
+import { Layout, Nav, Button, Breadcrumb, Avatar, Steps, Pagination, Row, Badge, Tag, Rating, Tooltip, Timeline, Popover } from '@douyinfe/semi-ui';
+import { IconSemiLogo, IconCamera, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting, IconEdit, IconList } from '@douyinfe/semi-icons';
 
 () => {
     const { Header, Footer, Sider, Content } = Layout;
@@ -214,8 +214,10 @@ import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, Ic
                             }}
                         >
                             <Row style={rowStyle}>
+                                <div id='popup-layer'></div>
                                 <Nav
                                     mode={'horizontal'}
+                                    getPopupContainer={() => document.querySelector('#popup-layer')}
                                     items={[
                                         { itemKey: 'user', text: 'Option1', icon: <IconEdit /> },
                                         { itemKey: 'union', text: 'Option2', icon: <IconCamera /> },

+ 5 - 1
packages/semi-ui/navigation/SubNav.tsx

@@ -315,7 +315,7 @@ export default class SubNav extends BaseComponent<SubNavProps, SubNavState> {
         let _elem: React.ReactNode = elem;
         const { children, dropdownStyle, disabled } = this.props;
 
-        const { mode, isInSubNav, isCollapsed, subNavCloseDelay, subNavOpenDelay, prefixCls } = this.context;
+        const { mode, isInSubNav, isCollapsed, subNavCloseDelay, subNavOpenDelay, prefixCls, getPopupContainer } = this.context;
 
         const isOpen = this.adapter.getIsOpen();
         const openKeysIsControlled = this.adapter.getOpenKeysIsControlled();
@@ -334,6 +334,10 @@ export default class SubNav extends BaseComponent<SubNavProps, SubNavState> {
             dropdownProps.visible = isOpen;
         }
 
+        if (getPopupContainer) {
+            dropdownProps.getPopupContainer = getPopupContainer;
+        }
+
         if (isCollapsed || mode === strings.MODE_HORIZONTAL) {
             // Do not show dropdown when disabled
             _elem = !disabled ? (

+ 40 - 0
packages/semi-ui/navigation/_story/Popup/index.jsx

@@ -0,0 +1,40 @@
+import React from 'react';
+import { Nav } from '@douyinfe/semi-ui';
+import { IconUser, IconStar, IconUserGroup, IconEdit, IconApps, IconSetting } from '@douyinfe/semi-icons';
+
+export default function GetPopupNav() {
+    const items = [
+        { itemKey: 'user', text: '用户管理', icon: <IconUser />, disabled: true },
+        { itemKey: 'union', text: '公会中心', icon: <IconStar /> },
+        {
+            text: '任务平台',
+            icon: <IconSetting />,
+            itemKey: 'job',
+            disabled: true,
+            items: [{ itemKey: 'job_manage', text: '任务管理', disabled: true }, '用户任务查询'],
+        },
+        {
+            text: '收藏夹',
+            icon: <IconStar />,
+            itemKey: 'star',
+            items: [{ itemKey: 'like', text: '我的喜欢', disabled: true }, '点赞'],
+        },
+    ];
+
+    return (
+        <div>
+            <div id={'con'} style={{ position: 'relative ' }}>
+            </div>
+            <Nav
+                items={items}
+                mode={'horizontal'}
+                defaultOpenKeys={['job', 'star']}
+                getPopupContainer={() => document.querySelector('#con')}
+                defaultSelectedKeys={['user']}
+                footer={{
+                    collapseButton: true,
+                }}
+            />
+        </div>
+    );
+}

+ 6 - 0
packages/semi-ui/navigation/_story/navigation.stories.jsx

@@ -11,6 +11,7 @@ import WithChildren from './WithChildren';
 import ItemsChange from './ItemsChange';
 import DisabledNav from './DisabledNav';
 import Button from '../../button';
+import GetPopupNav from './Popup';
 
 import {
   IconMail,
@@ -328,3 +329,8 @@ export const DisabledNavDemo = () => <DisabledNav />;
 DisabledNavDemo.story = {
   name: 'disabled nav'
 }
+
+export const PopupDemo = () => <GetPopupNav />;
+PopupDemo.story = {
+  name: 'getPopupContainer'
+}

+ 7 - 3
packages/semi-ui/navigation/index.tsx

@@ -63,6 +63,7 @@ export interface NavProps extends BaseProps {
     toggleIconPosition?: string;
     tooltipHideDelay?: number;
     tooltipShowDelay?: number;
+    getPopupContainer?: () => HTMLElement;
     onClick?: (data: { itemKey: React.ReactText; domEvent: MouseEvent; isOpen: boolean }) => void;
     onCollapseChange?: (isCollapse: boolean) => void;
     onDeselect?: (data?: any) => void;
@@ -147,7 +148,8 @@ class Nav extends BaseComponent<NavProps, NavState> {
         prefixCls: PropTypes.string,
         header: PropTypes.oneOfType([PropTypes.node, PropTypes.object]),
         footer: PropTypes.oneOfType([PropTypes.node, PropTypes.object]),
-        limitIndent: PropTypes.bool
+        limitIndent: PropTypes.bool,
+        getPopupContainer: PropTypes.func,
     };
 
     static defaultProps = {
@@ -301,7 +303,8 @@ class Nav extends BaseComponent<NavProps, NavState> {
             header,
             toggleIconPosition,
             limitIndent,
-            renderWrapper
+            renderWrapper,
+            getPopupContainer
         } = this.props;
 
         const { selectedKeys, openKeys, items, isCollapsed } = this.state;
@@ -400,7 +403,8 @@ class Nav extends BaseComponent<NavProps, NavState> {
                             prefixCls,
                             toggleIconPosition,
                             limitIndent,
-                            renderWrapper
+                            renderWrapper,
+                            getPopupContainer
                         } as any}
                     >
                         <div className={finalCls} style={finalStyle}>

+ 4 - 2
packages/semi-ui/navigation/nav-context.ts

@@ -1,8 +1,9 @@
 import React from 'react';
 
-import { NavProps } from './index';
+import type { NavProps } from './index';
 import { Locale } from '../locale/interface';
  
+import type { DropdownProps } from '../dropdown';
 export interface NavContextType {
     isCollapsed?: boolean;
     mode?: NavProps['mode'];
@@ -20,7 +21,8 @@ export interface NavContextType {
     subNavCloseDelay?: NavProps['subNavCloseDelay'];
     subNavOpenDelay?: NavProps['subNavOpenDelay'];
     canUpdateOpenKeys?: boolean;
-    renderWrapper?: NavProps['renderWrapper']
+    renderWrapper?: NavProps['renderWrapper'];
+    getPopupContainer?: DropdownProps['getPopupContainer']
 }
 
 const NavContext = React.createContext<NavContextType>({