diff --git a/.npmrc b/.npmrc index cffe8cdef..1b78f1c6f 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ save-exact=true +legacy-peer-deps=true diff --git a/package.json b/package.json index 4330c81e8..a64127e2e 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ }, "dependencies": { "@excalidraw/extensions": "link:src/packages/extensions", + "@excalidraw/random-username": "1.0.0", + "@radix-ui/react-popover": "1.0.3", "@radix-ui/react-tabs": "1.0.2", "@sentry/browser": "6.2.5", "@sentry/integrations": "6.2.5", @@ -27,6 +29,7 @@ "@testing-library/react": "12.1.5", "@tldraw/vec": "1.7.1", "browser-fs-access": "0.29.1", + "canvas-roundrect-polyfill": "0.0.1", "clsx": "1.1.1", "cross-env": "7.0.3", "fake-indexeddb": "3.1.7", @@ -34,7 +37,7 @@ "i18next-browser-languagedetector": "6.1.4", "idb-keyval": "6.0.3", "image-blob-reduce": "3.0.1", - "jotai": "1.6.4", + "jotai": "1.13.1", "lodash.throttle": "4.1.1", "nanoid": "3.3.3", "open-color": "1.9.1", @@ -96,8 +99,17 @@ }, "homepage": ".", "jest": { + "collectCoverageFrom": [ + "src/**/*.{js,jsx,ts,tsx}" + ], + "coveragePathIgnorePatterns": [ + "/locales", + "/src/packages/excalidraw/dist/", + "/src/packages/excalidraw/types", + "/src/packages/excalidraw/example" + ], "transformIgnorePatterns": [ - "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access)/)" + "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access|canvas-roundrect-polyfill)/)" ], "resetMocks": false }, @@ -128,6 +140,7 @@ "test:typecheck": "tsc", "test:update": "yarn test:app --updateSnapshot --watchAll=false", "test": "yarn test:app", + "test:coverage": "react-scripts test --passWithNoTests --coverage --watchAll", "autorelease": "node scripts/autorelease.js", "prerelease": "node scripts/prerelease.js", "release": "node scripts/release.js" diff --git a/src/actions/actionAddToLibrary.ts b/src/actions/actionAddToLibrary.ts index a4fca560a..ef69a60de 100644 --- a/src/actions/actionAddToLibrary.ts +++ b/src/actions/actionAddToLibrary.ts @@ -12,7 +12,10 @@ export const actionAddToLibrary = register({ const selectedElements = getSelectedElements( getNonDeletedElements(elements), appState, - true, + { + includeBoundTextElement: true, + includeElementsInFrames: true, + }, ); if (selectedElements.some((element) => element.type === "image")) { return { diff --git a/src/actions/actionAlign.tsx b/src/actions/actionAlign.tsx index eceb42171..d917f8037 100644 --- a/src/actions/actionAlign.tsx +++ b/src/actions/actionAlign.tsx @@ -10,6 +10,7 @@ import { import { ToolButton } from "../components/ToolButton"; import { getNonDeletedElements } from "../element"; import { ExcalidrawElement } from "../element/types"; +import { updateFrameMembershipOfSelectedElements } from "../frame"; import { t } from "../i18n"; import { KEYS } from "../keys"; import { getSelectedElements, isSomeElementSelected } from "../scene"; @@ -17,10 +18,20 @@ import { AppState } from "../types"; import { arrayToMap, getShortcutKey } from "../utils"; import { register } from "./register"; -const enableActionGroup = ( +const alignActionsPredicate = ( elements: readonly ExcalidrawElement[], appState: AppState, -) => getSelectedElements(getNonDeletedElements(elements), appState).length > 1; +) => { + const selectedElements = getSelectedElements( + getNonDeletedElements(elements), + appState, + ); + return ( + selectedElements.length > 1 && + // TODO enable aligning frames when implemented properly + !selectedElements.some((el) => el.type === "frame") + ); +}; const alignSelectedElements = ( elements: readonly ExcalidrawElement[], @@ -36,14 +47,16 @@ const alignSelectedElements = ( const updatedElementsMap = arrayToMap(updatedElements); - return elements.map( - (element) => updatedElementsMap.get(element.id) || element, + return updateFrameMembershipOfSelectedElements( + elements.map((element) => updatedElementsMap.get(element.id) || element), + appState, ); }; export const actionAlignTop = register({ name: "alignTop", trackEvent: { category: "element" }, + predicate: alignActionsPredicate, perform: (elements, appState) => { return { appState, @@ -58,7 +71,7 @@ export const actionAlignTop = register({ event[KEYS.CTRL_OR_CMD] && event.shiftKey && event.key === KEYS.ARROW_UP, PanelComponent: ({ elements, appState, updateData }) => (