diff --git a/src/slidePane/demos/tabs.tsx b/src/slidePane/demos/tabs.tsx index b5f21b51e..ceae0d040 100644 --- a/src/slidePane/demos/tabs.tsx +++ b/src/slidePane/demos/tabs.tsx @@ -24,7 +24,8 @@ export default () => { }, ] as const } - activeKey="changelog" + defaultKey="changelog" + onChange={(key) => console.log('currentKey', key)} > {(key) => { switch (key) { diff --git a/src/slidePane/demos/tabsControl.tsx b/src/slidePane/demos/tabsControl.tsx new file mode 100644 index 000000000..a20c3dd36 --- /dev/null +++ b/src/slidePane/demos/tabsControl.tsx @@ -0,0 +1,44 @@ +import React, { useState } from 'react'; +import { Button } from 'antd'; +import { SlidePane } from 'dt-react-component'; + +export default () => { + const [visible, setVisible] = useState(false); + const [activeKey, setActiveKey] = useState<'basicInfo' | 'changelog'>('changelog'); + + return ( + <> + + setVisible(false)} + title={'Title'} + tabs={ + [ + { + key: 'basicInfo', + title: '基本信息', + }, + { + key: 'changelog', + title: '变更记录', + }, + ] as const + } + activeKey={activeKey} + onChange={(key) => setActiveKey(key)} + > + {(key) => { + switch (key) { + case 'basicInfo': + return
基本信息
; + case 'changelog': + return
变更记录
; + default: + break; + } + }} +
+ + ); +}; diff --git a/src/slidePane/index.md b/src/slidePane/index.md index 3bd24d131..f3a13e93a 100644 --- a/src/slidePane/index.md +++ b/src/slidePane/index.md @@ -21,6 +21,7 @@ demo: + @@ -31,17 +32,19 @@ demo: [AlertProps](https://4x-ant-design.antgroup.com/components/alert-cn/#API) -| 参数 | 说明 | 类型 | 默认值 | -| ------------- | ------------------------------ | ----------------------------------------------------- | --------- | -| activeKeys | 右侧面板的内容的 Tabs 的选中项 | `string` | - | -| banner | 提示 | `React.ReactNode \| AlertProps` | - | -| bodyClassName | 内容容器的类名 | `string` | - | -| bodyStyle | 内容容器的样式 | `CSSProperties` | - | -| children | 右侧面板展示内容 | `(key: string) => React.ReactNode \| React.ReactNode` | - | -| footer | 右侧面板的底部内容 | `React.ReactNode` | - | -| size | 尺寸 | `'small' \| 'default' \| 'large'` | `default` | -| tabs | 右侧面板的内容的 Tabs | `{ key: string; title: React.ReactNode }[]` | - | -| title | 右侧面板的 title | `React.ReactNode` | - | +| 参数 | 说明 | 类型 | 默认值 | +| ------------- | ---------------------------------- | ----------------------------------------------------- | --------- | +| activeKey | 右侧面板的内容的 Tabs 的选中项 | `string` | - | +| banner | 提示 | `React.ReactNode \| AlertProps` | - | +| bodyClassName | 内容容器的类名 | `string` | - | +| bodyStyle | 内容容器的样式 | `CSSProperties` | - | +| children | 右侧面板展示内容 | `(key: string) => React.ReactNode \| React.ReactNode` | - | +| defaultKey | 右侧面板的内容的 Tabs 的默认选中项 | `string` | - | +| footer | 右侧面板的底部内容 | `React.ReactNode` | - | +| size | 尺寸 | `small \| default \| large` | `default` | +| tabs | 右侧面板的内容的 Tabs | `{ key: string; title: React.ReactNode }[]` | - | +| title | 右侧面板的 title | `React.ReactNode` | - | +| onChange | 右侧面板的 Tabs 切换回调 | `(key: string) => void` | - | :::info 其余属性继承 [antd4.x 的 Drawer](https://4x.ant.design/components/drawer-cn/#API) diff --git a/src/slidePane/index.tsx b/src/slidePane/index.tsx index 2e0c080f0..a0d7f8f74 100644 --- a/src/slidePane/index.tsx +++ b/src/slidePane/index.tsx @@ -30,14 +30,24 @@ interface NormalSlidePane extends Omit { interface TabsSlidePane extends Omit { tabs?: T; + defaultKey?: TabKey; activeKey?: TabKey; children?: (key: TabKey) => React.ReactNode; + onChange?: (key: TabKey) => void; } -function isFunction(props: any): props is TabsSlidePane { +function isFunction(props: SlidePaneProps): props is TabsSlidePane { return typeof props.children === 'function'; } +function isTabMode(props: SlidePaneProps): props is TabsSlidePane { + return 'tabs' in props; +} + +function isControlled(props: SlidePaneProps): props is TabsSlidePane { + return 'activeKey' in props; +} + export type SlidePaneProps = TabsSlidePane | NormalSlidePane; const getWidthFromSize = (size: NormalSlidePane['size']) => { @@ -64,7 +74,6 @@ const SlidePane = (props: SlidePaneProps) => { title, width, size = 'default', - children, footer, banner, onClose, @@ -74,14 +83,16 @@ const SlidePane = (props: SlidePaneProps) => { const composeOpen = open || visible; const finalWidth = width ?? getWidthFromSize(size); - const [tabKey, setTabKey] = useState(''); + const [internalTabKey, setInternalTabKey] = useState(''); useEffect(() => { composeOpen && - isFunction(props) && - setTabKey(props.activeKey || props.tabs?.[0]?.key || ''); + isTabMode(props) && + setInternalTabKey(props.defaultKey ?? props.tabs?.[0]?.key ?? ''); }, [composeOpen]); + const currentKey = isControlled(props) ? props.activeKey : internalTabKey; + const renderButton = () => { return ( (props: SlidePaneProps) => { ); }; + const handleChangeKey = (key: TabKey) => { + !isControlled(props) && setInternalTabKey(key); + isTabMode(props) && props.onChange?.(key); + }; + return ( (props: SlidePaneProps) => { {...(isValidBanner(banner) ? {} : omit(banner, 'message'))} /> )} - {isFunction(props) && ( + {isTabMode(props) && ( {props.tabs?.map((tab: { key: string; title: React.ReactNode }) => ( @@ -130,7 +146,7 @@ const SlidePane = (props: SlidePaneProps) => { className={classNames(`${slidePrefixCls}-body`, bodyClassName)} style={bodyStyle} > - {typeof children === 'function' ? children(tabKey) : children} + {isFunction(props) ? props.children?.(currentKey ?? '') : props.children} {footer ? (
{footer}