123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import { GroupId, ExcalidrawElement, NonDeleted } from "./element/types";
- import { AppState } from "./types";
- import { getSelectedElements } from "./scene";
- export function selectGroup(
- groupId: GroupId,
- appState: AppState,
- elements: readonly NonDeleted<ExcalidrawElement>[],
- ): AppState {
- const elementsInGroup = elements.filter((element) =>
- element.groupIds.includes(groupId),
- );
- if (elementsInGroup.length < 2) {
- if (
- appState.selectedGroupIds[groupId] ||
- appState.editingGroupId === groupId
- ) {
- return {
- ...appState,
- selectedGroupIds: { ...appState.selectedGroupIds, [groupId]: false },
- editingGroupId: null,
- };
- }
- return appState;
- }
- return {
- ...appState,
- selectedGroupIds: { ...appState.selectedGroupIds, [groupId]: true },
- selectedElementIds: {
- ...appState.selectedElementIds,
- ...Object.fromEntries(
- elementsInGroup.map((element) => [element.id, true]),
- ),
- },
- };
- }
- /**
- * If the element's group is selected, don't render an individual
- * selection border around it.
- */
- export function isSelectedViaGroup(
- appState: AppState,
- element: ExcalidrawElement,
- ) {
- return !!element.groupIds
- .filter((groupId) => groupId !== appState.editingGroupId)
- .find((groupId) => appState.selectedGroupIds[groupId]);
- }
- export function getSelectedGroupIds(appState: AppState): GroupId[] {
- return Object.entries(appState.selectedGroupIds)
- .filter(([groupId, isSelected]) => isSelected)
- .map(([groupId, isSelected]) => groupId);
- }
- /**
- * When you select an element, you often want to actually select the whole group it's in, unless
- * you're currently editing that group.
- */
- export function selectGroupsForSelectedElements(
- appState: AppState,
- elements: readonly NonDeleted<ExcalidrawElement>[],
- ): AppState {
- let nextAppState = { ...appState };
- const selectedElements = getSelectedElements(elements, appState);
- for (const selectedElement of selectedElements) {
- let groupIds = selectedElement.groupIds;
- if (appState.editingGroupId) {
- // handle the case where a group is nested within a group
- const indexOfEditingGroup = groupIds.indexOf(appState.editingGroupId);
- if (indexOfEditingGroup > -1) {
- groupIds = groupIds.slice(0, indexOfEditingGroup);
- }
- }
- if (groupIds.length > 0) {
- const groupId = groupIds[groupIds.length - 1];
- nextAppState = selectGroup(groupId, nextAppState, elements);
- }
- }
- return nextAppState;
- }
- export function isElementInGroup(element: ExcalidrawElement, groupId: string) {
- return element.groupIds.includes(groupId);
- }
- export function getElementsInGroup(
- elements: readonly ExcalidrawElement[],
- groupId: string,
- ) {
- return elements.filter((element) => isElementInGroup(element, groupId));
- }
- export function getSelectedGroupIdForElement(
- element: ExcalidrawElement,
- selectedGroupIds: { [groupId: string]: boolean },
- ) {
- return element.groupIds.find((groupId) => selectedGroupIds[groupId]);
- }
- export function getNewGroupIdsForDuplication(
- groupIds: ExcalidrawElement["groupIds"],
- editingGroupId: AppState["editingGroupId"],
- mapper: (groupId: GroupId) => GroupId,
- ) {
- const copy = [...groupIds];
- const positionOfEditingGroupId = editingGroupId
- ? groupIds.indexOf(editingGroupId)
- : -1;
- const endIndex =
- positionOfEditingGroupId > -1 ? positionOfEditingGroupId : groupIds.length;
- for (let i = 0; i < endIndex; i++) {
- copy[i] = mapper(copy[i]);
- }
- return copy;
- }
- export function addToGroup(
- prevGroupIds: ExcalidrawElement["groupIds"],
- newGroupId: GroupId,
- editingGroupId: AppState["editingGroupId"],
- ) {
- // insert before the editingGroupId, or push to the end.
- const groupIds = [...prevGroupIds];
- const positionOfEditingGroupId = editingGroupId
- ? groupIds.indexOf(editingGroupId)
- : -1;
- const positionToInsert =
- positionOfEditingGroupId > -1 ? positionOfEditingGroupId : groupIds.length;
- groupIds.splice(positionToInsert, 0, newGroupId);
- return groupIds;
- }
- export function removeFromSelectedGroups(
- groupIds: ExcalidrawElement["groupIds"],
- selectedGroupIds: { [groupId: string]: boolean },
- ) {
- return groupIds.filter((groupId) => !selectedGroupIds[groupId]);
- }
|