mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-27 11:19:53 +02:00
Compare commits
14 Commits
aakansha-c
...
updatescen
Author | SHA1 | Date | |
---|---|---|---|
![]() |
eb206cc932 | ||
![]() |
16c287c848 | ||
![]() |
78024873e5 | ||
![]() |
4e41bd9dbb | ||
![]() |
edc23b854f | ||
![]() |
4843c49556 | ||
![]() |
d565413082 | ||
![]() |
dcda7184d0 | ||
![]() |
8d413670c8 | ||
![]() |
f774452124 | ||
![]() |
db4ed1ecb1 | ||
![]() |
489f45b910 | ||
![]() |
a17be085b0 | ||
![]() |
4e07a608d3 |
@@ -23,9 +23,7 @@ export const actionChangeProjectName = register({
|
||||
label={t("labels.fileTitle")}
|
||||
value={appState.name || "Unnamed"}
|
||||
onChange={(name: string) => updateData(name)}
|
||||
isNameEditable={
|
||||
typeof appProps.name === "undefined" && !appState.viewModeEnabled
|
||||
}
|
||||
isNameEditable={typeof appProps.name === "undefined"}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
@@ -7,10 +7,12 @@ import { AppState } from "./types";
|
||||
import { SVG_EXPORT_TAG } from "./scene/export";
|
||||
import { tryParseSpreadsheet, Spreadsheet, VALID_SPREADSHEET } from "./charts";
|
||||
import { canvasToBlob } from "./data/blob";
|
||||
import { EXPORT_DATA_TYPES } from "./constants";
|
||||
|
||||
const TYPE_ELEMENTS = "excalidraw/elements";
|
||||
|
||||
type ElementsClipboard = {
|
||||
type: typeof EXPORT_DATA_TYPES.excalidrawClipboard;
|
||||
type: typeof TYPE_ELEMENTS;
|
||||
created: number;
|
||||
elements: ExcalidrawElement[];
|
||||
};
|
||||
|
||||
@@ -29,16 +31,8 @@ export const probablySupportsClipboardBlob =
|
||||
"ClipboardItem" in window &&
|
||||
"toBlob" in HTMLCanvasElement.prototype;
|
||||
|
||||
const clipboardContainsElements = (
|
||||
contents: any,
|
||||
): contents is { elements: ExcalidrawElement[] } => {
|
||||
if (
|
||||
[
|
||||
EXPORT_DATA_TYPES.excalidraw,
|
||||
EXPORT_DATA_TYPES.excalidrawClipboard,
|
||||
].includes(contents?.type) &&
|
||||
Array.isArray(contents.elements)
|
||||
) {
|
||||
const isElementsClipboard = (contents: any): contents is ElementsClipboard => {
|
||||
if (contents?.type === TYPE_ELEMENTS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -49,7 +43,8 @@ export const copyToClipboard = async (
|
||||
appState: AppState,
|
||||
) => {
|
||||
const contents: ElementsClipboard = {
|
||||
type: EXPORT_DATA_TYPES.excalidrawClipboard,
|
||||
type: TYPE_ELEMENTS,
|
||||
created: Date.now(),
|
||||
elements: getSelectedElements(elements, appState),
|
||||
};
|
||||
const json = JSON.stringify(contents);
|
||||
@@ -136,9 +131,15 @@ export const parseClipboard = async (
|
||||
|
||||
try {
|
||||
const systemClipboardData = JSON.parse(systemClipboard);
|
||||
if (clipboardContainsElements(systemClipboardData)) {
|
||||
// system clipboard elements are newer than in-app clipboard
|
||||
if (
|
||||
isElementsClipboard(systemClipboardData) &&
|
||||
(!appClipboardData?.created ||
|
||||
appClipboardData.created < systemClipboardData.created)
|
||||
) {
|
||||
return { elements: systemClipboardData.elements };
|
||||
}
|
||||
// in-app clipboard is newer than system clipboard
|
||||
return appClipboardData;
|
||||
} catch {
|
||||
// system clipboard doesn't contain excalidraw elements → return plaintext
|
||||
|
@@ -525,7 +525,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
||||
let gridSize = actionResult?.appState?.gridSize || null;
|
||||
let theme = actionResult?.appState?.theme || "light";
|
||||
let name = actionResult?.appState?.name ?? this.state.name;
|
||||
let name = actionResult?.appState?.name || this.state.name;
|
||||
|
||||
if (typeof this.props.viewModeEnabled !== "undefined") {
|
||||
viewModeEnabled = this.props.viewModeEnabled;
|
||||
}
|
||||
@@ -1022,7 +1023,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
// potential issues, this fixes a case where the tab isn't focused during
|
||||
// init, which would trigger onChange with empty elements, which would then
|
||||
// override whatever is in localStorage currently.
|
||||
if (!this.state.isLoading && !prevState.isLoading) {
|
||||
if (!this.state.isLoading) {
|
||||
this.props.onChange?.(
|
||||
this.scene.getElementsIncludingDeleted(),
|
||||
this.state,
|
||||
@@ -1404,7 +1405,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event[KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {
|
||||
if (event[KEYS.CTRL_OR_CMD]) {
|
||||
this.setState({ isBindingEnabled: false });
|
||||
}
|
||||
|
||||
|
@@ -31,16 +31,9 @@
|
||||
.ExportDialog__name {
|
||||
grid-column: project-name;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.TextInput {
|
||||
height: calc(1rem - 3px);
|
||||
width: 200px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
margin-left: 8px;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&--readonly {
|
||||
background: none;
|
||||
@@ -48,9 +41,6 @@
|
||||
&:hover {
|
||||
background: none;
|
||||
}
|
||||
width: auto;
|
||||
max-width: 200px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -144,37 +144,34 @@ const LibraryMenuItems = ({
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{!!library.length && (
|
||||
<>
|
||||
<ToolButton
|
||||
key="export"
|
||||
type="button"
|
||||
title={t("buttons.export")}
|
||||
aria-label={t("buttons.export")}
|
||||
icon={exportFile}
|
||||
onClick={() => {
|
||||
saveLibraryAsJSON()
|
||||
.catch(muteFSAbortError)
|
||||
.catch((error) => {
|
||||
setAppState({ errorMessage: error.message });
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<ToolButton
|
||||
key="reset"
|
||||
type="button"
|
||||
title={t("buttons.resetLibrary")}
|
||||
aria-label={t("buttons.resetLibrary")}
|
||||
icon={trash}
|
||||
onClick={() => {
|
||||
if (window.confirm(t("alerts.resetLibrary"))) {
|
||||
Library.resetLibrary();
|
||||
setLibraryItems([]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<ToolButton
|
||||
key="export"
|
||||
type="button"
|
||||
title={t("buttons.export")}
|
||||
aria-label={t("buttons.export")}
|
||||
icon={exportFile}
|
||||
onClick={() => {
|
||||
saveLibraryAsJSON()
|
||||
.catch(muteFSAbortError)
|
||||
.catch((error) => {
|
||||
setAppState({ errorMessage: error.message });
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<ToolButton
|
||||
key="reset"
|
||||
type="button"
|
||||
title={t("buttons.resetLibrary")}
|
||||
aria-label={t("buttons.resetLibrary")}
|
||||
icon={trash}
|
||||
onClick={() => {
|
||||
if (window.confirm(t("alerts.resetLibrary"))) {
|
||||
Library.resetLibrary();
|
||||
setLibraryItems([]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<a
|
||||
href={`https://libraries.excalidraw.com?referrer=${referrer}`}
|
||||
target="_excalidraw_libraries"
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import "./TextInput.scss";
|
||||
|
||||
import React, { Component } from "react";
|
||||
import { selectNode, removeSelection } from "../utils";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
@@ -9,18 +10,17 @@ type Props = {
|
||||
isNameEditable: boolean;
|
||||
};
|
||||
|
||||
type State = {
|
||||
fileName: string;
|
||||
};
|
||||
export class ProjectName extends Component<Props, State> {
|
||||
state = {
|
||||
fileName: this.props.value,
|
||||
export class ProjectName extends Component<Props> {
|
||||
private handleFocus = (event: React.FocusEvent<HTMLElement>) => {
|
||||
selectNode(event.currentTarget);
|
||||
};
|
||||
private handleBlur = (event: any) => {
|
||||
const value = event.target.value;
|
||||
|
||||
private handleBlur = (event: React.FocusEvent<HTMLElement>) => {
|
||||
const value = event.currentTarget.innerText.trim();
|
||||
if (value !== this.props.value) {
|
||||
this.props.onChange(value);
|
||||
}
|
||||
removeSelection();
|
||||
};
|
||||
|
||||
private handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
@@ -32,30 +32,39 @@ export class ProjectName extends Component<Props, State> {
|
||||
event.currentTarget.blur();
|
||||
}
|
||||
};
|
||||
private makeEditable = (editable: HTMLSpanElement | null) => {
|
||||
if (!editable) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
editable.contentEditable = "plaintext-only";
|
||||
} catch {
|
||||
editable.contentEditable = "true";
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<>
|
||||
<label htmlFor="file-name">
|
||||
{`${this.props.label}${this.props.isNameEditable ? "" : ":"}`}
|
||||
</label>
|
||||
{this.props.isNameEditable ? (
|
||||
<input
|
||||
className="TextInput"
|
||||
onBlur={this.handleBlur}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
id="file-name"
|
||||
value={this.state.fileName}
|
||||
onChange={(event) =>
|
||||
this.setState({ fileName: event.target.value })
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<span className="TextInput TextInput--readonly" id="file-name">
|
||||
{this.props.value}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
return this.props.isNameEditable ? (
|
||||
<span
|
||||
suppressContentEditableWarning
|
||||
ref={this.makeEditable}
|
||||
data-type="wysiwyg"
|
||||
className="TextInput"
|
||||
role="textbox"
|
||||
aria-label={this.props.label}
|
||||
onBlur={this.handleBlur}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onFocus={this.handleFocus}
|
||||
>
|
||||
{this.props.value}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
className="TextInput TextInput--readonly"
|
||||
aria-label={this.props.label}
|
||||
>
|
||||
{this.props.value}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -84,15 +84,9 @@ export const MIME_TYPES = {
|
||||
excalidrawlib: "application/vnd.excalidrawlib+json",
|
||||
};
|
||||
|
||||
export const EXPORT_DATA_TYPES = {
|
||||
excalidraw: "excalidraw",
|
||||
excalidrawClipboard: "excalidraw/clipboard",
|
||||
excalidrawLibrary: "excalidrawlib",
|
||||
} as const;
|
||||
|
||||
export const STORAGE_KEYS = {
|
||||
LOCAL_STORAGE_LIBRARY: "excalidraw-library",
|
||||
} as const;
|
||||
};
|
||||
|
||||
// time in milliseconds
|
||||
export const TAP_TWICE_TIMEOUT = 300;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { cleanAppStateForExport } from "../appState";
|
||||
import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants";
|
||||
import { MIME_TYPES } from "../constants";
|
||||
import { clearElementsForExport } from "../element";
|
||||
import { CanvasError } from "../errors";
|
||||
import { t } from "../i18n";
|
||||
@@ -121,7 +121,7 @@ export const loadFromBlob = async (
|
||||
export const loadLibraryFromBlob = async (blob: Blob) => {
|
||||
const contents = await parseFileContents(blob);
|
||||
const data: LibraryData = JSON.parse(contents);
|
||||
if (data.type !== EXPORT_DATA_TYPES.excalidrawLibrary) {
|
||||
if (data.type !== "excalidrawlib") {
|
||||
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
||||
}
|
||||
return data;
|
||||
|
@@ -2,7 +2,7 @@ import decodePng from "png-chunks-extract";
|
||||
import tEXt from "png-chunk-text";
|
||||
import encodePng from "png-chunks-encode";
|
||||
import { stringToBase64, encode, decode, base64ToString } from "./encode";
|
||||
import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants";
|
||||
import { MIME_TYPES } from "../constants";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PNG
|
||||
@@ -67,10 +67,7 @@ export const decodePngMetadata = async (blob: Blob) => {
|
||||
const encodedData = JSON.parse(metadata.text);
|
||||
if (!("encoded" in encodedData)) {
|
||||
// legacy, un-encoded scene JSON
|
||||
if (
|
||||
"type" in encodedData &&
|
||||
encodedData.type === EXPORT_DATA_TYPES.excalidraw
|
||||
) {
|
||||
if ("type" in encodedData && encodedData.type === "excalidraw") {
|
||||
return metadata.text;
|
||||
}
|
||||
throw new Error("FAILED");
|
||||
@@ -118,10 +115,7 @@ export const decodeSvgMetadata = async ({ svg }: { svg: string }) => {
|
||||
const encodedData = JSON.parse(json);
|
||||
if (!("encoded" in encodedData)) {
|
||||
// legacy, un-encoded scene JSON
|
||||
if (
|
||||
"type" in encodedData &&
|
||||
encodedData.type === EXPORT_DATA_TYPES.excalidraw
|
||||
) {
|
||||
if ("type" in encodedData && encodedData.type === "excalidraw") {
|
||||
return json;
|
||||
}
|
||||
throw new Error("FAILED");
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { fileOpen, fileSave } from "browser-fs-access";
|
||||
import { cleanAppStateForExport } from "../appState";
|
||||
import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants";
|
||||
import { MIME_TYPES } from "../constants";
|
||||
import { clearElementsForExport } from "../element";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
@@ -14,7 +14,7 @@ export const serializeAsJSON = (
|
||||
): string =>
|
||||
JSON.stringify(
|
||||
{
|
||||
type: EXPORT_DATA_TYPES.excalidraw,
|
||||
type: "excalidraw",
|
||||
version: 2,
|
||||
source: window.location.origin,
|
||||
elements: clearElementsForExport(elements),
|
||||
@@ -69,7 +69,7 @@ export const isValidExcalidrawData = (data?: {
|
||||
appState?: any;
|
||||
}): data is ImportedDataState => {
|
||||
return (
|
||||
data?.type === EXPORT_DATA_TYPES.excalidraw &&
|
||||
data?.type === "excalidraw" &&
|
||||
(!data.elements ||
|
||||
(Array.isArray(data.elements) &&
|
||||
(!data.appState || typeof data.appState === "object")))
|
||||
@@ -80,7 +80,7 @@ export const isValidLibrary = (json: any) => {
|
||||
return (
|
||||
typeof json === "object" &&
|
||||
json &&
|
||||
json.type === EXPORT_DATA_TYPES.excalidrawLibrary &&
|
||||
json.type === "excalidrawlib" &&
|
||||
json.version === 1
|
||||
);
|
||||
};
|
||||
@@ -89,7 +89,7 @@ export const saveLibraryAsJSON = async () => {
|
||||
const library = await Library.loadLibrary();
|
||||
const serialized = JSON.stringify(
|
||||
{
|
||||
type: EXPORT_DATA_TYPES.excalidrawLibrary,
|
||||
type: "excalidrawlib",
|
||||
version: 1,
|
||||
library,
|
||||
},
|
||||
|
@@ -87,30 +87,9 @@ export const mutateElement = <TElement extends Mutable<ExcalidrawElement>>(
|
||||
export const newElementWith = <TElement extends ExcalidrawElement>(
|
||||
element: TElement,
|
||||
updates: ElementUpdate<TElement>,
|
||||
): TElement => {
|
||||
let didChange = false;
|
||||
for (const key in updates) {
|
||||
const value = (updates as any)[key];
|
||||
if (typeof value !== "undefined") {
|
||||
if (
|
||||
(element as any)[key] === value &&
|
||||
// if object, always update in case its deep prop was mutated
|
||||
(typeof value !== "object" || value === null || key === "groupIds")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
didChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!didChange) {
|
||||
return element;
|
||||
}
|
||||
|
||||
return {
|
||||
...element,
|
||||
...updates,
|
||||
version: element.version + 1,
|
||||
versionNonce: randomInteger(),
|
||||
};
|
||||
};
|
||||
): TElement => ({
|
||||
...element,
|
||||
...updates,
|
||||
version: element.version + 1,
|
||||
versionNonce: randomInteger(),
|
||||
});
|
||||
|
@@ -61,7 +61,7 @@
|
||||
"architect": "Architect",
|
||||
"artist": "Artist",
|
||||
"cartoonist": "Cartoonist",
|
||||
"fileTitle": "File name",
|
||||
"fileTitle": "File title",
|
||||
"colorPicker": "Color picker",
|
||||
"canvasBackground": "Canvas background",
|
||||
"drawingCanvas": "Drawing canvas",
|
||||
|
@@ -18,7 +18,7 @@ Please add the latest change on the top under the correct section.
|
||||
|
||||
### Features
|
||||
|
||||
- Add `name` prop to indicate the name of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over `intialData.appState.name`, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw [#3273](https://github.com/excalidraw/excalidraw/pull/3273).
|
||||
- Add `name` prop which indicates the name of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over `intialData.appState.name`, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw [#3273](https://github.com/excalidraw/excalidraw/pull/3273).
|
||||
- Export API `setCanvasOffsets` via `ref` to set the offsets for Excalidraw[#3265](https://github.com/excalidraw/excalidraw/pull/3265).
|
||||
#### BREAKING CHANGE
|
||||
- `offsetLeft` and `offsetTop` props have been removed now so you have to use the `setCanvasOffsets` via `ref` to achieve the same.
|
||||
|
@@ -3357,8 +3357,8 @@ Object {
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 4,
|
||||
"versionNonce": 453191,
|
||||
"version": 8,
|
||||
"versionNonce": 1116226695,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
@@ -3429,7 +3429,7 @@ Object {
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#fa5252",
|
||||
"backgroundColor": "transparent",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
@@ -3452,6 +3452,78 @@ Object {
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"name": "Untitled-201933152653",
|
||||
"selectedElementIds": Object {
|
||||
"id0": true,
|
||||
},
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
},
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#fa5252",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 10,
|
||||
"id": "id0",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 337897,
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 5,
|
||||
"versionNonce": 401146281,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"name": "Untitled-201933152653",
|
||||
"selectedElementIds": Object {
|
||||
"id0": true,
|
||||
},
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
},
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#fa5252",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 10,
|
||||
"id": "id0",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 337897,
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 6,
|
||||
"versionNonce": 2019559783,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
@@ -3480,8 +3552,8 @@ Object {
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 4,
|
||||
"versionNonce": 453191,
|
||||
"version": 8,
|
||||
"versionNonce": 1116226695,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
@@ -14673,7 +14745,7 @@ Object {
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"versionNonce": 1505387817,
|
||||
"versionNonce": 81784553,
|
||||
"width": 20,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
@@ -14692,14 +14764,14 @@ Object {
|
||||
"isDeleted": false,
|
||||
"opacity": 60,
|
||||
"roughness": 2,
|
||||
"seed": 238820263,
|
||||
"seed": 23633383,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "dotted",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 9,
|
||||
"versionNonce": 1604849351,
|
||||
"version": 13,
|
||||
"versionNonce": 915032327,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
@@ -14862,7 +14934,7 @@ Object {
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 449462985,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
@@ -14909,42 +14981,6 @@ Object {
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
},
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#e64980",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 449462985,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 4,
|
||||
"versionNonce": 2019559783,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"name": "Untitled-201933152653",
|
||||
"selectedElementIds": Object {
|
||||
"id1": true,
|
||||
},
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
},
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
@@ -14952,29 +14988,6 @@ Object {
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id0",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 337897,
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 2,
|
||||
"versionNonce": 1278240551,
|
||||
"width": 20,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
},
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#e64980",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "cross-hatch",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
@@ -15029,9 +15042,9 @@ Object {
|
||||
},
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#e64980",
|
||||
"backgroundColor": "transparent",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "cross-hatch",
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
@@ -15042,7 +15055,7 @@ Object {
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 6,
|
||||
"versionNonce": 1116226695,
|
||||
@@ -15090,7 +15103,7 @@ Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#e64980",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "cross-hatch",
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
@@ -15100,11 +15113,11 @@ Object {
|
||||
"seed": 449462985,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "dotted",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 7,
|
||||
"versionNonce": 1014066025,
|
||||
"version": 8,
|
||||
"versionNonce": 238820263,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
@@ -15155,14 +15168,14 @@ Object {
|
||||
"id": "id1",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 2,
|
||||
"seed": 238820263,
|
||||
"roughness": 1,
|
||||
"seed": 449462985,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "dotted",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 8,
|
||||
"version": 9,
|
||||
"versionNonce": 400692809,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
@@ -15213,16 +15226,193 @@ Object {
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
"isDeleted": false,
|
||||
"opacity": 60,
|
||||
"roughness": 2,
|
||||
"seed": 238820263,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 449462985,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 10,
|
||||
"versionNonce": 1604849351,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"name": "Untitled-201933152653",
|
||||
"selectedElementIds": Object {
|
||||
"id1": true,
|
||||
},
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
},
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id0",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 337897,
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 2,
|
||||
"versionNonce": 1278240551,
|
||||
"width": 20,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
},
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#e64980",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "cross-hatch",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 449462985,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "dotted",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 9,
|
||||
"versionNonce": 1604849351,
|
||||
"version": 11,
|
||||
"versionNonce": 1505387817,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"name": "Untitled-201933152653",
|
||||
"selectedElementIds": Object {
|
||||
"id1": true,
|
||||
},
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
},
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id0",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 337897,
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 2,
|
||||
"versionNonce": 1278240551,
|
||||
"width": 20,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
},
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#e64980",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "cross-hatch",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 2,
|
||||
"seed": 23633383,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "dotted",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 12,
|
||||
"versionNonce": 493213705,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"name": "Untitled-201933152653",
|
||||
"selectedElementIds": Object {
|
||||
"id1": true,
|
||||
},
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
},
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id0",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 337897,
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 2,
|
||||
"versionNonce": 1278240551,
|
||||
"width": 20,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
},
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#e64980",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "cross-hatch",
|
||||
"groupIds": Array [],
|
||||
"height": 20,
|
||||
"id": "id1",
|
||||
"isDeleted": false,
|
||||
"opacity": 60,
|
||||
"roughness": 2,
|
||||
"seed": 23633383,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "dotted",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 13,
|
||||
"versionNonce": 915032327,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
@@ -15258,7 +15448,7 @@ Object {
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"versionNonce": 1505387817,
|
||||
"versionNonce": 81784553,
|
||||
"width": 20,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
@@ -15274,14 +15464,14 @@ Object {
|
||||
"isDeleted": false,
|
||||
"opacity": 60,
|
||||
"roughness": 2,
|
||||
"seed": 238820263,
|
||||
"seed": 23633383,
|
||||
"strokeColor": "#c92a2a",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "dotted",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"version": 9,
|
||||
"versionNonce": 1604849351,
|
||||
"version": 13,
|
||||
"versionNonce": 915032327,
|
||||
"width": 20,
|
||||
"x": 40,
|
||||
"y": 40,
|
||||
@@ -16879,8 +17069,8 @@ Object {
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"versionNonce": 449462985,
|
||||
"version": 5,
|
||||
"versionNonce": 401146281,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
@@ -16951,7 +17141,7 @@ Object {
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#fa5252",
|
||||
"backgroundColor": "transparent",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
@@ -16974,6 +17164,42 @@ Object {
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"appState": Object {
|
||||
"editingGroupId": null,
|
||||
"editingLinearElement": null,
|
||||
"name": "Untitled-201933152653",
|
||||
"selectedElementIds": Object {
|
||||
"id0": true,
|
||||
},
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
},
|
||||
"elements": Array [
|
||||
Object {
|
||||
"angle": 0,
|
||||
"backgroundColor": "#fa5252",
|
||||
"boundElementIds": null,
|
||||
"fillStyle": "hachure",
|
||||
"groupIds": Array [],
|
||||
"height": 10,
|
||||
"id": "id0",
|
||||
"isDeleted": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"seed": 337897,
|
||||
"strokeColor": "#000000",
|
||||
"strokeSharpness": "sharp",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 5,
|
||||
"versionNonce": 401146281,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
@@ -20381,7 +20607,7 @@ Object {
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 6,
|
||||
"versionNonce": 760410951,
|
||||
"versionNonce": 1006504105,
|
||||
"width": 20,
|
||||
"x": 10,
|
||||
"y": -10,
|
||||
@@ -20407,7 +20633,7 @@ Object {
|
||||
"strokeWidth": 1,
|
||||
"type": "rectangle",
|
||||
"version": 6,
|
||||
"versionNonce": 1006504105,
|
||||
"versionNonce": 289600103,
|
||||
"width": 30,
|
||||
"x": 40,
|
||||
"y": 0,
|
||||
@@ -20450,8 +20676,8 @@ Object {
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"type": "arrow",
|
||||
"version": 9,
|
||||
"versionNonce": 81784553,
|
||||
"version": 11,
|
||||
"versionNonce": 1315507081,
|
||||
"width": 60,
|
||||
"x": 130,
|
||||
"y": 10,
|
||||
|
@@ -3,7 +3,6 @@ import { render, waitFor } from "./test-utils";
|
||||
import ExcalidrawApp from "../excalidraw-app";
|
||||
import { API } from "./helpers/api";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { EXPORT_DATA_TYPES } from "../constants";
|
||||
|
||||
const { h } = window;
|
||||
|
||||
@@ -30,7 +29,7 @@ describe("appState", () => {
|
||||
new Blob(
|
||||
[
|
||||
JSON.stringify({
|
||||
type: EXPORT_DATA_TYPES.excalidraw,
|
||||
type: "excalidraw",
|
||||
appState: {
|
||||
viewBackgroundColor: "#000",
|
||||
},
|
||||
|
@@ -111,11 +111,11 @@ describe("<Excalidraw/>", () => {
|
||||
const { container } = await render(<Excalidraw />);
|
||||
|
||||
fireEvent.click(queryByTestId(container, "export-button")!);
|
||||
const textInput: HTMLInputElement | null = document.querySelector(
|
||||
const textInput = document.querySelector(
|
||||
".ExportDialog__name .TextInput",
|
||||
);
|
||||
expect(textInput?.value).toContain(`${t("labels.untitled")}`);
|
||||
expect(textInput?.nodeName).toBe("INPUT");
|
||||
expect(textInput?.textContent).toContain(`${t("labels.untitled")}`);
|
||||
expect(textInput?.hasAttribute("data-type")).toBe(true);
|
||||
});
|
||||
|
||||
it('should set the name and not allow editing when the name prop is present"', async () => {
|
||||
@@ -124,10 +124,11 @@ describe("<Excalidraw/>", () => {
|
||||
|
||||
await fireEvent.click(queryByTestId(container, "export-button")!);
|
||||
const textInput = document.querySelector(
|
||||
".ExportDialog__name .TextInput--readonly",
|
||||
".ExportDialog__name .TextInput",
|
||||
);
|
||||
expect(textInput?.textContent).toEqual(name);
|
||||
expect(textInput?.nodeName).toBe("SPAN");
|
||||
|
||||
expect(textInput?.hasAttribute("data-type")).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -6,7 +6,6 @@ import { API } from "./helpers/api";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { waitFor } from "@testing-library/react";
|
||||
import { createUndoAction, createRedoAction } from "../actions/actionHistory";
|
||||
import { EXPORT_DATA_TYPES } from "../constants";
|
||||
|
||||
const { h } = window;
|
||||
|
||||
@@ -77,7 +76,7 @@ describe("history", () => {
|
||||
new Blob(
|
||||
[
|
||||
JSON.stringify({
|
||||
type: EXPORT_DATA_TYPES.excalidraw,
|
||||
type: "excalidraw",
|
||||
appState: {
|
||||
...getDefaultAppState(),
|
||||
viewBackgroundColor: "#000",
|
||||
|
@@ -131,7 +131,9 @@ export const debounce = <T extends any[]>(
|
||||
};
|
||||
ret.flush = () => {
|
||||
clearTimeout(handle);
|
||||
fn(...(lastArgs || []));
|
||||
if (lastArgs) {
|
||||
fn(...lastArgs);
|
||||
}
|
||||
};
|
||||
ret.cancel = () => {
|
||||
clearTimeout(handle);
|
||||
|
Reference in New Issue
Block a user