-
Notifications
You must be signed in to change notification settings - Fork 46
/
Tree.tsx
141 lines (131 loc) · 3.94 KB
/
Tree.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { Omit } from "emotion-theming/types/helper"
import * as React from "react"
import { Draggable, DraggableProps, Droppable, DroppableProps, DroppableStateSnapshot } from "react-beautiful-dnd"
import styled from "../utils/styled"
import ChildTree from "./ChildTree"
import { IconComponentType } from "../Icon"
interface BaseTree {
label: string
key?: string | number
paddingLeft?: number
paddingRight?: number
highlight?: boolean
initiallyOpen?: boolean
tag?: string
tagColor?: string
disabled?: boolean
icon?: IconComponentType
iconColor?: string
onClick?: (event: React.MouseEvent) => void
onContextMenu?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
cursor?: string
actions?: React.ReactNode
forwardRef?: (element?: HTMLElement | null) => any
strong?: boolean
fontSize?: number
fontColor?: string
emphasized?: boolean
monospace?: boolean
ignoreSearchWords?: boolean
}
interface TreeWithChildren extends BaseTree {
childNodes?: Tree[]
draggableProps?: never
droppableProps?: Omit<DroppableProps, "children">
}
interface TreeWithoutChildren extends BaseTree {
childNodes?: never
draggableProps?: Omit<DraggableProps, "children" | "index">
droppableProps?: never
}
export type Tree = TreeWithChildren | TreeWithoutChildren
export interface TreeProps {
trees: Tree[]
paddingLeft?: number
paddingRight?: number
searchWords?: string[]
droppableProps?: Omit<DroppableProps, "children">
placeholder?: React.ComponentType<DroppableStateSnapshot>
freeze?: boolean
_level?: number
_hasIconOffset?: boolean
}
const Container = styled.div`
label: TreeContainer;
user-select: none;
`
const Tree: React.SFC<TreeProps> = ({
_level = 0,
_hasIconOffset = false,
paddingLeft,
paddingRight,
trees,
droppableProps,
placeholder,
searchWords,
freeze,
}) => {
const isLowestLevel = trees.length === 0 || trees.some(tree => !tree.childNodes || !tree.childNodes.length)
/**
* If this is a category with children, no drag and drop
* because only children can be dragged/sorted.
*/
if (!isLowestLevel || !droppableProps) {
return (
<Container>
{trees.map((treeData, index) => (
<ChildTree
paddingLeft={paddingLeft}
paddingRight={paddingRight}
level={_level}
hasIconOffset={_hasIconOffset}
key={index}
{...treeData}
searchWords={searchWords}
freeze={freeze}
/>
))}
</Container>
)
}
return (
<Droppable {...droppableProps}>
{(droppableProvided, droppableSnapshot) => (
<Container ref={droppableProvided.innerRef} {...droppableProvided.droppableProps}>
{trees.length ? (
<>
{trees.map((treeData, index) => (
<Draggable
key={treeData.key !== undefined ? treeData.key : index}
{...treeData.draggableProps || { draggableId: treeData.label }}
index={index}
>
{draggableProvided => {
return (
<ChildTree
paddingLeft={paddingLeft}
paddingRight={paddingRight}
hasIconOffset={_hasIconOffset}
level={_level}
forwardRef={draggableProvided.innerRef}
searchWords={searchWords}
freeze={freeze}
{...treeData}
{...draggableProvided.draggableProps}
{...draggableProvided.dragHandleProps}
/>
)
}}
</Draggable>
))}
</>
) : (
placeholder && React.createElement(placeholder, droppableSnapshot)
)}
{droppableProvided.placeholder}
</Container>
)}
</Droppable>
)
}
export default Tree