UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

143 lines (142 loc) 5.32 kB
import { batch, computed, signal } from "@preact/signals-core"; import groupBy from "lodash/groupBy"; import { ESelectionStrategy } from "../../utils/types/types"; import { GroupState } from "./Group"; export class GroupsListStore { constructor(rootStore, graph) { this.rootStore = rootStore; this.graph = graph; this.$groupsMap = signal(new Map()); this.$groups = computed(() => { return Array.from(this.$groupsMap.value.values()); }); this.$blockGroups = computed(() => { return groupBy(this.rootStore.blocksList.$blocks.value, (item) => item.$state.value.group); }); this.$selectedGroups = computed(() => { return this.$groups.value.filter((group) => group.selected); }); } updateGroupsMap(groups) { this.$groupsMap.value = new Map(groups); } addGroup(group) { this.$groupsMap.value.set(group.id, this.getOrCreateGroupState(group)); this.updateGroupsMap(this.$groupsMap.value); return group.id; } deleteGroups(groups) { const map = new Map(this.$groupsMap.value); groups.forEach((gId) => { const id = typeof gId === "string" ? gId : gId.id; map.delete(id); }); this.updateGroupsMap(map); } updateGroups(groups) { this.updateGroupsMap(groups.reduce((acc, group) => { const state = this.getOrCreateGroupState(group); acc.set(group.id, state); return acc; }, this.$groupsMap.value)); } setGroups(groups) { const groupStates = groups.map((group) => this.getOrCreateGroupState(group)); this.applyGroupsState(groupStates); } getOrCreateGroupState(group) { const groupState = this.$groupsMap.value.get(group.id); if (groupState) { groupState.updateGroup(group); return groupState; } return GroupState.fromTGroup(this, group); } applyGroupsState(groups) { this.updateGroupsMap(groups.map((group) => [group.id, group])); } getGroupState(id) { return this.$groupsMap.value.get(id); } getGroup(id) { return this.getGroupState(id)?.asTGroup(); } reset() { this.applyGroupsState([]); } toJSON() { return this.$groups.value.map((group) => group.asTGroup()); } setGroupSelection(group, selected, params) { const groupState = group instanceof GroupState ? group : this.$groupsMap.value.get(group); if (!groupState) { return false; } if (selected !== Boolean(groupState.selected)) { if (!params?.ignoreChanges) { groupState.updateGroup({ selected }); } return true; } return false; } computeSelectionChange(ids, selected, strategy = ESelectionStrategy.REPLACE) { const list = new Set(this.$selectedGroups.value); let add; let removed; if (!selected) { removed = new Set(this.getGroupStates(ids).filter((group) => { if (this.setGroupSelection(group.id, false, { ignoreChanges: true })) { list.delete(group); return true; } return false; })); } else { if (strategy === ESelectionStrategy.REPLACE) { removed = new Set(this.$selectedGroups.value.filter((group) => { return this.setGroupSelection(group.id, false, { ignoreChanges: true }); })); list.clear(); } add = new Set(this.getGroupStates(ids).filter((group) => { if (this.setGroupSelection(group.id, true, { ignoreChanges: true }) || strategy === ESelectionStrategy.REPLACE) { removed?.delete(group); list.add(group); return true; } return false; })); } return { add: Array.from(add || []), removed: Array.from(removed || []), list: Array.from(list) }; } updateGroupsSelection(ids, selected, strategy = ESelectionStrategy.REPLACE) { const { add, removed, list } = this.computeSelectionChange(ids, selected, strategy); if (add.length || removed.length) { this.graph.executеDefaultEventAction("groups-selection-change", { list: list.map((group) => group.id), changes: { add: add.map((group) => group.id), removed: removed.map((group) => group.id), }, }, () => { batch(() => { removed.forEach((group) => { this.setGroupSelection(group.id, false); }); add.forEach((group) => { this.setGroupSelection(group.id, true); }); }); }); } } resetSelection() { this.updateGroupsSelection(this.$selectedGroups.value.map((group) => group.id), false); } getGroupStates(ids) { return ids.map((id) => this.getGroupState(id)).filter(Boolean); } }