Files
2025-03-07 19:22:02 +01:00

80 lines
3.1 KiB
JavaScript

import { useControllableState } from '@fluentui/react-utilities';
import { ImmutableMap } from '../../utils/ImmutableMap';
import * as React from 'react';
import { createCheckedItems } from '../../utils/createCheckedItems';
export function useFlatControllableCheckedItems(props, headlessTree) {
return useControllableState({
initialState: ImmutableMap.empty,
state: React.useMemo(()=>props.selectionMode ? props.checkedItems && createCheckedItems(props.checkedItems) : undefined, [
props.checkedItems,
props.selectionMode
]),
defaultState: props.defaultCheckedItems ? ()=>initializeCheckedItems(props, headlessTree) : undefined
});
}
export function createNextFlatCheckedItems(data, previousCheckedItems, headlessTree) {
if (data.selectionMode === 'single') {
return ImmutableMap.from([
[
data.value,
data.checked
]
]);
}
const treeItem = headlessTree.get(data.value);
if (!treeItem) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error(`@fluentui/react-tree [useHeadlessFlatTree]:
Tree item ${data.value} not found.`);
}
return previousCheckedItems;
}
let nextCheckedItems = previousCheckedItems;
for (const children of headlessTree.subtree(data.value)){
nextCheckedItems = nextCheckedItems.set(children.value, data.checked);
}
nextCheckedItems = nextCheckedItems.set(data.value, data.checked);
let isAncestorsMixed = false;
for (const parent of headlessTree.ancestors(treeItem.value)){
// if one parent is mixed, all ancestors are mixed
if (isAncestorsMixed) {
nextCheckedItems = nextCheckedItems.set(parent.value, 'mixed');
continue;
}
let checkedChildrenAmount = 0;
for (const child of headlessTree.children(parent.value)){
if ((nextCheckedItems.get(child.value) || false) === data.checked) {
checkedChildrenAmount++;
}
}
// if all children are checked, parent is checked
if (checkedChildrenAmount === parent.childrenValues.length) {
nextCheckedItems = nextCheckedItems.set(parent.value, data.checked);
} else {
// if one parent is mixed, all ancestors are mixed
isAncestorsMixed = true;
nextCheckedItems = nextCheckedItems.set(parent.value, 'mixed');
}
}
return nextCheckedItems;
}
function initializeCheckedItems(props, headlessTree) {
if (!props.selectionMode) {
return ImmutableMap.empty;
}
let state = createCheckedItems(props.defaultCheckedItems);
// if selectionMode is multiselect, we need to calculate the checked state of all children
// and ancestors of the defaultCheckedItems
if (props.selectionMode === 'multiselect') {
for (const [value, checked] of state){
state = createNextFlatCheckedItems({
value,
checked,
selectionMode: props.selectionMode
}, state, headlessTree);
}
}
return state;
}