-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add an example for customizing the multi-selection behavior (#845)
* docs: add an example for customizing the multi-selection behavior * docs: update the customized multi-selection example
- Loading branch information
Showing
2 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
...t-docs/pages/components/tree/multi-selection-checkboxes-with-custom-selection-behavior.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import { | ||
Box, | ||
Checkbox, | ||
Flex, | ||
Icon, | ||
OverflowTooltip, | ||
Scrollbar, | ||
TreeItem, | ||
TreeItemContent, | ||
TreeItemToggle, | ||
TreeItemToggleIcon, | ||
Tree, | ||
useColorStyle, | ||
useTree, | ||
} from '@tonic-ui/react'; | ||
import { | ||
useConst, | ||
} from '@tonic-ui/react-hooks'; | ||
import { ensureArray } from 'ensure-type'; | ||
import React, { useCallback, useMemo } from 'react'; | ||
import { | ||
buildTreeNodes, | ||
findExpandableNodeIds, | ||
} from './utils'; | ||
|
||
const TreeItemRender = ({ | ||
node, | ||
nodeDepth = 0, | ||
}) => { | ||
const [colorStyle] = useColorStyle(); | ||
const nodeId = node.id; | ||
const nodeLabel = node.label; | ||
const { multiSelect } = useTree(); | ||
|
||
const render = useCallback(({ isExpandable, isExpanded, isSelected, select, selectRange, toggleSelection }) => { | ||
const icon = (() => { | ||
if (isExpandable) { | ||
return isExpanded ? 'folder-open' : 'folder'; | ||
} | ||
return 'server'; | ||
})(); | ||
const iconColor = isExpandable ? 'yellow:50' : 'currentColor'; | ||
|
||
return ( | ||
<TreeItemContent | ||
sx={{ | ||
// Hide the background color of the tree node when the checkbox is selected | ||
backgroundColor: isSelected ? 'transparent' : undefined, | ||
|
||
// [Optional] Display a connecting line to indicate which is the last node when hovered over the tree item | ||
':hover + [role="group"]': { | ||
position: 'relative', | ||
'::before': { | ||
backgroundColor: colorStyle.background.highlighted, | ||
content: '""', | ||
position: 'absolute', | ||
top: 0, | ||
bottom: 0, | ||
left: 20 + nodeDepth * 24 - (1/2), // Adjust the horizontal position based on depth | ||
width: 1, | ||
}, | ||
}, | ||
}} | ||
onClick={(event) => { | ||
// Prevent default event handler to manage tree item selection | ||
event.preventDefault(); | ||
|
||
const isCtrlPressed = event.ctrlKey; | ||
const isMetaPressed = event.metaKey; | ||
const isShiftPressed = event.shiftKey; | ||
|
||
if (multiSelect && isShiftPressed) { | ||
selectRange(); | ||
return; | ||
} | ||
|
||
if (multiSelect && (isCtrlPressed || isMetaPressed)) { | ||
toggleSelection(); | ||
return; | ||
} | ||
|
||
if (multiSelect) { | ||
toggleSelection(); | ||
} else { | ||
select(); | ||
} | ||
}} | ||
> | ||
<Flex | ||
flex="none" | ||
width="6x" | ||
> | ||
{isExpandable && ( | ||
<TreeItemToggle> | ||
<TreeItemToggleIcon /> | ||
</TreeItemToggle> | ||
)} | ||
</Flex> | ||
<Flex | ||
mr="2x" | ||
> | ||
<Checkbox | ||
checked={isSelected} | ||
onChange={event => { | ||
// Prevent default event handler to manage tree item selection | ||
event.preventDefault(); | ||
|
||
toggleSelection(); | ||
}} | ||
/> | ||
</Flex> | ||
<Icon icon={icon} color={iconColor} mr="2x" /> | ||
<OverflowTooltip label={nodeLabel}> | ||
{({ ref, style }) => ( | ||
<Box | ||
ref={ref} | ||
{...style} | ||
flex="auto" | ||
fontWeight={isSelected ? 'semibold' : 'normal'} | ||
> | ||
{nodeLabel} | ||
</Box> | ||
)} | ||
</OverflowTooltip> | ||
</TreeItemContent> | ||
); | ||
}, [colorStyle, nodeDepth, nodeLabel]); | ||
|
||
return ( | ||
<TreeItem | ||
nodeId={nodeId} | ||
render={render} | ||
> | ||
{ensureArray(node.children).map(node => ( | ||
<TreeItemRender | ||
key={node.id} | ||
node={node} | ||
nodeDepth={nodeDepth + 1} | ||
/> | ||
))} | ||
</TreeItem> | ||
); | ||
}; | ||
|
||
const App = () => { | ||
const [colorStyle] = useColorStyle(); | ||
const treeNodes = useConst(() => buildTreeNodes()); | ||
const expandableNodeIds = useMemo(() => findExpandableNodeIds(treeNodes), [treeNodes]); | ||
|
||
return ( | ||
<Box | ||
sx={{ | ||
//minWidth: 160, | ||
//maxWidth: '40%', | ||
boxShadow: colorStyle.shadow.thick, | ||
}} | ||
> | ||
<Scrollbar | ||
height={240} | ||
overflowY="auto" | ||
> | ||
<Tree | ||
aria-label="multi-selection with checkboxes" | ||
defaultExpanded={expandableNodeIds} | ||
isSelectable | ||
isUnselectable | ||
multiSelect | ||
> | ||
{ensureArray(treeNodes).map(node => ( | ||
<TreeItemRender | ||
key={node.id} | ||
node={node} | ||
/> | ||
))} | ||
</Tree> | ||
</Scrollbar> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default App; |