From 22ecb2bbca154f51356010633fcc2020c7ea2fd7 Mon Sep 17 00:00:00 2001 From: LuckyFBB <976060700@qq.com> Date: Wed, 6 Mar 2024 20:25:13 +0800 Subject: [PATCH 1/3] feat(slidepane): support tab control --- src/slidePane/demos/tabs.tsx | 3 +- src/slidePane/demos/tabsControl.tsx | 44 +++++++++++++++++++++++++++++ src/slidePane/index.md | 25 ++++++++-------- src/slidePane/index.tsx | 29 +++++++++++++++---- 4 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 src/slidePane/demos/tabsControl.tsx 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..4e1cf0811 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 { return typeof props.children === 'function'; } +function isTabMode(props: any): props is TabsSlidePane { + return props.tabs !== 'undefined'; +} + +function isControlled(props: any): props is TabsSlidePane { + return props.activeKey !== undefined; +} + export type SlidePaneProps = TabsSlidePane | NormalSlidePane; const getWidthFromSize = (size: NormalSlidePane['size']) => { @@ -74,14 +84,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) => { {isFunction(props) && ( {props.tabs?.map((tab: { key: string; title: React.ReactNode }) => ( @@ -130,7 +147,7 @@ const SlidePane = (props: SlidePaneProps) => { className={classNames(`${slidePrefixCls}-body`, bodyClassName)} style={bodyStyle} > - {typeof children === 'function' ? children(tabKey) : children} + {typeof children === 'function' ? children(currentKey ?? '') : children} {footer ? (
{footer}
From 34418aa2819e0963d153d1a6a6090dde5597ba5b Mon Sep 17 00:00:00 2001 From: LuckyFBB <976060700@qq.com> Date: Fri, 26 Apr 2024 10:42:18 +0800 Subject: [PATCH 2/3] fix(slidepane): update isTabMode judge --- src/slidePane/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slidePane/index.tsx b/src/slidePane/index.tsx index 4e1cf0811..398cf6e9c 100644 --- a/src/slidePane/index.tsx +++ b/src/slidePane/index.tsx @@ -41,7 +41,7 @@ function isFunction(props: any): props is TabsSlidePane { } function isTabMode(props: any): props is TabsSlidePane { - return props.tabs !== 'undefined'; + return typeof props.tabs !== 'undefined'; } function isControlled(props: any): props is TabsSlidePane { From ee3538873f0701fa4029542bc8ef3c235f906f07 Mon Sep 17 00:00:00 2001 From: LuckyFBB <976060700@qq.com> Date: Thu, 29 Aug 2024 18:38:45 +0800 Subject: [PATCH 3/3] fix(slidepane): change ts judge --- src/slidePane/index.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slidePane/index.tsx b/src/slidePane/index.tsx index 398cf6e9c..a0d7f8f74 100644 --- a/src/slidePane/index.tsx +++ b/src/slidePane/index.tsx @@ -36,16 +36,16 @@ interface TabsSlidePane extends Omit) => void; } -function isFunction(props: any): props is TabsSlidePane { +function isFunction(props: SlidePaneProps): props is TabsSlidePane { return typeof props.children === 'function'; } -function isTabMode(props: any): props is TabsSlidePane { - return typeof props.tabs !== 'undefined'; +function isTabMode(props: SlidePaneProps): props is TabsSlidePane { + return 'tabs' in props; } -function isControlled(props: any): props is TabsSlidePane { - return props.activeKey !== undefined; +function isControlled(props: SlidePaneProps): props is TabsSlidePane { + return 'activeKey' in props; } export type SlidePaneProps = TabsSlidePane | NormalSlidePane; @@ -74,7 +74,6 @@ const SlidePane = (props: SlidePaneProps) => { title, width, size = 'default', - children, footer, banner, onClose, @@ -131,7 +130,7 @@ const SlidePane = (props: SlidePaneProps) => { {...(isValidBanner(banner) ? {} : omit(banner, 'message'))} /> )} - {isFunction(props) && ( + {isTabMode(props) && ( (props: SlidePaneProps) => { className={classNames(`${slidePrefixCls}-body`, bodyClassName)} style={bodyStyle} > - {typeof children === 'function' ? children(currentKey ?? '') : children} + {isFunction(props) ? props.children?.(currentKey ?? '') : props.children} {footer ? (
{footer}