@veracity/vui 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/avatar/theme.d.ts +1 -0
- package/dist/cjs/avatar/theme.d.ts.map +1 -1
- package/dist/cjs/avatar/theme.js +2 -1
- package/dist/cjs/badge/theme.d.ts +1 -0
- package/dist/cjs/badge/theme.d.ts.map +1 -1
- package/dist/cjs/badge/theme.js +2 -1
- package/dist/cjs/button/theme.d.ts +1 -0
- package/dist/cjs/button/theme.d.ts.map +1 -1
- package/dist/cjs/button/theme.js +2 -1
- package/dist/cjs/divider/divider.js +1 -1
- package/dist/cjs/dragAndDrop/dragAndDrop.d.ts +1 -1
- package/dist/cjs/dragAndDrop/dragAndDrop.d.ts.map +1 -1
- package/dist/cjs/dragAndDrop/dragAndDrop.js +3 -3
- package/dist/cjs/dragAndDrop/dragAndDrop.types.d.ts +1 -1
- package/dist/cjs/dragAndDrop/dragAndDrop.types.d.ts.map +1 -1
- package/dist/cjs/dragAndDrop/theme.d.ts +18 -3
- package/dist/cjs/dragAndDrop/theme.d.ts.map +1 -1
- package/dist/cjs/dragAndDrop/theme.js +23 -3
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/input/consts.d.ts +17 -3
- package/dist/cjs/input/consts.d.ts.map +1 -1
- package/dist/cjs/input/consts.js +27 -13
- package/dist/cjs/input/helpText.js +2 -2
- package/dist/cjs/input/input.d.ts.map +1 -1
- package/dist/cjs/input/input.js +8 -11
- package/dist/cjs/input/input.types.d.ts +6 -6
- package/dist/cjs/input/input.types.d.ts.map +1 -1
- package/dist/cjs/input/inputIcon.d.ts.map +1 -1
- package/dist/cjs/input/inputIcon.js +2 -1
- package/dist/cjs/input/theme.d.ts +33 -17
- package/dist/cjs/input/theme.d.ts.map +1 -1
- package/dist/cjs/input/theme.js +32 -22
- package/dist/cjs/skeleton/skeleton.types.d.ts +1 -1
- package/dist/cjs/skeleton/skeleton.types.d.ts.map +1 -1
- package/dist/cjs/skeleton/theme.d.ts +10 -14
- package/dist/cjs/skeleton/theme.d.ts.map +1 -1
- package/dist/cjs/skeleton/theme.js +10 -21
- package/dist/cjs/tag/theme.d.ts +1 -0
- package/dist/cjs/tag/theme.d.ts.map +1 -1
- package/dist/cjs/tag/theme.js +2 -1
- package/dist/cjs/theme/components.d.ts +110 -19
- package/dist/cjs/theme/components.d.ts.map +1 -1
- package/dist/cjs/theme/components.js +3 -1
- package/dist/cjs/theme/defaultTheme.d.ts +110 -19
- package/dist/cjs/theme/defaultTheme.d.ts.map +1 -1
- package/dist/cjs/tooltip/tooltip.js +1 -1
- package/dist/cjs/tooltip/tooltipContent.d.ts +1 -1
- package/dist/cjs/tooltip/tooltipContent.d.ts.map +1 -1
- package/dist/cjs/tooltip/tooltipContent.js +1 -4
- package/dist/cjs/tree/context.d.ts +5 -0
- package/dist/cjs/tree/context.d.ts.map +1 -0
- package/dist/cjs/tree/context.js +7 -0
- package/dist/cjs/tree/index.d.ts +8 -0
- package/dist/cjs/tree/index.d.ts.map +1 -0
- package/dist/cjs/tree/index.js +28 -0
- package/dist/cjs/tree/theme.d.ts +59 -0
- package/dist/cjs/tree/theme.d.ts.map +1 -0
- package/dist/cjs/tree/theme.js +69 -0
- package/dist/cjs/tree/tree.d.ts +14 -0
- package/dist/cjs/tree/tree.d.ts.map +1 -0
- package/dist/cjs/tree/tree.js +116 -0
- package/dist/cjs/tree/tree.types.d.ts +58 -0
- package/dist/cjs/tree/tree.types.d.ts.map +1 -0
- package/dist/cjs/tree/tree.types.js +2 -0
- package/dist/cjs/tree/treeIcon.d.ts +5 -0
- package/dist/cjs/tree/treeIcon.d.ts.map +1 -0
- package/dist/cjs/tree/treeIcon.js +29 -0
- package/dist/cjs/tree/treeItem.d.ts +8 -0
- package/dist/cjs/tree/treeItem.d.ts.map +1 -0
- package/dist/cjs/tree/treeItem.js +131 -0
- package/dist/cjs/tree/treeText.d.ts +5 -0
- package/dist/cjs/tree/treeText.d.ts.map +1 -0
- package/dist/cjs/tree/treeText.js +29 -0
- package/dist/cjs/tree/useTreeState.d.ts +9 -0
- package/dist/cjs/tree/useTreeState.d.ts.map +1 -0
- package/dist/cjs/tree/useTreeState.js +10 -0
- package/dist/esm/avatar/theme.d.ts +1 -0
- package/dist/esm/avatar/theme.d.ts.map +1 -1
- package/dist/esm/avatar/theme.js +2 -1
- package/dist/esm/badge/theme.d.ts +1 -0
- package/dist/esm/badge/theme.d.ts.map +1 -1
- package/dist/esm/badge/theme.js +2 -1
- package/dist/esm/button/theme.d.ts +1 -0
- package/dist/esm/button/theme.d.ts.map +1 -1
- package/dist/esm/button/theme.js +2 -1
- package/dist/esm/divider/divider.js +1 -1
- package/dist/esm/dragAndDrop/dragAndDrop.d.ts +1 -1
- package/dist/esm/dragAndDrop/dragAndDrop.d.ts.map +1 -1
- package/dist/esm/dragAndDrop/dragAndDrop.js +3 -3
- package/dist/esm/dragAndDrop/dragAndDrop.types.d.ts +1 -1
- package/dist/esm/dragAndDrop/dragAndDrop.types.d.ts.map +1 -1
- package/dist/esm/dragAndDrop/theme.d.ts +18 -3
- package/dist/esm/dragAndDrop/theme.d.ts.map +1 -1
- package/dist/esm/dragAndDrop/theme.js +23 -3
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/input/consts.d.ts +17 -3
- package/dist/esm/input/consts.d.ts.map +1 -1
- package/dist/esm/input/consts.js +26 -12
- package/dist/esm/input/helpText.js +3 -3
- package/dist/esm/input/input.d.ts.map +1 -1
- package/dist/esm/input/input.js +6 -9
- package/dist/esm/input/input.types.d.ts +6 -6
- package/dist/esm/input/input.types.d.ts.map +1 -1
- package/dist/esm/input/inputIcon.d.ts.map +1 -1
- package/dist/esm/input/inputIcon.js +2 -1
- package/dist/esm/input/theme.d.ts +33 -17
- package/dist/esm/input/theme.d.ts.map +1 -1
- package/dist/esm/input/theme.js +32 -22
- package/dist/esm/skeleton/skeleton.types.d.ts +1 -1
- package/dist/esm/skeleton/skeleton.types.d.ts.map +1 -1
- package/dist/esm/skeleton/theme.d.ts +10 -14
- package/dist/esm/skeleton/theme.d.ts.map +1 -1
- package/dist/esm/skeleton/theme.js +10 -21
- package/dist/esm/tag/theme.d.ts +1 -0
- package/dist/esm/tag/theme.d.ts.map +1 -1
- package/dist/esm/tag/theme.js +2 -1
- package/dist/esm/theme/components.d.ts +110 -19
- package/dist/esm/theme/components.d.ts.map +1 -1
- package/dist/esm/theme/components.js +3 -1
- package/dist/esm/theme/defaultTheme.d.ts +110 -19
- package/dist/esm/theme/defaultTheme.d.ts.map +1 -1
- package/dist/esm/tooltip/tooltip.js +1 -1
- package/dist/esm/tooltip/tooltipContent.d.ts +1 -1
- package/dist/esm/tooltip/tooltipContent.d.ts.map +1 -1
- package/dist/esm/tooltip/tooltipContent.js +1 -4
- package/dist/esm/tree/context.d.ts +5 -0
- package/dist/esm/tree/context.d.ts.map +1 -0
- package/dist/esm/tree/context.js +3 -0
- package/dist/esm/tree/index.d.ts +8 -0
- package/dist/esm/tree/index.d.ts.map +1 -0
- package/dist/esm/tree/index.js +7 -0
- package/dist/esm/tree/theme.d.ts +59 -0
- package/dist/esm/tree/theme.d.ts.map +1 -0
- package/dist/esm/tree/theme.js +67 -0
- package/dist/esm/tree/tree.d.ts +14 -0
- package/dist/esm/tree/tree.d.ts.map +1 -0
- package/dist/esm/tree/tree.js +74 -0
- package/dist/esm/tree/tree.types.d.ts +58 -0
- package/dist/esm/tree/tree.types.d.ts.map +1 -0
- package/dist/esm/tree/tree.types.js +1 -0
- package/dist/esm/tree/treeIcon.d.ts +5 -0
- package/dist/esm/tree/treeIcon.d.ts.map +1 -0
- package/dist/esm/tree/treeIcon.js +12 -0
- package/dist/esm/tree/treeItem.d.ts +8 -0
- package/dist/esm/tree/treeItem.d.ts.map +1 -0
- package/dist/esm/tree/treeItem.js +91 -0
- package/dist/esm/tree/treeText.d.ts +5 -0
- package/dist/esm/tree/treeText.d.ts.map +1 -0
- package/dist/esm/tree/treeText.js +12 -0
- package/dist/esm/tree/useTreeState.d.ts +9 -0
- package/dist/esm/tree/useTreeState.d.ts.map +1 -0
- package/dist/esm/tree/useTreeState.js +6 -0
- package/package.json +1 -1
- package/src/avatar/theme.ts +2 -1
- package/src/badge/theme.ts +2 -1
- package/src/button/theme.ts +2 -1
- package/src/divider/divider.tsx +1 -1
- package/src/dragAndDrop/dragAndDrop.tsx +3 -3
- package/src/dragAndDrop/dragAndDrop.types.ts +1 -1
- package/src/dragAndDrop/theme.ts +24 -3
- package/src/index.ts +1 -0
- package/src/input/consts.ts +27 -12
- package/src/input/helpText.tsx +3 -3
- package/src/input/input.tsx +5 -14
- package/src/input/input.types.ts +6 -6
- package/src/input/inputIcon.tsx +2 -1
- package/src/input/theme.ts +31 -27
- package/src/skeleton/skeleton.types.ts +1 -1
- package/src/skeleton/theme.ts +9 -28
- package/src/tag/theme.ts +2 -1
- package/src/theme/components.ts +3 -1
- package/src/tooltip/tooltip.tsx +1 -1
- package/src/tooltip/tooltipContent.tsx +17 -21
- package/src/tree/context.ts +5 -0
- package/src/tree/index.ts +7 -0
- package/src/tree/theme.ts +76 -0
- package/src/tree/tree.tsx +121 -0
- package/src/tree/tree.types.ts +65 -0
- package/src/tree/treeIcon.tsx +16 -0
- package/src/tree/treeItem.tsx +177 -0
- package/src/tree/treeText.tsx +26 -0
- package/src/tree/useTreeState.ts +10 -0
package/src/tag/theme.ts
CHANGED
package/src/theme/components.ts
CHANGED
|
@@ -38,6 +38,7 @@ import Table from '../table/theme'
|
|
|
38
38
|
import Tabs from '../tabs/theme'
|
|
39
39
|
import Tag from '../tag/theme'
|
|
40
40
|
import Textarea from '../textarea/theme'
|
|
41
|
+
import Tree from '../tree/theme'
|
|
41
42
|
|
|
42
43
|
export default {
|
|
43
44
|
Accordion,
|
|
@@ -79,5 +80,6 @@ export default {
|
|
|
79
80
|
Table,
|
|
80
81
|
Tabs,
|
|
81
82
|
Tag,
|
|
82
|
-
Textarea
|
|
83
|
+
Textarea,
|
|
84
|
+
Tree
|
|
83
85
|
}
|
package/src/tooltip/tooltip.tsx
CHANGED
|
@@ -4,24 +4,20 @@ import Box from '../box'
|
|
|
4
4
|
import { color } from './tooltip.setup'
|
|
5
5
|
import { TooltipProps } from './tooltip.types'
|
|
6
6
|
|
|
7
|
-
export const TooltipContent = (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{children}
|
|
25
|
-
</Box>
|
|
26
|
-
)
|
|
27
|
-
}
|
|
7
|
+
export const TooltipContent = ({ children, fontSize = '16px', maxWidth = '400px' }: TooltipProps) => (
|
|
8
|
+
<Box
|
|
9
|
+
bg={color}
|
|
10
|
+
boxShadow="2"
|
|
11
|
+
className="vui-tooltip-content"
|
|
12
|
+
color="white"
|
|
13
|
+
fontSize={fontSize}
|
|
14
|
+
m={1}
|
|
15
|
+
maxW={maxWidth}
|
|
16
|
+
overflowY="auto"
|
|
17
|
+
p={1}
|
|
18
|
+
pl={2}
|
|
19
|
+
pr={2}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</Box>
|
|
23
|
+
)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Dict } from '../utils'
|
|
2
|
+
|
|
3
|
+
function variantDefault(props: Dict) {
|
|
4
|
+
const item: Dict = {
|
|
5
|
+
activeBg: 'skyBlue.30',
|
|
6
|
+
hoverBg: 'skyBlue.20',
|
|
7
|
+
selectedBg: 'skyBlue.10',
|
|
8
|
+
px: 2
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return { item }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const baseStyle = {}
|
|
15
|
+
|
|
16
|
+
const defaultProps = {
|
|
17
|
+
size: 'md',
|
|
18
|
+
variant: 'default'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const parts = ['container', 'icon', 'item', 'text']
|
|
22
|
+
|
|
23
|
+
const sizes = {
|
|
24
|
+
sm: {
|
|
25
|
+
icon: {
|
|
26
|
+
size: 'xs'
|
|
27
|
+
},
|
|
28
|
+
item: {
|
|
29
|
+
fontSize: 'md',
|
|
30
|
+
h: 32,
|
|
31
|
+
py: '3px'
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
md: {
|
|
35
|
+
icon: {
|
|
36
|
+
size: 'sm'
|
|
37
|
+
},
|
|
38
|
+
item: {
|
|
39
|
+
fontSize: 'md',
|
|
40
|
+
h: 40,
|
|
41
|
+
py: '5px'
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
lg: {
|
|
45
|
+
item: {
|
|
46
|
+
fontSize: 'md',
|
|
47
|
+
h: 48,
|
|
48
|
+
py: '7px'
|
|
49
|
+
},
|
|
50
|
+
icon: {
|
|
51
|
+
size: 'md'
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
xl: {
|
|
55
|
+
item: {
|
|
56
|
+
fontSize: 'lg',
|
|
57
|
+
h: 56,
|
|
58
|
+
py: '9px'
|
|
59
|
+
},
|
|
60
|
+
icon: {
|
|
61
|
+
scale: 2
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const variants = {
|
|
67
|
+
default: variantDefault
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default {
|
|
71
|
+
baseStyle,
|
|
72
|
+
defaultProps,
|
|
73
|
+
parts,
|
|
74
|
+
sizes,
|
|
75
|
+
variants
|
|
76
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React, { Children, ReactElement, useEffect, useMemo } from 'react'
|
|
2
|
+
|
|
3
|
+
import { styled, useStyleConfig, vui, VuiComponent } from '../core'
|
|
4
|
+
import { cs, filterUndefined } from '../utils'
|
|
5
|
+
import { TreeProvider } from './context'
|
|
6
|
+
import { TreeItemId, TreeItemProps, TreeProps } from './tree.types'
|
|
7
|
+
import TreeIcon from './treeIcon'
|
|
8
|
+
import TreeItem from './treeItem'
|
|
9
|
+
import TreeText from './treeText'
|
|
10
|
+
import { useTreeState } from './useTreeState'
|
|
11
|
+
|
|
12
|
+
export const TreeBase = styled.divBox`
|
|
13
|
+
display: flex;
|
|
14
|
+
height: auto;
|
|
15
|
+
align-content: flex-start;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
`
|
|
18
|
+
|
|
19
|
+
/** Displays a tree of tree link items and optional heading. Exposes some props to the children via context. */
|
|
20
|
+
export const Tree = vui<'div', TreeProps>((props, ref) => {
|
|
21
|
+
const {
|
|
22
|
+
activeItemId,
|
|
23
|
+
children,
|
|
24
|
+
className,
|
|
25
|
+
iconCollapse = 'falMinus',
|
|
26
|
+
iconExpand = 'falPlus',
|
|
27
|
+
items,
|
|
28
|
+
onClickItem,
|
|
29
|
+
size,
|
|
30
|
+
variant,
|
|
31
|
+
...rest
|
|
32
|
+
} = props
|
|
33
|
+
const styles = useStyleConfig('Tree', props)
|
|
34
|
+
|
|
35
|
+
const { itemsInternal, setItemsInternal, activeItemIndex, setActiveItemIndex } = useTreeState(activeItemId)
|
|
36
|
+
|
|
37
|
+
const context = useMemo(() => filterUndefined({ size, variant }), [size, variant])
|
|
38
|
+
|
|
39
|
+
const transformChildrenToItems = (children: any) => {
|
|
40
|
+
const t: TreeItemProps[] = []
|
|
41
|
+
|
|
42
|
+
if (children) {
|
|
43
|
+
;(Children.toArray(children) as ReactElement[]).forEach((child: ReactElement<TreeItemProps>, index: number) => {
|
|
44
|
+
if (child?.props?.text) {
|
|
45
|
+
let items: TreeItemProps[] = []
|
|
46
|
+
|
|
47
|
+
if (child.props.children) {
|
|
48
|
+
items = transformChildrenToItems(child.props.children) as unknown as TreeItemProps[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
t.push({
|
|
52
|
+
id: child.props.id,
|
|
53
|
+
text: child.props.text,
|
|
54
|
+
isActive: child.props.isActive,
|
|
55
|
+
items: child.props.items || items,
|
|
56
|
+
isCollapsed: child.props.isCollapsed,
|
|
57
|
+
disabled: child.props.disabled,
|
|
58
|
+
onClickTreeItem: onClickTreeItem
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return t
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (items) {
|
|
69
|
+
setItemsInternal(items as TreeItemProps[])
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const t: TreeItemProps[] = []
|
|
74
|
+
if (children) {
|
|
75
|
+
const transformed = transformChildrenToItems(children) as unknown as TreeItemProps[]
|
|
76
|
+
t.push(...transformed)
|
|
77
|
+
}
|
|
78
|
+
setItemsInternal(t)
|
|
79
|
+
if (activeItemId !== undefined && t?.find((i: TreeItemProps) => i.id === activeItemId)) {
|
|
80
|
+
setActiveItemIndex(activeItemId)
|
|
81
|
+
}
|
|
82
|
+
}, [children, activeItemId])
|
|
83
|
+
|
|
84
|
+
const onClickTreeItem = (id: TreeItemId) => {
|
|
85
|
+
setActiveItemIndex(id)
|
|
86
|
+
if (onClickItem) {
|
|
87
|
+
onClickItem(id)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<TreeProvider value={context}>
|
|
93
|
+
<TreeBase className={cs('vui-tree', className)} ref={ref} {...styles.container} {...rest}>
|
|
94
|
+
{itemsInternal?.map(({ id, isActive, ...props }, index: number) => {
|
|
95
|
+
return (
|
|
96
|
+
<TreeItem
|
|
97
|
+
activeItemIndex={activeItemIndex}
|
|
98
|
+
iconCollapse={iconCollapse}
|
|
99
|
+
iconExpand={iconExpand}
|
|
100
|
+
id={id}
|
|
101
|
+
isActive={activeItemIndex ? activeItemIndex === id : false}
|
|
102
|
+
key={id ?? index}
|
|
103
|
+
onClickTreeItem={onClickTreeItem}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
})}
|
|
108
|
+
</TreeBase>
|
|
109
|
+
</TreeProvider>
|
|
110
|
+
)
|
|
111
|
+
}) as VuiComponent<'div', TreeProps> & {
|
|
112
|
+
Icon: typeof TreeIcon
|
|
113
|
+
Item: typeof TreeItem
|
|
114
|
+
Text: typeof TreeText
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
Tree.Icon = TreeIcon
|
|
118
|
+
Tree.Item = TreeItem
|
|
119
|
+
Tree.Text = TreeText
|
|
120
|
+
|
|
121
|
+
export default Tree
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ReactNode, ReactText } from 'react'
|
|
2
|
+
|
|
3
|
+
import { IconProp } from '../icon'
|
|
4
|
+
import { LinkProps } from '../link'
|
|
5
|
+
import { SystemProps } from '../system'
|
|
6
|
+
import { ThemingProps } from '../theme'
|
|
7
|
+
import { PropsOf } from '../utils'
|
|
8
|
+
|
|
9
|
+
export type TreeProps = SystemProps &
|
|
10
|
+
ThemingProps<'Tree'> & {
|
|
11
|
+
/** Currently selected item. */
|
|
12
|
+
activeItemId?: TreeItemId
|
|
13
|
+
/** Socket defining the collapse icon on the left. */
|
|
14
|
+
iconCollapse?: IconProp
|
|
15
|
+
/** Socket defining the expand icon on the left. */
|
|
16
|
+
iconExpand?: IconProp
|
|
17
|
+
/** Socket displaying a tree of items. */
|
|
18
|
+
items?: PropsOf<'div', TreeItemProps>[] | JSX.Element
|
|
19
|
+
/** Socket defining the size of the tree. */
|
|
20
|
+
onClickItem?: (id: TreeItemId) => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type TreeItemLinkProps = PropsOf<'a', LinkProps> | object
|
|
24
|
+
|
|
25
|
+
export type TreeItemId = string | number
|
|
26
|
+
|
|
27
|
+
export type TreeOnToggleEvent = {
|
|
28
|
+
id: TreeItemId
|
|
29
|
+
collapsed: boolean
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type TreeItemProps = SystemProps &
|
|
33
|
+
ThemingProps<'Tree'> & {
|
|
34
|
+
activeItemId?: TreeItemId
|
|
35
|
+
/** internal, not exposed */
|
|
36
|
+
activeItemIndex?: TreeItemId
|
|
37
|
+
/** Unique ID */
|
|
38
|
+
id: TreeItemId
|
|
39
|
+
/** Centers the content vertically and horizontally. @deprecated */
|
|
40
|
+
center?: boolean
|
|
41
|
+
/** Centers the content horizontally. @deprecated */
|
|
42
|
+
centerH?: boolean
|
|
43
|
+
/** Centers the content vertically. @deprecated */
|
|
44
|
+
centerV?: boolean
|
|
45
|
+
/** Socket defining the collapse icon on the left. */
|
|
46
|
+
iconCollapse?: IconProp
|
|
47
|
+
/** Socket defining the expand icon on the left. */
|
|
48
|
+
iconExpand?: IconProp
|
|
49
|
+
/** The children of this tree item. */
|
|
50
|
+
items?: PropsOf<'div', TreeItemProps>[]
|
|
51
|
+
children?: ReactNode
|
|
52
|
+
/** Collapsed state */
|
|
53
|
+
isCollapsed?: boolean
|
|
54
|
+
/** Displays item and its content in disabled state with appropriate styling. */
|
|
55
|
+
disabled?: boolean
|
|
56
|
+
/** Displays item in selected state with appropriate styling. */
|
|
57
|
+
isActive?: boolean
|
|
58
|
+
/** If provided, content is wrapper with a link and the props are provided to the element. */
|
|
59
|
+
linkProps?: TreeItemLinkProps
|
|
60
|
+
/** Socket displaying text within the item. */
|
|
61
|
+
text: ReactText | JSX.Element
|
|
62
|
+
/** Collapse change state */
|
|
63
|
+
onToggle?: (event: TreeOnToggleEvent) => void
|
|
64
|
+
onClickTreeItem?: (id: TreeItemId) => void
|
|
65
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { useStyleConfig, vui } from '../core'
|
|
4
|
+
import Icon, { IconProps } from '../icon'
|
|
5
|
+
import { cs } from '../utils'
|
|
6
|
+
import { useTreeContext } from './context'
|
|
7
|
+
|
|
8
|
+
/** Displays an icon on the side of the TreeItem. */
|
|
9
|
+
export const TreeIcon = vui<'svg', IconProps>((props, ref) => {
|
|
10
|
+
const { className, ...rest } = props
|
|
11
|
+
const styles = useStyleConfig('Tree', useTreeContext())
|
|
12
|
+
|
|
13
|
+
return <Icon className={cs('vui-treeIcon', className)} ref={ref} size="xs" {...styles.icon} {...rest} />
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export default TreeIcon
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { Box } from '../box'
|
|
4
|
+
import { styled, useStyleConfig, vui } from '../core'
|
|
5
|
+
import { cs, isArray, isReactText } from '../utils'
|
|
6
|
+
import { useTreeContext } from './context'
|
|
7
|
+
import { TreeItemProps } from './tree.types'
|
|
8
|
+
import TreeIcon from './treeIcon'
|
|
9
|
+
import TreeText from './treeText'
|
|
10
|
+
|
|
11
|
+
export const TreeItemBase = styled.divBox`
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
line-height: normal;
|
|
15
|
+
outline: none;
|
|
16
|
+
align-content: flex-start;
|
|
17
|
+
align-items: flex-start;
|
|
18
|
+
overflow: visible;
|
|
19
|
+
height: auto;
|
|
20
|
+
|
|
21
|
+
& [aria-disabled='true'] {
|
|
22
|
+
cursor: not-allowed;
|
|
23
|
+
user-select: none;
|
|
24
|
+
}
|
|
25
|
+
`
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Displays a tree item with text and optional icons. Can be shown as selected.
|
|
29
|
+
*/
|
|
30
|
+
export const TreeItem = vui<'div', TreeItemProps>((props, ref) => {
|
|
31
|
+
const mergedProps = { ...useTreeContext(), ...props }
|
|
32
|
+
|
|
33
|
+
const {
|
|
34
|
+
activeItemId,
|
|
35
|
+
activeItemIndex,
|
|
36
|
+
children,
|
|
37
|
+
center,
|
|
38
|
+
centerH,
|
|
39
|
+
centerV = true,
|
|
40
|
+
className,
|
|
41
|
+
iconCollapse = 'falMinus',
|
|
42
|
+
isCollapsed,
|
|
43
|
+
disabled,
|
|
44
|
+
iconExpand = 'falPlus',
|
|
45
|
+
id,
|
|
46
|
+
items,
|
|
47
|
+
isActive,
|
|
48
|
+
isTruncated,
|
|
49
|
+
key,
|
|
50
|
+
onClickTreeItem,
|
|
51
|
+
onToggle,
|
|
52
|
+
text,
|
|
53
|
+
...rest
|
|
54
|
+
} = mergedProps
|
|
55
|
+
const styles = useStyleConfig('Tree', useTreeContext())
|
|
56
|
+
const { activeBg, h, hoverBg, p, px, py, selectedBg, ...itemStyles } = styles.item
|
|
57
|
+
|
|
58
|
+
const [collapsedInternal, setIsCollapsedInternal] = useState<boolean>(false)
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
setIsCollapsedInternal(!!isCollapsed)
|
|
62
|
+
}, [isCollapsed])
|
|
63
|
+
|
|
64
|
+
const toggle = (e: Event) => {
|
|
65
|
+
if (!disabled) {
|
|
66
|
+
onToggle?.({ id, collapsed: !collapsedInternal })
|
|
67
|
+
setIsCollapsedInternal(!collapsedInternal)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const target = e.target as HTMLDivElement
|
|
71
|
+
const active = target?.closest('.vui-tree')?.getElementsByClassName('vui-treeItem-active')[0] as HTMLDivElement
|
|
72
|
+
active ? (active.style.backgroundColor = 'transparent') : null
|
|
73
|
+
|
|
74
|
+
onClickTreeItem?.(id)
|
|
75
|
+
|
|
76
|
+
// Avoids triggering parent's onClick
|
|
77
|
+
e.stopPropagation()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const interactiveProps = !disabled
|
|
81
|
+
? {
|
|
82
|
+
cursor: 'pointer',
|
|
83
|
+
focusVisibleRing: 2,
|
|
84
|
+
hoverBg: 'transparent',
|
|
85
|
+
activeBg: 'transparent',
|
|
86
|
+
userSelect: 'none'
|
|
87
|
+
}
|
|
88
|
+
: {}
|
|
89
|
+
|
|
90
|
+
const hoverTreeItem = (e: Event, type: string) => {
|
|
91
|
+
const target = e.target as HTMLDivElement
|
|
92
|
+
|
|
93
|
+
if (target.classList.contains('vui-treeItem-permanent')) {
|
|
94
|
+
target.style.backgroundColor = type === 'over' ? '#e2f1ff' : 'transparent'
|
|
95
|
+
e.stopPropagation()
|
|
96
|
+
} else {
|
|
97
|
+
e.preventDefault()
|
|
98
|
+
const permanent = target
|
|
99
|
+
.closest('.vui-treeItem')
|
|
100
|
+
?.getElementsByClassName('vui-treeItem-permanent')[0] as HTMLDivElement
|
|
101
|
+
|
|
102
|
+
const collapsible = target
|
|
103
|
+
.closest('.vui-treeItem')
|
|
104
|
+
?.getElementsByClassName('vui-treeItem-collapsible')[0] as HTMLDivElement
|
|
105
|
+
|
|
106
|
+
const active = target.closest('.vui-treeItem')?.getElementsByClassName('vui-treeItem-active')[0] as HTMLDivElement
|
|
107
|
+
|
|
108
|
+
permanent ? (permanent.style.backgroundColor = type === 'over' ? '#e2f1ff' : 'transparent') : null
|
|
109
|
+
collapsible ? (collapsible.style.backgroundColor = 'transparent') : null
|
|
110
|
+
active ? (active.style.backgroundColor = 'hsl(139, 100%, 90%)') : null
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const isCollapsable = (isArray(children) && children.length > 0) || (isArray(items) && items.length > 0)
|
|
115
|
+
const isActiveInternal = (!activeItemIndex && isActive) || activeItemIndex === id
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<TreeItemBase
|
|
119
|
+
alignItems="start"
|
|
120
|
+
className={cs('vui-treeItem', className)}
|
|
121
|
+
h={collapsedInternal ? h : isCollapsable ? 'auto' : h}
|
|
122
|
+
id={id}
|
|
123
|
+
m={0}
|
|
124
|
+
onClick={!disabled ? (e: Event) => toggle(e) : undefined}
|
|
125
|
+
onMouseOut={!disabled ? (e: Event) => hoverTreeItem(e, 'out') : undefined}
|
|
126
|
+
onMouseOver={!disabled ? (e: Event) => hoverTreeItem(e, 'over') : undefined}
|
|
127
|
+
p={0}
|
|
128
|
+
ref={ref}
|
|
129
|
+
w={1}
|
|
130
|
+
{...itemStyles}
|
|
131
|
+
{...interactiveProps}
|
|
132
|
+
{...rest}
|
|
133
|
+
hoverBg="transparent"
|
|
134
|
+
>
|
|
135
|
+
<Box flexDirection="column" hoverBg="transparent" m={0} pl={2} pr={0} py={py} w={1}>
|
|
136
|
+
<Box
|
|
137
|
+
alignItems="center"
|
|
138
|
+
bg={isActiveInternal ? 'hsl(139, 100%, 90%)' : 'transparent'}
|
|
139
|
+
className={isActiveInternal ? 'vui-treeItem-active' : 'vui-treeItem-permanent'}
|
|
140
|
+
flexDirection="row"
|
|
141
|
+
hoverBg="transparent"
|
|
142
|
+
m={0}
|
|
143
|
+
p={0}
|
|
144
|
+
w={1}
|
|
145
|
+
>
|
|
146
|
+
{items && items?.length > 0 && (
|
|
147
|
+
<>{collapsedInternal ? <TreeIcon mr={1} name={iconExpand} /> : <TreeIcon mr={1} name={iconCollapse} />}</>
|
|
148
|
+
)}
|
|
149
|
+
{items?.length === 0 && <TreeIcon mr={1} name="cusDotFullAlt" />}
|
|
150
|
+
{isReactText(text) ? <TreeText {...{ isTruncated, text }} /> : text}
|
|
151
|
+
</Box>
|
|
152
|
+
|
|
153
|
+
{isCollapsable && !collapsedInternal && (
|
|
154
|
+
<Box className="vui-treeItem-collapsible" flexDirection="column" hoverBg="transparent" m={0} p={0} w={1}>
|
|
155
|
+
{children ??
|
|
156
|
+
(isArray<TreeItemProps>(items)
|
|
157
|
+
? items.map(({ key, ...props }, index) => {
|
|
158
|
+
return (
|
|
159
|
+
<TreeItem
|
|
160
|
+
activeItemIndex={activeItemIndex}
|
|
161
|
+
iconCollapse={iconCollapse}
|
|
162
|
+
iconExpand={iconExpand}
|
|
163
|
+
key={key ?? index}
|
|
164
|
+
onClickTreeItem={onClickTreeItem}
|
|
165
|
+
{...props}
|
|
166
|
+
/>
|
|
167
|
+
)
|
|
168
|
+
})
|
|
169
|
+
: items)}
|
|
170
|
+
</Box>
|
|
171
|
+
)}
|
|
172
|
+
</Box>
|
|
173
|
+
</TreeItemBase>
|
|
174
|
+
)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
export default TreeItem
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { useStyleConfig, vui } from '../core'
|
|
4
|
+
import T, { TProps } from '../t'
|
|
5
|
+
import { cs, ellipsisOverflow } from '../utils'
|
|
6
|
+
import { useTreeContext } from './context'
|
|
7
|
+
|
|
8
|
+
/** Displays text within the TreeItem. */
|
|
9
|
+
export const TreeText = vui<'span', TProps>((props, ref) => {
|
|
10
|
+
const { className, ...rest } = props
|
|
11
|
+
const styles = useStyleConfig('Tree', useTreeContext())
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<T
|
|
15
|
+
className={cs('vui-treeText', className)}
|
|
16
|
+
fontSize="inherit"
|
|
17
|
+
py={styles.item.py}
|
|
18
|
+
ref={ref}
|
|
19
|
+
{...ellipsisOverflow}
|
|
20
|
+
{...styles.text}
|
|
21
|
+
{...rest}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export default TreeText
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { TreeItemId, TreeItemProps } from './tree.types'
|
|
4
|
+
|
|
5
|
+
export const useTreeState = (activeItemId?: TreeItemId) => {
|
|
6
|
+
const [itemsInternal, setItemsInternal] = useState<TreeItemProps[]>([])
|
|
7
|
+
const [activeItemIndex, setActiveItemIndex] = useState<TreeItemId>(activeItemId ?? '')
|
|
8
|
+
|
|
9
|
+
return { itemsInternal, setItemsInternal, activeItemIndex, setActiveItemIndex }
|
|
10
|
+
}
|