Merge branch 'master' into ryan-di/line-snapping
# Conflicts: # packages/element/src/linearElementEditor.ts # packages/element/src/snapping.ts # packages/excalidraw/components/App.tsx
This commit is contained in:
commit
09b18cacec
2
.github/workflows/autorelease-excalidraw.yml
vendored
2
.github/workflows/autorelease-excalidraw.yml
vendored
@ -24,4 +24,4 @@ jobs:
|
|||||||
- name: Auto release
|
- name: Auto release
|
||||||
run: |
|
run: |
|
||||||
yarn add @actions/core -W
|
yarn add @actions/core -W
|
||||||
yarn autorelease
|
yarn release --tag=next --non-interactive
|
||||||
|
|||||||
55
.github/workflows/autorelease-preview.yml
vendored
55
.github/workflows/autorelease-preview.yml
vendored
@ -1,55 +0,0 @@
|
|||||||
name: Auto release excalidraw preview
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created, edited]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Auto-release-excalidraw-preview:
|
|
||||||
name: Auto release preview
|
|
||||||
if: github.event.comment.body == '@excalibot trigger release' && github.event.issue.pull_request
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: React to release comment
|
|
||||||
uses: peter-evans/create-or-update-comment@v1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.PUSH_TRANSLATIONS_COVERAGE_PAT }}
|
|
||||||
comment-id: ${{ github.event.comment.id }}
|
|
||||||
reactions: "+1"
|
|
||||||
- name: Get PR SHA
|
|
||||||
id: sha
|
|
||||||
uses: actions/github-script@v4
|
|
||||||
with:
|
|
||||||
result-encoding: string
|
|
||||||
script: |
|
|
||||||
const { owner, repo, number } = context.issue;
|
|
||||||
const pr = await github.pulls.get({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
pull_number: number,
|
|
||||||
});
|
|
||||||
return pr.data.head.sha
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
ref: ${{ steps.sha.outputs.result }}
|
|
||||||
fetch-depth: 2
|
|
||||||
- name: Setup Node.js 18.x
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: 18.x
|
|
||||||
- name: Set up publish access
|
|
||||||
run: |
|
|
||||||
npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
|
|
||||||
env:
|
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
- name: Auto release preview
|
|
||||||
id: "autorelease"
|
|
||||||
run: |
|
|
||||||
yarn add @actions/core -W
|
|
||||||
yarn autorelease preview ${{ github.event.issue.number }}
|
|
||||||
- name: Post comment post release
|
|
||||||
if: always()
|
|
||||||
uses: peter-evans/create-or-update-comment@v1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.PUSH_TRANSLATIONS_COVERAGE_PAT }}
|
|
||||||
issue-number: ${{ github.event.issue.number }}
|
|
||||||
body: "@${{ github.event.comment.user.login }} ${{ steps.autorelease.outputs.result }}"
|
|
||||||
@ -28,32 +28,12 @@ To start the example app using the `@excalidraw/excalidraw` package, follow the
|
|||||||
|
|
||||||
## Releasing
|
## Releasing
|
||||||
|
|
||||||
### Create a test release
|
|
||||||
|
|
||||||
You can create a test release by posting the below comment in your pull request:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
@excalibot trigger release
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the version is released `@excalibot` will post a comment with the release version.
|
|
||||||
|
|
||||||
### Creating a production release
|
### Creating a production release
|
||||||
|
|
||||||
To release the next stable version follow the below steps:
|
To release the next stable version follow the below steps:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn prerelease:excalidraw
|
yarn release --tag=latest --version=0.19.0
|
||||||
```
|
```
|
||||||
|
|
||||||
You need to pass the `version` for which you want to create the release. This will make the changes needed before making the release like updating `package.json`, `changelog` and more.
|
You will need to pass the `latest` tag with `version` for which you want to create the release. This will make the changes needed before publishing the packages into NPM, like updating dependencies of all `@excalidraw/*` packages, generating new entries in `CHANGELOG.md` and more.
|
||||||
|
|
||||||
The next step is to run the `release` script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn release:excalidraw
|
|
||||||
```
|
|
||||||
|
|
||||||
This will publish the package.
|
|
||||||
|
|
||||||
Right now there are two steps to create a production release but once this works fine these scripts will be combined and more automation will be done.
|
|
||||||
|
|||||||
@ -33,6 +33,7 @@ const ExcalidrawScope = {
|
|||||||
initialData,
|
initialData,
|
||||||
useI18n: ExcalidrawComp.useI18n,
|
useI18n: ExcalidrawComp.useI18n,
|
||||||
convertToExcalidrawElements: ExcalidrawComp.convertToExcalidrawElements,
|
convertToExcalidrawElements: ExcalidrawComp.convertToExcalidrawElements,
|
||||||
|
CaptureUpdateAction: ExcalidrawComp.CaptureUpdateAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ExcalidrawScope;
|
export default ExcalidrawScope;
|
||||||
|
|||||||
@ -3,7 +3,8 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:workspace": "yarn workspace @excalidraw/excalidraw run build:esm && yarn copy:assets",
|
"build:packages": "yarn --cwd ../../ build:packages",
|
||||||
|
"build:workspace": "yarn build:packages && yarn copy:assets",
|
||||||
"copy:assets": "cp -r ../../packages/excalidraw/dist/prod/fonts ./public",
|
"copy:assets": "cp -r ../../packages/excalidraw/dist/prod/fonts ./public",
|
||||||
"dev": "yarn build:workspace && next dev -p 3005",
|
"dev": "yarn build:workspace && next dev -p 3005",
|
||||||
"build": "yarn build:workspace && next build",
|
"build": "yarn build:workspace && next build",
|
||||||
|
|||||||
@ -17,6 +17,6 @@
|
|||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview --port 5002",
|
"preview": "vite preview --port 5002",
|
||||||
"build:preview": "yarn build && yarn preview",
|
"build:preview": "yarn build && yarn preview",
|
||||||
"build:package": "yarn workspace @excalidraw/excalidraw run build:esm"
|
"build:packages": "yarn --cwd ../../ build:packages"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"outputDirectory": "dist",
|
"outputDirectory": "dist",
|
||||||
"installCommand": "yarn install",
|
"installCommand": "yarn install",
|
||||||
"buildCommand": "yarn build:package && yarn build"
|
"buildCommand": "yarn build:packages && yarn build"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
} from "@excalidraw/excalidraw/renderer/helpers";
|
} from "@excalidraw/excalidraw/renderer/helpers";
|
||||||
import { type AppState } from "@excalidraw/excalidraw/types";
|
import { type AppState } from "@excalidraw/excalidraw/types";
|
||||||
import { throttleRAF } from "@excalidraw/common";
|
import { throttleRAF } from "@excalidraw/common";
|
||||||
import { useCallback, useImperativeHandle, useRef } from "react";
|
import { useCallback } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isLineSegment,
|
isLineSegment,
|
||||||
@ -18,6 +18,8 @@ import {
|
|||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
import { isCurve } from "@excalidraw/math/curve";
|
import { isCurve } from "@excalidraw/math/curve";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
import type { Curve } from "@excalidraw/math";
|
import type { Curve } from "@excalidraw/math";
|
||||||
|
|
||||||
import type { DebugElement } from "@excalidraw/utils/visualdebug";
|
import type { DebugElement } from "@excalidraw/utils/visualdebug";
|
||||||
@ -113,10 +115,6 @@ const _debugRenderer = (
|
|||||||
scale,
|
scale,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (appState.height !== canvas.height || appState.width !== canvas.width) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
const context = bootstrapCanvas({
|
const context = bootstrapCanvas({
|
||||||
canvas,
|
canvas,
|
||||||
scale,
|
scale,
|
||||||
@ -314,35 +312,29 @@ export const DebugFooter = ({ onChange }: { onChange: () => void }) => {
|
|||||||
interface DebugCanvasProps {
|
interface DebugCanvasProps {
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
scale: number;
|
scale: number;
|
||||||
ref?: React.Ref<HTMLCanvasElement>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DebugCanvas = ({ appState, scale, ref }: DebugCanvasProps) => {
|
const DebugCanvas = React.forwardRef<HTMLCanvasElement, DebugCanvasProps>(
|
||||||
const { width, height } = appState;
|
({ appState, scale }, ref) => {
|
||||||
|
const { width, height } = appState;
|
||||||
|
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
return (
|
||||||
useImperativeHandle<HTMLCanvasElement | null, HTMLCanvasElement | null>(
|
<canvas
|
||||||
ref,
|
style={{
|
||||||
() => canvasRef.current,
|
width,
|
||||||
[canvasRef],
|
height,
|
||||||
);
|
position: "absolute",
|
||||||
|
zIndex: 2,
|
||||||
return (
|
pointerEvents: "none",
|
||||||
<canvas
|
}}
|
||||||
style={{
|
width={width * scale}
|
||||||
width,
|
height={height * scale}
|
||||||
height,
|
ref={ref}
|
||||||
position: "absolute",
|
>
|
||||||
zIndex: 2,
|
Debug Canvas
|
||||||
pointerEvents: "none",
|
</canvas>
|
||||||
}}
|
);
|
||||||
width={width * scale}
|
},
|
||||||
height={height * scale}
|
);
|
||||||
ref={canvasRef}
|
|
||||||
>
|
|
||||||
Debug Canvas
|
|
||||||
</canvas>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DebugCanvas;
|
export default DebugCanvas;
|
||||||
|
|||||||
15
package.json
15
package.json
@ -52,13 +52,17 @@
|
|||||||
"build-node": "node ./scripts/build-node.js",
|
"build-node": "node ./scripts/build-node.js",
|
||||||
"build:app:docker": "yarn --cwd ./excalidraw-app build:app:docker",
|
"build:app:docker": "yarn --cwd ./excalidraw-app build:app:docker",
|
||||||
"build:app": "yarn --cwd ./excalidraw-app build:app",
|
"build:app": "yarn --cwd ./excalidraw-app build:app",
|
||||||
"build:package": "yarn --cwd ./packages/excalidraw build:esm",
|
"build:common": "yarn --cwd ./packages/common build:esm",
|
||||||
|
"build:element": "yarn --cwd ./packages/element build:esm",
|
||||||
|
"build:excalidraw": "yarn --cwd ./packages/excalidraw build:esm",
|
||||||
|
"build:math": "yarn --cwd ./packages/math build:esm",
|
||||||
|
"build:packages": "yarn build:common && yarn build:math && yarn build:element && yarn build:excalidraw",
|
||||||
"build:version": "yarn --cwd ./excalidraw-app build:version",
|
"build:version": "yarn --cwd ./excalidraw-app build:version",
|
||||||
"build": "yarn --cwd ./excalidraw-app build",
|
"build": "yarn --cwd ./excalidraw-app build",
|
||||||
"build:preview": "yarn --cwd ./excalidraw-app build:preview",
|
"build:preview": "yarn --cwd ./excalidraw-app build:preview",
|
||||||
"start": "yarn --cwd ./excalidraw-app start",
|
"start": "yarn --cwd ./excalidraw-app start",
|
||||||
"start:production": "yarn --cwd ./excalidraw-app start:production",
|
"start:production": "yarn --cwd ./excalidraw-app start:production",
|
||||||
"start:example": "yarn build:package && yarn --cwd ./examples/with-script-in-browser start",
|
"start:example": "yarn build:packages && yarn --cwd ./examples/with-script-in-browser start",
|
||||||
"test:all": "yarn test:typecheck && yarn test:code && yarn test:other && yarn test:app --watch=false",
|
"test:all": "yarn test:typecheck && yarn test:code && yarn test:other && yarn test:app --watch=false",
|
||||||
"test:app": "vitest",
|
"test:app": "vitest",
|
||||||
"test:code": "eslint --max-warnings=0 --ext .js,.ts,.tsx .",
|
"test:code": "eslint --max-warnings=0 --ext .js,.ts,.tsx .",
|
||||||
@ -76,9 +80,10 @@
|
|||||||
"locales-coverage:description": "node scripts/locales-coverage-description.js",
|
"locales-coverage:description": "node scripts/locales-coverage-description.js",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"prettier": "prettier \"**/*.{css,scss,json,md,html,yml}\" --ignore-path=.eslintignore",
|
"prettier": "prettier \"**/*.{css,scss,json,md,html,yml}\" --ignore-path=.eslintignore",
|
||||||
"autorelease": "node scripts/autorelease.js",
|
"release": "node scripts/release.js",
|
||||||
"prerelease:excalidraw": "node scripts/prerelease.js",
|
"release:test": "node scripts/release.js --tag=test",
|
||||||
"release:excalidraw": "node scripts/release.js",
|
"release:next": "node scripts/release.js --tag=next",
|
||||||
|
"release:latest": "node scripts/release.js --tag=latest",
|
||||||
"rm:build": "rimraf --glob excalidraw-app/build excalidraw-app/dist excalidraw-app/dev-dist packages/*/dist packages/*/build examples/*/build examples/*/dist",
|
"rm:build": "rimraf --glob excalidraw-app/build excalidraw-app/dist excalidraw-app/dev-dist packages/*/dist packages/*/build examples/*/build examples/*/dist",
|
||||||
"rm:node_modules": "rimraf --glob node_modules excalidraw-app/node_modules packages/*/node_modules",
|
"rm:node_modules": "rimraf --glob node_modules excalidraw-app/node_modules packages/*/node_modules",
|
||||||
"clean-install": "yarn rm:node_modules && yarn install"
|
"clean-install": "yarn rm:node_modules && yarn install"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@excalidraw/common",
|
"name": "@excalidraw/common",
|
||||||
"version": "0.1.0",
|
"version": "0.18.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./dist/types/common/src/index.d.ts",
|
"types": "./dist/types/common/src/index.d.ts",
|
||||||
"main": "./dist/prod/index.js",
|
"main": "./dist/prod/index.js",
|
||||||
@ -13,7 +13,10 @@
|
|||||||
"default": "./dist/prod/index.js"
|
"default": "./dist/prod/index.js"
|
||||||
},
|
},
|
||||||
"./*": {
|
"./*": {
|
||||||
"types": "./dist/types/common/src/*.d.ts"
|
"types": "./dist/types/common/src/*.d.ts",
|
||||||
|
"development": "./dist/dev/index.js",
|
||||||
|
"production": "./dist/prod/index.js",
|
||||||
|
"default": "./dist/prod/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export const APP_NAME = "Excalidraw";
|
|||||||
// (happens a lot with fast clicks with the text tool)
|
// (happens a lot with fast clicks with the text tool)
|
||||||
export const TEXT_AUTOWRAP_THRESHOLD = 36; // px
|
export const TEXT_AUTOWRAP_THRESHOLD = 36; // px
|
||||||
export const DRAGGING_THRESHOLD = 10; // px
|
export const DRAGGING_THRESHOLD = 10; // px
|
||||||
|
export const MINIMUM_ARROW_SIZE = 20; // px
|
||||||
export const LINE_CONFIRM_THRESHOLD = 8; // px
|
export const LINE_CONFIRM_THRESHOLD = 8; // px
|
||||||
export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5;
|
export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5;
|
||||||
export const ELEMENT_TRANSLATE_AMOUNT = 1;
|
export const ELEMENT_TRANSLATE_AMOUNT = 1;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@excalidraw/element",
|
"name": "@excalidraw/element",
|
||||||
"version": "0.1.0",
|
"version": "0.18.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./dist/types/element/src/index.d.ts",
|
"types": "./dist/types/element/src/index.d.ts",
|
||||||
"main": "./dist/prod/index.js",
|
"main": "./dist/prod/index.js",
|
||||||
@ -13,7 +13,10 @@
|
|||||||
"default": "./dist/prod/index.js"
|
"default": "./dist/prod/index.js"
|
||||||
},
|
},
|
||||||
"./*": {
|
"./*": {
|
||||||
"types": "./dist/types/element/src/*.d.ts"
|
"types": "./dist/types/element/src/*.d.ts",
|
||||||
|
"development": "./dist/dev/index.js",
|
||||||
|
"production": "./dist/prod/index.js",
|
||||||
|
"default": "./dist/prod/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@ -52,5 +55,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"gen:types": "rimraf types && tsc",
|
"gen:types": "rimraf types && tsc",
|
||||||
"build:esm": "rimraf dist && node ../../scripts/buildBase.js && yarn gen:types"
|
"build:esm": "rimraf dist && node ../../scripts/buildBase.js && yarn gen:types"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@excalidraw/common": "0.18.0",
|
||||||
|
"@excalidraw/math": "0.18.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import { updateBoundElements } from "./binding";
|
import { updateBoundElements } from "./binding";
|
||||||
import { getCommonBoundingBox } from "./bounds";
|
import { getCommonBoundingBox } from "./bounds";
|
||||||
import { getMaximumGroups } from "./groups";
|
import { getSelectedElementsByGroup } from "./groups";
|
||||||
|
|
||||||
import type { Scene } from "./Scene";
|
import type { Scene } from "./Scene";
|
||||||
|
|
||||||
@ -16,11 +18,12 @@ export const alignElements = (
|
|||||||
selectedElements: ExcalidrawElement[],
|
selectedElements: ExcalidrawElement[],
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
|
appState: Readonly<AppState>,
|
||||||
): ExcalidrawElement[] => {
|
): ExcalidrawElement[] => {
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const groups: ExcalidrawElement[][] = getSelectedElementsByGroup(
|
||||||
const groups: ExcalidrawElement[][] = getMaximumGroups(
|
|
||||||
selectedElements,
|
selectedElements,
|
||||||
elementsMap,
|
scene.getNonDeletedElementsMap(),
|
||||||
|
appState,
|
||||||
);
|
);
|
||||||
const selectionBoundingBox = getCommonBoundingBox(selectedElements);
|
const selectionBoundingBox = getCommonBoundingBox(selectedElements);
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import {
|
|||||||
arrayToMap,
|
arrayToMap,
|
||||||
arrayToObject,
|
arrayToObject,
|
||||||
assertNever,
|
assertNever,
|
||||||
|
invariant,
|
||||||
isDevEnv,
|
isDevEnv,
|
||||||
isShallowEqual,
|
isShallowEqual,
|
||||||
isTestEnv,
|
isTestEnv,
|
||||||
@ -548,7 +549,7 @@ export class AppStateDelta implements DeltaContainer<AppState> {
|
|||||||
selectedElementIds: addedSelectedElementIds = {},
|
selectedElementIds: addedSelectedElementIds = {},
|
||||||
selectedGroupIds: addedSelectedGroupIds = {},
|
selectedGroupIds: addedSelectedGroupIds = {},
|
||||||
selectedLinearElementId,
|
selectedLinearElementId,
|
||||||
editingLinearElementId,
|
selectedLinearElementIsEditing,
|
||||||
...directlyApplicablePartial
|
...directlyApplicablePartial
|
||||||
} = this.delta.inserted;
|
} = this.delta.inserted;
|
||||||
|
|
||||||
@ -564,39 +565,46 @@ export class AppStateDelta implements DeltaContainer<AppState> {
|
|||||||
removedSelectedGroupIds,
|
removedSelectedGroupIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedLinearElement =
|
let selectedLinearElement = appState.selectedLinearElement;
|
||||||
selectedLinearElementId && nextElements.has(selectedLinearElementId)
|
|
||||||
? new LinearElementEditor(
|
|
||||||
nextElements.get(
|
|
||||||
selectedLinearElementId,
|
|
||||||
) as NonDeleted<ExcalidrawLinearElement>,
|
|
||||||
nextElements,
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const editingLinearElement =
|
if (selectedLinearElementId === null) {
|
||||||
editingLinearElementId && nextElements.has(editingLinearElementId)
|
// Unselect linear element (visible change)
|
||||||
? new LinearElementEditor(
|
selectedLinearElement = null;
|
||||||
nextElements.get(
|
} else if (
|
||||||
editingLinearElementId,
|
selectedLinearElementId &&
|
||||||
) as NonDeleted<ExcalidrawLinearElement>,
|
nextElements.has(selectedLinearElementId)
|
||||||
nextElements,
|
) {
|
||||||
)
|
selectedLinearElement = new LinearElementEditor(
|
||||||
: null;
|
nextElements.get(
|
||||||
|
selectedLinearElementId,
|
||||||
|
) as NonDeleted<ExcalidrawLinearElement>,
|
||||||
|
nextElements,
|
||||||
|
selectedLinearElementIsEditing === true, // Can be unknown which is defaulted to false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
// Value being 'null' is equivaluent to unknown in this case because it only gets set
|
||||||
|
// to null when 'selectedLinearElementId' is set to null
|
||||||
|
selectedLinearElementIsEditing != null
|
||||||
|
) {
|
||||||
|
invariant(
|
||||||
|
selectedLinearElement,
|
||||||
|
`selectedLinearElement is null when selectedLinearElementIsEditing is set to ${selectedLinearElementIsEditing}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
selectedLinearElement = {
|
||||||
|
...selectedLinearElement,
|
||||||
|
isEditing: selectedLinearElementIsEditing,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const nextAppState = {
|
const nextAppState = {
|
||||||
...appState,
|
...appState,
|
||||||
...directlyApplicablePartial,
|
...directlyApplicablePartial,
|
||||||
selectedElementIds: mergedSelectedElementIds,
|
selectedElementIds: mergedSelectedElementIds,
|
||||||
selectedGroupIds: mergedSelectedGroupIds,
|
selectedGroupIds: mergedSelectedGroupIds,
|
||||||
selectedLinearElement:
|
selectedLinearElement,
|
||||||
typeof selectedLinearElementId !== "undefined"
|
|
||||||
? selectedLinearElement // element was either inserted or deleted
|
|
||||||
: appState.selectedLinearElement, // otherwise assign what we had before
|
|
||||||
editingLinearElement:
|
|
||||||
typeof editingLinearElementId !== "undefined"
|
|
||||||
? editingLinearElement // element was either inserted or deleted
|
|
||||||
: appState.editingLinearElement, // otherwise assign what we had before
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const constainsVisibleChanges = this.filterInvisibleChanges(
|
const constainsVisibleChanges = this.filterInvisibleChanges(
|
||||||
@ -725,8 +733,7 @@ export class AppStateDelta implements DeltaContainer<AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "selectedLinearElementId":
|
case "selectedLinearElementId": {
|
||||||
case "editingLinearElementId":
|
|
||||||
const appStateKey = AppStateDelta.convertToAppStateKey(key);
|
const appStateKey = AppStateDelta.convertToAppStateKey(key);
|
||||||
const linearElement = nextAppState[appStateKey];
|
const linearElement = nextAppState[appStateKey];
|
||||||
|
|
||||||
@ -746,6 +753,19 @@ export class AppStateDelta implements DeltaContainer<AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case "selectedLinearElementIsEditing": {
|
||||||
|
// Changes in editing state are always visible
|
||||||
|
const prevIsEditing =
|
||||||
|
prevAppState.selectedLinearElement?.isEditing ?? false;
|
||||||
|
const nextIsEditing =
|
||||||
|
nextAppState.selectedLinearElement?.isEditing ?? false;
|
||||||
|
|
||||||
|
if (prevIsEditing !== nextIsEditing) {
|
||||||
|
visibleDifferenceFlag.value = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "lockedMultiSelections": {
|
case "lockedMultiSelections": {
|
||||||
const prevLockedUnits = prevAppState[key] || {};
|
const prevLockedUnits = prevAppState[key] || {};
|
||||||
const nextLockedUnits = nextAppState[key] || {};
|
const nextLockedUnits = nextAppState[key] || {};
|
||||||
@ -779,16 +799,11 @@ export class AppStateDelta implements DeltaContainer<AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static convertToAppStateKey(
|
private static convertToAppStateKey(
|
||||||
key: keyof Pick<
|
key: keyof Pick<ObservedElementsAppState, "selectedLinearElementId">,
|
||||||
ObservedElementsAppState,
|
): keyof Pick<AppState, "selectedLinearElement"> {
|
||||||
"selectedLinearElementId" | "editingLinearElementId"
|
|
||||||
>,
|
|
||||||
): keyof Pick<AppState, "selectedLinearElement" | "editingLinearElement"> {
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "selectedLinearElementId":
|
case "selectedLinearElementId":
|
||||||
return "selectedLinearElement";
|
return "selectedLinearElement";
|
||||||
case "editingLinearElementId":
|
|
||||||
return "editingLinearElement";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,8 +871,8 @@ export class AppStateDelta implements DeltaContainer<AppState> {
|
|||||||
editingGroupId,
|
editingGroupId,
|
||||||
selectedGroupIds,
|
selectedGroupIds,
|
||||||
selectedElementIds,
|
selectedElementIds,
|
||||||
editingLinearElementId,
|
|
||||||
selectedLinearElementId,
|
selectedLinearElementId,
|
||||||
|
selectedLinearElementIsEditing,
|
||||||
croppingElementId,
|
croppingElementId,
|
||||||
lockedMultiSelections,
|
lockedMultiSelections,
|
||||||
activeLockedId,
|
activeLockedId,
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
|
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import { getCommonBoundingBox } from "./bounds";
|
import { getCommonBoundingBox } from "./bounds";
|
||||||
import { newElementWith } from "./mutateElement";
|
import { newElementWith } from "./mutateElement";
|
||||||
|
|
||||||
import { getMaximumGroups } from "./groups";
|
import { getSelectedElementsByGroup } from "./groups";
|
||||||
|
|
||||||
import type { ElementsMap, ExcalidrawElement } from "./types";
|
import type { ElementsMap, ExcalidrawElement } from "./types";
|
||||||
|
|
||||||
@ -14,6 +16,7 @@ export const distributeElements = (
|
|||||||
selectedElements: ExcalidrawElement[],
|
selectedElements: ExcalidrawElement[],
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
distribution: Distribution,
|
distribution: Distribution,
|
||||||
|
appState: Readonly<AppState>,
|
||||||
): ExcalidrawElement[] => {
|
): ExcalidrawElement[] => {
|
||||||
const [start, mid, end, extent] =
|
const [start, mid, end, extent] =
|
||||||
distribution.axis === "x"
|
distribution.axis === "x"
|
||||||
@ -21,7 +24,11 @@ export const distributeElements = (
|
|||||||
: (["minY", "midY", "maxY", "height"] as const);
|
: (["minY", "midY", "maxY", "height"] as const);
|
||||||
|
|
||||||
const bounds = getCommonBoundingBox(selectedElements);
|
const bounds = getCommonBoundingBox(selectedElements);
|
||||||
const groups = getMaximumGroups(selectedElements, elementsMap)
|
const groups = getSelectedElementsByGroup(
|
||||||
|
selectedElements,
|
||||||
|
elementsMap,
|
||||||
|
appState,
|
||||||
|
)
|
||||||
.map((group) => [group, getCommonBoundingBox(group)] as const)
|
.map((group) => [group, getCommonBoundingBox(group)] as const)
|
||||||
.sort((a, b) => a[1][mid] - b[1][mid]);
|
.sort((a, b) => a[1][mid] - b[1][mid]);
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ type IframeDataWithSandbox = MarkRequired<IframeData, "sandbox">;
|
|||||||
const embeddedLinkCache = new Map<string, IframeDataWithSandbox>();
|
const embeddedLinkCache = new Map<string, IframeDataWithSandbox>();
|
||||||
|
|
||||||
const RE_YOUTUBE =
|
const RE_YOUTUBE =
|
||||||
/^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)(?:\?t=|&t=|\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\s]*$/;
|
/^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)/;
|
||||||
|
|
||||||
const RE_VIMEO =
|
const RE_VIMEO =
|
||||||
/^(?:http(?:s)?:\/\/)?(?:(?:w){3}\.)?(?:player\.)?vimeo\.com\/(?:video\/)?([^?\s]+)(?:\?.*)?$/;
|
/^(?:http(?:s)?:\/\/)?(?:(?:w){3}\.)?(?:player\.)?vimeo\.com\/(?:video\/)?([^?\s]+)(?:\?.*)?$/;
|
||||||
@ -56,6 +56,35 @@ const RE_REDDIT =
|
|||||||
const RE_REDDIT_EMBED =
|
const RE_REDDIT_EMBED =
|
||||||
/^<blockquote[\s\S]*?\shref=["'](https?:\/\/(?:www\.)?reddit\.com\/[^"']*)/i;
|
/^<blockquote[\s\S]*?\shref=["'](https?:\/\/(?:www\.)?reddit\.com\/[^"']*)/i;
|
||||||
|
|
||||||
|
const parseYouTubeTimestamp = (url: string): number => {
|
||||||
|
let timeParam: string | null | undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const urlObj = new URL(url.startsWith("http") ? url : `https://${url}`);
|
||||||
|
timeParam =
|
||||||
|
urlObj.searchParams.get("t") || urlObj.searchParams.get("start");
|
||||||
|
} catch (error) {
|
||||||
|
const timeMatch = url.match(/[?&#](?:t|start)=([^&#\s]+)/);
|
||||||
|
timeParam = timeMatch?.[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timeParam) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^\d+$/.test(timeParam)) {
|
||||||
|
return parseInt(timeParam, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeMatch = timeParam.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/);
|
||||||
|
if (!timeMatch) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, hours = "0", minutes = "0", seconds = "0"] = timeMatch;
|
||||||
|
return parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds);
|
||||||
|
};
|
||||||
|
|
||||||
const ALLOWED_DOMAINS = new Set([
|
const ALLOWED_DOMAINS = new Set([
|
||||||
"youtube.com",
|
"youtube.com",
|
||||||
"youtu.be",
|
"youtu.be",
|
||||||
@ -113,7 +142,8 @@ export const getEmbedLink = (
|
|||||||
let aspectRatio = { w: 560, h: 840 };
|
let aspectRatio = { w: 560, h: 840 };
|
||||||
const ytLink = link.match(RE_YOUTUBE);
|
const ytLink = link.match(RE_YOUTUBE);
|
||||||
if (ytLink?.[2]) {
|
if (ytLink?.[2]) {
|
||||||
const time = ytLink[3] ? `&start=${ytLink[3]}` : ``;
|
const startTime = parseYouTubeTimestamp(originalLink);
|
||||||
|
const time = startTime > 0 ? `&start=${startTime}` : ``;
|
||||||
const isPortrait = link.includes("shorts");
|
const isPortrait = link.includes("shorts");
|
||||||
type = "video";
|
type = "video";
|
||||||
switch (ytLink[1]) {
|
switch (ytLink[1]) {
|
||||||
|
|||||||
@ -7,6 +7,8 @@ import type { Mutable } from "@excalidraw/common/utility-types";
|
|||||||
|
|
||||||
import { getBoundTextElement } from "./textElement";
|
import { getBoundTextElement } from "./textElement";
|
||||||
|
|
||||||
|
import { isBoundToContainer } from "./typeChecks";
|
||||||
|
|
||||||
import { makeNextSelectedElementIds, getSelectedElements } from "./selection";
|
import { makeNextSelectedElementIds, getSelectedElements } from "./selection";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@ -402,3 +404,78 @@ export const getNewGroupIdsForDuplication = (
|
|||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// given a list of selected elements, return the element grouped by their immediate group selected state
|
||||||
|
// in the case if only one group is selected and all elements selected are within the group, it will respect group hierarchy in accordance to their nested grouping order
|
||||||
|
export const getSelectedElementsByGroup = (
|
||||||
|
selectedElements: ExcalidrawElement[],
|
||||||
|
elementsMap: ElementsMap,
|
||||||
|
appState: Readonly<AppState>,
|
||||||
|
): ExcalidrawElement[][] => {
|
||||||
|
const selectedGroupIds = getSelectedGroupIds(appState);
|
||||||
|
const unboundElements = selectedElements.filter(
|
||||||
|
(element) => !isBoundToContainer(element),
|
||||||
|
);
|
||||||
|
const groups: Map<string, ExcalidrawElement[]> = new Map();
|
||||||
|
const elements: Map<string, ExcalidrawElement[]> = new Map();
|
||||||
|
|
||||||
|
// helper function to add an element to the elements map
|
||||||
|
const addToElementsMap = (element: ExcalidrawElement) => {
|
||||||
|
// elements
|
||||||
|
const currentElementMembers = elements.get(element.id) || [];
|
||||||
|
const boundTextElement = getBoundTextElement(element, elementsMap);
|
||||||
|
|
||||||
|
if (boundTextElement) {
|
||||||
|
currentElementMembers.push(boundTextElement);
|
||||||
|
}
|
||||||
|
elements.set(element.id, [...currentElementMembers, element]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// helper function to add an element to the groups map
|
||||||
|
const addToGroupsMap = (element: ExcalidrawElement, groupId: string) => {
|
||||||
|
// groups
|
||||||
|
const currentGroupMembers = groups.get(groupId) || [];
|
||||||
|
const boundTextElement = getBoundTextElement(element, elementsMap);
|
||||||
|
|
||||||
|
if (boundTextElement) {
|
||||||
|
currentGroupMembers.push(boundTextElement);
|
||||||
|
}
|
||||||
|
groups.set(groupId, [...currentGroupMembers, element]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// helper function to handle the case where a single group is selected
|
||||||
|
// and all elements selected are within the group, it will respect group hierarchy in accordance to
|
||||||
|
// their nested grouping order
|
||||||
|
const handleSingleSelectedGroupCase = (
|
||||||
|
element: ExcalidrawElement,
|
||||||
|
selectedGroupId: GroupId,
|
||||||
|
) => {
|
||||||
|
const indexOfSelectedGroupId = element.groupIds.indexOf(selectedGroupId, 0);
|
||||||
|
const nestedGroupCount = element.groupIds.slice(
|
||||||
|
0,
|
||||||
|
indexOfSelectedGroupId,
|
||||||
|
).length;
|
||||||
|
return nestedGroupCount > 0
|
||||||
|
? addToGroupsMap(element, element.groupIds[indexOfSelectedGroupId - 1])
|
||||||
|
: addToElementsMap(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isAllInSameGroup = selectedElements.every((element) =>
|
||||||
|
isSelectedViaGroup(appState, element),
|
||||||
|
);
|
||||||
|
|
||||||
|
unboundElements.forEach((element) => {
|
||||||
|
const selectedGroupId = getSelectedGroupIdForElement(
|
||||||
|
element,
|
||||||
|
appState.selectedGroupIds,
|
||||||
|
);
|
||||||
|
if (!selectedGroupId) {
|
||||||
|
addToElementsMap(element);
|
||||||
|
} else if (selectedGroupIds.length === 1 && isAllInSameGroup) {
|
||||||
|
handleSingleSelectedGroupCase(element, selectedGroupId);
|
||||||
|
} else {
|
||||||
|
addToGroupsMap(element, selectedGroupId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Array.from(groups.values()).concat(Array.from(elements.values()));
|
||||||
|
};
|
||||||
|
|||||||
@ -153,10 +153,12 @@ export class LinearElementEditor {
|
|||||||
public readonly segmentMidPointHoveredCoords: GlobalPoint | null;
|
public readonly segmentMidPointHoveredCoords: GlobalPoint | null;
|
||||||
public readonly elbowed: boolean;
|
public readonly elbowed: boolean;
|
||||||
public readonly customLineAngle: number | null;
|
public readonly customLineAngle: number | null;
|
||||||
|
public readonly isEditing: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
|
isEditing: boolean = false,
|
||||||
) {
|
) {
|
||||||
this.elementId = element.id as string & {
|
this.elementId = element.id as string & {
|
||||||
_brand: "excalidrawLinearElementId";
|
_brand: "excalidrawLinearElementId";
|
||||||
@ -191,6 +193,7 @@ export class LinearElementEditor {
|
|||||||
this.segmentMidPointHoveredCoords = null;
|
this.segmentMidPointHoveredCoords = null;
|
||||||
this.elbowed = isElbowArrow(element) && element.elbowed;
|
this.elbowed = isElbowArrow(element) && element.elbowed;
|
||||||
this.customLineAngle = null;
|
this.customLineAngle = null;
|
||||||
|
this.isEditing = isEditing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -198,6 +201,7 @@ export class LinearElementEditor {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
static POINT_HANDLE_SIZE = 10;
|
static POINT_HANDLE_SIZE = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id the `elementId` from the instance of this class (so that we can
|
* @param id the `elementId` from the instance of this class (so that we can
|
||||||
* statically guarantee this method returns an ExcalidrawLinearElement)
|
* statically guarantee this method returns an ExcalidrawLinearElement)
|
||||||
@ -219,11 +223,14 @@ export class LinearElementEditor {
|
|||||||
setState: React.Component<any, AppState>["setState"],
|
setState: React.Component<any, AppState>["setState"],
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
) {
|
) {
|
||||||
if (!appState.editingLinearElement || !appState.selectionElement) {
|
if (
|
||||||
|
!appState.selectedLinearElement?.isEditing ||
|
||||||
|
!appState.selectionElement
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { editingLinearElement } = appState;
|
const { selectedLinearElement } = appState;
|
||||||
const { selectedPointsIndices, elementId } = editingLinearElement;
|
const { selectedPointsIndices, elementId } = selectedLinearElement;
|
||||||
|
|
||||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
@ -264,8 +271,8 @@ export class LinearElementEditor {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
editingLinearElement: {
|
selectedLinearElement: {
|
||||||
...editingLinearElement,
|
...selectedLinearElement,
|
||||||
selectedPointsIndices: nextSelectedPoints.length
|
selectedPointsIndices: nextSelectedPoints.length
|
||||||
? nextSelectedPoints
|
? nextSelectedPoints
|
||||||
: null,
|
: null,
|
||||||
@ -597,9 +604,6 @@ export class LinearElementEditor {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...app.state,
|
...app.state,
|
||||||
editingLinearElement: app.state.editingLinearElement
|
|
||||||
? newLinearElementEditor
|
|
||||||
: null,
|
|
||||||
selectedLinearElement: newLinearElementEditor,
|
selectedLinearElement: newLinearElementEditor,
|
||||||
suggestedBindings,
|
suggestedBindings,
|
||||||
snapLines: _snapLines,
|
snapLines: _snapLines,
|
||||||
@ -737,7 +741,7 @@ export class LinearElementEditor {
|
|||||||
// Since its not needed outside editor unless 2 pointer lines or bound text
|
// Since its not needed outside editor unless 2 pointer lines or bound text
|
||||||
if (
|
if (
|
||||||
!isElbowArrow(element) &&
|
!isElbowArrow(element) &&
|
||||||
!appState.editingLinearElement &&
|
!appState.selectedLinearElement?.isEditing &&
|
||||||
element.points.length > 2 &&
|
element.points.length > 2 &&
|
||||||
!boundText
|
!boundText
|
||||||
) {
|
) {
|
||||||
@ -803,7 +807,7 @@ export class LinearElementEditor {
|
|||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
points.length >= 3 &&
|
points.length >= 3 &&
|
||||||
!appState.editingLinearElement &&
|
!appState.selectedLinearElement?.isEditing &&
|
||||||
!isElbowArrow(element)
|
!isElbowArrow(element)
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
@ -1000,7 +1004,7 @@ export class LinearElementEditor {
|
|||||||
segmentMidpoint,
|
segmentMidpoint,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
} else if (event.altKey && appState.editingLinearElement) {
|
} else if (event.altKey && appState.selectedLinearElement?.isEditing) {
|
||||||
if (linearElementEditor.lastUncommittedPoint == null) {
|
if (linearElementEditor.lastUncommittedPoint == null) {
|
||||||
scene.mutateElement(element, {
|
scene.mutateElement(element, {
|
||||||
points: [
|
points: [
|
||||||
@ -1141,19 +1145,19 @@ export class LinearElementEditor {
|
|||||||
scenePointerY: number,
|
scenePointerY: number,
|
||||||
app: AppClassProperties,
|
app: AppClassProperties,
|
||||||
): {
|
): {
|
||||||
linearElementEditor: LinearElementEditor;
|
editingLinearElement: LinearElementEditor;
|
||||||
snapLines: readonly SnapLine[];
|
snapLines: readonly SnapLine[];
|
||||||
} | null {
|
} | null {
|
||||||
const appState = app.state;
|
const appState = app.state;
|
||||||
if (!appState.editingLinearElement) {
|
if (!appState.selectedLinearElement?.isEditing) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { elementId, lastUncommittedPoint } = appState.editingLinearElement;
|
const { elementId, lastUncommittedPoint } = appState.selectedLinearElement;
|
||||||
const elementsMap = app.scene.getNonDeletedElementsMap();
|
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return {
|
return {
|
||||||
linearElementEditor: appState.editingLinearElement,
|
editingLinearElement: appState.selectedLinearElement,
|
||||||
snapLines: appState.snapLines,
|
snapLines: appState.snapLines,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1166,8 +1170,8 @@ export class LinearElementEditor {
|
|||||||
LinearElementEditor.deletePoints(element, app, [points.length - 1]);
|
LinearElementEditor.deletePoints(element, app, [points.length - 1]);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
linearElementEditor: {
|
editingLinearElement: {
|
||||||
...appState.editingLinearElement,
|
...appState.selectedLinearElement,
|
||||||
lastUncommittedPoint: null,
|
lastUncommittedPoint: null,
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
pointerOffset: { x: 0, y: 0 },
|
pointerOffset: { x: 0, y: 0 },
|
||||||
@ -1298,9 +1302,9 @@ export class LinearElementEditor {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const originalPointerX =
|
const originalPointerX =
|
||||||
scenePointerX - appState.editingLinearElement.pointerOffset.x;
|
scenePointerX - appState.selectedLinearElement.pointerOffset.x;
|
||||||
const originalPointerY =
|
const originalPointerY =
|
||||||
scenePointerY - appState.editingLinearElement.pointerOffset.y;
|
scenePointerY - appState.selectedLinearElement.pointerOffset.y;
|
||||||
|
|
||||||
const { snapOffset, snapLines: snappingLines } = snapLinearElementPoint(
|
const { snapOffset, snapLines: snappingLines } = snapLinearElementPoint(
|
||||||
app.scene.getNonDeletedElements(),
|
app.scene.getNonDeletedElements(),
|
||||||
@ -1347,8 +1351,8 @@ export class LinearElementEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
linearElementEditor: {
|
editingLinearElement: {
|
||||||
...appState.editingLinearElement,
|
...appState.selectedLinearElement,
|
||||||
lastUncommittedPoint: element.points[element.points.length - 1],
|
lastUncommittedPoint: element.points[element.points.length - 1],
|
||||||
},
|
},
|
||||||
snapLines,
|
snapLines,
|
||||||
@ -1509,12 +1513,12 @@ export class LinearElementEditor {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
static duplicateSelectedPoints(appState: AppState, scene: Scene): AppState {
|
static duplicateSelectedPoints(appState: AppState, scene: Scene): AppState {
|
||||||
invariant(
|
invariant(
|
||||||
appState.editingLinearElement,
|
appState.selectedLinearElement?.isEditing,
|
||||||
"Not currently editing a linear element",
|
"Not currently editing a linear element",
|
||||||
);
|
);
|
||||||
|
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const { selectedPointsIndices, elementId } = appState.editingLinearElement;
|
const { selectedPointsIndices, elementId } = appState.selectedLinearElement;
|
||||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||||
|
|
||||||
invariant(
|
invariant(
|
||||||
@ -1576,8 +1580,8 @@ export class LinearElementEditor {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...appState,
|
...appState,
|
||||||
editingLinearElement: {
|
selectedLinearElement: {
|
||||||
...appState.editingLinearElement,
|
...appState.selectedLinearElement,
|
||||||
selectedPointsIndices: nextSelectedIndices,
|
selectedPointsIndices: nextSelectedIndices,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -1589,8 +1593,9 @@ export class LinearElementEditor {
|
|||||||
pointIndices: readonly number[],
|
pointIndices: readonly number[],
|
||||||
) {
|
) {
|
||||||
const isUncommittedPoint =
|
const isUncommittedPoint =
|
||||||
app.state.editingLinearElement?.lastUncommittedPoint ===
|
app.state.selectedLinearElement?.isEditing &&
|
||||||
element.points[element.points.length - 1];
|
app.state.selectedLinearElement?.lastUncommittedPoint ===
|
||||||
|
element.points[element.points.length - 1];
|
||||||
|
|
||||||
const nextPoints = element.points.filter((_, idx) => {
|
const nextPoints = element.points.filter((_, idx) => {
|
||||||
return !pointIndices.includes(idx);
|
return !pointIndices.includes(idx);
|
||||||
@ -1763,7 +1768,7 @@ export class LinearElementEditor {
|
|||||||
pointFrom(pointerCoords.x, pointerCoords.y),
|
pointFrom(pointerCoords.x, pointerCoords.y),
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
!appState.editingLinearElement &&
|
!appState.selectedLinearElement?.isEditing &&
|
||||||
dist < DRAGGING_THRESHOLD / appState.zoom.value
|
dist < DRAGGING_THRESHOLD / appState.zoom.value
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -106,6 +106,11 @@ const getCanvasPadding = (element: ExcalidrawElement) => {
|
|||||||
return element.strokeWidth * 12;
|
return element.strokeWidth * 12;
|
||||||
case "text":
|
case "text":
|
||||||
return element.fontSize / 2;
|
return element.fontSize / 2;
|
||||||
|
case "arrow":
|
||||||
|
if (element.endArrowhead || element.endArrowhead) {
|
||||||
|
return 40;
|
||||||
|
}
|
||||||
|
return 20;
|
||||||
default:
|
default:
|
||||||
return 20;
|
return 20;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,11 +14,7 @@ import {
|
|||||||
getDraggedElementsBounds,
|
getDraggedElementsBounds,
|
||||||
getElementAbsoluteCoords,
|
getElementAbsoluteCoords,
|
||||||
} from "@excalidraw/element";
|
} from "@excalidraw/element";
|
||||||
import {
|
import { isBoundToContainer, isElbowArrow } from "@excalidraw/element";
|
||||||
isBoundToContainer,
|
|
||||||
isFrameLikeElement,
|
|
||||||
isElbowArrow,
|
|
||||||
} from "@excalidraw/element";
|
|
||||||
|
|
||||||
import { getMaximumGroups } from "@excalidraw/element";
|
import { getMaximumGroups } from "@excalidraw/element";
|
||||||
|
|
||||||
@ -379,20 +375,13 @@ const getReferenceElements = (
|
|||||||
selectedElements: NonDeletedExcalidrawElement[],
|
selectedElements: NonDeletedExcalidrawElement[],
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
) => {
|
) =>
|
||||||
const selectedFrames = selectedElements
|
getVisibleAndNonSelectedElements(
|
||||||
.filter((element) => isFrameLikeElement(element))
|
|
||||||
.map((frame) => frame.id);
|
|
||||||
|
|
||||||
return getVisibleAndNonSelectedElements(
|
|
||||||
elements,
|
elements,
|
||||||
selectedElements,
|
selectedElements,
|
||||||
appState,
|
appState,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
).filter(
|
|
||||||
(element) => !(element.frameId && selectedFrames.includes(element.frameId)),
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export const getVisibleGaps = (
|
export const getVisibleGaps = (
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
|
|||||||
@ -27,6 +27,8 @@ import {
|
|||||||
isImageElement,
|
isImageElement,
|
||||||
} from "./index";
|
} from "./index";
|
||||||
|
|
||||||
|
import type { ApplyToOptions } from "./delta";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
OrderedExcalidrawElement,
|
OrderedExcalidrawElement,
|
||||||
@ -570,9 +572,15 @@ export class StoreDelta {
|
|||||||
delta: StoreDelta,
|
delta: StoreDelta,
|
||||||
elements: SceneElementsMap,
|
elements: SceneElementsMap,
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
|
options: ApplyToOptions = {
|
||||||
|
excludedProperties: new Set(),
|
||||||
|
},
|
||||||
): [SceneElementsMap, AppState, boolean] {
|
): [SceneElementsMap, AppState, boolean] {
|
||||||
const [nextElements, elementsContainVisibleChange] =
|
const [nextElements, elementsContainVisibleChange] = delta.elements.applyTo(
|
||||||
delta.elements.applyTo(elements);
|
elements,
|
||||||
|
StoreSnapshot.empty().elements,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
|
||||||
const [nextAppState, appStateContainsVisibleChange] =
|
const [nextAppState, appStateContainsVisibleChange] =
|
||||||
delta.appState.applyTo(appState, nextElements);
|
delta.appState.applyTo(appState, nextElements);
|
||||||
@ -970,8 +978,8 @@ const getDefaultObservedAppState = (): ObservedAppState => {
|
|||||||
viewBackgroundColor: COLOR_PALETTE.white,
|
viewBackgroundColor: COLOR_PALETTE.white,
|
||||||
selectedElementIds: {},
|
selectedElementIds: {},
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
editingLinearElementId: null,
|
|
||||||
selectedLinearElementId: null,
|
selectedLinearElementId: null,
|
||||||
|
selectedLinearElementIsEditing: null,
|
||||||
croppingElementId: null,
|
croppingElementId: null,
|
||||||
activeLockedId: null,
|
activeLockedId: null,
|
||||||
lockedMultiSelections: {},
|
lockedMultiSelections: {},
|
||||||
@ -990,14 +998,14 @@ export const getObservedAppState = (
|
|||||||
croppingElementId: appState.croppingElementId,
|
croppingElementId: appState.croppingElementId,
|
||||||
activeLockedId: appState.activeLockedId,
|
activeLockedId: appState.activeLockedId,
|
||||||
lockedMultiSelections: appState.lockedMultiSelections,
|
lockedMultiSelections: appState.lockedMultiSelections,
|
||||||
editingLinearElementId:
|
|
||||||
(appState as AppState).editingLinearElement?.elementId ?? // prefer app state, as it's likely newer
|
|
||||||
(appState as ObservedAppState).editingLinearElementId ?? // fallback to observed app state, as it's likely older coming from a previous snapshot
|
|
||||||
null,
|
|
||||||
selectedLinearElementId:
|
selectedLinearElementId:
|
||||||
(appState as AppState).selectedLinearElement?.elementId ??
|
(appState as AppState).selectedLinearElement?.elementId ??
|
||||||
(appState as ObservedAppState).selectedLinearElementId ??
|
(appState as ObservedAppState).selectedLinearElementId ??
|
||||||
null,
|
null,
|
||||||
|
selectedLinearElementIsEditing:
|
||||||
|
(appState as AppState).selectedLinearElement?.isEditing ??
|
||||||
|
(appState as ObservedAppState).selectedLinearElementIsEditing ??
|
||||||
|
null,
|
||||||
};
|
};
|
||||||
|
|
||||||
Reflect.defineProperty(observedAppState, hiddenObservedAppStateProp, {
|
Reflect.defineProperty(observedAppState, hiddenObservedAppStateProp, {
|
||||||
|
|||||||
@ -330,7 +330,7 @@ export const shouldShowBoundingBox = (
|
|||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
appState: InteractiveCanvasAppState,
|
appState: InteractiveCanvasAppState,
|
||||||
) => {
|
) => {
|
||||||
if (appState.editingLinearElement) {
|
if (appState.selectedLinearElement?.isEditing) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (elements.length > 1) {
|
if (elements.length > 1) {
|
||||||
|
|||||||
@ -589,4 +589,424 @@ describe("aligning", () => {
|
|||||||
expect(API.getSelectedElements()[2].x).toEqual(250);
|
expect(API.getSelectedElements()[2].x).toEqual(250);
|
||||||
expect(API.getSelectedElements()[3].x).toEqual(150);
|
expect(API.getSelectedElements()[3].x).toEqual(150);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const createGroupAndSelectInEditGroupMode = () => {
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down();
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(0, 0);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
// select the first element.
|
||||||
|
// The second rectangle is already reselected because it was the last element created
|
||||||
|
mouse.reset();
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.moveTo(10, 0);
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
API.executeAction(actionGroup);
|
||||||
|
mouse.reset();
|
||||||
|
mouse.moveTo(10, 0);
|
||||||
|
mouse.doubleClick();
|
||||||
|
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.click();
|
||||||
|
mouse.moveTo(100, 100);
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
it("aligns elements within a group while in group edit mode correctly to the top", () => {
|
||||||
|
createGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignTop);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns elements within a group while in group edit mode correctly to the bottom", () => {
|
||||||
|
createGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignBottom);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
});
|
||||||
|
it("aligns elements within a group while in group edit mode correctly to the left", () => {
|
||||||
|
createGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignLeft);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns elements within a group while in group edit mode correctly to the right", () => {
|
||||||
|
createGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignRight);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
});
|
||||||
|
it("aligns elements within a group while in group edit mode correctly to the vertical center", () => {
|
||||||
|
createGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignVerticallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(50);
|
||||||
|
});
|
||||||
|
it("aligns elements within a group while in group edit mode correctly to the horizontal center", () => {
|
||||||
|
createGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignHorizontallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
const createNestedGroupAndSelectInEditGroupMode = () => {
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down();
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(0, 0);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
// Select the first element.
|
||||||
|
// The second rectangle is already reselected because it was the last element created
|
||||||
|
mouse.reset();
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.moveTo(10, 0);
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
API.executeAction(actionGroup);
|
||||||
|
|
||||||
|
mouse.reset();
|
||||||
|
mouse.moveTo(200, 200);
|
||||||
|
// create third element
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(0, 0);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
// third element is already selected, select the initial group and group together
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.moveTo(10, 0);
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
API.executeAction(actionGroup);
|
||||||
|
|
||||||
|
// double click to enter edit mode
|
||||||
|
mouse.doubleClick();
|
||||||
|
|
||||||
|
// select nested group and other element within the group
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.moveTo(200, 200);
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
it("aligns element and nested group while in group edit mode correctly to the top", () => {
|
||||||
|
createNestedGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignTop);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns element and nested group while in group edit mode correctly to the bottom", () => {
|
||||||
|
createNestedGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignBottom);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(200);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
});
|
||||||
|
it("aligns element and nested group while in group edit mode correctly to the left", () => {
|
||||||
|
createNestedGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignLeft);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns element and nested group while in group edit mode correctly to the right", () => {
|
||||||
|
createNestedGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignRight);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(200);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
});
|
||||||
|
it("aligns element and nested group while in group edit mode correctly to the vertical center", () => {
|
||||||
|
createNestedGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignVerticallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(100);
|
||||||
|
});
|
||||||
|
it("aligns elements and nested group within a group while in group edit mode correctly to the horizontal center", () => {
|
||||||
|
createNestedGroupAndSelectInEditGroupMode();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignHorizontallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
const createAndSelectSingleGroup = () => {
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down();
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(0, 0);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
// Select the first element.
|
||||||
|
// The second rectangle is already reselected because it was the last element created
|
||||||
|
mouse.reset();
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.moveTo(10, 0);
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
API.executeAction(actionGroup);
|
||||||
|
};
|
||||||
|
|
||||||
|
it("aligns elements within a single-selected group correctly to the top", () => {
|
||||||
|
createAndSelectSingleGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignTop);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group correctly to the bottom", () => {
|
||||||
|
createAndSelectSingleGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignBottom);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group correctly to the left", () => {
|
||||||
|
createAndSelectSingleGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignLeft);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group correctly to the right", () => {
|
||||||
|
createAndSelectSingleGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignRight);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group correctly to the vertical center", () => {
|
||||||
|
createAndSelectSingleGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignVerticallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(50);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group correctly to the horizontal center", () => {
|
||||||
|
createAndSelectSingleGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignHorizontallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
const createAndSelectSingleGroupWithNestedGroup = () => {
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down();
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(0, 0);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
// Select the first element.
|
||||||
|
// The second rectangle is already reselected because it was the last element created
|
||||||
|
mouse.reset();
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.moveTo(10, 0);
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
API.executeAction(actionGroup);
|
||||||
|
|
||||||
|
mouse.reset();
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(200, 200);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
|
||||||
|
// Add group to current selection
|
||||||
|
mouse.restorePosition(10, 0);
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the nested group
|
||||||
|
API.executeAction(actionGroup);
|
||||||
|
};
|
||||||
|
it("aligns elements within a single-selected group containing a nested group correctly to the top", () => {
|
||||||
|
createAndSelectSingleGroupWithNestedGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignTop);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group containing a nested group correctly to the bottom", () => {
|
||||||
|
createAndSelectSingleGroupWithNestedGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignBottom);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(200);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group containing a nested group correctly to the left", () => {
|
||||||
|
createAndSelectSingleGroupWithNestedGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignLeft);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(0);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group containing a nested group correctly to the right", () => {
|
||||||
|
createAndSelectSingleGroupWithNestedGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignRight);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(200);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group containing a nested group correctly to the vertical center", () => {
|
||||||
|
createAndSelectSingleGroupWithNestedGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignVerticallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(100);
|
||||||
|
});
|
||||||
|
it("aligns elements within a single-selected group containing a nested group correctly to the horizontal center", () => {
|
||||||
|
createAndSelectSingleGroupWithNestedGroup();
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(actionAlignHorizontallyCentered);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(100);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -155,10 +155,10 @@ describe("element binding", () => {
|
|||||||
// NOTE this mouse down/up + await needs to be done in order to repro
|
// NOTE this mouse down/up + await needs to be done in order to repro
|
||||||
// the issue, due to https://github.com/excalidraw/excalidraw/blob/46bff3daceb602accf60c40a84610797260fca94/src/components/App.tsx#L740
|
// the issue, due to https://github.com/excalidraw/excalidraw/blob/46bff3daceb602accf60c40a84610797260fca94/src/components/App.tsx#L740
|
||||||
mouse.reset();
|
mouse.reset();
|
||||||
expect(h.state.editingLinearElement).not.toBe(null);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
mouse.down(0, 0);
|
mouse.down(0, 0);
|
||||||
await new Promise((r) => setTimeout(r, 100));
|
await new Promise((r) => setTimeout(r, 100));
|
||||||
expect(h.state.editingLinearElement).toBe(null);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
expect(API.getSelectedElement().type).toBe("rectangle");
|
expect(API.getSelectedElement().type).toBe("rectangle");
|
||||||
mouse.up();
|
mouse.up();
|
||||||
expect(API.getSelectedElement().type).toBe("rectangle");
|
expect(API.getSelectedElement().type).toBe("rectangle");
|
||||||
|
|||||||
@ -16,6 +16,7 @@ describe("AppStateDelta", () => {
|
|||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
croppingElementId: null,
|
croppingElementId: null,
|
||||||
editingLinearElementId: null,
|
editingLinearElementId: null,
|
||||||
|
selectedLinearElementIsEditing: null,
|
||||||
lockedMultiSelections: {},
|
lockedMultiSelections: {},
|
||||||
activeLockedId: null,
|
activeLockedId: null,
|
||||||
};
|
};
|
||||||
@ -58,6 +59,7 @@ describe("AppStateDelta", () => {
|
|||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
croppingElementId: null,
|
croppingElementId: null,
|
||||||
selectedLinearElementId: null,
|
selectedLinearElementId: null,
|
||||||
|
selectedLinearElementIsEditing: null,
|
||||||
editingLinearElementId: null,
|
editingLinearElementId: null,
|
||||||
activeLockedId: null,
|
activeLockedId: null,
|
||||||
lockedMultiSelections: {},
|
lockedMultiSelections: {},
|
||||||
@ -105,6 +107,7 @@ describe("AppStateDelta", () => {
|
|||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
croppingElementId: null,
|
croppingElementId: null,
|
||||||
selectedLinearElementId: null,
|
selectedLinearElementId: null,
|
||||||
|
selectedLinearElementIsEditing: null,
|
||||||
editingLinearElementId: null,
|
editingLinearElementId: null,
|
||||||
activeLockedId: null,
|
activeLockedId: null,
|
||||||
lockedMultiSelections: {},
|
lockedMultiSelections: {},
|
||||||
|
|||||||
128
packages/element/tests/distribute.test.tsx
Normal file
128
packages/element/tests/distribute.test.tsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import {
|
||||||
|
distributeHorizontally,
|
||||||
|
distributeVertically,
|
||||||
|
} from "@excalidraw/excalidraw/actions";
|
||||||
|
import { defaultLang, setLanguage } from "@excalidraw/excalidraw/i18n";
|
||||||
|
import { Excalidraw } from "@excalidraw/excalidraw";
|
||||||
|
|
||||||
|
import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
||||||
|
import { UI, Pointer, Keyboard } from "@excalidraw/excalidraw/tests/helpers/ui";
|
||||||
|
import {
|
||||||
|
act,
|
||||||
|
unmountComponent,
|
||||||
|
render,
|
||||||
|
} from "@excalidraw/excalidraw/tests/test-utils";
|
||||||
|
|
||||||
|
const mouse = new Pointer("mouse");
|
||||||
|
|
||||||
|
// Scenario: three rectangles that will be distributed with gaps
|
||||||
|
const createAndSelectThreeRectanglesWithGap = () => {
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down();
|
||||||
|
mouse.up(100, 100);
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(10, 10);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(300, 300);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
// Last rectangle is selected by default
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.click(0, 10);
|
||||||
|
mouse.click(10, 0);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scenario: three rectangles that will be distributed by their centers
|
||||||
|
const createAndSelectThreeRectanglesWithoutGap = () => {
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down();
|
||||||
|
mouse.up(100, 100);
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(10, 10);
|
||||||
|
mouse.up(200, 200);
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
UI.clickTool("rectangle");
|
||||||
|
mouse.down(200, 200);
|
||||||
|
mouse.up(100, 100);
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
// Last rectangle is selected by default
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
mouse.click(0, 10);
|
||||||
|
mouse.click(10, 0);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("distributing", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
unmountComponent();
|
||||||
|
mouse.reset();
|
||||||
|
|
||||||
|
await act(() => {
|
||||||
|
return setLanguage(defaultLang);
|
||||||
|
});
|
||||||
|
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should distribute selected elements horizontally", async () => {
|
||||||
|
createAndSelectThreeRectanglesWithGap();
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(10);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(300);
|
||||||
|
|
||||||
|
API.executeAction(distributeHorizontally);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(300);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should distribute selected elements vertically", async () => {
|
||||||
|
createAndSelectThreeRectanglesWithGap();
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(10);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(300);
|
||||||
|
|
||||||
|
API.executeAction(distributeVertically);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(300);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should distribute selected elements horizontally based on their centers", async () => {
|
||||||
|
createAndSelectThreeRectanglesWithoutGap();
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(10);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(distributeHorizontally);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].x).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should distribute selected elements vertically with based on their centers", async () => {
|
||||||
|
createAndSelectThreeRectanglesWithoutGap();
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(10);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
|
||||||
|
API.executeAction(distributeVertically);
|
||||||
|
|
||||||
|
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||||
|
expect(API.getSelectedElements()[1].y).toEqual(50);
|
||||||
|
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
153
packages/element/tests/embeddable.test.ts
Normal file
153
packages/element/tests/embeddable.test.ts
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import { getEmbedLink } from "../src/embeddable";
|
||||||
|
|
||||||
|
describe("YouTube timestamp parsing", () => {
|
||||||
|
it("should parse YouTube URLs with timestamp in seconds", () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=90",
|
||||||
|
expectedStart: 90,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://youtu.be/dQw4w9WgXcQ?t=120",
|
||||||
|
expectedStart: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&start=150",
|
||||||
|
expectedStart: 150,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
testCases.forEach(({ url, expectedStart }) => {
|
||||||
|
const result = getEmbedLink(url);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
expect(result?.type).toBe("video");
|
||||||
|
if (result?.type === "video" || result?.type === "generic") {
|
||||||
|
expect(result.link).toContain(`start=${expectedStart}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should parse YouTube URLs with timestamp in time format", () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=1m30s",
|
||||||
|
expectedStart: 90, // 1*60 + 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://youtu.be/dQw4w9WgXcQ?t=2m45s",
|
||||||
|
expectedStart: 165, // 2*60 + 45
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=1h2m3s",
|
||||||
|
expectedStart: 3723, // 1*3600 + 2*60 + 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=45s",
|
||||||
|
expectedStart: 45,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=5m",
|
||||||
|
expectedStart: 300, // 5*60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=2h",
|
||||||
|
expectedStart: 7200, // 2*3600
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
testCases.forEach(({ url, expectedStart }) => {
|
||||||
|
const result = getEmbedLink(url);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
expect(result?.type).toBe("video");
|
||||||
|
if (result?.type === "video" || result?.type === "generic") {
|
||||||
|
expect(result.link).toContain(`start=${expectedStart}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle YouTube URLs without timestamps", () => {
|
||||||
|
const testCases = [
|
||||||
|
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||||
|
"https://youtu.be/dQw4w9WgXcQ",
|
||||||
|
"https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||||
|
];
|
||||||
|
|
||||||
|
testCases.forEach((url) => {
|
||||||
|
const result = getEmbedLink(url);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
expect(result?.type).toBe("video");
|
||||||
|
if (result?.type === "video" || result?.type === "generic") {
|
||||||
|
expect(result.link).not.toContain("start=");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle YouTube shorts URLs with timestamps", () => {
|
||||||
|
const url = "https://www.youtube.com/shorts/dQw4w9WgXcQ?t=30";
|
||||||
|
const result = getEmbedLink(url);
|
||||||
|
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
expect(result?.type).toBe("video");
|
||||||
|
if (result?.type === "video" || result?.type === "generic") {
|
||||||
|
expect(result.link).toContain("start=30");
|
||||||
|
}
|
||||||
|
// Shorts should have portrait aspect ratio
|
||||||
|
expect(result?.intrinsicSize).toEqual({ w: 315, h: 560 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle playlist URLs with timestamps", () => {
|
||||||
|
const url =
|
||||||
|
"https://www.youtube.com/playlist?list=PLrAXtmRdnEQy1KbG5lbfgQ0-PKQY6FKYZ&t=60";
|
||||||
|
const result = getEmbedLink(url);
|
||||||
|
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
expect(result?.type).toBe("video");
|
||||||
|
if (result?.type === "video" || result?.type === "generic") {
|
||||||
|
expect(result.link).toContain("start=60");
|
||||||
|
expect(result.link).toContain("list=PLrAXtmRdnEQy1KbG5lbfgQ0-PKQY6FKYZ");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle malformed or edge case timestamps", () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=abc",
|
||||||
|
expectedStart: 0, // Invalid timestamp should default to 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=",
|
||||||
|
expectedStart: 0, // Empty timestamp should default to 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=0",
|
||||||
|
expectedStart: 0, // Zero timestamp should be handled
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
testCases.forEach(({ url, expectedStart }) => {
|
||||||
|
const result = getEmbedLink(url);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
expect(result?.type).toBe("video");
|
||||||
|
if (result?.type === "video" || result?.type === "generic") {
|
||||||
|
if (expectedStart === 0) {
|
||||||
|
expect(result.link).not.toContain("start=");
|
||||||
|
} else {
|
||||||
|
expect(result.link).toContain(`start=${expectedStart}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should preserve other URL parameters", () => {
|
||||||
|
const url =
|
||||||
|
"https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=90&feature=youtu.be&list=PLtest";
|
||||||
|
const result = getEmbedLink(url);
|
||||||
|
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
expect(result?.type).toBe("video");
|
||||||
|
if (result?.type === "video" || result?.type === "generic") {
|
||||||
|
expect(result.link).toContain("start=90");
|
||||||
|
expect(result.link).toContain("enablejsapi=1");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -136,7 +136,8 @@ describe("Test Linear Elements", () => {
|
|||||||
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||||
Keyboard.keyPress(KEYS.ENTER);
|
Keyboard.keyPress(KEYS.ENTER);
|
||||||
});
|
});
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(line.id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(line.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const drag = (startPoint: GlobalPoint, endPoint: GlobalPoint) => {
|
const drag = (startPoint: GlobalPoint, endPoint: GlobalPoint) => {
|
||||||
@ -253,75 +254,82 @@ describe("Test Linear Elements", () => {
|
|||||||
});
|
});
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Edit line")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Edit line")!);
|
||||||
|
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should enter line editor via enter (line)", () => {
|
it("should enter line editor via enter (line)", () => {
|
||||||
createTwoPointerLinearElement("line");
|
createTwoPointerLinearElement("line");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
mouse.clickAt(midpoint[0], midpoint[1]);
|
mouse.clickAt(midpoint[0], midpoint[1]);
|
||||||
Keyboard.keyPress(KEYS.ENTER);
|
Keyboard.keyPress(KEYS.ENTER);
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ctrl+enter alias (to align with arrows)
|
// ctrl+enter alias (to align with arrows)
|
||||||
it("should enter line editor via ctrl+enter (line)", () => {
|
it("should enter line editor via ctrl+enter (line)", () => {
|
||||||
createTwoPointerLinearElement("line");
|
createTwoPointerLinearElement("line");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
mouse.clickAt(midpoint[0], midpoint[1]);
|
mouse.clickAt(midpoint[0], midpoint[1]);
|
||||||
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||||
Keyboard.keyPress(KEYS.ENTER);
|
Keyboard.keyPress(KEYS.ENTER);
|
||||||
});
|
});
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should enter line editor via ctrl+enter (arrow)", () => {
|
it("should enter line editor via ctrl+enter (arrow)", () => {
|
||||||
createTwoPointerLinearElement("arrow");
|
createTwoPointerLinearElement("arrow");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
mouse.clickAt(midpoint[0], midpoint[1]);
|
mouse.clickAt(midpoint[0], midpoint[1]);
|
||||||
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||||
Keyboard.keyPress(KEYS.ENTER);
|
Keyboard.keyPress(KEYS.ENTER);
|
||||||
});
|
});
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should enter line editor on ctrl+dblclick (simple arrow)", () => {
|
it("should enter line editor on ctrl+dblclick (simple arrow)", () => {
|
||||||
createTwoPointerLinearElement("arrow");
|
createTwoPointerLinearElement("arrow");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||||
mouse.doubleClick();
|
mouse.doubleClick();
|
||||||
});
|
});
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should enter line editor on ctrl+dblclick (line)", () => {
|
it("should enter line editor on ctrl+dblclick (line)", () => {
|
||||||
createTwoPointerLinearElement("line");
|
createTwoPointerLinearElement("line");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||||
mouse.doubleClick();
|
mouse.doubleClick();
|
||||||
});
|
});
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should enter line editor on dblclick (line)", () => {
|
it("should enter line editor on dblclick (line)", () => {
|
||||||
createTwoPointerLinearElement("line");
|
createTwoPointerLinearElement("line");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
mouse.doubleClick();
|
mouse.doubleClick();
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not enter line editor on dblclick (arrow)", async () => {
|
it("should not enter line editor on dblclick (arrow)", async () => {
|
||||||
createTwoPointerLinearElement("arrow");
|
createTwoPointerLinearElement("arrow");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
mouse.doubleClick();
|
mouse.doubleClick();
|
||||||
expect(h.state.editingLinearElement).toEqual(null);
|
expect(h.state.selectedLinearElement).toBe(null);
|
||||||
await getTextEditor();
|
await getTextEditor();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -330,10 +338,12 @@ describe("Test Linear Elements", () => {
|
|||||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||||
enterLineEditingMode(arrow);
|
enterLineEditingMode(arrow);
|
||||||
|
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(arrow.id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(arrow.id);
|
||||||
|
|
||||||
mouse.doubleClick();
|
mouse.doubleClick();
|
||||||
expect(h.state.editingLinearElement?.elementId).toEqual(arrow.id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
expect(h.state.selectedLinearElement?.elementId).toEqual(arrow.id);
|
||||||
expect(h.elements.length).toEqual(1);
|
expect(h.elements.length).toEqual(1);
|
||||||
|
|
||||||
expect(document.querySelector(TEXT_EDITOR_SELECTOR)).toBe(null);
|
expect(document.querySelector(TEXT_EDITOR_SELECTOR)).toBe(null);
|
||||||
@ -367,7 +377,7 @@ describe("Test Linear Elements", () => {
|
|||||||
// drag line from midpoint
|
// drag line from midpoint
|
||||||
drag(midpoint, pointFrom(midpoint[0] + delta, midpoint[1] + delta));
|
drag(midpoint, pointFrom(midpoint[0] + delta, midpoint[1] + delta));
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`12`,
|
`11`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||||
|
|
||||||
@ -469,7 +479,7 @@ describe("Test Linear Elements", () => {
|
|||||||
drag(startPoint, endPoint);
|
drag(startPoint, endPoint);
|
||||||
|
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`12`,
|
`11`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||||
|
|
||||||
@ -537,7 +547,7 @@ describe("Test Linear Elements", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`16`,
|
`14`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||||
|
|
||||||
@ -588,7 +598,7 @@ describe("Test Linear Elements", () => {
|
|||||||
drag(hitCoords, pointFrom(hitCoords[0] - delta, hitCoords[1] - delta));
|
drag(hitCoords, pointFrom(hitCoords[0] - delta, hitCoords[1] - delta));
|
||||||
|
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`12`,
|
`11`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||||
|
|
||||||
@ -629,7 +639,7 @@ describe("Test Linear Elements", () => {
|
|||||||
drag(hitCoords, pointFrom(hitCoords[0] + delta, hitCoords[1] + delta));
|
drag(hitCoords, pointFrom(hitCoords[0] + delta, hitCoords[1] + delta));
|
||||||
|
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`12`,
|
`11`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||||
|
|
||||||
@ -677,7 +687,7 @@ describe("Test Linear Elements", () => {
|
|||||||
deletePoint(points[2]);
|
deletePoint(points[2]);
|
||||||
expect(line.points.length).toEqual(3);
|
expect(line.points.length).toEqual(3);
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`18`,
|
`17`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||||
|
|
||||||
@ -735,7 +745,7 @@ describe("Test Linear Elements", () => {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`16`,
|
`14`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||||
expect(line.points.length).toEqual(5);
|
expect(line.points.length).toEqual(5);
|
||||||
@ -833,7 +843,7 @@ describe("Test Linear Elements", () => {
|
|||||||
drag(hitCoords, pointFrom(hitCoords[0] + delta, hitCoords[1] + delta));
|
drag(hitCoords, pointFrom(hitCoords[0] + delta, hitCoords[1] + delta));
|
||||||
|
|
||||||
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
`12`,
|
`11`,
|
||||||
);
|
);
|
||||||
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import { alignElements } from "@excalidraw/element";
|
|||||||
|
|
||||||
import { CaptureUpdateAction } from "@excalidraw/element";
|
import { CaptureUpdateAction } from "@excalidraw/element";
|
||||||
|
|
||||||
|
import { getSelectedElementsByGroup } from "@excalidraw/element";
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import type { Alignment } from "@excalidraw/element";
|
import type { Alignment } from "@excalidraw/element";
|
||||||
@ -38,7 +40,11 @@ export const alignActionsPredicate = (
|
|||||||
) => {
|
) => {
|
||||||
const selectedElements = app.scene.getSelectedElements(appState);
|
const selectedElements = app.scene.getSelectedElements(appState);
|
||||||
return (
|
return (
|
||||||
selectedElements.length > 1 &&
|
getSelectedElementsByGroup(
|
||||||
|
selectedElements,
|
||||||
|
app.scene.getNonDeletedElementsMap(),
|
||||||
|
appState as Readonly<AppState>,
|
||||||
|
).length > 1 &&
|
||||||
// TODO enable aligning frames when implemented properly
|
// TODO enable aligning frames when implemented properly
|
||||||
!selectedElements.some((el) => isFrameLikeElement(el))
|
!selectedElements.some((el) => isFrameLikeElement(el))
|
||||||
);
|
);
|
||||||
@ -52,7 +58,12 @@ const alignSelectedElements = (
|
|||||||
) => {
|
) => {
|
||||||
const selectedElements = app.scene.getSelectedElements(appState);
|
const selectedElements = app.scene.getSelectedElements(appState);
|
||||||
|
|
||||||
const updatedElements = alignElements(selectedElements, alignment, app.scene);
|
const updatedElements = alignElements(
|
||||||
|
selectedElements,
|
||||||
|
alignment,
|
||||||
|
app.scene,
|
||||||
|
appState,
|
||||||
|
);
|
||||||
|
|
||||||
const updatedElementsMap = arrayToMap(updatedElements);
|
const updatedElementsMap = arrayToMap(updatedElements);
|
||||||
|
|
||||||
|
|||||||
@ -205,16 +205,19 @@ export const actionDeleteSelected = register({
|
|||||||
icon: TrashIcon,
|
icon: TrashIcon,
|
||||||
trackEvent: { category: "element", action: "delete" },
|
trackEvent: { category: "element", action: "delete" },
|
||||||
perform: (elements, appState, formData, app) => {
|
perform: (elements, appState, formData, app) => {
|
||||||
if (appState.editingLinearElement) {
|
if (appState.selectedLinearElement?.isEditing) {
|
||||||
const {
|
const {
|
||||||
elementId,
|
elementId,
|
||||||
selectedPointsIndices,
|
selectedPointsIndices,
|
||||||
startBindingElement,
|
startBindingElement,
|
||||||
endBindingElement,
|
endBindingElement,
|
||||||
} = appState.editingLinearElement;
|
} = appState.selectedLinearElement;
|
||||||
const elementsMap = app.scene.getNonDeletedElementsMap();
|
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
const linearElement = LinearElementEditor.getElement(
|
||||||
if (!element) {
|
elementId,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
if (!linearElement) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// case: no point selected → do nothing, as deleting the whole element
|
// case: no point selected → do nothing, as deleting the whole element
|
||||||
@ -225,10 +228,10 @@ export const actionDeleteSelected = register({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case: deleting last remaining point
|
// case: deleting all points
|
||||||
if (element.points.length < 2) {
|
if (selectedPointsIndices.length >= linearElement.points.length) {
|
||||||
const nextElements = elements.map((el) => {
|
const nextElements = elements.map((el) => {
|
||||||
if (el.id === element.id) {
|
if (el.id === linearElement.id) {
|
||||||
return newElementWith(el, { isDeleted: true });
|
return newElementWith(el, { isDeleted: true });
|
||||||
}
|
}
|
||||||
return el;
|
return el;
|
||||||
@ -239,7 +242,7 @@ export const actionDeleteSelected = register({
|
|||||||
elements: nextElements,
|
elements: nextElements,
|
||||||
appState: {
|
appState: {
|
||||||
...nextAppState,
|
...nextAppState,
|
||||||
editingLinearElement: null,
|
selectedLinearElement: null,
|
||||||
},
|
},
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
};
|
};
|
||||||
@ -252,20 +255,24 @@ export const actionDeleteSelected = register({
|
|||||||
? null
|
? null
|
||||||
: startBindingElement,
|
: startBindingElement,
|
||||||
endBindingElement: selectedPointsIndices?.includes(
|
endBindingElement: selectedPointsIndices?.includes(
|
||||||
element.points.length - 1,
|
linearElement.points.length - 1,
|
||||||
)
|
)
|
||||||
? null
|
? null
|
||||||
: endBindingElement,
|
: endBindingElement,
|
||||||
};
|
};
|
||||||
|
|
||||||
LinearElementEditor.deletePoints(element, app, selectedPointsIndices);
|
LinearElementEditor.deletePoints(
|
||||||
|
linearElement,
|
||||||
|
app,
|
||||||
|
selectedPointsIndices,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
elements,
|
elements,
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
editingLinearElement: {
|
selectedLinearElement: {
|
||||||
...appState.editingLinearElement,
|
...appState.selectedLinearElement,
|
||||||
...binding,
|
...binding,
|
||||||
selectedPointsIndices:
|
selectedPointsIndices:
|
||||||
selectedPointsIndices?.[0] > 0
|
selectedPointsIndices?.[0] > 0
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import { distributeElements } from "@excalidraw/element";
|
|||||||
|
|
||||||
import { CaptureUpdateAction } from "@excalidraw/element";
|
import { CaptureUpdateAction } from "@excalidraw/element";
|
||||||
|
|
||||||
|
import { getSelectedElementsByGroup } from "@excalidraw/element";
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import type { Distribution } from "@excalidraw/element";
|
import type { Distribution } from "@excalidraw/element";
|
||||||
@ -31,7 +33,11 @@ import type { AppClassProperties, AppState } from "../types";
|
|||||||
const enableActionGroup = (appState: AppState, app: AppClassProperties) => {
|
const enableActionGroup = (appState: AppState, app: AppClassProperties) => {
|
||||||
const selectedElements = app.scene.getSelectedElements(appState);
|
const selectedElements = app.scene.getSelectedElements(appState);
|
||||||
return (
|
return (
|
||||||
selectedElements.length > 1 &&
|
getSelectedElementsByGroup(
|
||||||
|
selectedElements,
|
||||||
|
app.scene.getNonDeletedElementsMap(),
|
||||||
|
appState as Readonly<AppState>,
|
||||||
|
).length > 2 &&
|
||||||
// TODO enable distributing frames when implemented properly
|
// TODO enable distributing frames when implemented properly
|
||||||
!selectedElements.some((el) => isFrameLikeElement(el))
|
!selectedElements.some((el) => isFrameLikeElement(el))
|
||||||
);
|
);
|
||||||
@ -49,6 +55,7 @@ const distributeSelectedElements = (
|
|||||||
selectedElements,
|
selectedElements,
|
||||||
app.scene.getNonDeletedElementsMap(),
|
app.scene.getNonDeletedElementsMap(),
|
||||||
distribution,
|
distribution,
|
||||||
|
appState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatedElementsMap = arrayToMap(updatedElements);
|
const updatedElementsMap = arrayToMap(updatedElements);
|
||||||
|
|||||||
@ -39,7 +39,7 @@ export const actionDuplicateSelection = register({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// duplicate selected point(s) if editing a line
|
// duplicate selected point(s) if editing a line
|
||||||
if (appState.editingLinearElement) {
|
if (appState.selectedLinearElement?.isEditing) {
|
||||||
// TODO: Invariants should be checked here instead of duplicateSelectedPoints()
|
// TODO: Invariants should be checked here instead of duplicateSelectedPoints()
|
||||||
try {
|
try {
|
||||||
const newAppState = LinearElementEditor.duplicateSelectedPoints(
|
const newAppState = LinearElementEditor.duplicateSelectedPoints(
|
||||||
|
|||||||
@ -94,9 +94,9 @@ export const actionFinalize = register({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appState.editingLinearElement) {
|
if (appState.selectedLinearElement?.isEditing) {
|
||||||
const { elementId, startBindingElement, endBindingElement } =
|
const { elementId, startBindingElement, endBindingElement } =
|
||||||
appState.editingLinearElement;
|
appState.selectedLinearElement;
|
||||||
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
const element = LinearElementEditor.getElement(elementId, elementsMap);
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
@ -122,7 +122,11 @@ export const actionFinalize = register({
|
|||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
cursorButton: "up",
|
cursorButton: "up",
|
||||||
editingLinearElement: null,
|
selectedLinearElement: new LinearElementEditor(
|
||||||
|
element,
|
||||||
|
arrayToMap(elementsMap),
|
||||||
|
false, // exit editing mode
|
||||||
|
),
|
||||||
},
|
},
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
};
|
};
|
||||||
@ -154,11 +158,7 @@ export const actionFinalize = register({
|
|||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
// pen and mouse have hover
|
// pen and mouse have hover
|
||||||
if (
|
if (appState.multiElement && element.type !== "freedraw") {
|
||||||
appState.multiElement &&
|
|
||||||
element.type !== "freedraw" &&
|
|
||||||
appState.lastPointerDownWith !== "touch"
|
|
||||||
) {
|
|
||||||
const { points, lastCommittedPoint } = element;
|
const { points, lastCommittedPoint } = element;
|
||||||
if (
|
if (
|
||||||
!lastCommittedPoint ||
|
!lastCommittedPoint ||
|
||||||
@ -289,7 +289,7 @@ export const actionFinalize = register({
|
|||||||
},
|
},
|
||||||
keyTest: (event, appState) =>
|
keyTest: (event, appState) =>
|
||||||
(event.key === KEYS.ESCAPE &&
|
(event.key === KEYS.ESCAPE &&
|
||||||
(appState.editingLinearElement !== null ||
|
(appState.selectedLinearElement?.isEditing ||
|
||||||
(!appState.newElement && appState.multiElement === null))) ||
|
(!appState.newElement && appState.multiElement === null))) ||
|
||||||
((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) &&
|
((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) &&
|
||||||
appState.multiElement !== null),
|
appState.multiElement !== null),
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import { LinearElementEditor } from "@excalidraw/element";
|
|
||||||
import {
|
import {
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
isLineElement,
|
isLineElement,
|
||||||
} from "@excalidraw/element";
|
} from "@excalidraw/element";
|
||||||
import { arrayToMap } from "@excalidraw/common";
|
import { arrayToMap, invariant } from "@excalidraw/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
toggleLinePolygonState,
|
toggleLinePolygonState,
|
||||||
@ -46,7 +45,7 @@ export const actionToggleLinearEditor = register({
|
|||||||
predicate: (elements, appState, _, app) => {
|
predicate: (elements, appState, _, app) => {
|
||||||
const selectedElements = app.scene.getSelectedElements(appState);
|
const selectedElements = app.scene.getSelectedElements(appState);
|
||||||
if (
|
if (
|
||||||
!appState.editingLinearElement &&
|
!appState.selectedLinearElement?.isEditing &&
|
||||||
selectedElements.length === 1 &&
|
selectedElements.length === 1 &&
|
||||||
isLinearElement(selectedElements[0]) &&
|
isLinearElement(selectedElements[0]) &&
|
||||||
!isElbowArrow(selectedElements[0])
|
!isElbowArrow(selectedElements[0])
|
||||||
@ -61,14 +60,25 @@ export const actionToggleLinearEditor = register({
|
|||||||
includeBoundTextElement: true,
|
includeBoundTextElement: true,
|
||||||
})[0] as ExcalidrawLinearElement;
|
})[0] as ExcalidrawLinearElement;
|
||||||
|
|
||||||
const editingLinearElement =
|
invariant(selectedElement, "No selected element found");
|
||||||
appState.editingLinearElement?.elementId === selectedElement.id
|
invariant(
|
||||||
? null
|
appState.selectedLinearElement,
|
||||||
: new LinearElementEditor(selectedElement, arrayToMap(elements));
|
"No selected linear element found",
|
||||||
|
);
|
||||||
|
invariant(
|
||||||
|
selectedElement.id === appState.selectedLinearElement.elementId,
|
||||||
|
"Selected element ID and linear editor elementId does not match",
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedLinearElement = {
|
||||||
|
...appState.selectedLinearElement,
|
||||||
|
isEditing: !appState.selectedLinearElement.isEditing,
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
editingLinearElement,
|
selectedLinearElement,
|
||||||
},
|
},
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export const actionSelectAll = register({
|
|||||||
trackEvent: { category: "canvas" },
|
trackEvent: { category: "canvas" },
|
||||||
viewMode: false,
|
viewMode: false,
|
||||||
perform: (elements, appState, value, app) => {
|
perform: (elements, appState, value, app) => {
|
||||||
if (appState.editingLinearElement) {
|
if (appState.selectedLinearElement?.isEditing) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,6 @@ export const getDefaultAppState = (): Omit<
|
|||||||
newElement: null,
|
newElement: null,
|
||||||
editingTextElement: null,
|
editingTextElement: null,
|
||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
editingLinearElement: null,
|
|
||||||
activeTool: {
|
activeTool: {
|
||||||
type: "selection",
|
type: "selection",
|
||||||
customType: null,
|
customType: null,
|
||||||
@ -175,7 +174,6 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
newElement: { browser: false, export: false, server: false },
|
newElement: { browser: false, export: false, server: false },
|
||||||
editingTextElement: { browser: false, export: false, server: false },
|
editingTextElement: { browser: false, export: false, server: false },
|
||||||
editingGroupId: { browser: true, export: false, server: false },
|
editingGroupId: { browser: true, export: false, server: false },
|
||||||
editingLinearElement: { browser: false, export: false, server: false },
|
|
||||||
activeTool: { browser: true, export: false, server: false },
|
activeTool: { browser: true, export: false, server: false },
|
||||||
penMode: { browser: true, export: false, server: false },
|
penMode: { browser: true, export: false, server: false },
|
||||||
penDetected: { browser: true, export: false, server: false },
|
penDetected: { browser: true, export: false, server: false },
|
||||||
|
|||||||
@ -140,7 +140,7 @@ export const SelectedShapeActions = ({
|
|||||||
targetElements.length === 1 || isSingleElementBoundContainer;
|
targetElements.length === 1 || isSingleElementBoundContainer;
|
||||||
|
|
||||||
const showLineEditorAction =
|
const showLineEditorAction =
|
||||||
!appState.editingLinearElement &&
|
!appState.selectedLinearElement?.isEditing &&
|
||||||
targetElements.length === 1 &&
|
targetElements.length === 1 &&
|
||||||
isLinearElement(targetElements[0]) &&
|
isLinearElement(targetElements[0]) &&
|
||||||
!isElbowArrow(targetElements[0]);
|
!isElbowArrow(targetElements[0]);
|
||||||
@ -505,15 +505,3 @@ export const ExitZenModeAction = ({
|
|||||||
{t("buttons.exitZenMode")}
|
{t("buttons.exitZenMode")}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const FinalizeAction = ({
|
|
||||||
renderAction,
|
|
||||||
className,
|
|
||||||
}: {
|
|
||||||
renderAction: ActionManager["renderAction"];
|
|
||||||
className?: string;
|
|
||||||
}) => (
|
|
||||||
<div className={`finalize-button ${className}`}>
|
|
||||||
{renderAction("finalize", { size: "small" })}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|||||||
@ -102,6 +102,7 @@ import {
|
|||||||
randomInteger,
|
randomInteger,
|
||||||
CLASSES,
|
CLASSES,
|
||||||
Emitter,
|
Emitter,
|
||||||
|
MINIMUM_ARROW_SIZE,
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -594,6 +595,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
* insert to DOM before user initially scrolls to them) */
|
* insert to DOM before user initially scrolls to them) */
|
||||||
private initializedEmbeds = new Set<ExcalidrawIframeLikeElement["id"]>();
|
private initializedEmbeds = new Set<ExcalidrawIframeLikeElement["id"]>();
|
||||||
|
|
||||||
|
private handleToastClose = () => {
|
||||||
|
this.setToast(null);
|
||||||
|
};
|
||||||
|
|
||||||
private elementsPendingErasure: ElementsPendingErasure = new Set();
|
private elementsPendingErasure: ElementsPendingErasure = new Set();
|
||||||
|
|
||||||
public flowChartCreator: FlowChartCreator = new FlowChartCreator();
|
public flowChartCreator: FlowChartCreator = new FlowChartCreator();
|
||||||
@ -1708,14 +1713,16 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
/>
|
/>
|
||||||
</ElementCanvasButtons>
|
</ElementCanvasButtons>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{this.state.toast !== null && (
|
{this.state.toast !== null && (
|
||||||
<Toast
|
<Toast
|
||||||
message={this.state.toast.message}
|
message={this.state.toast.message}
|
||||||
onClose={() => this.setToast(null)}
|
onClose={this.handleToastClose}
|
||||||
duration={this.state.toast.duration}
|
duration={this.state.toast.duration}
|
||||||
closable={this.state.toast.closable}
|
closable={this.state.toast.closable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{this.state.contextMenu && (
|
{this.state.contextMenu && (
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
items={this.state.contextMenu.items}
|
items={this.state.contextMenu.items}
|
||||||
@ -2152,9 +2159,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
public dismissLinearEditor = () => {
|
public dismissLinearEditor = () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.setState({
|
if (this.state.selectedLinearElement?.isEditing) {
|
||||||
editingLinearElement: null,
|
this.setState({
|
||||||
});
|
selectedLinearElement: {
|
||||||
|
...this.state.selectedLinearElement,
|
||||||
|
isEditing: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2850,15 +2862,15 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.state.editingLinearElement &&
|
this.state.selectedLinearElement?.isEditing &&
|
||||||
!this.state.selectedElementIds[this.state.editingLinearElement.elementId]
|
!this.state.selectedElementIds[this.state.selectedLinearElement.elementId]
|
||||||
) {
|
) {
|
||||||
// defer so that the scheduleCapture flag isn't reset via current update
|
// defer so that the scheduleCapture flag isn't reset via current update
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// execute only if the condition still holds when the deferred callback
|
// execute only if the condition still holds when the deferred callback
|
||||||
// executes (it can be scheduled multiple times depending on how
|
// executes (it can be scheduled multiple times depending on how
|
||||||
// many times the component renders)
|
// many times the component renders)
|
||||||
this.state.editingLinearElement &&
|
this.state.selectedLinearElement?.isEditing &&
|
||||||
this.actionManager.executeAction(actionFinalize);
|
this.actionManager.executeAction(actionFinalize);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -4413,17 +4425,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (event[KEYS.CTRL_OR_CMD] || isLineElement(selectedElement)) {
|
if (event[KEYS.CTRL_OR_CMD] || isLineElement(selectedElement)) {
|
||||||
if (isLinearElement(selectedElement)) {
|
if (isLinearElement(selectedElement)) {
|
||||||
if (
|
if (
|
||||||
!this.state.editingLinearElement ||
|
!this.state.selectedLinearElement?.isEditing ||
|
||||||
this.state.editingLinearElement.elementId !== selectedElement.id
|
this.state.selectedLinearElement.elementId !==
|
||||||
|
selectedElement.id
|
||||||
) {
|
) {
|
||||||
this.store.scheduleCapture();
|
this.store.scheduleCapture();
|
||||||
if (!isElbowArrow(selectedElement)) {
|
if (!isElbowArrow(selectedElement)) {
|
||||||
this.setState({
|
this.actionManager.executeAction(actionToggleLinearEditor);
|
||||||
editingLinearElement: new LinearElementEditor(
|
|
||||||
selectedElement,
|
|
||||||
this.scene.getNonDeletedElementsMap(),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4920,7 +4928,17 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}),
|
}),
|
||||||
onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
|
onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
|
||||||
const isDeleted = !nextOriginalText.trim();
|
const isDeleted = !nextOriginalText.trim();
|
||||||
updateElement(nextOriginalText, isDeleted);
|
|
||||||
|
if (isDeleted && !isExistingElement) {
|
||||||
|
// let's just remove the element from the scene, as it's an empty just created text element
|
||||||
|
this.scene.replaceAllElements(
|
||||||
|
this.scene
|
||||||
|
.getElementsIncludingDeleted()
|
||||||
|
.filter((x) => x.id !== element.id),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
updateElement(nextOriginalText, isDeleted);
|
||||||
|
}
|
||||||
// select the created text element only if submitting via keyboard
|
// select the created text element only if submitting via keyboard
|
||||||
// (when submitting via click it should act as signal to deselect)
|
// (when submitting via click it should act as signal to deselect)
|
||||||
if (!isDeleted && viaKeyboard) {
|
if (!isDeleted && viaKeyboard) {
|
||||||
@ -4949,9 +4967,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
element,
|
element,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if (!isDeleted || isExistingElement) {
|
|
||||||
this.store.scheduleCapture();
|
// we need to record either way, whether the text element was added or removed
|
||||||
}
|
// since we need to sync this delta to other clients, otherwise it would end up with inconsistencies
|
||||||
|
this.store.scheduleCapture();
|
||||||
|
|
||||||
flushSync(() => {
|
flushSync(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -5415,15 +5434,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (
|
if (
|
||||||
((event[KEYS.CTRL_OR_CMD] && isSimpleArrow(selectedLinearElement)) ||
|
((event[KEYS.CTRL_OR_CMD] && isSimpleArrow(selectedLinearElement)) ||
|
||||||
isLineElement(selectedLinearElement)) &&
|
isLineElement(selectedLinearElement)) &&
|
||||||
this.state.editingLinearElement?.elementId !== selectedLinearElement.id
|
(!this.state.selectedLinearElement?.isEditing ||
|
||||||
|
this.state.selectedLinearElement.elementId !==
|
||||||
|
selectedLinearElement.id)
|
||||||
) {
|
) {
|
||||||
this.store.scheduleCapture();
|
// Use the proper action to ensure immediate history capture
|
||||||
this.setState({
|
this.actionManager.executeAction(actionToggleLinearEditor);
|
||||||
editingLinearElement: new LinearElementEditor(
|
|
||||||
selectedLinearElement,
|
|
||||||
this.scene.getNonDeletedElementsMap(),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
} else if (
|
} else if (
|
||||||
this.state.selectedLinearElement &&
|
this.state.selectedLinearElement &&
|
||||||
@ -5488,8 +5504,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
this.state.editingLinearElement &&
|
this.state.selectedLinearElement?.isEditing &&
|
||||||
this.state.editingLinearElement.elementId ===
|
this.state.selectedLinearElement.elementId ===
|
||||||
selectedLinearElement.id &&
|
selectedLinearElement.id &&
|
||||||
isLineElement(selectedLinearElement)
|
isLineElement(selectedLinearElement)
|
||||||
) {
|
) {
|
||||||
@ -5544,7 +5560,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
// shouldn't edit/create text when inside line editor (often false positive)
|
// shouldn't edit/create text when inside line editor (often false positive)
|
||||||
|
|
||||||
if (!this.state.editingLinearElement) {
|
if (!this.state.selectedLinearElement?.isEditing) {
|
||||||
const container = this.getTextBindableContainerAtPosition(
|
const container = this.getTextBindableContainerAtPosition(
|
||||||
sceneX,
|
sceneX,
|
||||||
sceneY,
|
sceneY,
|
||||||
@ -5846,8 +5862,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.state.editingLinearElement &&
|
this.state.selectedLinearElement?.isEditing &&
|
||||||
!this.state.editingLinearElement.isDragging
|
!this.state.selectedLinearElement.isDragging
|
||||||
) {
|
) {
|
||||||
const result = LinearElementEditor.handlePointerMove(
|
const result = LinearElementEditor.handlePointerMove(
|
||||||
event,
|
event,
|
||||||
@ -5857,32 +5873,36 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const { linearElementEditor: editingLinearElement, snapLines } = result;
|
const { editingLinearElement, snapLines } = result;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
editingLinearElement &&
|
editingLinearElement &&
|
||||||
editingLinearElement !== this.state.editingLinearElement
|
editingLinearElement !== this.state.selectedLinearElement
|
||||||
) {
|
) {
|
||||||
// Since we are reading from previous state which is not possible with
|
// Since we are reading from previous state which is not possible with
|
||||||
// automatic batching in React 18 hence using flush sync to synchronously
|
// automatic batching in React 18 hence using flush sync to synchronously
|
||||||
// update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.
|
// update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.
|
||||||
flushSync(() => {
|
flushSync(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
editingLinearElement,
|
selectedLinearElement: editingLinearElement,
|
||||||
snapLines,
|
snapLines,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (editingLinearElement?.lastUncommittedPoint != null) {
|
const latestLinearElement = this.scene.getElement(
|
||||||
|
editingLinearElement.elementId,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
editingLinearElement.lastUncommittedPoint != null &&
|
||||||
|
latestLinearElement &&
|
||||||
|
isBindingElementType(latestLinearElement.type)
|
||||||
|
) {
|
||||||
this.maybeSuggestBindingAtCursor(
|
this.maybeSuggestBindingAtCursor(
|
||||||
scenePointer,
|
scenePointer,
|
||||||
editingLinearElement.elbowed,
|
editingLinearElement.elbowed,
|
||||||
);
|
);
|
||||||
} else {
|
} else if (this.state.suggestedBindings.length) {
|
||||||
// causes stack overflow if not sync
|
this.setState({ suggestedBindings: [] });
|
||||||
flushSync(() => {
|
|
||||||
this.setState({ suggestedBindings: [] });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6118,7 +6138,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (
|
if (
|
||||||
selectedElements.length === 1 &&
|
selectedElements.length === 1 &&
|
||||||
!isOverScrollBar &&
|
!isOverScrollBar &&
|
||||||
!this.state.editingLinearElement
|
!this.state.selectedLinearElement?.isEditing
|
||||||
) {
|
) {
|
||||||
// for linear elements, we'd like to prioritize point dragging over edge resizing
|
// for linear elements, we'd like to prioritize point dragging over edge resizing
|
||||||
// therefore, we update and check hovered point index first
|
// therefore, we update and check hovered point index first
|
||||||
@ -6236,15 +6256,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
||||||
} else if (isOverScrollBar) {
|
} else if (isOverScrollBar) {
|
||||||
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
||||||
} else if (
|
|
||||||
this.state.selectedLinearElement &&
|
|
||||||
hitElement?.id === this.state.selectedLinearElement.elementId
|
|
||||||
) {
|
|
||||||
this.handleHoverSelectedLinearElement(
|
|
||||||
this.state.selectedLinearElement,
|
|
||||||
scenePointerX,
|
|
||||||
scenePointerY,
|
|
||||||
);
|
|
||||||
} else if (
|
} else if (
|
||||||
// if using cmd/ctrl, we're not dragging
|
// if using cmd/ctrl, we're not dragging
|
||||||
!event[KEYS.CTRL_OR_CMD]
|
!event[KEYS.CTRL_OR_CMD]
|
||||||
@ -6286,6 +6297,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
} else {
|
} else {
|
||||||
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.state.selectedLinearElement) {
|
||||||
|
this.handleHoverSelectedLinearElement(
|
||||||
|
this.state.selectedLinearElement,
|
||||||
|
scenePointerX,
|
||||||
|
scenePointerY,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.openDialog?.name === "elementLinkSelector" && hitElement) {
|
if (this.state.openDialog?.name === "elementLinkSelector" && hitElement) {
|
||||||
@ -7123,7 +7142,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
selectedElements.length === 1 &&
|
selectedElements.length === 1 &&
|
||||||
!this.state.editingLinearElement &&
|
!this.state.selectedLinearElement?.isEditing &&
|
||||||
!isElbowArrow(selectedElements[0]) &&
|
!isElbowArrow(selectedElements[0]) &&
|
||||||
!(
|
!(
|
||||||
this.state.selectedLinearElement &&
|
this.state.selectedLinearElement &&
|
||||||
@ -7194,8 +7213,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.state.selectedLinearElement) {
|
if (this.state.selectedLinearElement) {
|
||||||
const linearElementEditor =
|
const linearElementEditor = this.state.selectedLinearElement;
|
||||||
this.state.editingLinearElement || this.state.selectedLinearElement;
|
|
||||||
const ret = LinearElementEditor.handlePointerDown(
|
const ret = LinearElementEditor.handlePointerDown(
|
||||||
event,
|
event,
|
||||||
this,
|
this,
|
||||||
@ -7209,10 +7227,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
if (ret.linearElementEditor) {
|
if (ret.linearElementEditor) {
|
||||||
this.setState({ selectedLinearElement: ret.linearElementEditor });
|
this.setState({ selectedLinearElement: ret.linearElementEditor });
|
||||||
|
|
||||||
if (this.state.editingLinearElement) {
|
|
||||||
this.setState({ editingLinearElement: ret.linearElementEditor });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (ret.didAddPoint) {
|
if (ret.didAddPoint) {
|
||||||
return true;
|
return true;
|
||||||
@ -7313,11 +7327,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.clearSelection(hitElement);
|
this.clearSelection(hitElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.editingLinearElement) {
|
if (this.state.selectedLinearElement?.isEditing) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: makeNextSelectedElementIds(
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
{
|
{
|
||||||
[this.state.editingLinearElement.elementId]: true,
|
[this.state.selectedLinearElement.elementId]: true,
|
||||||
},
|
},
|
||||||
this.state,
|
this.state,
|
||||||
),
|
),
|
||||||
@ -8176,16 +8190,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scene,
|
this.scene,
|
||||||
);
|
);
|
||||||
|
|
||||||
flushSync(() => {
|
this.setState({
|
||||||
if (this.state.selectedLinearElement) {
|
selectedLinearElement: {
|
||||||
this.setState({
|
...this.state.selectedLinearElement,
|
||||||
selectedLinearElement: {
|
segmentMidPointHoveredCoords: ret.segmentMidPointHoveredCoords,
|
||||||
...this.state.selectedLinearElement,
|
pointerDownState: ret.pointerDownState,
|
||||||
segmentMidPointHoveredCoords: ret.segmentMidPointHoveredCoords,
|
},
|
||||||
pointerDownState: ret.pointerDownState,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -8244,7 +8254,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
pointDistance(
|
pointDistance(
|
||||||
pointFrom(pointerCoords.x, pointerCoords.y),
|
pointFrom(pointerCoords.x, pointerCoords.y),
|
||||||
pointFrom(pointerDownState.origin.x, pointerDownState.origin.y),
|
pointFrom(pointerDownState.origin.x, pointerDownState.origin.y),
|
||||||
) < DRAGGING_THRESHOLD
|
) *
|
||||||
|
this.state.zoom.value <
|
||||||
|
MINIMUM_ARROW_SIZE
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -8262,8 +8274,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
if (this.state.selectedLinearElement) {
|
if (this.state.selectedLinearElement) {
|
||||||
const linearElementEditor =
|
const linearElementEditor = this.state.selectedLinearElement;
|
||||||
this.state.editingLinearElement || this.state.selectedLinearElement;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
LinearElementEditor.shouldAddMidpoint(
|
LinearElementEditor.shouldAddMidpoint(
|
||||||
@ -8299,16 +8310,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.state.editingLinearElement) {
|
|
||||||
this.setState({
|
|
||||||
editingLinearElement: {
|
|
||||||
...this.state.editingLinearElement,
|
|
||||||
pointerDownState: ret.pointerDownState,
|
|
||||||
selectedPointsIndices: ret.selectedPointsIndices,
|
|
||||||
segmentMidPointHoveredCoords: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -8342,9 +8343,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isSelectingPointsInLineEditor =
|
const isSelectingPointsInLineEditor =
|
||||||
this.state.editingLinearElement &&
|
this.state.selectedLinearElement?.isEditing &&
|
||||||
event.shiftKey &&
|
event.shiftKey &&
|
||||||
this.state.editingLinearElement.elementId ===
|
this.state.selectedLinearElement.elementId ===
|
||||||
pointerDownState.hit.element?.id;
|
pointerDownState.hit.element?.id;
|
||||||
if (
|
if (
|
||||||
(hasHitASelectedElement ||
|
(hasHitASelectedElement ||
|
||||||
@ -8697,23 +8698,21 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
pointerDownState.lastCoords.x = pointerCoords.x;
|
pointerDownState.lastCoords.x = pointerCoords.x;
|
||||||
pointerDownState.lastCoords.y = pointerCoords.y;
|
pointerDownState.lastCoords.y = pointerCoords.y;
|
||||||
if (event.altKey) {
|
if (event.altKey) {
|
||||||
flushSync(() => {
|
this.setActiveTool(
|
||||||
this.setActiveTool(
|
{ type: "lasso", fromSelection: true },
|
||||||
{ type: "lasso", fromSelection: true },
|
event.shiftKey,
|
||||||
event.shiftKey,
|
);
|
||||||
);
|
this.lassoTrail.startPath(
|
||||||
this.lassoTrail.startPath(
|
pointerDownState.origin.x,
|
||||||
pointerDownState.origin.x,
|
pointerDownState.origin.y,
|
||||||
pointerDownState.origin.y,
|
event.shiftKey,
|
||||||
event.shiftKey,
|
);
|
||||||
);
|
this.setAppState({
|
||||||
this.setAppState({
|
selectionElement: null,
|
||||||
selectionElement: null,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} else {
|
return;
|
||||||
this.maybeDragNewGenericElement(pointerDownState, event);
|
|
||||||
}
|
}
|
||||||
|
this.maybeDragNewGenericElement(pointerDownState, event);
|
||||||
} else if (this.state.activeTool.type === "lasso") {
|
} else if (this.state.activeTool.type === "lasso") {
|
||||||
if (!event.altKey && this.state.activeTool.fromSelection) {
|
if (!event.altKey && this.state.activeTool.fromSelection) {
|
||||||
this.setActiveTool({ type: "selection" });
|
this.setActiveTool({ type: "selection" });
|
||||||
@ -8920,7 +8919,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
const elements = this.scene.getNonDeletedElements();
|
const elements = this.scene.getNonDeletedElements();
|
||||||
|
|
||||||
// box-select line editor points
|
// box-select line editor points
|
||||||
if (this.state.editingLinearElement) {
|
if (this.state.selectedLinearElement?.isEditing) {
|
||||||
LinearElementEditor.handleBoxSelection(
|
LinearElementEditor.handleBoxSelection(
|
||||||
event,
|
event,
|
||||||
this.state,
|
this.state,
|
||||||
@ -9163,23 +9162,23 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
// Handle end of dragging a point of a linear element, might close a loop
|
// Handle end of dragging a point of a linear element, might close a loop
|
||||||
// and sets binding element
|
// and sets binding element
|
||||||
if (this.state.editingLinearElement) {
|
if (this.state.selectedLinearElement?.isEditing) {
|
||||||
if (
|
if (
|
||||||
!pointerDownState.boxSelection.hasOccurred &&
|
!pointerDownState.boxSelection.hasOccurred &&
|
||||||
pointerDownState.hit?.element?.id !==
|
pointerDownState.hit?.element?.id !==
|
||||||
this.state.editingLinearElement.elementId
|
this.state.selectedLinearElement.elementId
|
||||||
) {
|
) {
|
||||||
this.actionManager.executeAction(actionFinalize);
|
this.actionManager.executeAction(actionFinalize);
|
||||||
} else {
|
} else {
|
||||||
const editingLinearElement = LinearElementEditor.handlePointerUp(
|
const editingLinearElement = LinearElementEditor.handlePointerUp(
|
||||||
childEvent,
|
childEvent,
|
||||||
this.state.editingLinearElement,
|
this.state.selectedLinearElement,
|
||||||
this.state,
|
this.state,
|
||||||
this.scene,
|
this.scene,
|
||||||
);
|
);
|
||||||
if (editingLinearElement !== this.state.editingLinearElement) {
|
if (editingLinearElement !== this.state.selectedLinearElement) {
|
||||||
this.setState({
|
this.setState({
|
||||||
editingLinearElement,
|
selectedLinearElement: editingLinearElement,
|
||||||
suggestedBindings: [],
|
suggestedBindings: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -9282,25 +9281,54 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.state,
|
this.state,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!pointerDownState.drag.hasOccurred && newElement && !multiElement) {
|
const dragDistance =
|
||||||
this.scene.mutateElement(
|
pointDistance(
|
||||||
newElement,
|
pointFrom(pointerCoords.x, pointerCoords.y),
|
||||||
{
|
pointFrom(pointerDownState.origin.x, pointerDownState.origin.y),
|
||||||
points: [
|
) * this.state.zoom.value;
|
||||||
...newElement.points,
|
|
||||||
pointFrom<LocalPoint>(
|
|
||||||
pointerCoords.x - newElement.x,
|
|
||||||
pointerCoords.y - newElement.y,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ informMutation: false, isDragging: false },
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setState({
|
if (
|
||||||
multiElement: newElement,
|
(!pointerDownState.drag.hasOccurred ||
|
||||||
newElement,
|
dragDistance < MINIMUM_ARROW_SIZE) &&
|
||||||
});
|
newElement &&
|
||||||
|
!multiElement
|
||||||
|
) {
|
||||||
|
if (this.device.isTouchScreen) {
|
||||||
|
const FIXED_DELTA_X = Math.min(
|
||||||
|
(this.state.width * 0.7) / this.state.zoom.value,
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.scene.mutateElement(
|
||||||
|
newElement,
|
||||||
|
{
|
||||||
|
x: newElement.x - FIXED_DELTA_X / 2,
|
||||||
|
points: [
|
||||||
|
pointFrom<LocalPoint>(0, 0),
|
||||||
|
pointFrom<LocalPoint>(FIXED_DELTA_X, 0),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ informMutation: false, isDragging: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
this.actionManager.executeAction(actionFinalize);
|
||||||
|
} else {
|
||||||
|
const dx = pointerCoords.x - newElement.x;
|
||||||
|
const dy = pointerCoords.y - newElement.y;
|
||||||
|
|
||||||
|
this.scene.mutateElement(
|
||||||
|
newElement,
|
||||||
|
{
|
||||||
|
points: [...newElement.points, pointFrom<LocalPoint>(dx, dy)],
|
||||||
|
},
|
||||||
|
{ informMutation: false, isDragging: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
multiElement: newElement,
|
||||||
|
newElement,
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
||||||
if (
|
if (
|
||||||
isBindingEnabled(this.state) &&
|
isBindingEnabled(this.state) &&
|
||||||
@ -9663,14 +9691,17 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
!pointerDownState.hit.wasAddedToSelection &&
|
!pointerDownState.hit.wasAddedToSelection &&
|
||||||
// if we're editing a line, pointerup shouldn't switch selection if
|
// if we're editing a line, pointerup shouldn't switch selection if
|
||||||
// box selected
|
// box selected
|
||||||
(!this.state.editingLinearElement ||
|
(!this.state.selectedLinearElement?.isEditing ||
|
||||||
!pointerDownState.boxSelection.hasOccurred) &&
|
!pointerDownState.boxSelection.hasOccurred) &&
|
||||||
// hitElement can be set when alt + ctrl to toggle lasso and we will
|
// hitElement can be set when alt + ctrl to toggle lasso and we will
|
||||||
// just respect the selected elements from lasso instead
|
// just respect the selected elements from lasso instead
|
||||||
this.state.activeTool.type !== "lasso"
|
this.state.activeTool.type !== "lasso"
|
||||||
) {
|
) {
|
||||||
// when inside line editor, shift selects points instead
|
// when inside line editor, shift selects points instead
|
||||||
if (childEvent.shiftKey && !this.state.editingLinearElement) {
|
if (
|
||||||
|
childEvent.shiftKey &&
|
||||||
|
!this.state.selectedLinearElement?.isEditing
|
||||||
|
) {
|
||||||
if (this.state.selectedElementIds[hitElement.id]) {
|
if (this.state.selectedElementIds[hitElement.id]) {
|
||||||
if (isSelectedViaGroup(this.state, hitElement)) {
|
if (isSelectedViaGroup(this.state, hitElement)) {
|
||||||
this.setState((_prevState) => {
|
this.setState((_prevState) => {
|
||||||
@ -9848,8 +9879,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
(!hitElement &&
|
(!hitElement &&
|
||||||
pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements))
|
pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements))
|
||||||
) {
|
) {
|
||||||
if (this.state.editingLinearElement) {
|
if (this.state.selectedLinearElement?.isEditing) {
|
||||||
this.setState({ editingLinearElement: null });
|
// Exit editing mode but keep the element selected
|
||||||
|
this.actionManager.executeAction(actionToggleLinearEditor);
|
||||||
} else {
|
} else {
|
||||||
// Deselect selected elements
|
// Deselect selected elements
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|||||||
@ -108,6 +108,7 @@ $verticalBreakpoint: 861px;
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -59,6 +59,8 @@ import { useStableCallback } from "../../hooks/useStableCallback";
|
|||||||
import { activeConfirmDialogAtom } from "../ActiveConfirmDialog";
|
import { activeConfirmDialogAtom } from "../ActiveConfirmDialog";
|
||||||
import { useStable } from "../../hooks/useStable";
|
import { useStable } from "../../hooks/useStable";
|
||||||
|
|
||||||
|
import { Ellipsify } from "../Ellipsify";
|
||||||
|
|
||||||
import * as defaultItems from "./defaultCommandPaletteItems";
|
import * as defaultItems from "./defaultCommandPaletteItems";
|
||||||
|
|
||||||
import "./CommandPalette.scss";
|
import "./CommandPalette.scss";
|
||||||
@ -964,7 +966,7 @@ const CommandItem = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{command.label}
|
<Ellipsify>{command.label}</Ellipsify>
|
||||||
</div>
|
</div>
|
||||||
{showShortcut && command.shortcut && (
|
{showShortcut && command.shortcut && (
|
||||||
<CommandShortcutHint shortcut={command.shortcut} />
|
<CommandShortcutHint shortcut={command.shortcut} />
|
||||||
|
|||||||
18
packages/excalidraw/components/Ellipsify.tsx
Normal file
18
packages/excalidraw/components/Ellipsify.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const Ellipsify = ({
|
||||||
|
children,
|
||||||
|
...rest
|
||||||
|
}: { children: React.ReactNode } & React.HTMLAttributes<HTMLSpanElement>) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
{...rest}
|
||||||
|
style={{
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
overflow: "hidden",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
...rest.style,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -114,7 +114,7 @@ const getHints = ({
|
|||||||
appState.selectionElement &&
|
appState.selectionElement &&
|
||||||
!selectedElements.length &&
|
!selectedElements.length &&
|
||||||
!appState.editingTextElement &&
|
!appState.editingTextElement &&
|
||||||
!appState.editingLinearElement
|
!appState.selectedLinearElement?.isEditing
|
||||||
) {
|
) {
|
||||||
return [t("hints.deepBoxSelect")];
|
return [t("hints.deepBoxSelect")];
|
||||||
}
|
}
|
||||||
@ -129,8 +129,8 @@ const getHints = ({
|
|||||||
|
|
||||||
if (selectedElements.length === 1) {
|
if (selectedElements.length === 1) {
|
||||||
if (isLinearElement(selectedElements[0])) {
|
if (isLinearElement(selectedElements[0])) {
|
||||||
if (appState.editingLinearElement) {
|
if (appState.selectedLinearElement?.isEditing) {
|
||||||
return appState.editingLinearElement.selectedPointsIndices
|
return appState.selectedLinearElement.selectedPointsIndices
|
||||||
? t("hints.lineEditor_pointSelected")
|
? t("hints.lineEditor_pointSelected")
|
||||||
: t("hints.lineEditor_nothingSelected");
|
: t("hints.lineEditor_nothingSelected");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export const InlineIcon = ({ icon }: { icon: React.ReactNode }) => {
|
|||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
lineHeight: 0,
|
lineHeight: 0,
|
||||||
verticalAlign: "middle",
|
verticalAlign: "middle",
|
||||||
|
flex: "0 0 auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{icon}
|
{icon}
|
||||||
|
|||||||
@ -192,7 +192,6 @@ const getRelevantAppStateProps = (
|
|||||||
viewModeEnabled: appState.viewModeEnabled,
|
viewModeEnabled: appState.viewModeEnabled,
|
||||||
openDialog: appState.openDialog,
|
openDialog: appState.openDialog,
|
||||||
editingGroupId: appState.editingGroupId,
|
editingGroupId: appState.editingGroupId,
|
||||||
editingLinearElement: appState.editingLinearElement,
|
|
||||||
selectedElementIds: appState.selectedElementIds,
|
selectedElementIds: appState.selectedElementIds,
|
||||||
frameToHighlight: appState.frameToHighlight,
|
frameToHighlight: appState.frameToHighlight,
|
||||||
offsetLeft: appState.offsetLeft,
|
offsetLeft: appState.offsetLeft,
|
||||||
|
|||||||
@ -34,6 +34,13 @@ const StaticCanvas = (props: StaticCanvasProps) => {
|
|||||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
const isComponentMounted = useRef(false);
|
const isComponentMounted = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
props.canvas.style.width = `${props.appState.width}px`;
|
||||||
|
props.canvas.style.height = `${props.appState.height}px`;
|
||||||
|
props.canvas.width = props.appState.width * props.scale;
|
||||||
|
props.canvas.height = props.appState.height * props.scale;
|
||||||
|
}, [props.appState.height, props.appState.width, props.canvas, props.scale]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const wrapper = wrapperRef.current;
|
const wrapper = wrapperRef.current;
|
||||||
if (!wrapper) {
|
if (!wrapper) {
|
||||||
@ -49,26 +56,6 @@ const StaticCanvas = (props: StaticCanvasProps) => {
|
|||||||
canvas.classList.add("excalidraw__canvas", "static");
|
canvas.classList.add("excalidraw__canvas", "static");
|
||||||
}
|
}
|
||||||
|
|
||||||
const widthString = `${props.appState.width}px`;
|
|
||||||
const heightString = `${props.appState.height}px`;
|
|
||||||
if (canvas.style.width !== widthString) {
|
|
||||||
canvas.style.width = widthString;
|
|
||||||
}
|
|
||||||
if (canvas.style.height !== heightString) {
|
|
||||||
canvas.style.height = heightString;
|
|
||||||
}
|
|
||||||
|
|
||||||
const scaledWidth = props.appState.width * props.scale;
|
|
||||||
const scaledHeight = props.appState.height * props.scale;
|
|
||||||
// setting width/height resets the canvas even if dimensions not changed,
|
|
||||||
// which would cause flicker when we skip frame (due to throttling)
|
|
||||||
if (canvas.width !== scaledWidth) {
|
|
||||||
canvas.width = scaledWidth;
|
|
||||||
}
|
|
||||||
if (canvas.height !== scaledHeight) {
|
|
||||||
canvas.height = scaledHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderStaticScene(
|
renderStaticScene(
|
||||||
{
|
{
|
||||||
canvas,
|
canvas,
|
||||||
|
|||||||
@ -19,6 +19,8 @@
|
|||||||
border-radius: var(--border-radius-lg);
|
border-radius: var(--border-radius-lg);
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: box-shadow 0.5s ease-in-out;
|
transition: box-shadow 0.5s ease-in-out;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
&.zen-mode {
|
&.zen-mode {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -100,6 +102,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: var(--border-radius-md);
|
border-radius: var(--border-radius-md);
|
||||||
|
flex: 1 0 auto;
|
||||||
|
|
||||||
@media screen and (min-width: 1921px) {
|
@media screen and (min-width: 1921px) {
|
||||||
height: 2.25rem;
|
height: 2.25rem;
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { useDevice } from "../App";
|
import { useDevice } from "../App";
|
||||||
|
|
||||||
|
import { Ellipsify } from "../Ellipsify";
|
||||||
|
|
||||||
import type { JSX } from "react";
|
import type { JSX } from "react";
|
||||||
|
|
||||||
const MenuItemContent = ({
|
const MenuItemContent = ({
|
||||||
@ -18,7 +20,7 @@ const MenuItemContent = ({
|
|||||||
<>
|
<>
|
||||||
{icon && <div className="dropdown-menu-item__icon">{icon}</div>}
|
{icon && <div className="dropdown-menu-item__icon">{icon}</div>}
|
||||||
<div style={textStyle} className="dropdown-menu-item__text">
|
<div style={textStyle} className="dropdown-menu-item__text">
|
||||||
{children}
|
<Ellipsify>{children}</Ellipsify>
|
||||||
</div>
|
</div>
|
||||||
{shortcut && !device.editor.isMobile && (
|
{shortcut && !device.editor.isMobile && (
|
||||||
<div className="dropdown-menu-item__shortcut">{shortcut}</div>
|
<div className="dropdown-menu-item__shortcut">{shortcut}</div>
|
||||||
|
|||||||
@ -2,13 +2,7 @@ import clsx from "clsx";
|
|||||||
|
|
||||||
import { actionShortcuts } from "../../actions";
|
import { actionShortcuts } from "../../actions";
|
||||||
import { useTunnels } from "../../context/tunnels";
|
import { useTunnels } from "../../context/tunnels";
|
||||||
import {
|
import { ExitZenModeAction, UndoRedoActions, ZoomActions } from "../Actions";
|
||||||
ExitZenModeAction,
|
|
||||||
FinalizeAction,
|
|
||||||
UndoRedoActions,
|
|
||||||
ZoomActions,
|
|
||||||
} from "../Actions";
|
|
||||||
import { useDevice } from "../App";
|
|
||||||
import { HelpButton } from "../HelpButton";
|
import { HelpButton } from "../HelpButton";
|
||||||
import { Section } from "../Section";
|
import { Section } from "../Section";
|
||||||
import Stack from "../Stack";
|
import Stack from "../Stack";
|
||||||
@ -29,10 +23,6 @@ const Footer = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { FooterCenterTunnel, WelcomeScreenHelpHintTunnel } = useTunnels();
|
const { FooterCenterTunnel, WelcomeScreenHelpHintTunnel } = useTunnels();
|
||||||
|
|
||||||
const device = useDevice();
|
|
||||||
const showFinalize =
|
|
||||||
!appState.viewModeEnabled && appState.multiElement && device.isTouchScreen;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer
|
<footer
|
||||||
role="contentinfo"
|
role="contentinfo"
|
||||||
@ -60,15 +50,6 @@ const Footer = ({
|
|||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showFinalize && (
|
|
||||||
<FinalizeAction
|
|
||||||
renderAction={actionManager.renderAction}
|
|
||||||
className={clsx("zen-mode-transition", {
|
|
||||||
"layer-ui__wrapper__footer-left--transition-left":
|
|
||||||
appState.zenModeEnabled,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Section>
|
</Section>
|
||||||
</Stack.Col>
|
</Stack.Col>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -281,6 +281,7 @@ export { Sidebar } from "./components/Sidebar/Sidebar";
|
|||||||
export { Button } from "./components/Button";
|
export { Button } from "./components/Button";
|
||||||
export { Footer };
|
export { Footer };
|
||||||
export { MainMenu };
|
export { MainMenu };
|
||||||
|
export { Ellipsify } from "./components/Ellipsify";
|
||||||
export { useDevice } from "./components/App";
|
export { useDevice } from "./components/App";
|
||||||
export { WelcomeScreen };
|
export { WelcomeScreen };
|
||||||
export { LiveCollaborationTrigger };
|
export { LiveCollaborationTrigger };
|
||||||
|
|||||||
@ -66,12 +66,22 @@
|
|||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"repository": "https://github.com/excalidraw/excalidraw",
|
||||||
|
"bugs": "https://github.com/excalidraw/excalidraw/issues",
|
||||||
|
"homepage": "https://github.com/excalidraw/excalidraw/tree/master/packages/excalidraw",
|
||||||
|
"scripts": {
|
||||||
|
"gen:types": "rimraf types && tsc",
|
||||||
|
"build:esm": "rimraf dist && node ../../scripts/buildPackage.js && yarn gen:types"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^17.0.2 || ^18.2.0 || ^19.0.0",
|
"react": "^17.0.2 || ^18.2.0 || ^19.0.0",
|
||||||
"react-dom": "^17.0.2 || ^18.2.0 || ^19.0.0"
|
"react-dom": "^17.0.2 || ^18.2.0 || ^19.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "6.0.2",
|
"@braintree/sanitize-url": "6.0.2",
|
||||||
|
"@excalidraw/common": "0.18.0",
|
||||||
|
"@excalidraw/element": "0.18.0",
|
||||||
|
"@excalidraw/math": "0.18.0",
|
||||||
"@excalidraw/laser-pointer": "1.3.1",
|
"@excalidraw/laser-pointer": "1.3.1",
|
||||||
"@excalidraw/mermaid-to-excalidraw": "1.1.2",
|
"@excalidraw/mermaid-to-excalidraw": "1.1.2",
|
||||||
"@excalidraw/random-username": "1.1.0",
|
"@excalidraw/random-username": "1.1.0",
|
||||||
@ -124,12 +134,5 @@
|
|||||||
"harfbuzzjs": "0.3.6",
|
"harfbuzzjs": "0.3.6",
|
||||||
"jest-diff": "29.7.0",
|
"jest-diff": "29.7.0",
|
||||||
"typescript": "4.9.4"
|
"typescript": "4.9.4"
|
||||||
},
|
|
||||||
"repository": "https://github.com/excalidraw/excalidraw",
|
|
||||||
"bugs": "https://github.com/excalidraw/excalidraw/issues",
|
|
||||||
"homepage": "https://github.com/excalidraw/excalidraw/tree/master/packages/excalidraw",
|
|
||||||
"scripts": {
|
|
||||||
"gen:types": "rimraf types && tsc",
|
|
||||||
"build:esm": "rimraf dist && node ../../scripts/buildPackage.js && yarn gen:types"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,7 +118,8 @@ const renderLinearElementPointHighlight = (
|
|||||||
) => {
|
) => {
|
||||||
const { elementId, hoverPointIndex } = appState.selectedLinearElement!;
|
const { elementId, hoverPointIndex } = appState.selectedLinearElement!;
|
||||||
if (
|
if (
|
||||||
appState.editingLinearElement?.selectedPointsIndices?.includes(
|
appState.selectedLinearElement?.isEditing &&
|
||||||
|
appState.selectedLinearElement?.selectedPointsIndices?.includes(
|
||||||
hoverPointIndex,
|
hoverPointIndex,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -180,7 +181,7 @@ const renderSingleLinearPoint = <Point extends GlobalPoint | LocalPoint>(
|
|||||||
point[0],
|
point[0],
|
||||||
point[1],
|
point[1],
|
||||||
(isOverlappingPoint
|
(isOverlappingPoint
|
||||||
? radius * (appState.editingLinearElement ? 1.5 : 2)
|
? radius * (appState.selectedLinearElement?.isEditing ? 1.5 : 2)
|
||||||
: radius) / appState.zoom.value,
|
: radius) / appState.zoom.value,
|
||||||
!isPhantomPoint,
|
!isPhantomPoint,
|
||||||
!isOverlappingPoint || isSelected,
|
!isOverlappingPoint || isSelected,
|
||||||
@ -448,7 +449,7 @@ const renderLinearPointHandles = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { POINT_HANDLE_SIZE } = LinearElementEditor;
|
const { POINT_HANDLE_SIZE } = LinearElementEditor;
|
||||||
const radius = appState.editingLinearElement
|
const radius = appState.selectedLinearElement?.isEditing
|
||||||
? POINT_HANDLE_SIZE
|
? POINT_HANDLE_SIZE
|
||||||
: POINT_HANDLE_SIZE / 2;
|
: POINT_HANDLE_SIZE / 2;
|
||||||
|
|
||||||
@ -470,7 +471,8 @@ const renderLinearPointHandles = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
let isSelected =
|
let isSelected =
|
||||||
!!appState.editingLinearElement?.selectedPointsIndices?.includes(idx);
|
!!appState.selectedLinearElement?.isEditing &&
|
||||||
|
!!appState.selectedLinearElement?.selectedPointsIndices?.includes(idx);
|
||||||
// when element is a polygon, highlight the last point as well if first
|
// when element is a polygon, highlight the last point as well if first
|
||||||
// point is selected since they overlap and the last point tends to be
|
// point is selected since they overlap and the last point tends to be
|
||||||
// rendered on top
|
// rendered on top
|
||||||
@ -479,7 +481,8 @@ const renderLinearPointHandles = (
|
|||||||
element.polygon &&
|
element.polygon &&
|
||||||
!isSelected &&
|
!isSelected &&
|
||||||
idx === element.points.length - 1 &&
|
idx === element.points.length - 1 &&
|
||||||
!!appState.editingLinearElement?.selectedPointsIndices?.includes(0)
|
!!appState.selectedLinearElement?.isEditing &&
|
||||||
|
!!appState.selectedLinearElement?.selectedPointsIndices?.includes(0)
|
||||||
) {
|
) {
|
||||||
isSelected = true;
|
isSelected = true;
|
||||||
}
|
}
|
||||||
@ -535,7 +538,7 @@ const renderLinearPointHandles = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
midPoints.forEach((segmentMidPoint) => {
|
midPoints.forEach((segmentMidPoint) => {
|
||||||
if (appState.editingLinearElement || points.length === 2) {
|
if (appState.selectedLinearElement?.isEditing || points.length === 2) {
|
||||||
renderSingleLinearPoint(
|
renderSingleLinearPoint(
|
||||||
context,
|
context,
|
||||||
appState,
|
appState,
|
||||||
@ -760,7 +763,10 @@ const _renderInteractiveScene = ({
|
|||||||
// Getting the element using LinearElementEditor during collab mismatches version - being one head of visible elements due to
|
// Getting the element using LinearElementEditor during collab mismatches version - being one head of visible elements due to
|
||||||
// ShapeCache returns empty hence making sure that we get the
|
// ShapeCache returns empty hence making sure that we get the
|
||||||
// correct element from visible elements
|
// correct element from visible elements
|
||||||
if (appState.editingLinearElement?.elementId === element.id) {
|
if (
|
||||||
|
appState.selectedLinearElement?.isEditing &&
|
||||||
|
appState.selectedLinearElement.elementId === element.id
|
||||||
|
) {
|
||||||
if (element) {
|
if (element) {
|
||||||
editingLinearElement = element as NonDeleted<ExcalidrawLinearElement>;
|
editingLinearElement = element as NonDeleted<ExcalidrawLinearElement>;
|
||||||
}
|
}
|
||||||
@ -853,7 +859,8 @@ const _renderInteractiveScene = ({
|
|||||||
// correct element from visible elements
|
// correct element from visible elements
|
||||||
if (
|
if (
|
||||||
selectedElements.length === 1 &&
|
selectedElements.length === 1 &&
|
||||||
appState.editingLinearElement?.elementId === selectedElements[0].id
|
appState.selectedLinearElement?.isEditing &&
|
||||||
|
appState.selectedLinearElement.elementId === selectedElements[0].id
|
||||||
) {
|
) {
|
||||||
renderLinearPointHandles(
|
renderLinearPointHandles(
|
||||||
context,
|
context,
|
||||||
@ -884,7 +891,7 @@ const _renderInteractiveScene = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Paint selected elements
|
// Paint selected elements
|
||||||
if (!appState.multiElement && !appState.editingLinearElement) {
|
if (!appState.multiElement && !appState.selectedLinearElement?.isEditing) {
|
||||||
const showBoundingBox = shouldShowBoundingBox(selectedElements, appState);
|
const showBoundingBox = shouldShowBoundingBox(selectedElements, appState);
|
||||||
|
|
||||||
const isSingleLinearElementSelected =
|
const isSingleLinearElementSelected =
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
import { throttleRAF } from "@excalidraw/common";
|
import { throttleRAF } from "@excalidraw/common";
|
||||||
|
|
||||||
import { renderElement } from "@excalidraw/element";
|
import {
|
||||||
|
getTargetFrame,
|
||||||
|
isInvisiblySmallElement,
|
||||||
|
renderElement,
|
||||||
|
shouldApplyFrameClip,
|
||||||
|
} from "@excalidraw/element";
|
||||||
|
|
||||||
import { bootstrapCanvas, getNormalizedCanvasDimensions } from "./helpers";
|
import { bootstrapCanvas, getNormalizedCanvasDimensions } from "./helpers";
|
||||||
|
|
||||||
|
import { frameClip } from "./staticScene";
|
||||||
|
|
||||||
import type { NewElementSceneRenderConfig } from "../scene/types";
|
import type { NewElementSceneRenderConfig } from "../scene/types";
|
||||||
|
|
||||||
const _renderNewElementScene = ({
|
const _renderNewElementScene = ({
|
||||||
@ -29,11 +36,37 @@ const _renderNewElementScene = ({
|
|||||||
normalizedHeight,
|
normalizedHeight,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Apply zoom
|
|
||||||
context.save();
|
context.save();
|
||||||
|
|
||||||
|
// Apply zoom
|
||||||
context.scale(appState.zoom.value, appState.zoom.value);
|
context.scale(appState.zoom.value, appState.zoom.value);
|
||||||
|
|
||||||
if (newElement && newElement.type !== "selection") {
|
if (newElement && newElement.type !== "selection") {
|
||||||
|
// e.g. when creating arrows and we're still below the arrow drag distance
|
||||||
|
// threshold
|
||||||
|
// (for now we skip render only with elements while we're creating to be
|
||||||
|
// safe)
|
||||||
|
if (isInvisiblySmallElement(newElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const frameId = newElement.frameId || appState.frameToHighlight?.id;
|
||||||
|
|
||||||
|
if (
|
||||||
|
frameId &&
|
||||||
|
appState.frameRendering.enabled &&
|
||||||
|
appState.frameRendering.clip
|
||||||
|
) {
|
||||||
|
const frame = getTargetFrame(newElement, elementsMap, appState);
|
||||||
|
|
||||||
|
if (
|
||||||
|
frame &&
|
||||||
|
shouldApplyFrameClip(newElement, frame, appState, elementsMap)
|
||||||
|
) {
|
||||||
|
frameClip(frame, context, renderConfig, appState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
renderElement(
|
renderElement(
|
||||||
newElement,
|
newElement,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
@ -46,6 +79,8 @@ const _renderNewElementScene = ({
|
|||||||
} else {
|
} else {
|
||||||
context.clearRect(0, 0, normalizedWidth, normalizedHeight);
|
context.clearRect(0, 0, normalizedWidth, normalizedHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.restore();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -113,7 +113,7 @@ const strokeGrid = (
|
|||||||
context.restore();
|
context.restore();
|
||||||
};
|
};
|
||||||
|
|
||||||
const frameClip = (
|
export const frameClip = (
|
||||||
frame: ExcalidrawFrameLikeElement,
|
frame: ExcalidrawFrameLikeElement,
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
renderConfig: StaticCanvasRenderConfig,
|
renderConfig: StaticCanvasRenderConfig,
|
||||||
|
|||||||
@ -908,7 +908,6 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1106,7 +1105,6 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1319,7 +1317,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1649,7 +1646,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1979,7 +1975,6 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2192,7 +2187,6 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2432,7 +2426,6 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2729,7 +2722,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3100,7 +3092,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3592,7 +3583,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3914,7 +3904,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4236,7 +4225,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5520,7 +5508,6 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -6736,7 +6723,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -7670,7 +7656,6 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8669,7 +8654,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9659,7 +9643,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
|
|||||||
@ -15,7 +15,11 @@ exports[`<Excalidraw/> > <MainMenu/> > should render main menu with host menu it
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Click me
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Click me
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
@ -27,7 +31,11 @@ exports[`<Excalidraw/> > <MainMenu/> > should render main menu with host menu it
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Excalidraw blog
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Excalidraw blog
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div
|
<div
|
||||||
@ -88,7 +96,11 @@ exports[`<Excalidraw/> > <MainMenu/> > should render main menu with host menu it
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Help
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Help
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__shortcut"
|
class="dropdown-menu-item__shortcut"
|
||||||
@ -138,7 +150,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Open
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Open
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__shortcut"
|
class="dropdown-menu-item__shortcut"
|
||||||
@ -175,7 +191,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Save to...
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Save to...
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@ -231,7 +251,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Export image...
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Export image...
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__shortcut"
|
class="dropdown-menu-item__shortcut"
|
||||||
@ -280,7 +304,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Find on canvas
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Find on canvas
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__shortcut"
|
class="dropdown-menu-item__shortcut"
|
||||||
@ -337,7 +365,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Help
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Help
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__shortcut"
|
class="dropdown-menu-item__shortcut"
|
||||||
@ -374,7 +406,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Reset the canvas
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Reset the canvas
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
@ -419,7 +455,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
GitHub
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
GitHub
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
@ -465,7 +505,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Follow us
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Follow us
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
@ -505,7 +549,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Discord chat
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Discord chat
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -542,7 +590,11 @@ exports[`<Excalidraw/> > Test UIOptions prop > Test canvasActions > should rende
|
|||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__text"
|
class="dropdown-menu-item__text"
|
||||||
>
|
>
|
||||||
Dark mode
|
<span
|
||||||
|
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
|
||||||
|
>
|
||||||
|
Dark mode
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dropdown-menu-item__shortcut"
|
class="dropdown-menu-item__shortcut"
|
||||||
|
|||||||
@ -34,7 +34,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -545,10 +544,12 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"id4": true,
|
"id4": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id4",
|
"selectedLinearElementId": "id4",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -646,7 +647,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1027,10 +1027,12 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"id4": true,
|
"id4": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id4",
|
"selectedLinearElementId": "id4",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1128,7 +1130,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1491,7 +1492,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1857,7 +1857,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2119,7 +2118,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2417,10 +2415,12 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
"id4": true,
|
"id4": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id4",
|
"selectedLinearElementId": "id4",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -2557,7 +2557,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2818,7 +2817,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3083,7 +3081,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3376,7 +3373,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3661,7 +3657,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3895,7 +3890,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4151,7 +4145,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4421,7 +4414,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4649,7 +4641,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4877,7 +4868,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5103,7 +5093,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5329,7 +5318,6 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5584,7 +5572,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5845,7 +5832,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -6207,7 +6193,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -6580,7 +6565,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -6891,7 +6875,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -7107,9 +7090,11 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"selectedLinearElementId": "id0",
|
"selectedLinearElementId": "id0",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -7118,16 +7103,16 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"removed": {},
|
"removed": {},
|
||||||
"updated": {},
|
"updated": {},
|
||||||
},
|
},
|
||||||
"id": "id12",
|
"id": "id4",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"appState": AppStateDelta {
|
"appState": AppStateDelta {
|
||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"editingLinearElementId": "id0",
|
"selectedLinearElementIsEditing": true,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"editingLinearElementId": null,
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -7136,16 +7121,16 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"removed": {},
|
"removed": {},
|
||||||
"updated": {},
|
"updated": {},
|
||||||
},
|
},
|
||||||
"id": "id13",
|
"id": "id6",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"appState": AppStateDelta {
|
"appState": AppStateDelta {
|
||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"editingLinearElementId": null,
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"editingLinearElementId": "id0",
|
"selectedLinearElementIsEditing": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -7154,7 +7139,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"removed": {},
|
"removed": {},
|
||||||
"updated": {},
|
"updated": {},
|
||||||
},
|
},
|
||||||
"id": "id14",
|
"id": "id10",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
@ -7193,7 +7178,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -7390,7 +7374,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -7741,7 +7724,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8092,7 +8074,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8497,7 +8478,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8783,7 +8763,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9046,7 +9025,6 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9310,7 +9288,6 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9541,7 +9518,6 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9837,7 +9813,6 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -10132,9 +10107,11 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
|||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"selectedLinearElementId": "id0",
|
"selectedLinearElementId": "id0",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -10182,7 +10159,6 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -10406,7 +10382,6 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -10853,7 +10828,6 @@ exports[`history > multiplayer undo/redo > should update history entries after r
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11112,7 +11086,6 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11346,7 +11319,6 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11582,7 +11554,6 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11984,7 +11955,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": "Couldn't load invalid file",
|
"errorMessage": "Couldn't load invalid file",
|
||||||
@ -12193,7 +12163,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -12402,7 +12371,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -12625,7 +12593,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -12848,7 +12815,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -13092,7 +13058,6 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -13328,7 +13293,6 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -13564,7 +13528,6 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -13810,7 +13773,6 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14140,7 +14102,6 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14309,7 +14270,6 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14592,7 +14552,6 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14854,7 +14813,6 @@ exports[`history > singleplayer undo/redo > should not modify anything on unrela
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -15006,7 +14964,6 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -15287,7 +15244,6 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -15448,7 +15404,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -15712,10 +15667,12 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -16004,12 +15961,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -16146,7 +16105,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -16627,12 +16585,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -16777,7 +16737,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -17258,12 +17217,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -17408,7 +17369,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -17954,12 +17914,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -18067,12 +18029,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -18120,7 +18084,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -18678,12 +18641,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -18791,12 +18756,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id13": true,
|
"id13": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id13",
|
"selectedLinearElementId": "id13",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -18864,7 +18831,6 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -19343,7 +19309,6 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -19853,7 +19818,6 @@ exports[`history > singleplayer undo/redo > should support element creation, del
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -20311,7 +20275,6 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -20590,9 +20553,11 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
|||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"selectedLinearElementId": "id0",
|
"selectedLinearElementId": "id0",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -20607,10 +20572,10 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
|||||||
"appState": AppStateDelta {
|
"appState": AppStateDelta {
|
||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"editingLinearElementId": "id0",
|
"selectedLinearElementIsEditing": true,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"editingLinearElementId": null,
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -20678,10 +20643,10 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
|||||||
"appState": AppStateDelta {
|
"appState": AppStateDelta {
|
||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"editingLinearElementId": null,
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"editingLinearElementId": "id0",
|
"selectedLinearElementIsEditing": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -34,7 +34,6 @@ exports[`given element A and group of elements B and given both are selected whe
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -459,7 +458,6 @@ exports[`given element A and group of elements B and given both are selected whe
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -874,7 +872,6 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": "id28",
|
"editingGroupId": "id28",
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1439,7 +1436,6 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -1645,7 +1641,6 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2028,7 +2023,6 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2272,7 +2266,6 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2451,7 +2444,6 @@ exports[`regression tests > can drag element that covers another element, while
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -2775,7 +2767,6 @@ exports[`regression tests > change the properties of a shape > [end of test] app
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3029,7 +3020,6 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3269,7 +3259,6 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3504,7 +3493,6 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -3761,7 +3749,6 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4074,7 +4061,6 @@ exports[`regression tests > deleting last but one element in editing group shoul
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4509,7 +4495,6 @@ exports[`regression tests > deselects group of selected elements on pointer down
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -4791,7 +4776,6 @@ exports[`regression tests > deselects group of selected elements on pointer up w
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5066,7 +5050,6 @@ exports[`regression tests > deselects selected element on pointer down when poin
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5273,7 +5256,6 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5472,7 +5454,6 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": "id11",
|
"editingGroupId": "id11",
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -5864,7 +5845,6 @@ exports[`regression tests > drags selected elements from point inside common bou
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -6160,7 +6140,6 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -6416,12 +6395,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
|||||||
"id9": true,
|
"id9": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id9",
|
"selectedLinearElementId": "id9",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id6": true,
|
"id6": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -6562,12 +6543,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
|||||||
"id15": true,
|
"id15": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id12": true,
|
"id12": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id12",
|
"selectedLinearElementId": "id12",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -6695,9 +6678,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
|||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"selectedLinearElementId": "id15",
|
"selectedLinearElementId": "id15",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -6716,12 +6701,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
|||||||
"id22": true,
|
"id22": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {
|
"selectedElementIds": {
|
||||||
"id15": true,
|
"id15": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id15",
|
"selectedLinearElementId": "id15",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -6847,9 +6834,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
|||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"selectedLinearElementId": "id22",
|
"selectedLinearElementId": "id22",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -6885,9 +6874,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
|||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedLinearElementId": "id22",
|
"selectedLinearElementId": "id22",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -6991,7 +6982,6 @@ exports[`regression tests > given a group of selected elements with an element t
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -7324,7 +7314,6 @@ exports[`regression tests > given a selected element A and a not selected elemen
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -7602,7 +7591,6 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -7836,7 +7824,6 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8075,7 +8062,6 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8190,7 +8176,7 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] undo st
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
@ -8203,7 +8189,7 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] undo st
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -8254,7 +8240,6 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8369,7 +8354,7 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] undo stac
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
@ -8382,7 +8367,7 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] undo stac
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "diamond",
|
"type": "diamond",
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -8433,7 +8418,6 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8548,7 +8532,7 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] undo stac
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
@ -8561,7 +8545,7 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] undo stac
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "ellipse",
|
"type": "ellipse",
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -8612,7 +8596,6 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8679,6 +8662,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
|||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
"isDragging": false,
|
"isDragging": false,
|
||||||
|
"isEditing": false,
|
||||||
"lastUncommittedPoint": null,
|
"lastUncommittedPoint": null,
|
||||||
"pointerDownState": {
|
"pointerDownState": {
|
||||||
"lastClickedIsEndPoint": false,
|
"lastClickedIsEndPoint": false,
|
||||||
@ -8739,10 +8723,12 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] undo stack
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id0",
|
"selectedLinearElementId": "id0",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -8761,7 +8747,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] undo stack
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
@ -8774,8 +8760,8 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] undo stack
|
|||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
@ -8789,7 +8775,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] undo stack
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -8840,7 +8826,6 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -8904,6 +8889,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
|||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
"isDragging": false,
|
"isDragging": false,
|
||||||
|
"isEditing": false,
|
||||||
"lastUncommittedPoint": null,
|
"lastUncommittedPoint": null,
|
||||||
"pointerDownState": {
|
"pointerDownState": {
|
||||||
"lastClickedIsEndPoint": false,
|
"lastClickedIsEndPoint": false,
|
||||||
@ -8964,10 +8950,12 @@ exports[`regression tests > key 6 selects line tool > [end of test] undo stack 1
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id0",
|
"selectedLinearElementId": "id0",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -8985,7 +8973,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] undo stack 1
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
@ -8998,8 +8986,8 @@ exports[`regression tests > key 6 selects line tool > [end of test] undo stack 1
|
|||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"polygon": false,
|
"polygon": false,
|
||||||
@ -9012,7 +9000,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] undo stack 1
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -9063,7 +9051,6 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9170,12 +9157,12 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": [
|
"lastCommittedPoint": [
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
"link": null,
|
"link": null,
|
||||||
"locked": false,
|
"locked": false,
|
||||||
@ -9186,12 +9173,12 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta
|
|||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"pressures": [
|
"pressures": [
|
||||||
@ -9207,7 +9194,7 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] undo sta
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "freedraw",
|
"type": "freedraw",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -9258,7 +9245,6 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9325,6 +9311,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
|||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
"isDragging": false,
|
"isDragging": false,
|
||||||
|
"isEditing": false,
|
||||||
"lastUncommittedPoint": null,
|
"lastUncommittedPoint": null,
|
||||||
"pointerDownState": {
|
"pointerDownState": {
|
||||||
"lastClickedIsEndPoint": false,
|
"lastClickedIsEndPoint": false,
|
||||||
@ -9385,10 +9372,12 @@ exports[`regression tests > key a selects arrow tool > [end of test] undo stack
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id0",
|
"selectedLinearElementId": "id0",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -9407,7 +9396,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] undo stack
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
@ -9420,8 +9409,8 @@ exports[`regression tests > key a selects arrow tool > [end of test] undo stack
|
|||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
@ -9435,7 +9424,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] undo stack
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -9486,7 +9475,6 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9601,7 +9589,7 @@ exports[`regression tests > key d selects diamond tool > [end of test] undo stac
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
@ -9614,7 +9602,7 @@ exports[`regression tests > key d selects diamond tool > [end of test] undo stac
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "diamond",
|
"type": "diamond",
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -9665,7 +9653,6 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -9729,6 +9716,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
|||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
"isDragging": false,
|
"isDragging": false,
|
||||||
|
"isEditing": false,
|
||||||
"lastUncommittedPoint": null,
|
"lastUncommittedPoint": null,
|
||||||
"pointerDownState": {
|
"pointerDownState": {
|
||||||
"lastClickedIsEndPoint": false,
|
"lastClickedIsEndPoint": false,
|
||||||
@ -9789,10 +9777,12 @@ exports[`regression tests > key l selects line tool > [end of test] undo stack 1
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
"selectedLinearElementId": "id0",
|
"selectedLinearElementId": "id0",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedElementIds": {},
|
"selectedElementIds": {},
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -9810,7 +9800,7 @@ exports[`regression tests > key l selects line tool > [end of test] undo stack 1
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
@ -9823,8 +9813,8 @@ exports[`regression tests > key l selects line tool > [end of test] undo stack 1
|
|||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"polygon": false,
|
"polygon": false,
|
||||||
@ -9837,7 +9827,7 @@ exports[`regression tests > key l selects line tool > [end of test] undo stack 1
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -9888,7 +9878,6 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -10003,7 +9992,7 @@ exports[`regression tests > key o selects ellipse tool > [end of test] undo stac
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
@ -10016,7 +10005,7 @@ exports[`regression tests > key o selects ellipse tool > [end of test] undo stac
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "ellipse",
|
"type": "ellipse",
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -10067,7 +10056,6 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -10174,12 +10162,12 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": [
|
"lastCommittedPoint": [
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
"link": null,
|
"link": null,
|
||||||
"locked": false,
|
"locked": false,
|
||||||
@ -10190,12 +10178,12 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta
|
|||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
10,
|
30,
|
||||||
10,
|
30,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"pressures": [
|
"pressures": [
|
||||||
@ -10211,7 +10199,7 @@ exports[`regression tests > key p selects freedraw tool > [end of test] undo sta
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "freedraw",
|
"type": "freedraw",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -10262,7 +10250,6 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -10377,7 +10364,7 @@ exports[`regression tests > key r selects rectangle tool > [end of test] undo st
|
|||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": 10,
|
"height": 30,
|
||||||
"index": "a0",
|
"index": "a0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
@ -10390,7 +10377,7 @@ exports[`regression tests > key r selects rectangle tool > [end of test] undo st
|
|||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"width": 10,
|
"width": 30,
|
||||||
"x": 10,
|
"x": 10,
|
||||||
"y": 10,
|
"y": 10,
|
||||||
},
|
},
|
||||||
@ -10441,7 +10428,6 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -10971,7 +10957,6 @@ exports[`regression tests > noop interaction after undo shouldn't create history
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11250,7 +11235,6 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11372,7 +11356,6 @@ exports[`regression tests > shift click on selected element should deselect it o
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11571,7 +11554,6 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -11889,7 +11871,6 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -12317,7 +12298,6 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -12956,7 +12936,6 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -13081,7 +13060,6 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": "id11",
|
"editingGroupId": "id11",
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -13711,7 +13689,6 @@ exports[`regression tests > switches from group of selected elements to another
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14049,7 +14026,6 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14312,7 +14288,6 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14434,7 +14409,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14527,9 +14501,11 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
|||||||
"delta": Delta {
|
"delta": Delta {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"selectedLinearElementId": null,
|
"selectedLinearElementId": null,
|
||||||
|
"selectedLinearElementIsEditing": null,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"selectedLinearElementId": "id6",
|
"selectedLinearElementId": "id6",
|
||||||
|
"selectedLinearElementIsEditing": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -14822,7 +14798,6 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
@ -14944,7 +14919,6 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
|
|||||||
@ -1073,7 +1073,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(6);
|
expect(API.getUndoStack().length).toBe(6);
|
||||||
expect(API.getRedoStack().length).toBe(0);
|
expect(API.getRedoStack().length).toBe(0);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
expect(h.state.selectedLinearElement).not.toBeNull();
|
expect(h.state.selectedLinearElement).not.toBeNull();
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1090,7 +1090,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(5);
|
expect(API.getUndoStack().length).toBe(5);
|
||||||
expect(API.getRedoStack().length).toBe(1);
|
expect(API.getRedoStack().length).toBe(1);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1114,7 +1114,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(4);
|
expect(API.getUndoStack().length).toBe(4);
|
||||||
expect(API.getRedoStack().length).toBe(2);
|
expect(API.getRedoStack().length).toBe(2);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1131,7 +1131,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(3);
|
expect(API.getUndoStack().length).toBe(3);
|
||||||
expect(API.getRedoStack().length).toBe(3);
|
expect(API.getRedoStack().length).toBe(3);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull(); // undo `open editor`
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false); // undo `open editor`
|
||||||
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1148,7 +1148,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(2);
|
expect(API.getUndoStack().length).toBe(2);
|
||||||
expect(API.getRedoStack().length).toBe(4);
|
expect(API.getRedoStack().length).toBe(4);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
|
expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1165,7 +1165,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(1);
|
expect(API.getUndoStack().length).toBe(1);
|
||||||
expect(API.getRedoStack().length).toBe(5);
|
expect(API.getRedoStack().length).toBe(5);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
expect(h.state.selectedLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement).toBeNull();
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1181,7 +1181,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(0);
|
expect(API.getUndoStack().length).toBe(0);
|
||||||
expect(API.getRedoStack().length).toBe(6);
|
expect(API.getRedoStack().length).toBe(6);
|
||||||
expect(API.getSelectedElements().length).toBe(0);
|
expect(API.getSelectedElements().length).toBe(0);
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
expect(h.state.selectedLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement).toBeNull();
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1197,7 +1197,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(1);
|
expect(API.getUndoStack().length).toBe(1);
|
||||||
expect(API.getRedoStack().length).toBe(5);
|
expect(API.getRedoStack().length).toBe(5);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
expect(h.state.selectedLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement).toBeNull();
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1213,7 +1213,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(2);
|
expect(API.getUndoStack().length).toBe(2);
|
||||||
expect(API.getRedoStack().length).toBe(4);
|
expect(API.getRedoStack().length).toBe(4);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
|
expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1230,7 +1230,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(3);
|
expect(API.getUndoStack().length).toBe(3);
|
||||||
expect(API.getRedoStack().length).toBe(3);
|
expect(API.getRedoStack().length).toBe(3);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull(); // undo `open editor`
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false); // undo `open editor`
|
||||||
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1247,7 +1247,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(4);
|
expect(API.getUndoStack().length).toBe(4);
|
||||||
expect(API.getRedoStack().length).toBe(2);
|
expect(API.getRedoStack().length).toBe(2);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1264,7 +1264,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(5);
|
expect(API.getUndoStack().length).toBe(5);
|
||||||
expect(API.getRedoStack().length).toBe(1);
|
expect(API.getRedoStack().length).toBe(1);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -1281,7 +1281,7 @@ describe("history", () => {
|
|||||||
expect(API.getUndoStack().length).toBe(6);
|
expect(API.getUndoStack().length).toBe(6);
|
||||||
expect(API.getRedoStack().length).toBe(0);
|
expect(API.getRedoStack().length).toBe(0);
|
||||||
expect(assertSelectedElements(h.elements[0]));
|
expect(assertSelectedElements(h.elements[0]));
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
expect(h.state.selectedLinearElement).not.toBeNull();
|
expect(h.state.selectedLinearElement).not.toBeNull();
|
||||||
expect(h.elements).toEqual([
|
expect(h.elements).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -3029,8 +3029,8 @@ describe("history", () => {
|
|||||||
|
|
||||||
expect(API.getUndoStack().length).toBe(4);
|
expect(API.getUndoStack().length).toBe(4);
|
||||||
expect(API.getRedoStack().length).toBe(0);
|
expect(API.getRedoStack().length).toBe(0);
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
|
||||||
expect(h.state.selectedLinearElement).not.toBeNull();
|
expect(h.state.selectedLinearElement).not.toBeNull();
|
||||||
|
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
|
||||||
|
|
||||||
// Simulate remote update
|
// Simulate remote update
|
||||||
API.updateScene({
|
API.updateScene({
|
||||||
@ -3043,16 +3043,16 @@ describe("history", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Keyboard.undo();
|
Keyboard.undo();
|
||||||
expect(API.getUndoStack().length).toBe(1);
|
expect(API.getUndoStack().length).toBe(3);
|
||||||
expect(API.getRedoStack().length).toBe(3);
|
expect(API.getRedoStack().length).toBe(1);
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement).not.toBeNull();
|
||||||
expect(h.state.selectedLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
|
||||||
|
|
||||||
Keyboard.redo();
|
Keyboard.redo();
|
||||||
expect(API.getUndoStack().length).toBe(4);
|
expect(API.getUndoStack().length).toBe(4);
|
||||||
expect(API.getRedoStack().length).toBe(0);
|
expect(API.getRedoStack().length).toBe(0);
|
||||||
expect(h.state.editingLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement).not.toBeNull();
|
||||||
expect(h.state.selectedLinearElement).toBeNull();
|
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should iterate through the history when z-index changes do not produce visible change and we synced changed indices", async () => {
|
it("should iterate through the history when z-index changes do not produce visible change and we synced changed indices", async () => {
|
||||||
|
|||||||
@ -150,7 +150,7 @@ describe("regression tests", () => {
|
|||||||
expect(h.state.activeTool.type).toBe(shape);
|
expect(h.state.activeTool.type).toBe(shape);
|
||||||
|
|
||||||
mouse.down(10, 10);
|
mouse.down(10, 10);
|
||||||
mouse.up(10, 10);
|
mouse.up(30, 30);
|
||||||
|
|
||||||
if (shouldSelect) {
|
if (shouldSelect) {
|
||||||
expect(API.getSelectedElement().type).toBe(shape);
|
expect(API.getSelectedElement().type).toBe(shape);
|
||||||
|
|||||||
@ -214,7 +214,6 @@ export type InteractiveCanvasAppState = Readonly<
|
|||||||
_CommonCanvasAppState & {
|
_CommonCanvasAppState & {
|
||||||
// renderInteractiveScene
|
// renderInteractiveScene
|
||||||
activeEmbeddable: AppState["activeEmbeddable"];
|
activeEmbeddable: AppState["activeEmbeddable"];
|
||||||
editingLinearElement: AppState["editingLinearElement"];
|
|
||||||
selectionElement: AppState["selectionElement"];
|
selectionElement: AppState["selectionElement"];
|
||||||
selectedGroupIds: AppState["selectedGroupIds"];
|
selectedGroupIds: AppState["selectedGroupIds"];
|
||||||
selectedLinearElement: AppState["selectedLinearElement"];
|
selectedLinearElement: AppState["selectedLinearElement"];
|
||||||
@ -250,10 +249,8 @@ export type ObservedElementsAppState = {
|
|||||||
editingGroupId: AppState["editingGroupId"];
|
editingGroupId: AppState["editingGroupId"];
|
||||||
selectedElementIds: AppState["selectedElementIds"];
|
selectedElementIds: AppState["selectedElementIds"];
|
||||||
selectedGroupIds: AppState["selectedGroupIds"];
|
selectedGroupIds: AppState["selectedGroupIds"];
|
||||||
// Avoiding storing whole instance, as it could lead into state incosistencies, empty undos/redos and etc.
|
|
||||||
editingLinearElementId: LinearElementEditor["elementId"] | null;
|
|
||||||
// Right now it's coupled to `editingLinearElement`, ideally it should not be really needed as we already have selectedElementIds & editingLinearElementId
|
|
||||||
selectedLinearElementId: LinearElementEditor["elementId"] | null;
|
selectedLinearElementId: LinearElementEditor["elementId"] | null;
|
||||||
|
selectedLinearElementIsEditing: boolean | null;
|
||||||
croppingElementId: AppState["croppingElementId"];
|
croppingElementId: AppState["croppingElementId"];
|
||||||
lockedMultiSelections: AppState["lockedMultiSelections"];
|
lockedMultiSelections: AppState["lockedMultiSelections"];
|
||||||
activeLockedId: AppState["activeLockedId"];
|
activeLockedId: AppState["activeLockedId"];
|
||||||
@ -308,7 +305,6 @@ export interface AppState {
|
|||||||
* set when a new text is created or when an existing text is being edited
|
* set when a new text is created or when an existing text is being edited
|
||||||
*/
|
*/
|
||||||
editingTextElement: NonDeletedExcalidrawElement | null;
|
editingTextElement: NonDeletedExcalidrawElement | null;
|
||||||
editingLinearElement: LinearElementEditor | null;
|
|
||||||
activeTool: {
|
activeTool: {
|
||||||
/**
|
/**
|
||||||
* indicates a previous tool we should revert back to if we deselect the
|
* indicates a previous tool we should revert back to if we deselect the
|
||||||
|
|||||||
@ -704,7 +704,7 @@ describe("textWysiwyg", () => {
|
|||||||
rectangle.x + rectangle.width / 2,
|
rectangle.x + rectangle.width / 2,
|
||||||
rectangle.y + rectangle.height / 2,
|
rectangle.y + rectangle.height / 2,
|
||||||
);
|
);
|
||||||
expect(h.elements.length).toBe(3);
|
expect(h.elements.length).toBe(2);
|
||||||
|
|
||||||
text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||||
expect(text.type).toBe("text");
|
expect(text.type).toBe("text");
|
||||||
@ -1198,7 +1198,7 @@ describe("textWysiwyg", () => {
|
|||||||
updateTextEditor(editor, " ");
|
updateTextEditor(editor, " ");
|
||||||
Keyboard.exitTextEditor(editor);
|
Keyboard.exitTextEditor(editor);
|
||||||
expect(rectangle.boundElements).toStrictEqual([]);
|
expect(rectangle.boundElements).toStrictEqual([]);
|
||||||
expect(h.elements[1].isDeleted).toBe(true);
|
expect(h.elements[1]).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should restore original container height and clear cache once text is unbind", async () => {
|
it("should restore original container height and clear cache once text is unbind", async () => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@excalidraw/math",
|
"name": "@excalidraw/math",
|
||||||
"version": "0.1.0",
|
"version": "0.18.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./dist/types/math/src/index.d.ts",
|
"types": "./dist/types/math/src/index.d.ts",
|
||||||
"main": "./dist/prod/index.js",
|
"main": "./dist/prod/index.js",
|
||||||
@ -13,7 +13,10 @@
|
|||||||
"default": "./dist/prod/index.js"
|
"default": "./dist/prod/index.js"
|
||||||
},
|
},
|
||||||
"./*": {
|
"./*": {
|
||||||
"types": "./dist/types/math/src/*.d.ts"
|
"types": "./dist/types/math/src/*.d.ts",
|
||||||
|
"development": "./dist/dev/index.js",
|
||||||
|
"production": "./dist/prod/index.js",
|
||||||
|
"default": "./dist/prod/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@ -56,5 +59,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"gen:types": "rimraf types && tsc",
|
"gen:types": "rimraf types && tsc",
|
||||||
"build:esm": "rimraf dist && node ../../scripts/buildBase.js && yarn gen:types"
|
"build:esm": "rimraf dist && node ../../scripts/buildBase.js && yarn gen:types"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@excalidraw/common": "0.18.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,6 @@ exports[`exportToSvg > with default arguments 1`] = `
|
|||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
|
||||||
"editingTextElement": null,
|
"editingTextElement": null,
|
||||||
"elementsToHighlight": null,
|
"elementsToHighlight": null,
|
||||||
"errorMessage": null,
|
"errorMessage": null,
|
||||||
|
|||||||
@ -1,71 +0,0 @@
|
|||||||
const { exec, execSync } = require("child_process");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const core = require("@actions/core");
|
|
||||||
|
|
||||||
const excalidrawDir = `${__dirname}/../packages/excalidraw`;
|
|
||||||
const excalidrawPackage = `${excalidrawDir}/package.json`;
|
|
||||||
const pkg = require(excalidrawPackage);
|
|
||||||
const isPreview = process.argv.slice(2)[0] === "preview";
|
|
||||||
|
|
||||||
const getShortCommitHash = () => {
|
|
||||||
return execSync("git rev-parse --short HEAD").toString().trim();
|
|
||||||
};
|
|
||||||
|
|
||||||
const publish = () => {
|
|
||||||
const tag = isPreview ? "preview" : "next";
|
|
||||||
|
|
||||||
try {
|
|
||||||
execSync(`yarn --frozen-lockfile`);
|
|
||||||
execSync(`yarn run build:esm`, { cwd: excalidrawDir });
|
|
||||||
execSync(`yarn --cwd ${excalidrawDir} publish --tag ${tag}`);
|
|
||||||
console.info(`Published ${pkg.name}@${tag}🎉`);
|
|
||||||
core.setOutput(
|
|
||||||
"result",
|
|
||||||
`**Preview version has been shipped** :rocket:
|
|
||||||
You can use [@excalidraw/excalidraw@${pkg.version}](https://www.npmjs.com/package/@excalidraw/excalidraw/v/${pkg.version}) for testing!`,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
core.setOutput("result", "package couldn't be published :warning:!");
|
|
||||||
console.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// get files changed between prev and head commit
|
|
||||||
exec(`git diff --name-only HEAD^ HEAD`, async (error, stdout, stderr) => {
|
|
||||||
if (error || stderr) {
|
|
||||||
console.error(error);
|
|
||||||
core.setOutput("result", ":warning: Package couldn't be published!");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
const changedFiles = stdout.trim().split("\n");
|
|
||||||
|
|
||||||
const excalidrawPackageFiles = changedFiles.filter((file) => {
|
|
||||||
return (
|
|
||||||
file.indexOf("packages/excalidraw") >= 0 ||
|
|
||||||
file.indexOf("buildPackage.js") > 0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (!excalidrawPackageFiles.length) {
|
|
||||||
console.info("Skipping release as no valid diff found");
|
|
||||||
core.setOutput("result", "Skipping release as no valid diff found");
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update package.json
|
|
||||||
let version = `${pkg.version}-${getShortCommitHash()}`;
|
|
||||||
|
|
||||||
// update readme
|
|
||||||
|
|
||||||
if (isPreview) {
|
|
||||||
// use pullNumber-commithash as the version for preview
|
|
||||||
const pullRequestNumber = process.argv.slice(3)[0];
|
|
||||||
version = `${pkg.version}-${pullRequestNumber}-${getShortCommitHash()}`;
|
|
||||||
}
|
|
||||||
pkg.version = version;
|
|
||||||
|
|
||||||
fs.writeFileSync(excalidrawPackage, JSON.stringify(pkg, null, 2), "utf8");
|
|
||||||
|
|
||||||
console.info("Publish in progress...");
|
|
||||||
publish();
|
|
||||||
});
|
|
||||||
@ -11,12 +11,9 @@ const getConfig = (outdir) => ({
|
|||||||
entryNames: "[name]",
|
entryNames: "[name]",
|
||||||
assetNames: "[dir]/[name]",
|
assetNames: "[dir]/[name]",
|
||||||
alias: {
|
alias: {
|
||||||
"@excalidraw/common": path.resolve(__dirname, "../packages/common/src"),
|
|
||||||
"@excalidraw/element": path.resolve(__dirname, "../packages/element/src"),
|
|
||||||
"@excalidraw/excalidraw": path.resolve(__dirname, "../packages/excalidraw"),
|
|
||||||
"@excalidraw/math": path.resolve(__dirname, "../packages/math/src"),
|
|
||||||
"@excalidraw/utils": path.resolve(__dirname, "../packages/utils/src"),
|
"@excalidraw/utils": path.resolve(__dirname, "../packages/utils/src"),
|
||||||
},
|
},
|
||||||
|
external: ["@excalidraw/common", "@excalidraw/element", "@excalidraw/math"],
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildDev(config) {
|
function buildDev(config) {
|
||||||
|
|||||||
@ -28,12 +28,9 @@ const getConfig = (outdir) => ({
|
|||||||
assetNames: "[dir]/[name]",
|
assetNames: "[dir]/[name]",
|
||||||
chunkNames: "[dir]/[name]-[hash]",
|
chunkNames: "[dir]/[name]-[hash]",
|
||||||
alias: {
|
alias: {
|
||||||
"@excalidraw/common": path.resolve(__dirname, "../packages/common/src"),
|
|
||||||
"@excalidraw/element": path.resolve(__dirname, "../packages/element/src"),
|
|
||||||
"@excalidraw/excalidraw": path.resolve(__dirname, "../packages/excalidraw"),
|
|
||||||
"@excalidraw/math": path.resolve(__dirname, "../packages/math/src"),
|
|
||||||
"@excalidraw/utils": path.resolve(__dirname, "../packages/utils/src"),
|
"@excalidraw/utils": path.resolve(__dirname, "../packages/utils/src"),
|
||||||
},
|
},
|
||||||
|
external: ["@excalidraw/common", "@excalidraw/element", "@excalidraw/math"],
|
||||||
loader: {
|
loader: {
|
||||||
".woff2": "file",
|
".woff2": "file",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
const fs = require("fs");
|
|
||||||
const util = require("util");
|
|
||||||
|
|
||||||
const exec = util.promisify(require("child_process").exec);
|
|
||||||
const updateChangelog = require("./updateChangelog");
|
|
||||||
|
|
||||||
const excalidrawDir = `${__dirname}/../packages/excalidraw/`;
|
|
||||||
const excalidrawPackage = `${excalidrawDir}/package.json`;
|
|
||||||
|
|
||||||
const updatePackageVersion = (nextVersion) => {
|
|
||||||
const pkg = require(excalidrawPackage);
|
|
||||||
pkg.version = nextVersion;
|
|
||||||
const content = `${JSON.stringify(pkg, null, 2)}\n`;
|
|
||||||
fs.writeFileSync(excalidrawPackage, content, "utf-8");
|
|
||||||
};
|
|
||||||
|
|
||||||
const prerelease = async (nextVersion) => {
|
|
||||||
try {
|
|
||||||
await updateChangelog(nextVersion);
|
|
||||||
updatePackageVersion(nextVersion);
|
|
||||||
await exec(`git add -u`);
|
|
||||||
await exec(
|
|
||||||
`git commit -m "docs: release @excalidraw/excalidraw@${nextVersion} 🎉"`,
|
|
||||||
);
|
|
||||||
|
|
||||||
console.info("Done!");
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const nextVersion = process.argv.slice(2)[0];
|
|
||||||
if (!nextVersion) {
|
|
||||||
console.error("Pass the next version to release!");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
prerelease(nextVersion);
|
|
||||||
@ -1,28 +1,239 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
const { execSync } = require("child_process");
|
const { execSync } = require("child_process");
|
||||||
|
|
||||||
const excalidrawDir = `${__dirname}/../packages/excalidraw`;
|
const updateChangelog = require("./updateChangelog");
|
||||||
const excalidrawPackage = `${excalidrawDir}/package.json`;
|
|
||||||
const pkg = require(excalidrawPackage);
|
|
||||||
|
|
||||||
const publish = () => {
|
// skipping utils for now, as it has independent release process
|
||||||
try {
|
const PACKAGES = ["common", "math", "element", "excalidraw"];
|
||||||
console.info("Installing the dependencies in root folder...");
|
const PACKAGES_DIR = path.resolve(__dirname, "../packages");
|
||||||
execSync(`yarn --frozen-lockfile`);
|
|
||||||
console.info("Installing the dependencies in excalidraw directory...");
|
/**
|
||||||
execSync(`yarn --frozen-lockfile`, { cwd: excalidrawDir });
|
* Returns the arguments for the release script.
|
||||||
console.info("Building ESM Package...");
|
*
|
||||||
execSync(`yarn run build:esm`, { cwd: excalidrawDir });
|
* Usage examples:
|
||||||
console.info("Publishing the package...");
|
* - yarn release --help -> prints this help message
|
||||||
execSync(`yarn --cwd ${excalidrawDir} publish`);
|
* - yarn release -> publishes `@excalidraw` packages with "test" tag and "-[hash]" version suffix
|
||||||
} catch (error) {
|
* - yarn release --tag=test -> same as above
|
||||||
console.error(error);
|
* - yarn release --tag=next -> publishes `@excalidraw` packages with "next" tag and version "-[hash]" suffix
|
||||||
|
* - yarn release --tag=next --non-interactive -> skips interactive prompts (runs on CI/CD), otherwise same as above
|
||||||
|
* - yarn release --tag=latest --version=0.19.0 -> publishes `@excalidraw` packages with "latest" tag and version "0.19.0" & prepares changelog for the release
|
||||||
|
*
|
||||||
|
* @returns [tag, version, nonInteractive]
|
||||||
|
*/
|
||||||
|
const getArguments = () => {
|
||||||
|
let tag = "test";
|
||||||
|
let version = "";
|
||||||
|
let nonInteractive = false;
|
||||||
|
|
||||||
|
for (const argument of process.argv.slice(2)) {
|
||||||
|
if (/--help/.test(argument)) {
|
||||||
|
console.info(`Available arguments:
|
||||||
|
--tag=<tag> -> (optional) "test" (default), "next" for auto release, "latest" for stable release
|
||||||
|
--version=<version> -> (optional) for "next" and "test", (required) for "latest" i.e. "0.19.0"
|
||||||
|
--non-interactive -> (optional) disables interactive prompts`);
|
||||||
|
|
||||||
|
console.info(`\nUsage examples:
|
||||||
|
- yarn release -> publishes \`@excalidraw\` packages with "test" tag and "-[hash]" version suffix
|
||||||
|
- yarn release --tag=test -> same as above
|
||||||
|
- yarn release --tag=next -> publishes \`@excalidraw\` packages with "next" tag and version "-[hash]" suffix
|
||||||
|
- yarn release --tag=next --non-interactive -> skips interactive prompts (runs on CI/CD), otherwise same as above
|
||||||
|
- yarn release --tag=latest --version=0.19.0 -> publishes \`@excalidraw\` packages with "latest" tag and version "0.19.0" & prepares changelog for the release`);
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/--tag=/.test(argument)) {
|
||||||
|
tag = argument.split("=")[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/--version=/.test(argument)) {
|
||||||
|
version = argument.split("=")[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/--non-interactive/.test(argument)) {
|
||||||
|
nonInteractive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag !== "latest" && tag !== "next" && tag !== "test") {
|
||||||
|
console.error(`Unsupported tag "${tag}", use "latest", "next" or "test".`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag === "latest" && !version) {
|
||||||
|
console.error("Pass the version to make the latest stable release!");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!version) {
|
||||||
|
// set the next version based on the excalidraw package version + commit hash
|
||||||
|
const excalidrawPackageVersion = require(getPackageJsonPath(
|
||||||
|
"excalidraw",
|
||||||
|
)).version;
|
||||||
|
|
||||||
|
const hash = getShortCommitHash();
|
||||||
|
|
||||||
|
if (!excalidrawPackageVersion.includes(hash)) {
|
||||||
|
version = `${excalidrawPackageVersion}-${hash}`;
|
||||||
|
} else {
|
||||||
|
// ensuring idempotency
|
||||||
|
version = excalidrawPackageVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info(`Running with tag "${tag}" and version "${version}"...`);
|
||||||
|
|
||||||
|
return [tag, version, nonInteractive];
|
||||||
|
};
|
||||||
|
|
||||||
|
const validatePackageName = (packageName) => {
|
||||||
|
if (!PACKAGES.includes(packageName)) {
|
||||||
|
console.error(`Package "${packageName}" not found!`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const release = () => {
|
const getPackageJsonPath = (packageName) => {
|
||||||
publish();
|
validatePackageName(packageName);
|
||||||
console.info(`Published ${pkg.version}!`);
|
return path.resolve(PACKAGES_DIR, packageName, "package.json");
|
||||||
};
|
};
|
||||||
|
|
||||||
release();
|
const updatePackageJsons = (nextVersion) => {
|
||||||
|
const packageJsons = new Map();
|
||||||
|
|
||||||
|
for (const packageName of PACKAGES) {
|
||||||
|
const pkg = require(getPackageJsonPath(packageName));
|
||||||
|
|
||||||
|
pkg.version = nextVersion;
|
||||||
|
|
||||||
|
if (pkg.dependencies) {
|
||||||
|
for (const dependencyName of PACKAGES) {
|
||||||
|
if (!pkg.dependencies[`@excalidraw/${dependencyName}`]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg.dependencies[`@excalidraw/${dependencyName}`] = nextVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packageJsons.set(packageName, `${JSON.stringify(pkg, null, 2)}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// modify once, to avoid inconsistent state
|
||||||
|
for (const packageName of PACKAGES) {
|
||||||
|
const content = packageJsons.get(packageName);
|
||||||
|
fs.writeFileSync(getPackageJsonPath(packageName), content, "utf-8");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getShortCommitHash = () => {
|
||||||
|
return execSync("git rev-parse --short HEAD").toString().trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
const askToCommit = (tag, nextVersion) => {
|
||||||
|
if (tag !== "latest") {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const rl = require("readline").createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
});
|
||||||
|
|
||||||
|
rl.question(
|
||||||
|
"Do you want to commit these changes to git? (Y/n): ",
|
||||||
|
(answer) => {
|
||||||
|
rl.close();
|
||||||
|
|
||||||
|
if (answer.toLowerCase() === "y") {
|
||||||
|
execSync(`git add -u`);
|
||||||
|
execSync(
|
||||||
|
`git commit -m "chore: release @excalidraw/excalidraw@${nextVersion} 🎉"`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
"Skipping commit. Don't forget to commit manually later!",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildPackages = () => {
|
||||||
|
console.info("Running yarn install...");
|
||||||
|
execSync(`yarn --frozen-lockfile`, { stdio: "inherit" });
|
||||||
|
|
||||||
|
console.info("Removing existing build artifacts...");
|
||||||
|
execSync(`yarn rm:build`, { stdio: "inherit" });
|
||||||
|
|
||||||
|
for (const packageName of PACKAGES) {
|
||||||
|
console.info(`Building "@excalidraw/${packageName}"...`);
|
||||||
|
execSync(`yarn run build:esm`, {
|
||||||
|
cwd: path.resolve(PACKAGES_DIR, packageName),
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const askToPublish = (tag, version) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const rl = require("readline").createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
});
|
||||||
|
|
||||||
|
rl.question(
|
||||||
|
"Do you want to publish these changes to npm? (Y/n): ",
|
||||||
|
(answer) => {
|
||||||
|
rl.close();
|
||||||
|
|
||||||
|
if (answer.toLowerCase() === "y") {
|
||||||
|
publishPackages(tag, version);
|
||||||
|
} else {
|
||||||
|
console.info("Skipping publish.");
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const publishPackages = (tag, version) => {
|
||||||
|
for (const packageName of PACKAGES) {
|
||||||
|
execSync(`yarn publish --tag ${tag}`, {
|
||||||
|
cwd: path.resolve(PACKAGES_DIR, packageName),
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.info(
|
||||||
|
`Published "@excalidraw/${packageName}@${tag}" with version "${version}"! 🎉`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** main */
|
||||||
|
(async () => {
|
||||||
|
const [tag, version, nonInteractive] = getArguments();
|
||||||
|
|
||||||
|
buildPackages();
|
||||||
|
|
||||||
|
if (tag === "latest") {
|
||||||
|
await updateChangelog(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePackageJsons(version);
|
||||||
|
|
||||||
|
if (nonInteractive) {
|
||||||
|
publishPackages(tag, version);
|
||||||
|
} else {
|
||||||
|
await askToCommit(tag, version);
|
||||||
|
await askToPublish(tag, version);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|||||||
@ -20,14 +20,16 @@ const headerForType = {
|
|||||||
perf: "Performance",
|
perf: "Performance",
|
||||||
build: "Build",
|
build: "Build",
|
||||||
};
|
};
|
||||||
|
|
||||||
const badCommits = [];
|
const badCommits = [];
|
||||||
const getCommitHashForLastVersion = async () => {
|
const getCommitHashForLastVersion = async () => {
|
||||||
try {
|
try {
|
||||||
const commitMessage = `"release @excalidraw/excalidraw@${lastVersion}"`;
|
const commitMessage = `"release @excalidraw/excalidraw"`;
|
||||||
const { stdout } = await exec(
|
const { stdout } = await exec(
|
||||||
`git log --format=format:"%H" --grep=${commitMessage}`,
|
`git log --format=format:"%H" --grep=${commitMessage}`,
|
||||||
);
|
);
|
||||||
return stdout;
|
// take commit hash from latest release
|
||||||
|
return stdout.split(/\r?\n/)[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user