Skip to content

Commit

Permalink
fix: sepatare TreeViewTitle to standalone component
Browse files Browse the repository at this point in the history
  • Loading branch information
asabotovich committed Sep 16, 2024
1 parent f5e16e9 commit e001280
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 29 deletions.
14 changes: 9 additions & 5 deletions src/harmony/TreeView/TreeView.stories.tsx
Original file line number Diff line number Diff line change
@@ -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<typeof TreeView> = {
title: '@Harmony/TreeView',
Expand All @@ -17,22 +17,26 @@ export const Default: Story = {
return (
<div style={{ padding: '100px' }}>
<TreeView>
<TreeViewNode title="Project 1">
<TreeViewNode title={<TreeViewTitle>Project 1</TreeViewTitle>}>
<TreeViewElement>Goal 1.1</TreeViewElement>
<TreeViewElement>Goal 1.2</TreeViewElement>
<TreeViewNode
title={
<div style={{ padding: '8px 12px', background: 'var(--gray-700)' }}>Project 1.2</div>
<TreeViewTitle>
<div style={{ padding: '8px 12px', background: 'var(--gray-700)' }}>
Project 1.2
</div>
</TreeViewTitle>
}
>
<TreeViewElement>Goal 1.1.1</TreeViewElement>
<TreeViewElement>Goal 1.2.1</TreeViewElement>
<TreeViewNode title="Project 1.2.1">
<TreeViewNode title={<TreeViewTitle>Project 1.2.1</TreeViewTitle>}>
<TreeViewElement>Goal 1.2.1.1</TreeViewElement>
</TreeViewNode>
</TreeViewNode>
</TreeViewNode>
<TreeViewNode title="Project 2" visible>
<TreeViewNode title={<TreeViewTitle>Project 2</TreeViewTitle>} visible>
<TreeViewElement>Goal 2.1</TreeViewElement>
<TreeViewElement>Goal 2.2</TreeViewElement>
</TreeViewNode>
Expand Down
72 changes: 49 additions & 23 deletions src/harmony/TreeView/TreeView.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -17,6 +17,14 @@ interface TreeViewNodeProps {
onHide?: () => void;
}

interface TreeViewContext {
visible?: boolean;
interactive?: boolean;
onTitleClick?: () => void;
}

const treeViewContext = createContext<TreeViewContext>({});

interface TreeViewProps extends React.HTMLAttributes<HTMLDivElement> {}

export const TreeView: FC<TreeViewProps> = ({ children, ...rest }) => {
Expand All @@ -31,6 +39,23 @@ export const TreeViewElement: FC<TreeViewProps> = ({ children, className, ...res
);
};

interface TreeViewTitleProps extends React.HTMLAttributes<HTMLDivElement> {}

export const TreeViewTitle: FC<TreeViewTitleProps> = ({ children, className }) => {
const { interactive, onTitleClick, visible } = useContext(treeViewContext);

return (
<div className={cn(s.TreeViewTitle, className)} onClick={interactive ? onTitleClick : undefined}>
<IconRightSmallOutline
className={cn([s.Icon, { [s.Icon_transform]: visible }])}
size="s"
onClick={interactive ? undefined : onTitleClick}
/>
<div className={s.TreeViewTitleContent}>{children}</div>
</div>
);
};

export const TreeViewNode: React.FC<TreeViewNodeProps> = ({
title,
children,
Expand All @@ -42,30 +67,31 @@ export const TreeViewNode: React.FC<TreeViewNodeProps> = ({
}) => {
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 (
<div className={className}>
<div className={s.TreeViewTitle} onClick={interactive ? onClick : undefined}>
<IconRightSmallOutline
className={cn([s.Icon, { [s.Icon_transform]: visible }])}
size="s"
onClick={interactive ? undefined : onClick}
/>
<div className={s.TreeViewTitleContent}>{title}</div>
<treeViewContext.Provider value={context}>
<div className={className}>
{title}
{nullable(visible && children, () => (
<div className={s.TreeViewContent}>{children}</div>
))}
</div>

{nullable(visible && children, () => (
<div className={s.TreeViewContent}>{children}</div>
))}
</div>
</treeViewContext.Provider>
);
};
2 changes: 1 addition & 1 deletion src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -11,4 +12,3 @@ export * from './useOfflineDetector';
export * from './usePortal';
export * from './useUpload';
export * from './useUrlParams';
export * from './useIntersectionLoader';

0 comments on commit e001280

Please sign in to comment.