From 913d257265c8470b6c8edab749e61c241c8a6a7c Mon Sep 17 00:00:00 2001 From: Wroud Date: Sun, 6 Sep 2020 23:56:29 +0300 Subject: [PATCH] chore(core-blocks): Tabs context improvements --- .../packages/core-blocks/src/Tabs/Tab/Tab.tsx | 7 ++--- .../packages/core-blocks/src/Tabs/TabList.tsx | 2 +- .../core-blocks/src/Tabs/TabPanel.tsx | 27 ++++++++++++++----- .../core-blocks/src/Tabs/TabsContext.ts | 7 ++++- .../core-blocks/src/Tabs/TabsState.tsx | 22 ++++++++++++--- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/webapp/packages/core-blocks/src/Tabs/Tab/Tab.tsx b/webapp/packages/core-blocks/src/Tabs/Tab/Tab.tsx index 597f6226e9..cb6564ffb2 100644 --- a/webapp/packages/core-blocks/src/Tabs/Tab/Tab.tsx +++ b/webapp/packages/core-blocks/src/Tabs/Tab/Tab.tsx @@ -38,10 +38,11 @@ export function Tab({ const handleOpen = useCallback((e: React.MouseEvent) => { e.preventDefault(); + state.select(tabId); if (onOpen) { onOpen(tabId); } - }, [onOpen]); + }, [state, onOpen, tabId]); const handleClose = useCallback((e: React.MouseEvent) => { e.preventDefault(); @@ -49,11 +50,11 @@ export function Tab({ if (onClose) { onClose(tabId); } - }, [onClose]); + }, [onClose, tabId]); return styled(useStyles())( ; + return ; } diff --git a/webapp/packages/core-blocks/src/Tabs/TabPanel.tsx b/webapp/packages/core-blocks/src/Tabs/TabPanel.tsx index 1778a23ecc..181de874a1 100644 --- a/webapp/packages/core-blocks/src/Tabs/TabPanel.tsx +++ b/webapp/packages/core-blocks/src/Tabs/TabPanel.tsx @@ -7,22 +7,23 @@ */ import { observer } from 'mobx-react'; -import { - useContext, PropsWithChildren, -} from 'react'; -import { TabPanel as BaseTabPanel } from 'reakit/Tab'; +import { useContext } from 'react'; +import { TabPanel as BaseTabPanel, TabStateReturn } from 'reakit/Tab'; import { TabsContext } from './TabsContext'; -type TabProps = PropsWithChildren<{ +type TabProps = { tabId: string; className?: string; -}>; + children?: React.ReactNode | ((state: TabStateReturn) => React.ReactNode); + lazy?: boolean; +}; export const TabPanel = observer(function TabPanel({ tabId, children, className, + lazy, }: TabProps) { const state = useContext(TabsContext); @@ -30,8 +31,20 @@ export const TabPanel = observer(function TabPanel({ throw new Error('Tabs context was not provided'); } + if (lazy && state.state.selectedId !== tabId) { + return null; + } + + if (typeof children === 'function') { + return ( + + {children(state.state)} + + ); + } + return ( - + {children} ); diff --git a/webapp/packages/core-blocks/src/Tabs/TabsContext.ts b/webapp/packages/core-blocks/src/Tabs/TabsContext.ts index ff26a52a3f..c0f761e13d 100644 --- a/webapp/packages/core-blocks/src/Tabs/TabsContext.ts +++ b/webapp/packages/core-blocks/src/Tabs/TabsContext.ts @@ -9,6 +9,11 @@ import { createContext } from 'react'; import { TabStateReturn } from 'reakit/Tab'; -export const TabsContext = createContext( +export interface ITabsContext { + state: TabStateReturn; + select: (tabId: string) => any; +} + +export const TabsContext = createContext( undefined ); diff --git a/webapp/packages/core-blocks/src/Tabs/TabsState.tsx b/webapp/packages/core-blocks/src/Tabs/TabsState.tsx index 13853388fe..11fcda8188 100644 --- a/webapp/packages/core-blocks/src/Tabs/TabsState.tsx +++ b/webapp/packages/core-blocks/src/Tabs/TabsState.tsx @@ -6,36 +6,50 @@ * you may not use this file except in compliance with the License. */ -import { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useCallback } from 'react'; import { useTabState } from 'reakit/Tab'; -import { TabsContext } from './TabsContext'; +import { TabsContext, ITabsContext } from './TabsContext'; type Props = React.PropsWithChildren<{ selectedId?: string; orientation?: 'horizontal' | 'vertical'; currentTabId?: string | null; manual?: boolean; + onChange?: (tabId: string) => any; }> export function TabsState({ - selectedId, orientation, currentTabId, children, manual, + selectedId, + orientation, + currentTabId, + children, + manual, + onChange, }: Props) { const state = useTabState({ selectedId: selectedId || currentTabId, orientation, manual, }); + if (currentTabId) { state.selectedId = currentTabId; } + useEffect(() => { if (!currentTabId) { return; } state.select(currentTabId); }, [currentTabId]); // hack currentId and selectedId not works - const value = useMemo(() => state, Object.values(state)); + + const handleChange = useCallback((tabId: string) => onChange && onChange(tabId), [onChange]); + + const value = useMemo(() => ({ + state, + select: handleChange, + }), [...Object.values(state), handleChange]); return (