iannbing / iannbing/react-simple-tree-menu

Choosing multiple tree items

Open
#188 3 comments 0 reactions 0 assignees View on GitHub
enhancement
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.