Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Tree): support set Indeterminate #1993

Merged
merged 5 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion js/date-picker/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ export function flagActive(data: any[], { ...args }: FlagActiveOptions) {
const _item = item;

if (multiple) {
_item.active = (value as DateValue[]).some((val) => isSame(dayjs(val).toDate(), _item.value, type) && !_item.additional);
_item.active = (value as DateValue[])?.some?.((val) => isSame(dayjs(val).toDate(), _item.value, type) && !_item.additional);
} else {
_item.active = start && isSame(item.value, start, type) && !_item.additional;
}
Expand Down
75 changes: 64 additions & 11 deletions js/tree-v1/tree-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ import {
TypeTreeNodeModel,
TypeTreeNodeData,
} from './types';
import {
createNodeModel,
updateNodeModel,
} from './tree-node-model';
import { createNodeModel, updateNodeModel } from './tree-node-model';
import log from '../log';

const { hasOwnProperty } = Object.prototype;
Expand All @@ -35,7 +32,12 @@ export const setableStatus: Record<string, boolean | null> = {

export const setableProps = Object.keys(setableStatus);

export const syncableProps = [...setableProps, 'actived', 'expanded', 'checked'];
export const syncableProps = [
...setableProps,
'actived',
'expanded',
'checked',
];

export const privateKey = '__tdesign_id__';

Expand Down Expand Up @@ -109,6 +111,8 @@ export class TreeNode {
// 节点在视图上实际的选中态
public checked: boolean;

public isIndeterminateManual: boolean;

// 节点实际是否为半选状态
public indeterminate: boolean;

Expand All @@ -130,7 +134,7 @@ export class TreeNode {
public constructor(
tree: TreeStore,
data?: TypeTreeNodeData,
parent?: TreeNode,
parent?: TreeNode
) {
this.data = data;
this.tree = tree;
Expand Down Expand Up @@ -552,7 +556,11 @@ export class TreeNode {
const { tree } = this;
const keys = Object.keys(item);
keys.forEach((key) => {
if (hasOwnProperty.call(setableStatus, key) || key === 'label' || key === 'disabled') {
if (
hasOwnProperty.call(setableStatus, key)
|| key === 'label'
|| key === 'disabled'
) {
this[key] = item[key];
}
});
Expand Down Expand Up @@ -737,7 +745,12 @@ export class TreeNode {
const { tree } = this;
const { hasFilter, config } = tree;
const { disabled, allowFoldNodeOnFilter } = config;
if (hasFilter && !allowFoldNodeOnFilter && this.vmIsLocked && !this.vmIsRest) {
if (
hasFilter
&& !allowFoldNodeOnFilter
&& this.vmIsLocked
&& !this.vmIsRest
) {
return true;
}
let state = disabled;
Expand Down Expand Up @@ -1124,6 +1137,7 @@ export class TreeNode {
...opts,
};
let map = tree.checkedMap;

if (!options.directly) {
map = new Map(tree.checkedMap);
}
Expand Down Expand Up @@ -1168,6 +1182,41 @@ export class TreeNode {
});
}
}
this.isIndeterminateManual = false;

return tree.getChecked(map);
}

public setIndeterminate(indeterminate: boolean, opts?: TypeSettingOptions) {
const { tree } = this;
const config = tree.config || {};
const options: TypeSettingOptions = {
// 为 true, 为 UI 操作,状态扩散受 disabled 影响
// 为 false, 为值操作, 状态扩散不受 disabled 影响
isAction: true,
// 为 true, 直接操作节点状态
// 为 false, 返回预期状态
directly: false,
...opts,
};
let map = tree.checkedMap;
if (!options.directly) {
map = new Map(tree.checkedMap);
}
if (!this.isCheckable()) {
// 当前节点非可选节点,则不可设置选中态
return tree.getChecked(map);
}
if (options.isAction && this.isDisabled()) {
// 对于 UI 动作,禁用时不可切换选中态
return tree.getChecked(map);
}
if (indeterminate === this.isIndeterminate()) {
// 值没有变更,则选中态无变化
return tree.getChecked(map);
}
this.indeterminate = indeterminate;
this.isIndeterminateManual = true;

return tree.getChecked(map);
}
Expand All @@ -1183,7 +1232,6 @@ export class TreeNode {
directly: false,
...opts,
};

// 碰到不可选节点,中断扩散
if (!this.isCheckable()) return;

Expand Down Expand Up @@ -1252,8 +1300,12 @@ export class TreeNode {
* 更新节点选中态
* @return void
*/
public updateChecked(): void {
const { tree, value } = this;
public updateChecked(from?: string): void {
const { tree, value, isIndeterminateManual } = this;
if (isIndeterminateManual && ['refresh'].includes(from)) {
return;
}

const { checkedMap } = tree;
this.checked = this.isChecked();
this.indeterminate = this.isIndeterminate();
Expand Down Expand Up @@ -1303,6 +1355,7 @@ export class TreeNode {
const relatedNodes = tree.getRelatedNodes([this.value]);
relatedNodes.forEach((node) => {
node.update();
if (node.isIndeterminateManual && node.indeterminate) return;
node.updateChecked();
});
}
Expand Down
31 changes: 25 additions & 6 deletions js/tree-v1/tree-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ export class TreeStore {
// 选中节点集合
public checkedMap: TypeIdMap;

// 设置半选集合
public indeterminateMap: TypeIdMap;

// 展开节点的集合
public expandedMap: TypeIdMap;

Expand Down Expand Up @@ -138,6 +141,7 @@ export class TreeStore {
this.expandedMap = new Map();
this.checkedMap = new Map();
this.updatedMap = new Map();
this.indeterminateMap = new Map();
this.filterMap = new Map();
this.prevFilter = null;
// 这个计时器确保频繁的 update 事件被归纳为1次完整数据更新后的触发
Expand Down Expand Up @@ -272,7 +276,7 @@ export class TreeStore {
*/
public getNodes(
item?: TypeTargetNode,
options?: TypeTreeFilterOptions,
options?: TypeTreeFilterOptions
): TreeNode[] {
let nodes: TreeNode[] = [];
let val: TreeNodeValue = '';
Expand Down Expand Up @@ -355,7 +359,7 @@ export class TreeStore {
*/
private parseNodeData(
para: TreeNodeValue | TreeNode | TypeTreeNodeData,
item: TypeTreeNodeData | TreeNode,
item: TypeTreeNodeData | TreeNode
) {
let value: TreeNodeValue = '';
let node = null;
Expand Down Expand Up @@ -398,7 +402,7 @@ export class TreeStore {
*/
public appendNodes(
para: TypeTargetNode | TypeTreeNodeData,
item?: TypeTreeNodeData | TreeNode,
item?: TypeTreeNodeData | TreeNode
): void {
const spec = this.parseNodeData(para, item);
if (spec.data) {
Expand Down Expand Up @@ -476,7 +480,7 @@ export class TreeStore {
// 所以遍历 nodeMap 确保初始化阶段 refreshState 方法也可以触发全部节点的更新
nodeMap.forEach((node) => {
node.update();
node.updateChecked();
node.updateChecked('refresh');
});
}

Expand Down Expand Up @@ -577,6 +581,21 @@ export class TreeStore {
this.setActived(list);
}

public replaceIndeterminate(list: TreeNodeValue[]): void {
this.setIndeterminate(list);
}

public setIndeterminate(indeterminate: TreeNodeValue[]): void {
indeterminate.forEach((val) => {
this.indeterminateMap.set(val, true);
const node = this.getNode(val);
if (node) {
node.setIndeterminate(true);
node.update();
}
});
}

/**
* 设置激活态
* @param {string[]} list 目标节点值数组
Expand Down Expand Up @@ -796,7 +815,7 @@ export class TreeStore {
public updateAll(): void {
this.nodeMap.forEach((node) => {
node.update();
node.updateChecked();
node.updateChecked('refresh');
});
}

Expand Down Expand Up @@ -834,7 +853,7 @@ export class TreeStore {
*/
public getRelatedNodes(
list: TreeNodeValue[],
options?: TypeRelatedNodesOptions,
options?: TypeRelatedNodesOptions
): TreeNode[] {
const conf = {
// 默认倒序排列,从底层节点开始遍历
Expand Down
Loading