weike-multi-cascader
Version:
A multiple cascader component for antd
165 lines (164 loc) • 6.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = require("react");
const unstated_next_1 = require("unstated-next");
const utils_1 = require("./libs/utils");
const constants_1 = require("./constants");
const useCascade = (params) => {
const { data, value: valueProp, selectAll, onChange, onCascaderChange, selectLeafOnly, fristColumMulti, isToolTip } = params || {};
const [popupVisible, setPopupVisible] = react_1.useState(false);
const dataRef = react_1.useRef(data);
react_1.useEffect(() => {
dataRef.current = data;
}, [data]);
const [flattenData, setFlattenData] = react_1.useState(() => {
if (selectAll) {
return utils_1.flattenTree([
{
title: 'All',
value: constants_1.All,
parent: null,
children: data,
},
]);
}
return utils_1.flattenTree(data || []);
});
react_1.useEffect(() => {
setFlattenData(() => {
if (selectAll) {
return utils_1.flattenTree([
{
title: 'All',
value: constants_1.All,
parent: null,
children: data,
},
]);
}
return utils_1.flattenTree(data || []);
});
}, [data, selectAll]);
const transformValue = react_1.useCallback((value) => {
const nextValue = utils_1.transformValue(value, flattenData);
if (onChange && !utils_1.shallowEqualArray(nextValue, value)) {
requestAnimationFrame(() => triggerChange(nextValue));
}
return nextValue;
}, [flattenData]);
const [menuData, setMenuData] = react_1.useState(() => {
if (selectAll && flattenData.length === 1) {
return [];
}
return [
selectAll
? flattenData[0].children
: flattenData.filter((item) => !item.parent),
];
});
const [menuPath, setMenuPath] = react_1.useState([]);
const [value, setValue] = react_1.useState(transformValue(valueProp || []));
const hackValue = react_1.useRef(value);
const selectedItems = react_1.useMemo(() => {
return flattenData.filter((node) => {
return (valueProp || hackValue.current).includes(node.value);
});
}, [flattenData, valueProp, popupVisible, hackValue.current]);
const triggerChange = react_1.useCallback((nextValue) => {
// 根据最新的value 返回实际内容
const returnItem = (value) => {
return flattenData.filter((node) => {
return value.includes(node.value);
});
};
if (onChange) {
onChange(nextValue, returnItem(nextValue));
}
hackValue.current = nextValue;
setValue(nextValue);
// setPopupVisible(false)
}, [selectedItems]);
const addMenu = react_1.useCallback((menu, index) => {
if (menu && menu.length) {
setMenuData((prevMenuData) => [...prevMenuData.slice(0, index), menu]);
}
else {
setMenuData((prevMenuData) => [...prevMenuData.slice(0, index)]);
}
}, []);
const addChildrenToNode = react_1.useCallback((target, children) => {
const found = utils_1.findNodeByValue(target.value, dataRef.current);
if (found) {
found.children = children;
}
return [...dataRef.current];
}, []);
const lastItemRef = react_1.useRef(null);
const handleCascaderChange = react_1.useCallback((item, depth) => {
const { children } = item;
lastItemRef.current = item;
onCascaderChange === null || onCascaderChange === void 0 ? void 0 : onCascaderChange(item, {
add: (newChildren) => {
const newData = addChildrenToNode(item, newChildren);
if (lastItemRef.current === item) {
item.children = newChildren;
newChildren.forEach((child) => {
child.parent = item;
});
setFlattenData((prev) => [...prev, ...newChildren]);
handleCascaderChange(item, depth);
}
return newData;
},
});
addMenu(children, depth + 1);
setMenuPath((prevMenuPath) => prevMenuPath.slice(0, depth).concat(item));
}, [menuPath, onCascaderChange]);
const handleSelectChange = react_1.useCallback((item, checked) => {
setValue((prevValue) => {
triggerChange(utils_1.sortByTree(utils_1.reconcile(item, checked, prevValue), flattenData));
return utils_1.sortByTree(utils_1.reconcile(item, checked, prevValue), flattenData);
});
}, [flattenData]);
const resetMenuState = react_1.useCallback(() => {
if (selectAll && flattenData.length === 1) {
return setMenuData([]);
}
else {
setMenuData([
selectAll
? flattenData[0].children
: flattenData.filter((item) => !item.parent),
]);
}
setMenuPath([]);
}, [flattenData, selectAll]);
// 传入的 value 有变更时重新计算
react_1.useEffect(() => {
if (popupVisible) {
setValue(transformValue(valueProp || hackValue.current));
resetMenuState();
}
}, [popupVisible]);
return {
menuPath,
popupVisible,
setPopupVisible,
menuData,
addMenu,
setMenuData,
value,
setValue,
handleCascaderChange,
handleSelectChange,
flattenData,
resetMenuState,
selectedItems,
triggerChange,
selectLeafOnly,
hackValue,
fristColumMulti,
isToolTip
};
};
exports.default = unstated_next_1.createContainer(useCascade);