iannbing / iannbing/react-simple-tree-menu
Choosing multiple tree items
- Dominant language
- TypeScript
- Stars
- 138
- Forks
- 44
- PR merge metrics
- No merged PRs in 30d
Description
Is it possible to select (and deselect) multiple tree items? I can't see any "multiple" alike option/param/prop to be set in neither of internal components config in documentation.
I haven't dug into this library code yet, but if such feature is not currently implemented, would it conceptually be as simple as changing `activeKey`, `initialActiveKey` and similar props that track active tree items from _string_ to _array_ along with adjusting logic accordingly?
I did a workaround, which in my opinion is _dirty_: component that uses `` keeps track of selected tree items and highlights them outside of library's components control. Is it possible to be done in a simpler or cleaner way?
**Demo**: https://codepen.io/ScriptyChris/pen/jOMZmdV?editors=1010
**Code**:
```
function CategoriesTree() {
const categoriesTreeRef = createRef();
const treeMenuRef = createRef();
const activeTreeNodes = new Map();
const getCategoriesTree = () => {
const treeData = JSON.parse(`[{"key":"first-level-node-1","index":0,"label":"first level node 1"},{"key":"first-level-node-2","index":1,"label":"first level node 2","nodes":[{"key":"second-level-node-1","index":0,"label":"second level node 1"},{"key":"second-level-node-2","index":1,"label":"second level node 2"},{"key":"second-level-node-3","index":2,"label":"second level node 3"},{"key":"second-level-node-4","index":3,"label":"second level node 4"},{"key":"second-level-node-5","index":4,"label":"second level node 5"},{"key":"second-level-node-6","index":5,"label":"second level node 6"}]},{"key":"first-level-node-3","index":2,"label":"first level node 3"},{"key":"first-level-node-4","index":3,"label":"first level node 4"},{"key":"first-level-node-5","index":4,"label":"first level node 5"}]`);
return (
toggleActiveTreeNode(clickedItem.level, clickedItem.index, clickedItem.label)}
ref={treeMenuRef}
/>
);
};
const toggleActiveTreeNode = (nodeLevel, nodeIndex, nodeLabel) => {
const currentNodeKey = `${nodeLevel}-${nodeIndex}`;
const isActiveTreeNode = activeTreeNodes.has(currentNodeKey);
if (isActiveTreeNode) {
activeTreeNodes.delete(currentNodeKey);
} else {
activeTreeNodes.set(currentNodeKey, nodeLabel);
}
// This is a dirty workaround, because 3rd-party TreeMenu component doesn't seem to support multi selection.
[[currentNodeKey], ...activeTreeNodes].forEach(([key], iteration) => {
const isCurrentNodeKey = iteration === 0;
const [level, index] = key.split('-');
const treeNodeLevelSelector = `.rstm-tree-item-level${level}`;
const treeNodeDOM = categoriesTreeRef.current.querySelectorAll(treeNodeLevelSelector)[index];
// "Force" DOM actions execution on elements controlled by React.
requestAnimationFrame(() => {
treeNodeDOM.classList.toggle('rstm-tree-item--active', !isCurrentNodeKey);
treeNodeDOM.setAttribute('aria-pressed', !isCurrentNodeKey);
});
});
};
return (
/*
Attribute [ref] is used on whole component wrapper, because
both useRef() hook and React.createRef() method don't seem to
give reference to nested functional component's DOM elements, such as used TreeMenu.
*/
{getCategoriesTree()}
);
}
```
Contributor guide
Assessment
This issue has not been assessed yet.