diff --git a/src/harmony/TreeView/TreeView.stories.tsx b/src/harmony/TreeView/TreeView.stories.tsx index 2654f72b..d25b2093 100644 --- a/src/harmony/TreeView/TreeView.stories.tsx +++ b/src/harmony/TreeView/TreeView.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; -import { TreeView, TreeViewElement, TreeViewNode } from './TreeView'; +import { TreeView, TreeViewElement, TreeViewNode, TreeViewTitle } from './TreeView'; const meta: Meta = { title: '@Harmony/TreeView', @@ -17,22 +17,26 @@ export const Default: Story = { return (
- + Project 1}> Goal 1.1 Goal 1.2 Project 1.2
+ +
+ Project 1.2 +
+
} > Goal 1.1.1 Goal 1.2.1 - + Project 1.2.1}> Goal 1.2.1.1 - + Project 2} visible> Goal 2.1 Goal 2.2 diff --git a/src/harmony/TreeView/TreeView.tsx b/src/harmony/TreeView/TreeView.tsx index 90560b6f..f43264a2 100644 --- a/src/harmony/TreeView/TreeView.tsx +++ b/src/harmony/TreeView/TreeView.tsx @@ -1,4 +1,4 @@ -import React, { FC, ReactNode, useCallback, useState } from 'react'; +import React, { createContext, FC, ReactNode, useContext, useMemo, useState } from 'react'; import { IconRightSmallOutline } from '@taskany/icons'; import cn from 'classnames'; @@ -17,6 +17,14 @@ interface TreeViewNodeProps { onHide?: () => void; } +interface TreeViewContext { + visible?: boolean; + interactive?: boolean; + onTitleClick?: () => void; +} + +const treeViewContext = createContext({}); + interface TreeViewProps extends React.HTMLAttributes {} export const TreeView: FC = ({ children, ...rest }) => { @@ -31,6 +39,23 @@ export const TreeViewElement: FC = ({ children, className, ...res ); }; +interface TreeViewTitleProps extends React.HTMLAttributes {} + +export const TreeViewTitle: FC = ({ children, className }) => { + const { interactive, onTitleClick, visible } = useContext(treeViewContext); + + return ( +
+ +
{children}
+
+ ); +}; + export const TreeViewNode: React.FC = ({ title, children, @@ -42,30 +67,31 @@ export const TreeViewNode: React.FC = ({ }) => { const [visible, setVisible] = useState(defaultVisible); - const onClick = useCallback(() => { - if (!visible && children) { - setVisible(true); - onShow?.(); - } else { - setVisible(false); - onHide?.(); - } - }, [visible, children, setVisible, onHide, onShow]); + const context = useMemo( + () => ({ + visible, + interactive, + onTitleClick: () => { + if (!visible && children) { + setVisible(true); + onShow?.(); + } else { + setVisible(false); + onHide?.(); + } + }, + }), + [visible, children, setVisible, onHide, onShow, interactive], + ); return ( -
-
- -
{title}
+ +
+ {title} + {nullable(visible && children, () => ( +
{children}
+ ))}
- - {nullable(visible && children, () => ( -
{children}
- ))} -
+ ); }; diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 3643f04c..01fd1be3 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -3,6 +3,7 @@ export * from './useCopyToClipboard'; export * from './useEventCallback'; export * from './useForkedRef'; export * from './useHotkeys'; +export * from './useIntersectionLoader'; export * from './useKeyPress'; export * from './useKeyboard'; export * from './useLatest'; @@ -11,4 +12,3 @@ export * from './useOfflineDetector'; export * from './usePortal'; export * from './useUpload'; export * from './useUrlParams'; -export * from './useIntersectionLoader';