Skip to content

Commit

Permalink
[pr] d2c
Browse files Browse the repository at this point in the history
  • Loading branch information
dwelle committed Nov 23, 2023
1 parent 203459c commit 09e68b7
Show file tree
Hide file tree
Showing 62 changed files with 2,108 additions and 428 deletions.
3 changes: 2 additions & 1 deletion src/actions/actionAlign.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "../components/icons";
import { ToolButton } from "../components/ToolButton";
import { getNonDeletedElements } from "../element";
import { isFrameLikeElement } from "../element/typeChecks";
import { ExcalidrawElement } from "../element/types";
import { updateFrameMembershipOfSelectedElements } from "../frame";
import { t } from "../i18n";
Expand All @@ -28,7 +29,7 @@ const alignActionsPredicate = (
return (
selectedElements.length > 1 &&
// TODO enable aligning frames when implemented properly
!selectedElements.some((el) => el.type === "frame")
!selectedElements.some((el) => isFrameLikeElement(el))
);
};

Expand Down
4 changes: 2 additions & 2 deletions src/actions/actionDeleteSelected.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { newElementWith } from "../element/mutateElement";
import { getElementsInGroup } from "../groups";
import { LinearElementEditor } from "../element/linearElementEditor";
import { fixBindingsAfterDeletion } from "../element/binding";
import { isBoundToContainer } from "../element/typeChecks";
import { isBoundToContainer, isFrameLikeElement } from "../element/typeChecks";
import { updateActiveTool } from "../utils";
import { TrashIcon } from "../components/icons";

