Skip to content

Commit

Permalink
feat(Tree): support setItem indeterminate (#3261)
Browse files Browse the repository at this point in the history
* feat(Tree): support set indeterminate

* feat(Tree): support set indeterminate

* chore: support set indeterminate

* chore: update common

* chore: fix test
  • Loading branch information
uyarn authored Dec 19, 2024
1 parent e8b89c1 commit 4282c4b
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/_common
2 changes: 1 addition & 1 deletion src/cascader/core/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function expendClickEffect(
// 非受控状态下更新状态
setValue(valueType === 'single' ? value : node.getPath().map((item) => item.value), 'check', node.getModel());

// 当 trigger 为 hover 时 ,点击节点一定是关闭 panel 的操作
// 当 trigger 为 hover 时 ,点击节点一定是关闭 panel 的操作
if (!checkStrictly || propsTrigger === 'hover') {
setVisible(false, {});
}
Expand Down
2 changes: 1 addition & 1 deletion src/dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const Dialog = forwardRef<DialogInstance, DialogProps>((originalProps, ref) => {

const onAnimateStart = () => {
if (!wrapRef.current) return;
onBeforeOpen?.()
onBeforeOpen?.();
wrapRef.current.style.display = 'block';
};

Expand Down
1 change: 0 additions & 1 deletion src/select/base/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ const Select = forwardRefWithStatics(
return;
}


const values = currentOptions
.filter((option) => !option.checkAll && !option.disabled)
.map((option) => option[keys?.value || 'value']);
Expand Down
28 changes: 26 additions & 2 deletions src/tree/Tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ const Tree = forwardRef<TreeInstanceFunctions<TreeOptionData>, TreeProps>((origi
allowDrop,
} = props;

const { value, onChange, expanded, onExpand, onActive, actived } = useControllable(props);
const { value, onChange, expanded, onExpand, onActive, actived, setTreeIndeterminate, indeterminate } =
useControllable(props);

// 国际化文本初始化
const emptyText = locale('empty');
Expand All @@ -81,6 +82,8 @@ const Tree = forwardRef<TreeInstanceFunctions<TreeOptionData>, TreeProps>((origi
onExpand,
onActive,
actived,
indeterminate,
setTreeIndeterminate,
},
initial,
);
Expand All @@ -104,6 +107,21 @@ const Tree = forwardRef<TreeInstanceFunctions<TreeOptionData>, TreeProps>((origi
return expanded;
},
);

// 因为是被 useImperativeHandle 依赖的方法,使用 usePersistFn 变成持久化的。或者也可以使用 useCallback
const setIndeterminate = usePersistFn(
(
node: TreeNode,
isIndeterminate: boolean,
ctx: { e?: MouseEvent<HTMLDivElement>; trigger: 'node-click' | 'icon-click' | 'setItem' },
) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { e, trigger } = ctx;
const indeterminate = node.setIndeterminate(isIndeterminate);
return indeterminate;
},
);

const treeRef = useRef(null);

const {
Expand Down Expand Up @@ -254,11 +272,17 @@ const Tree = forwardRef<TreeInstanceFunctions<TreeOptionData>, TreeProps>((origi
setChecked(node, spec.checked, { trigger: 'setItem' });
delete spec.checked;
}
if ('indeterminate' in options) {
// @ts-ignore
setTreeIndeterminate((prevIndeterminate: TreeNodeValue[]) => [...prevIndeterminate, value]);
setIndeterminate(node, spec.indeterminate, { trigger: 'setItem' });
delete spec.indeterminate;
}
node.set(spec);
}
},
}),
[store, setExpanded, setActived, setChecked, handleScrollToElement],
[store, setExpanded, setActived, setTreeIndeterminate, setChecked, setIndeterminate, handleScrollToElement],
);

/* ======== render ======= */
Expand Down
17 changes: 14 additions & 3 deletions src/tree/hooks/useControllable.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { useState } from 'react';
import useControlled from '../../hooks/useControlled';
import { TdTreeProps } from '../type';
import type { TreeNodeValue } from '../../_common/js/tree-v1/types';

export default function useControllable(
props: TdTreeProps,
): Pick<TdTreeProps, 'value' | 'onChange' | 'expanded' | 'onExpand' | 'actived' | 'onActive'> {
export default function useControllable(props: TdTreeProps): Pick<
TdTreeProps,
'value' | 'onChange' | 'expanded' | 'onExpand' | 'actived' | 'onActive'
> & {
setTreeIndeterminate: (value: Array<TreeNodeValue>) => void;
indeterminate: Array<TreeNodeValue>;
} {
const [value, onChange] = useControlled(props, 'value', props.onChange);

const [expanded, onExpand] = useControlled(props, 'expanded', props.onExpand);

const [actived, onActive] = useControlled(props, 'actived', props.onActive);

// Indeterminate state
const [indeterminate, setTreeIndeterminate] = useState([]);

return {
value,
onChange,
expanded,
onExpand,
actived,
onActive,
setTreeIndeterminate,
indeterminate,
};
}
22 changes: 19 additions & 3 deletions src/tree/hooks/useStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import { usePersistFn } from '../../hooks/usePersistFn';

import type { TdTreeProps } from '../type';
import type { TypeEventState } from '../interface';
import type { TypeTreeNodeData } from '../../_common/js/tree-v1/types';
import type { TreeNodeValue, TypeTreeNodeData } from '../../_common/js/tree-v1/types';
import TreeNode from '../../_common/js/tree-v1/tree-node';

export function useStore(props: TdTreeProps, refresh: () => void): TreeStore {
export function useStore(
props: TdTreeProps & { indeterminate: any; setTreeIndeterminate: any },
refresh: () => void,
): TreeStore {
const storeRef = useRef<TreeStore>();
const [filterChanged, toggleFilterChanged] = useState(false);
const [prevExpanded, changePrevExpanded] = useState(null);
Expand All @@ -34,6 +38,8 @@ export function useStore(props: TdTreeProps, refresh: () => void): TreeStore {
valueMode,
filter,
onLoad,
indeterminate,
setTreeIndeterminate,
allowFoldNodeOnFilter = false,
} = props;

Expand Down Expand Up @@ -129,7 +135,6 @@ export function useStore(props: TdTreeProps, refresh: () => void): TreeStore {
// 刷新节点,必须在配置选中之前执行
// 这样选中态联动判断才能找到父节点
store.refreshNodes();

// 初始化选中状态
if (Array.isArray(value)) {
store.setChecked(value);
Expand Down Expand Up @@ -223,6 +228,11 @@ export function useStore(props: TdTreeProps, refresh: () => void): TreeStore {
useUpdateLayoutEffect(() => {
if (Array.isArray(value)) {
store.replaceChecked(value);
const checkedValue = store.getCheckedNodes().map((v: TreeNode) => v.data[keys?.value || 'value']);
const indeterminateConflict = checkedValue.filter((v) => indeterminate.includes(v));
if (indeterminateConflict.length) {
setTreeIndeterminate(indeterminate.filter((v: TreeNodeValue) => !indeterminateConflict.includes(v)));
}
}
}, [store, value, data]);

Expand All @@ -239,6 +249,12 @@ export function useStore(props: TdTreeProps, refresh: () => void): TreeStore {
}
}, [actived, store]);

useUpdateLayoutEffect(() => {
if (Array.isArray(indeterminate)) {
store.replaceIndeterminate(indeterminate);
}
}, [indeterminate, store, data]);

useUpdateLayoutEffect(() => {
store.setConfig({
filter,
Expand Down

0 comments on commit 4282c4b

Please sign in to comment.