From 32cbb54fe558a52ac389f16eaa6f83a7e8429562 Mon Sep 17 00:00:00 2001 From: roseline124 Date: Thu, 4 Sep 2025 18:50:09 +0900 Subject: [PATCH 1/2] fix: Bug where the dropdown icon did not appear in the branch --- src/tree/RootTreeContext.tsx | 2 ++ src/tree/Tree.stories.tsx | 7 +++---- src/tree/Tree.tsx | 13 ++++--------- src/tree/TreeItem.tsx | 4 ++-- src/tree/TreeItemLayout.tsx | 4 ++-- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/tree/RootTreeContext.tsx b/src/tree/RootTreeContext.tsx index 830010b..9f267b7 100644 --- a/src/tree/RootTreeContext.tsx +++ b/src/tree/RootTreeContext.tsx @@ -2,11 +2,13 @@ import * as React from 'react'; export interface RootTreeContextValue { open?: boolean; + dropDownIcon?: React.ReactNode; } export const RootTreeContext = React.createContext( { open: false, + dropDownIcon: '▶', } ); diff --git a/src/tree/Tree.stories.tsx b/src/tree/Tree.stories.tsx index 0618b7d..000b0d6 100644 --- a/src/tree/Tree.stories.tsx +++ b/src/tree/Tree.stories.tsx @@ -28,9 +28,8 @@ export default meta; type Story = StoryObj; export const Default: Story = { - args: { - 'aria-label': 'Default', - children: ( + render: () => { + return ( customer id: 1234567890 @@ -63,6 +62,6 @@ export const Default: Story = { - ), + ); }, }; diff --git a/src/tree/Tree.tsx b/src/tree/Tree.tsx index a9f9065..fc89a1b 100644 --- a/src/tree/Tree.tsx +++ b/src/tree/Tree.tsx @@ -27,8 +27,8 @@ const RootTree = ({ ...props }: TreeProps) => { return ( - - + +
{children}
@@ -37,14 +37,9 @@ const RootTree = ({ ); }; -const SubTree = ({ - children, - className = '', - dropDownIcon, - ...props -}: TreeProps) => { +const SubTree = ({ children, className = '', ...props }: TreeProps) => { return ( - +
{children}
diff --git a/src/tree/TreeItem.tsx b/src/tree/TreeItem.tsx index a1fe716..984bd35 100644 --- a/src/tree/TreeItem.tsx +++ b/src/tree/TreeItem.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; -import { TreeItemContext } from './TreeItemContext'; import { useRootTreeContext } from './RootTreeContext'; import './TreeItem.css'; +import { TreeItemContext } from './TreeItemContext'; export interface TreeItemProps { itemType: 'leaf' | 'branch'; @@ -37,7 +37,7 @@ export const TreeItem = ({
{React.Children.map(children, (child, level) => { if (level === 0) { diff --git a/src/tree/TreeItemLayout.tsx b/src/tree/TreeItemLayout.tsx index dcf7eb5..fa13872 100644 --- a/src/tree/TreeItemLayout.tsx +++ b/src/tree/TreeItemLayout.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { useTreeItemContext } from './TreeItemContext'; import './TreeItemLayout.css'; -import { useSubTreeContext } from './SubTreeContext'; +import { useRootTreeContext } from './RootTreeContext'; export interface TreeItemLayoutProps extends React.HTMLAttributes { @@ -14,8 +14,8 @@ export const TreeItemLayout = ({ className = '', ...props }: TreeItemLayoutProps) => { - const { dropDownIcon } = useSubTreeContext(); const { itemType, isOpen, onToggle } = useTreeItemContext(); + const { dropDownIcon } = useRootTreeContext(); return (
Date: Thu, 4 Sep 2025 19:01:12 +0900 Subject: [PATCH 2/2] fix: add level to tree item layout --- src/tree/Tree.tsx | 19 +++++++++++++------ src/tree/TreeItem.tsx | 12 +++++++----- src/tree/TreeItemContext.tsx | 1 + src/tree/TreeItemLayout.tsx | 4 +++- src/tree/TreeLevelContext.tsx | 15 +++++++++++++++ src/tree/index.ts | 2 +- 6 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 src/tree/TreeLevelContext.tsx diff --git a/src/tree/Tree.tsx b/src/tree/Tree.tsx index fc89a1b..609676b 100644 --- a/src/tree/Tree.tsx +++ b/src/tree/Tree.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { RootTreeContext } from './RootTreeContext'; import { SubTreeContext } from './SubTreeContext'; +import { TreeLevelContext } from './TreeLevelContext'; // Tree 컴포넌트의 Props 타입 export interface TreeProps { @@ -29,20 +30,26 @@ const RootTree = ({ return ( -
- {children} -
+ +
+ {children} +
+
); }; const SubTree = ({ children, className = '', ...props }: TreeProps) => { + const { level } = React.useContext(TreeLevelContext); + return ( -
- {children} -
+ +
+ {children} +
+
); }; diff --git a/src/tree/TreeItem.tsx b/src/tree/TreeItem.tsx index 984bd35..dd1181e 100644 --- a/src/tree/TreeItem.tsx +++ b/src/tree/TreeItem.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { useRootTreeContext } from './RootTreeContext'; import './TreeItem.css'; import { TreeItemContext } from './TreeItemContext'; +import { useTreeLevelContext } from './TreeLevelContext'; export interface TreeItemProps { itemType: 'leaf' | 'branch'; @@ -15,6 +16,7 @@ export const TreeItem = ({ className = '', }: TreeItemProps) => { const { open: defaultOpen } = useRootTreeContext(); + const { level } = useTreeLevelContext(); const [isOpen, setIsOpen] = React.useState(defaultOpen ?? false); const handleToggle = React.useCallback(() => { @@ -28,8 +30,9 @@ export const TreeItem = ({ itemType, isOpen, onToggle: handleToggle, + level, }), - [itemType, isOpen, handleToggle] + [itemType, isOpen, handleToggle, level] ); return ( @@ -39,18 +42,17 @@ export const TreeItem = ({ aria-expanded={itemType === 'branch' ? isOpen : undefined} className={`tree-item ${className}`} > - {React.Children.map(children, (child, level) => { - if (level === 0) { + {React.Children.map(children, (child, childIndex) => { + if (childIndex === 0) { // 첫 번째 자식은 TreeItemLayout (노드 자체) return child; - } else if (level === 1 && itemType === 'branch') { + } else if (childIndex === 1 && itemType === 'branch') { // 두 번째 자식은 중첩된 Tree (자식들) return (
{child} diff --git a/src/tree/TreeItemContext.tsx b/src/tree/TreeItemContext.tsx index 1283a05..b2a89b8 100644 --- a/src/tree/TreeItemContext.tsx +++ b/src/tree/TreeItemContext.tsx @@ -4,6 +4,7 @@ export interface TreeItemContextValue { itemType: 'leaf' | 'branch'; isOpen: boolean; onToggle: () => void; + level: number; } export const TreeItemContext = React.createContext( diff --git a/src/tree/TreeItemLayout.tsx b/src/tree/TreeItemLayout.tsx index fa13872..3801161 100644 --- a/src/tree/TreeItemLayout.tsx +++ b/src/tree/TreeItemLayout.tsx @@ -14,7 +14,7 @@ export const TreeItemLayout = ({ className = '', ...props }: TreeItemLayoutProps) => { - const { itemType, isOpen, onToggle } = useTreeItemContext(); + const { itemType, isOpen, onToggle, level } = useTreeItemContext(); const { dropDownIcon } = useRootTreeContext(); return ( @@ -25,6 +25,8 @@ export const TreeItemLayout = ({ : 'tree-item-layout-leaf' } ${className}`} onClick={itemType === 'branch' ? onToggle : undefined} + data-level={level} + style={{ paddingLeft: `${level * 1.5}rem` }} {...props} > {itemType === 'branch' && ( diff --git a/src/tree/TreeLevelContext.tsx b/src/tree/TreeLevelContext.tsx new file mode 100644 index 0000000..1bf354e --- /dev/null +++ b/src/tree/TreeLevelContext.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; + +export interface TreeLevelContextValue { + level: number; +} + +export const TreeLevelContext = React.createContext({ + level: 0, +}); + +export const useTreeLevelContext = () => { + return React.useContext(TreeLevelContext); +}; + +TreeLevelContext.displayName = 'TreeLevelContext'; diff --git a/src/tree/index.ts b/src/tree/index.ts index d2363bc..e33eefd 100644 --- a/src/tree/index.ts +++ b/src/tree/index.ts @@ -5,4 +5,4 @@ export * from './TreeWithJson'; export * from './TreeItemContext'; export * from './RootTreeContext'; export * from './SubTreeContext'; -export * from './Tree'; +export * from './TreeLevelContext';