Expand All @@ -20,7 +20,7 @@ const deleteSelectedElements = (
) => {
const framesToBeDeleted = new Set(
getSelectedElements(
elements.filter((el) => el.type === "frame"),
elements.filter((el) => isFrameLikeElement(el)),
appState,
).map((el) => el.id),
);
Expand Down
3 changes: 2 additions & 1 deletion src/actions/actionDistribute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import { ToolButton } from "../components/ToolButton";
import { distributeElements, Distribution } from "../distribute";
import { getNonDeletedElements } from "../element";
import { isFrameLikeElement } from "../element/typeChecks";
import { ExcalidrawElement } from "../element/types";
import { updateFrameMembershipOfSelectedElements } from "../frame";
import { t } from "../i18n";
Expand All @@ -19,7 +20,7 @@ const enableActionGroup = (appState: AppState, app: AppClassProperties) => {
return (
selectedElements.length > 1 &&
// TODO enable distributing frames when implemented properly
!selectedElements.some((el) => el.type === "frame")
!selectedElements.some((el) => isFrameLikeElement(el))
);
};

Expand Down
10 changes: 5 additions & 5 deletions src/actions/actionDuplicateSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
bindTextToShapeAfterDuplication,
getBoundTextElement,
} from "../element/textElement";
import { isBoundToContainer, isFrameElement } from "../element/typeChecks";
import { isBoundToContainer, isFrameLikeElement } from "../element/typeChecks";
import { normalizeElementOrder } from "../element/sortElements";
import { DuplicateIcon } from "../components/icons";
import {
Expand Down Expand Up @@ -140,11 +140,11 @@ const duplicateElements = (
}

const boundTextElement = getBoundTextElement(element);
const isElementAFrame = isFrameElement(element);
const isElementAFrameLike = isFrameLikeElement(element);

if (idsOfElementsToDuplicate.get(element.id)) {
// if a group or a container/bound-text or frame, duplicate atomically
if (element.groupIds.length || boundTextElement || isElementAFrame) {
if (element.groupIds.length || boundTextElement || isElementAFrameLike) {
const groupId = getSelectedGroupForElement(appState, element);
if (groupId) {
// TODO:
Expand All @@ -154,7 +154,7 @@ const duplicateElements = (
sortedElements,
groupId,
).flatMap((element) =>
isFrameElement(element)
isFrameLikeElement(element)
? [...getFrameChildren(elements, element.id), element]
: [element],
);
Expand All @@ -180,7 +180,7 @@ const duplicateElements = (
);
continue;
}
if (isElementAFrame) {
if (isElementAFrameLike) {
const elementsInFrame = getFrameChildren(sortedElements, element.id);

elementsWithClones.push(
Expand Down
3 changes: 2 additions & 1 deletion src/actions/actionElementLock.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { newElementWith } from "../element/mutateElement";
import { isFrameLikeElement } from "../element/typeChecks";
import { ExcalidrawElement } from "../element/types";
import { KEYS } from "../keys";
import { arrayToMap } from "../utils";
Expand Down Expand Up @@ -51,7 +52,7 @@ export const actionToggleElementLock = register({
selectedElementIds: appState.selectedElementIds,
includeBoundTextElement: false,
});
if (selected.length === 1 && selected[0].type !== "frame") {
if (selected.length === 1 && !isFrameLikeElement(selected[0])) {
return selected[0].locked
? "labels.elementLock.unlock"
: "labels.elementLock.lock";
Expand Down
25 changes: 17 additions & 8 deletions src/actions/actionFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,27 @@ import { AppClassProperties, AppState } from "../types";
import { updateActiveTool } from "../utils";
import { setCursorForShape } from "../cursor";
import { register } from "./register";
import { isFrameLikeElement } from "../element/typeChecks";

const isSingleFrameSelected = (appState: AppState, app: AppClassProperties) => {
const selectedElements = app.scene.getSelectedElements(appState);

return selectedElements.length === 1 && selectedElements[0].type === "frame";
return (
selectedElements.length === 1 && isFrameLikeElement(selectedElements[0])
);
};

export const actionSelectAllElementsInFrame = register({
name: "selectAllElementsInFrame",
trackEvent: { category: "canvas" },
perform: (elements, appState, _, app) => {
const selectedFrame = app.scene.getSelectedElements(appState)[0];
const selectedElement =
app.scene.getSelectedElements(appState).at(0) || null;

if (selectedFrame && selectedFrame.type === "frame") {
if (isFrameLikeElement(selectedElement)) {
const elementsInFrame = getFrameChildren(
getNonDeletedElements(elements),
selectedFrame.id,
selectedElement.id,
).filter((element) => !(element.type === "text" && element.containerId));

return {
Expand Down Expand Up @@ -54,15 +58,20 @@ export const actionRemoveAllElementsFromFrame = register({
name: "removeAllElementsFromFrame",
trackEvent: { category: "history" },
perform: (elements, appState, _, app) => {
const selectedFrame = app.scene.getSelectedElements(appState)[0];
const selectedElement =
app.scene.getSelectedElements(appState).at(0) || null;

if (selectedFrame && selectedFrame.type === "frame") {
if (isFrameLikeElement(selectedElement)) {
return {
elements: removeAllElementsFromFrame(elements, selectedFrame, appState),
elements: removeAllElementsFromFrame(
elements,
selectedElement,
appState,
),
appState: {
...appState,
selectedElementIds: {
[selectedFrame.id]: true,
[selectedElement.id]: true,
},
},
commitToHistory: true,
Expand Down
8 changes: 4 additions & 4 deletions src/actions/actionGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import { AppClassProperties, AppState } from "../types";
import { isBoundToContainer } from "../element/typeChecks";
import {
getElementsInResizingFrame,
getFrameElements,
groupByFrames,
getFrameLikeElements,
groupByFrameLikes,
removeElementsFromFrame,
replaceAllElementsInFrame,
} from "../frame";
Expand Down Expand Up @@ -102,7 +102,7 @@ export const actionGroup = register({
// when it happens, we want to remove elements that are in the frame
// and are going to be grouped from the frame (mouthful, I know)
if (groupingElementsFromDifferentFrames) {
const frameElementsMap = groupByFrames(selectedElements);
const frameElementsMap = groupByFrameLikes(selectedElements);

frameElementsMap.forEach((elementsInFrame, frameId) => {
nextElements = removeElementsFromFrame(
Expand Down Expand Up @@ -219,7 +219,7 @@ export const actionUngroup = register({
.map((element) => element.frameId!),
);

const targetFrames = getFrameElements(elements).filter((frame) =>
const targetFrames = getFrameLikeElements(elements).filter((frame) =>
selectedElementFrameIds.has(frame.id),
);

Expand Down
4 changes: 2 additions & 2 deletions src/actions/actionStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
hasBoundTextElement,
canApplyRoundnessTypeToElement,
getDefaultRoundnessTypeForElement,
isFrameElement,
isFrameLikeElement,
isArrowElement,
} from "../element/typeChecks";
import { getSelectedElements } from "../scene";
Expand Down Expand Up @@ -138,7 +138,7 @@ export const actionPasteStyles = register({
});
}

if (isFrameElement(element)) {
if (isFrameLikeElement(element)) {
newElement = newElementWith(newElement, {
roundness: null,
backgroundColor: "transparent",
Expand Down
7 changes: 5 additions & 2 deletions src/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import {
EXPORT_DATA_TYPES,
MIME_TYPES,
} from "./constants";
import { isInitializedImageElement } from "./element/typeChecks";
import {
isFrameLikeElement,
isInitializedImageElement,
} from "./element/typeChecks";
import { deepCopyElement } from "./element/newElement";
import { mutateElement } from "./element/mutateElement";
import { getContainingFrame } from "./frame";
Expand Down Expand Up @@ -124,7 +127,7 @@ export const serializeAsClipboardJSON = ({
files: BinaryFiles | null;
}) => {
const framesToCopy = new Set(
elements.filter((element) => element.type === "frame"),
elements.filter((element) => isFrameLikeElement(element)),
);
let foundFile = false;

Expand Down
32 changes: 29 additions & 3 deletions src/components/Actions.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from "react";
import { ActionManager } from "../actions/manager";
import { getNonDeletedElements } from "../element";
import { ExcalidrawElement } from "../element/types";
import { ExcalidrawElement, ExcalidrawElementType } from "../element/types";
import { t } from "../i18n";
import { useDevice } from "../components/App";
import {
Expand Down Expand Up @@ -36,6 +36,8 @@ import {
frameToolIcon,
mermaidLogoIcon,
laserPointerToolIcon,
OpenAIIcon,
MagicIcon,
} from "./icons";
import { KEYS } from "../keys";

Expand Down Expand Up @@ -79,7 +81,8 @@ export const SelectedShapeActions = ({
const showLinkIcon =
targetElements.length === 1 || isSingleElementBoundContainer;

let commonSelectedType: string | null = targetElements[0]?.type || null;
let commonSelectedType: ExcalidrawElementType | null =
targetElements[0]?.type || null;

for (const element of targetElements) {
if (element.type !== commonSelectedType) {
Expand All @@ -94,7 +97,8 @@ export const SelectedShapeActions = ({
{((hasStrokeColor(appState.activeTool.type) &&
appState.activeTool.type !== "image" &&
commonSelectedType !== "image" &&
commonSelectedType !== "frame") ||
commonSelectedType !== "frame" &&
commonSelectedType !== "magicframe") ||
targetElements.some((element) => hasStrokeColor(element.type))) &&
renderAction("changeStrokeColor")}
</div>
Expand Down Expand Up @@ -331,13 +335,35 @@ export const ShapesSwitcher = ({
>
{t("toolBar.laser")}
</DropdownMenu.Item>
<div style={{ margin: "6px 0", fontSize: 14, fontWeight: 600 }}>
Generate
</div>
<DropdownMenu.Item
onSelect={() => app.setOpenDialog("mermaid")}
icon={mermaidLogoIcon}
data-testid="toolbar-embeddable"
>
{t("toolBar.mermaidToExcalidraw")}
</DropdownMenu.Item>

{app.props.aiEnabled !== false && (
<>
<DropdownMenu.Item
onSelect={() => app.onMagicButtonSelect()}
icon={MagicIcon}
data-testid="toolbar-magicframe"
>
{t("toolBar.magicframe")}
</DropdownMenu.Item>
<DropdownMenu.Item
onSelect={() => app.setOpenDialog("magicSettings")}
icon={OpenAIIcon}
data-testid="toolbar-magicSettings"
>
{t("toolBar.magicSettings")}
</DropdownMenu.Item>
</>
)}
</DropdownMenu.Content>
</DropdownMenu>
</>
Expand Down

0 comments on commit 09e68b7

Please sign in to comment.