@excalidraw/excalidraw 0.17.1-1ed53b1 → 0.17.1-22b3927
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-JKPJV7MZ.js → chunk-Q6A4M3MN.js} +4 -2
- package/dist/browser/dev/excalidraw-assets-dev/chunk-Q6A4M3MN.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-OKAZAA6U.js → chunk-VC7RRIDZ.js} +230 -93
- package/dist/browser/dev/excalidraw-assets-dev/chunk-VC7RRIDZ.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{dist-ITJNUBZF.js → dist-6QVAH5JA.js} +36 -14
- package/dist/browser/dev/excalidraw-assets-dev/dist-6QVAH5JA.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-BF4XUPIZ.js → en-Y27YPU72.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-LVS32KQQ.js → image-J7S3ALXP.js} +2 -2
- package/dist/browser/dev/index.js +335 -116
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/chunk-CWO763YJ.js +55 -0
- package/dist/browser/prod/excalidraw-assets/{chunk-O4AI3NNG.js → chunk-IZMZ6RPD.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/dist-567JAXHK.js +7 -0
- package/dist/browser/prod/excalidraw-assets/{en-N7CLNF6C.js → en-GSUSWMSH.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/image-SZBFRCU2.js +1 -0
- package/dist/browser/prod/index.js +24 -24
- package/dist/dev/{en-UQDDYCH7.json → en-OIPCBIOA.json} +3 -1
- package/dist/dev/index.js +576 -207
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionAddToLibrary.d.ts +3 -3
- package/dist/excalidraw/actions/actionAlign.d.ts +6 -6
- package/dist/excalidraw/actions/actionBoundText.d.ts +3 -3
- package/dist/excalidraw/actions/actionBoundText.js +3 -1
- package/dist/excalidraw/actions/actionCanvas.d.ts +13 -13
- package/dist/excalidraw/actions/actionClipboard.d.ts +12 -12
- package/dist/excalidraw/actions/actionDeleteSelected.d.ts +3 -3
- package/dist/excalidraw/actions/actionDistribute.d.ts +2 -2
- package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +1 -1
- package/dist/excalidraw/actions/actionElementLock.d.ts +2 -2
- package/dist/excalidraw/actions/actionExport.d.ts +11 -11
- package/dist/excalidraw/actions/actionFinalize.d.ts +2 -2
- package/dist/excalidraw/actions/actionFlip.d.ts +2 -2
- package/dist/excalidraw/actions/actionFrame.d.ts +312 -4
- package/dist/excalidraw/actions/actionGroup.d.ts +312 -2
- package/dist/excalidraw/actions/actionHistory.js +4 -4
- package/dist/excalidraw/actions/actionLinearEditor.d.ts +1 -1
- package/dist/excalidraw/actions/actionLink.d.ts +1 -1
- package/dist/excalidraw/actions/actionMenu.d.ts +3 -3
- package/dist/excalidraw/actions/actionNavigate.d.ts +2 -2
- package/dist/excalidraw/actions/actionProperties.d.ts +13 -13
- package/dist/excalidraw/actions/actionProperties.js +1 -1
- package/dist/excalidraw/actions/actionSelectAll.d.ts +1 -1
- package/dist/excalidraw/actions/actionStyles.d.ts +5 -2
- package/dist/excalidraw/actions/actionTextAutoResize.d.ts +17 -0
- package/dist/excalidraw/actions/actionTextAutoResize.js +38 -0
- package/dist/excalidraw/actions/actionToggleGridMode.d.ts +1 -1
- package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +1 -1
- package/dist/excalidraw/actions/actionToggleStats.d.ts +1 -1
- package/dist/excalidraw/actions/actionToggleViewMode.d.ts +1 -1
- package/dist/excalidraw/actions/actionToggleZenMode.d.ts +1 -1
- package/dist/excalidraw/actions/actionZindex.d.ts +4 -4
- package/dist/excalidraw/actions/types.d.ts +1 -1
- package/dist/excalidraw/change.js +13 -6
- package/dist/excalidraw/components/Actions.js +1 -1
- package/dist/excalidraw/components/App.d.ts +2 -2
- package/dist/excalidraw/components/App.js +133 -51
- package/dist/excalidraw/components/ButtonIconSelect.js +1 -1
- package/dist/excalidraw/components/CheckboxItem.js +1 -1
- package/dist/excalidraw/components/CommandPalette/CommandPalette.js +2 -2
- package/dist/excalidraw/components/ContextMenu.js +1 -1
- package/dist/excalidraw/components/Dialog.js +1 -1
- package/dist/excalidraw/components/FollowMode/FollowMode.js +1 -1
- package/dist/excalidraw/components/IconPicker.js +2 -2
- package/dist/excalidraw/components/LayerUI.js +2 -2
- package/dist/excalidraw/components/MobileMenu.js +1 -1
- package/dist/excalidraw/components/PasteChartDialog.js +1 -1
- package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +3 -2
- package/dist/excalidraw/components/canvases/InteractiveCanvas.js +4 -2
- package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +1 -1
- package/dist/excalidraw/components/canvases/StaticCanvas.js +2 -2
- package/dist/excalidraw/components/icons.js +6 -2
- package/dist/excalidraw/constants.d.ts +1 -0
- package/dist/excalidraw/constants.js +5 -0
- package/dist/excalidraw/data/restore.js +3 -0
- package/dist/excalidraw/element/dragElements.d.ts +2 -2
- package/dist/excalidraw/element/dragElements.js +27 -3
- package/dist/excalidraw/element/embeddable.d.ts +1 -1
- package/dist/excalidraw/element/index.d.ts +1 -1
- package/dist/excalidraw/element/index.js +1 -1
- package/dist/excalidraw/element/mutateElement.d.ts +1 -1
- package/dist/excalidraw/element/mutateElement.js +5 -3
- package/dist/excalidraw/element/newElement.d.ts +2 -5
- package/dist/excalidraw/element/newElement.js +16 -14
- package/dist/excalidraw/element/resizeElements.js +73 -21
- package/dist/excalidraw/element/resizeTest.js +2 -4
- package/dist/excalidraw/element/textElement.d.ts +1 -0
- package/dist/excalidraw/element/textElement.js +11 -3
- package/dist/excalidraw/element/textWysiwyg.d.ts +10 -4
- package/dist/excalidraw/element/textWysiwyg.js +38 -17
- package/dist/excalidraw/element/transformHandles.js +0 -10
- package/dist/excalidraw/element/types.d.ts +7 -0
- package/dist/excalidraw/fractionalIndex.js +2 -4
- package/dist/excalidraw/locales/en.json +3 -1
- package/dist/excalidraw/mermaid.d.ts +2 -0
- package/dist/excalidraw/mermaid.js +28 -0
- package/dist/excalidraw/renderer/interactiveScene.d.ts +1 -1
- package/dist/excalidraw/renderer/interactiveScene.js +31 -5
- package/dist/excalidraw/renderer/renderElement.d.ts +2 -2
- package/dist/excalidraw/renderer/renderElement.js +2 -2
- package/dist/excalidraw/scene/Fonts.d.ts +1 -3
- package/dist/excalidraw/scene/Fonts.js +6 -12
- package/dist/excalidraw/scene/Renderer.d.ts +1 -1
- package/dist/excalidraw/scene/Renderer.js +2 -3
- package/dist/excalidraw/scene/Scene.d.ts +10 -4
- package/dist/excalidraw/scene/Scene.js +14 -8
- package/dist/excalidraw/scene/export.js +1 -1
- package/dist/excalidraw/scene/types.d.ts +2 -1
- package/dist/excalidraw/snapping.js +2 -1
- package/dist/excalidraw/store.d.ts +32 -2
- package/dist/excalidraw/store.js +27 -0
- package/dist/excalidraw/types.d.ts +1 -0
- package/dist/prod/{en-UQDDYCH7.json → en-OIPCBIOA.json} +3 -1
- package/dist/prod/index.js +42 -42
- package/package.json +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/chunk-JKPJV7MZ.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-OKAZAA6U.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/dist-ITJNUBZF.js.map +0 -7
- package/dist/browser/prod/excalidraw-assets/chunk-SXBDZOS3.js +0 -55
- package/dist/browser/prod/excalidraw-assets/dist-54276HPL.js +0 -6
- package/dist/browser/prod/excalidraw-assets/image-VAGBVQ3G.js +0 -1
- /package/dist/browser/dev/excalidraw-assets-dev/{en-BF4XUPIZ.js.map → en-Y27YPU72.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-LVS32KQQ.js.map → image-J7S3ALXP.js.map} +0 -0
|
@@ -23,7 +23,7 @@ const getTransform = (width, height, angle, appState, maxWidth, maxHeight) => {
|
|
|
23
23
|
}
|
|
24
24
|
return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
|
|
25
25
|
};
|
|
26
|
-
export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element, canvas, excalidrawContainer, app, }) => {
|
|
26
|
+
export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element, canvas, excalidrawContainer, app, autoSelect = true, }) => {
|
|
27
27
|
const textPropertiesUpdated = (updatedTextElement, editable) => {
|
|
28
28
|
if (!editable.style.fontFamily || !editable.style.fontSize) {
|
|
29
29
|
return false;
|
|
@@ -53,8 +53,6 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
53
53
|
let maxWidth = updatedTextElement.width;
|
|
54
54
|
let maxHeight = updatedTextElement.height;
|
|
55
55
|
let textElementWidth = updatedTextElement.width;
|
|
56
|
-
// Set to element height by default since that's
|
|
57
|
-
// what is going to be used for unbounded text
|
|
58
56
|
const textElementHeight = updatedTextElement.height;
|
|
59
57
|
if (container && updatedTextElement.containerId) {
|
|
60
58
|
if (isArrowElement(container)) {
|
|
@@ -113,6 +111,9 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
113
111
|
maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
|
|
114
112
|
textElementWidth = Math.min(textElementWidth, maxWidth);
|
|
115
113
|
}
|
|
114
|
+
else {
|
|
115
|
+
textElementWidth += 0.5;
|
|
116
|
+
}
|
|
116
117
|
// Make sure text editor height doesn't go beyond viewport
|
|
117
118
|
const editorMaxHeight = (appState.height - viewportY) / appState.zoom.value;
|
|
118
119
|
Object.assign(editable.style, {
|
|
@@ -149,7 +150,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
149
150
|
editable.classList.add("excalidraw-wysiwyg");
|
|
150
151
|
let whiteSpace = "pre";
|
|
151
152
|
let wordBreak = "normal";
|
|
152
|
-
if (isBoundToContainer(element)) {
|
|
153
|
+
if (isBoundToContainer(element) || !element.autoResize) {
|
|
153
154
|
whiteSpace = "pre-wrap";
|
|
154
155
|
wordBreak = "break-word";
|
|
155
156
|
}
|
|
@@ -326,6 +327,11 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
326
327
|
// so that we don't need to create separate a callback for event handlers
|
|
327
328
|
let submittedViaKeyboard = false;
|
|
328
329
|
const handleSubmit = () => {
|
|
330
|
+
// prevent double submit
|
|
331
|
+
if (isDestroyed) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
isDestroyed = true;
|
|
329
335
|
// cleanup must be run before onSubmit otherwise when app blurs the wysiwyg
|
|
330
336
|
// it'd get stuck in an infinite loop of blur→onSubmit after we re-focus the
|
|
331
337
|
// wysiwyg on update
|
|
@@ -334,10 +340,8 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
334
340
|
if (!updateElement) {
|
|
335
341
|
return;
|
|
336
342
|
}
|
|
337
|
-
let text = editable.value;
|
|
338
343
|
const container = getContainerElement(updateElement, app.scene.getNonDeletedElementsMap());
|
|
339
344
|
if (container) {
|
|
340
|
-
text = updateElement.text;
|
|
341
345
|
if (editable.value.trim()) {
|
|
342
346
|
const boundTextElementId = getBoundTextElementId(container);
|
|
343
347
|
if (!boundTextElementId || boundTextElementId !== element.id) {
|
|
@@ -361,16 +365,11 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
361
365
|
redrawTextBoundingBox(updateElement, container, app.scene.getNonDeletedElementsMap());
|
|
362
366
|
}
|
|
363
367
|
onSubmit({
|
|
364
|
-
text,
|
|
365
368
|
viaKeyboard: submittedViaKeyboard,
|
|
366
|
-
|
|
369
|
+
nextOriginalText: editable.value,
|
|
367
370
|
});
|
|
368
371
|
};
|
|
369
372
|
const cleanup = () => {
|
|
370
|
-
if (isDestroyed) {
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
isDestroyed = true;
|
|
374
373
|
// remove events to ensure they don't late-fire
|
|
375
374
|
editable.onblur = null;
|
|
376
375
|
editable.oninput = null;
|
|
@@ -439,9 +438,24 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
439
438
|
// alt-tabbing away
|
|
440
439
|
window.addEventListener("blur", handleSubmit);
|
|
441
440
|
}
|
|
441
|
+
else if (event.target instanceof HTMLElement &&
|
|
442
|
+
!event.target.contains(editable) &&
|
|
443
|
+
// Vitest simply ignores stopPropagation, capture-mode, or rAF
|
|
444
|
+
// so without introducing crazier hacks, nothing we can do
|
|
445
|
+
!isTestEnv()) {
|
|
446
|
+
// On mobile, blur event doesn't seem to always fire correctly,
|
|
447
|
+
// so we want to also submit on pointerdown outside the wysiwyg.
|
|
448
|
+
// Done in the next frame to prevent pointerdown from creating a new text
|
|
449
|
+
// immediately (if tools locked) so that users on mobile have chance
|
|
450
|
+
// to submit first (to hide virtual keyboard).
|
|
451
|
+
// Note: revisit if we want to differ this behavior on Desktop
|
|
452
|
+
requestAnimationFrame(() => {
|
|
453
|
+
handleSubmit();
|
|
454
|
+
});
|
|
455
|
+
}
|
|
442
456
|
};
|
|
443
457
|
// handle updates of textElement properties of editing element
|
|
444
|
-
const unbindUpdate = Scene.getScene(element).
|
|
458
|
+
const unbindUpdate = Scene.getScene(element).onUpdate(() => {
|
|
445
459
|
updateWysiwygStyle();
|
|
446
460
|
const isColorPickerActive = !!document.activeElement?.closest(".color-picker-content");
|
|
447
461
|
if (!isColorPickerActive) {
|
|
@@ -450,9 +464,11 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
450
464
|
});
|
|
451
465
|
// ---------------------------------------------------------------------------
|
|
452
466
|
let isDestroyed = false;
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
467
|
+
if (autoSelect) {
|
|
468
|
+
// select on init (focusing is done separately inside the bindBlurEvent()
|
|
469
|
+
// because we need it to happen *after* the blur event from `pointerdown`)
|
|
470
|
+
editable.select();
|
|
471
|
+
}
|
|
456
472
|
bindBlurEvent();
|
|
457
473
|
// reposition wysiwyg in case of canvas is resized. Using ResizeObserver
|
|
458
474
|
// is preferred so we catch changes from host, where window may not resize.
|
|
@@ -466,7 +482,12 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
466
482
|
else {
|
|
467
483
|
window.addEventListener("resize", updateWysiwygStyle);
|
|
468
484
|
}
|
|
469
|
-
|
|
485
|
+
editable.onpointerdown = (event) => event.stopPropagation();
|
|
486
|
+
// rAF (+ capture to by doubly sure) so we don't catch te pointerdown that
|
|
487
|
+
// triggered the wysiwyg
|
|
488
|
+
requestAnimationFrame(() => {
|
|
489
|
+
window.addEventListener("pointerdown", onPointerDown, { capture: true });
|
|
490
|
+
});
|
|
470
491
|
window.addEventListener("wheel", stopEvent, {
|
|
471
492
|
passive: false,
|
|
472
493
|
capture: true,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getElementAbsoluteCoords } from "./bounds";
|
|
2
2
|
import { rotate } from "../math";
|
|
3
|
-
import { isTextElement } from ".";
|
|
4
3
|
import { isFrameLikeElement, isLinearElement } from "./typeChecks";
|
|
5
4
|
import { DEFAULT_TRANSFORM_HANDLE_SPACING, isAndroid, isIOS, } from "../constants";
|
|
6
5
|
const transformHandleSizes = {
|
|
@@ -28,12 +27,6 @@ export const OMIT_SIDES_FOR_FRAME = {
|
|
|
28
27
|
w: true,
|
|
29
28
|
rotation: true,
|
|
30
29
|
};
|
|
31
|
-
const OMIT_SIDES_FOR_TEXT_ELEMENT = {
|
|
32
|
-
e: true,
|
|
33
|
-
s: true,
|
|
34
|
-
n: true,
|
|
35
|
-
w: true,
|
|
36
|
-
};
|
|
37
30
|
const OMIT_SIDES_FOR_LINE_SLASH = {
|
|
38
31
|
e: true,
|
|
39
32
|
s: true,
|
|
@@ -147,9 +140,6 @@ export const getTransformHandles = (element, zoom, elementsMap, pointerType = "m
|
|
|
147
140
|
}
|
|
148
141
|
}
|
|
149
142
|
}
|
|
150
|
-
else if (isTextElement(element)) {
|
|
151
|
-
omitSides = OMIT_SIDES_FOR_TEXT_ELEMENT;
|
|
152
|
-
}
|
|
153
143
|
else if (isFrameLikeElement(element)) {
|
|
154
144
|
omitSides = {
|
|
155
145
|
...omitSides,
|
|
@@ -154,6 +154,13 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase & Readonly<{
|
|
|
154
154
|
verticalAlign: VerticalAlign;
|
|
155
155
|
containerId: ExcalidrawGenericElement["id"] | null;
|
|
156
156
|
originalText: string;
|
|
157
|
+
/**
|
|
158
|
+
* If `true` the width will fit the text. If `false`, the text will
|
|
159
|
+
* wrap to fit the width.
|
|
160
|
+
*
|
|
161
|
+
* @default true
|
|
162
|
+
*/
|
|
163
|
+
autoResize: boolean;
|
|
157
164
|
/**
|
|
158
165
|
* Unitless line height (aligned to W3C). To get line height in px, multiply
|
|
159
166
|
* with font size (using `getLineHeightInPx` helper).
|
|
@@ -97,12 +97,10 @@ const getMovedIndicesGroups = (elements, movedElements) => {
|
|
|
97
97
|
const indicesGroups = [];
|
|
98
98
|
let i = 0;
|
|
99
99
|
while (i < elements.length) {
|
|
100
|
-
if (movedElements.has(elements[i].id)
|
|
101
|
-
!isValidFractionalIndex(elements[i]?.index, elements[i - 1]?.index, elements[i + 1]?.index)) {
|
|
100
|
+
if (movedElements.has(elements[i].id)) {
|
|
102
101
|
const indicesGroup = [i - 1, i]; // push the lower bound index as the first item
|
|
103
102
|
while (++i < elements.length) {
|
|
104
|
-
if (!
|
|
105
|
-
!isValidFractionalIndex(elements[i]?.index, elements[i - 1]?.index, elements[i + 1]?.index))) {
|
|
103
|
+
if (!movedElements.has(elements[i].id)) {
|
|
106
104
|
break;
|
|
107
105
|
}
|
|
108
106
|
indicesGroup.push(i);
|
|
@@ -148,7 +148,9 @@
|
|
|
148
148
|
"discordChat": "Discord chat",
|
|
149
149
|
"zoomToFitViewport": "Zoom to fit in viewport",
|
|
150
150
|
"zoomToFitSelection": "Zoom to fit selection",
|
|
151
|
-
"zoomToFit": "Zoom to fit all elements"
|
|
151
|
+
"zoomToFit": "Zoom to fit all elements",
|
|
152
|
+
"installPWA": "Install Excalidraw locally (PWA)",
|
|
153
|
+
"autoResize": "Enable text auto-resizing"
|
|
152
154
|
},
|
|
153
155
|
"library": {
|
|
154
156
|
"noItems": "No items added yet...",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** heuristically checks whether the text may be a mermaid diagram definition */
|
|
2
|
+
export const isMaybeMermaidDefinition = (text) => {
|
|
3
|
+
const chartTypes = [
|
|
4
|
+
"flowchart",
|
|
5
|
+
"sequenceDiagram",
|
|
6
|
+
"classDiagram",
|
|
7
|
+
"stateDiagram",
|
|
8
|
+
"stateDiagram-v2",
|
|
9
|
+
"erDiagram",
|
|
10
|
+
"journey",
|
|
11
|
+
"gantt",
|
|
12
|
+
"pie",
|
|
13
|
+
"quadrantChart",
|
|
14
|
+
"requirementDiagram",
|
|
15
|
+
"gitGraph",
|
|
16
|
+
"C4Context",
|
|
17
|
+
"mindmap",
|
|
18
|
+
"timeline",
|
|
19
|
+
"zenuml",
|
|
20
|
+
"sankey",
|
|
21
|
+
"xychart",
|
|
22
|
+
"block",
|
|
23
|
+
];
|
|
24
|
+
const re = new RegExp(`^(?:%%{.*?}%%[\\s\\n]*)?\\b${chartTypes
|
|
25
|
+
.map((x) => `${x}(-beta)?`)
|
|
26
|
+
.join("|")}\\b`);
|
|
27
|
+
return re.test(text.trim());
|
|
28
|
+
};
|
|
@@ -9,7 +9,7 @@ export declare const renderInteractiveSceneThrottled: {
|
|
|
9
9
|
* Interactive scene is the ui-canvas where we render bounding boxes, selections
|
|
10
10
|
* and other ui stuff.
|
|
11
11
|
*/
|
|
12
|
-
export declare const renderInteractiveScene: <U extends ({ canvas, elementsMap, visibleElements, selectedElements, scale, appState, renderConfig, device, }: InteractiveSceneRenderConfig) => {
|
|
12
|
+
export declare const renderInteractiveScene: <U extends ({ canvas, elementsMap, visibleElements, selectedElements, allElementsMap, scale, appState, renderConfig, device, }: InteractiveSceneRenderConfig) => {
|
|
13
13
|
atLeastOneVisibleElement: boolean;
|
|
14
14
|
elementsMap: RenderableElementsMap;
|
|
15
15
|
scrollBars?: undefined;
|
|
@@ -12,7 +12,7 @@ import { maxBindingGap } from "../element/binding";
|
|
|
12
12
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
|
13
13
|
import { bootstrapCanvas, fillCircle, getNormalizedCanvasDimensions, } from "./helpers";
|
|
14
14
|
import oc from "open-color";
|
|
15
|
-
import { isFrameLikeElement, isLinearElement } from "../element/typeChecks";
|
|
15
|
+
import { isFrameLikeElement, isLinearElement, isTextElement, } from "../element/typeChecks";
|
|
16
16
|
const renderLinearElementPointHighlight = (context, appState, elementsMap) => {
|
|
17
17
|
const { elementId, hoverPointIndex } = appState.selectedLinearElement;
|
|
18
18
|
if (appState.editingLinearElement?.selectedPointsIndices?.includes(hoverPointIndex)) {
|
|
@@ -124,10 +124,11 @@ const renderBindingHighlightForSuggestedPointBinding = (context, suggestedBindin
|
|
|
124
124
|
fillCircle(context, x, y, threshold);
|
|
125
125
|
});
|
|
126
126
|
};
|
|
127
|
-
const renderSelectionBorder = (context, appState, elementProperties
|
|
127
|
+
const renderSelectionBorder = (context, appState, elementProperties) => {
|
|
128
128
|
const { angle, elementX1, elementY1, elementX2, elementY2, selectionColors, cx, cy, dashed, activeEmbeddable, } = elementProperties;
|
|
129
129
|
const elementWidth = elementX2 - elementX1;
|
|
130
130
|
const elementHeight = elementY2 - elementY1;
|
|
131
|
+
const padding = DEFAULT_TRANSFORM_HANDLE_SPACING * 2;
|
|
131
132
|
const linePadding = padding / appState.zoom.value;
|
|
132
133
|
const lineWidth = 8 / appState.zoom.value;
|
|
133
134
|
const spaceWidth = 4 / appState.zoom.value;
|
|
@@ -264,7 +265,23 @@ const renderTransformHandles = (context, renderConfig, appState, transformHandle
|
|
|
264
265
|
}
|
|
265
266
|
});
|
|
266
267
|
};
|
|
267
|
-
const
|
|
268
|
+
const renderTextBox = (text, context, appState, selectionColor) => {
|
|
269
|
+
context.save();
|
|
270
|
+
const padding = (DEFAULT_TRANSFORM_HANDLE_SPACING * 2) / appState.zoom.value;
|
|
271
|
+
const width = text.width + padding * 2;
|
|
272
|
+
const height = text.height + padding * 2;
|
|
273
|
+
const cx = text.x + width / 2;
|
|
274
|
+
const cy = text.y + height / 2;
|
|
275
|
+
const shiftX = -(width / 2 + padding);
|
|
276
|
+
const shiftY = -(height / 2 + padding);
|
|
277
|
+
context.translate(cx + appState.scrollX, cy + appState.scrollY);
|
|
278
|
+
context.rotate(text.angle);
|
|
279
|
+
context.lineWidth = 1 / appState.zoom.value;
|
|
280
|
+
context.strokeStyle = selectionColor;
|
|
281
|
+
context.strokeRect(shiftX, shiftY, width, height);
|
|
282
|
+
context.restore();
|
|
283
|
+
};
|
|
284
|
+
const _renderInteractiveScene = ({ canvas, elementsMap, visibleElements, selectedElements, allElementsMap, scale, appState, renderConfig, device, }) => {
|
|
268
285
|
if (canvas === null) {
|
|
269
286
|
return { atLeastOneVisibleElement: false, elementsMap };
|
|
270
287
|
}
|
|
@@ -295,12 +312,18 @@ const _renderInteractiveScene = ({ canvas, elementsMap, visibleElements, selecte
|
|
|
295
312
|
// Paint selection element
|
|
296
313
|
if (appState.selectionElement) {
|
|
297
314
|
try {
|
|
298
|
-
renderSelectionElement(appState.selectionElement, context, appState);
|
|
315
|
+
renderSelectionElement(appState.selectionElement, context, appState, renderConfig.selectionColor);
|
|
299
316
|
}
|
|
300
317
|
catch (error) {
|
|
301
318
|
console.error(error);
|
|
302
319
|
}
|
|
303
320
|
}
|
|
321
|
+
if (appState.editingElement && isTextElement(appState.editingElement)) {
|
|
322
|
+
const textElement = allElementsMap.get(appState.editingElement.id);
|
|
323
|
+
if (textElement && !textElement.autoResize) {
|
|
324
|
+
renderTextBox(textElement, context, appState, renderConfig.selectionColor);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
304
327
|
if (appState.isBindingEnabled) {
|
|
305
328
|
appState.suggestedBindings
|
|
306
329
|
.filter((binding) => binding != null)
|
|
@@ -405,7 +428,10 @@ const _renderInteractiveScene = ({ canvas, elementsMap, visibleElements, selecte
|
|
|
405
428
|
context.fillStyle = oc.white;
|
|
406
429
|
const transformHandles = getTransformHandles(selectedElements[0], appState.zoom, elementsMap, "mouse", // when we render we don't know which pointer type so use mouse,
|
|
407
430
|
getOmitSidesForDevice(device));
|
|
408
|
-
if (!appState.viewModeEnabled &&
|
|
431
|
+
if (!appState.viewModeEnabled &&
|
|
432
|
+
showBoundingBox &&
|
|
433
|
+
// do not show transform handles when text is being edited
|
|
434
|
+
!isTextElement(appState.editingElement)) {
|
|
409
435
|
renderTransformHandles(context, renderConfig, appState, transformHandles, selectedElements[0].angle);
|
|
410
436
|
}
|
|
411
437
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExcalidrawElement, ExcalidrawTextElement, NonDeletedExcalidrawElement, ExcalidrawFreeDrawElement, ExcalidrawFrameLikeElement, NonDeletedSceneElementsMap } from "../element/types";
|
|
2
2
|
import type { RoughCanvas } from "roughjs/bin/canvas";
|
|
3
|
-
import type { StaticCanvasRenderConfig, RenderableElementsMap } from "../scene/types";
|
|
3
|
+
import type { StaticCanvasRenderConfig, RenderableElementsMap, InteractiveCanvasRenderConfig } from "../scene/types";
|
|
4
4
|
import type { AppState, StaticCanvasAppState, InteractiveCanvasAppState, ElementsPendingErasure } from "../types";
|
|
5
5
|
export declare const IMAGE_INVERT_FILTER = "invert(100%) hue-rotate(180deg) saturate(1.25)";
|
|
6
6
|
export declare const getRenderOpacity: (element: ExcalidrawElement, containingFrame: ExcalidrawFrameLikeElement | null, elementsPendingErasure: ElementsPendingErasure) => number;
|
|
@@ -17,7 +17,7 @@ export interface ExcalidrawElementWithCanvas {
|
|
|
17
17
|
}
|
|
18
18
|
export declare const DEFAULT_LINK_SIZE = 14;
|
|
19
19
|
export declare const elementWithCanvasCache: WeakMap<ExcalidrawElement, ExcalidrawElementWithCanvas>;
|
|
20
|
-
export declare const renderSelectionElement: (element: NonDeletedExcalidrawElement, context: CanvasRenderingContext2D, appState: InteractiveCanvasAppState) => void;
|
|
20
|
+
export declare const renderSelectionElement: (element: NonDeletedExcalidrawElement, context: CanvasRenderingContext2D, appState: InteractiveCanvasAppState, selectionColor: InteractiveCanvasRenderConfig["selectionColor"]) => void;
|
|
21
21
|
export declare const renderElement: (element: NonDeletedExcalidrawElement, elementsMap: RenderableElementsMap, allElementsMap: NonDeletedSceneElementsMap, rc: RoughCanvas, context: CanvasRenderingContext2D, renderConfig: StaticCanvasRenderConfig, appState: StaticCanvasAppState) => void;
|
|
22
22
|
export declare const pathsCache: WeakMap<ExcalidrawFreeDrawElement, Path2D>;
|
|
23
23
|
export declare function generateFreeDrawShape(element: ExcalidrawFreeDrawElement): Path2D;
|
|
@@ -323,7 +323,7 @@ const drawElementFromCanvas = (elementWithCanvas, context, renderConfig, appStat
|
|
|
323
323
|
context.restore();
|
|
324
324
|
// Clear the nested element we appended to the DOM
|
|
325
325
|
};
|
|
326
|
-
export const renderSelectionElement = (element, context, appState) => {
|
|
326
|
+
export const renderSelectionElement = (element, context, appState, selectionColor) => {
|
|
327
327
|
context.save();
|
|
328
328
|
context.translate(element.x + appState.scrollX, element.y + appState.scrollY);
|
|
329
329
|
context.fillStyle = "rgba(0, 0, 200, 0.04)";
|
|
@@ -334,7 +334,7 @@ export const renderSelectionElement = (element, context, appState) => {
|
|
|
334
334
|
const offset = 0.5 / appState.zoom.value;
|
|
335
335
|
context.fillRect(offset, offset, element.width, element.height);
|
|
336
336
|
context.lineWidth = 1 / appState.zoom.value;
|
|
337
|
-
context.strokeStyle =
|
|
337
|
+
context.strokeStyle = selectionColor;
|
|
338
338
|
context.strokeRect(offset, offset, element.width, element.height);
|
|
339
339
|
context.restore();
|
|
340
340
|
};
|
|
@@ -2,10 +2,8 @@ import type { ExcalidrawElement } from "../element/types";
|
|
|
2
2
|
import type Scene from "./Scene";
|
|
3
3
|
export declare class Fonts {
|
|
4
4
|
private scene;
|
|
5
|
-
|
|
6
|
-
constructor({ scene, onSceneUpdated, }: {
|
|
5
|
+
constructor({ scene }: {
|
|
7
6
|
scene: Scene;
|
|
8
|
-
onSceneUpdated: () => void;
|
|
9
7
|
});
|
|
10
8
|
private static loadedFontFaces;
|
|
11
9
|
/**
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { isTextElement
|
|
1
|
+
import { isTextElement } from "../element";
|
|
2
2
|
import { newElementWith } from "../element/mutateElement";
|
|
3
|
-
import { getContainerElement } from "../element/textElement";
|
|
4
|
-
import { isBoundToContainer } from "../element/typeChecks";
|
|
5
3
|
import { getFontString } from "../utils";
|
|
6
4
|
import { ShapeCache } from "./ShapeCache";
|
|
7
5
|
export class Fonts {
|
|
8
6
|
scene;
|
|
9
|
-
|
|
10
|
-
constructor({ scene, onSceneUpdated, }) {
|
|
7
|
+
constructor({ scene }) {
|
|
11
8
|
this.scene = scene;
|
|
12
|
-
this.onSceneUpdated = onSceneUpdated;
|
|
13
9
|
}
|
|
14
10
|
// it's ok to track fonts across multiple instances only once, so let's use
|
|
15
11
|
// a static member to reduce memory footprint
|
|
@@ -39,17 +35,15 @@ export class Fonts {
|
|
|
39
35
|
}
|
|
40
36
|
let didUpdate = false;
|
|
41
37
|
this.scene.mapElements((element) => {
|
|
42
|
-
if (isTextElement(element)
|
|
43
|
-
ShapeCache.delete(element);
|
|
38
|
+
if (isTextElement(element)) {
|
|
44
39
|
didUpdate = true;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
});
|
|
40
|
+
ShapeCache.delete(element);
|
|
41
|
+
return newElementWith(element, {}, true);
|
|
48
42
|
}
|
|
49
43
|
return element;
|
|
50
44
|
});
|
|
51
45
|
if (didUpdate) {
|
|
52
|
-
this.
|
|
46
|
+
this.scene.triggerUpdate();
|
|
53
47
|
}
|
|
54
48
|
};
|
|
55
49
|
loadFontsForElements = async (elements) => {
|
|
@@ -14,7 +14,7 @@ export declare class Renderer {
|
|
|
14
14
|
width: AppState["width"];
|
|
15
15
|
editingElement: AppState["editingElement"];
|
|
16
16
|
pendingImageElementId: AppState["pendingImageElementId"];
|
|
17
|
-
|
|
17
|
+
sceneNonce: ReturnType<InstanceType<typeof Scene>["getSceneNonce"]>;
|
|
18
18
|
}) => {
|
|
19
19
|
elementsMap: Map<string, NonDeletedExcalidrawElement> & import("../utility-types").MakeBrand<"NonDeletedElementsMap"> & import("../utility-types").MakeBrand<"RenderableElementsMap">;
|
|
20
20
|
visibleElements: readonly NonDeletedExcalidrawElement[];
|
|
@@ -45,9 +45,8 @@ export class Renderer {
|
|
|
45
45
|
return elementsMap;
|
|
46
46
|
};
|
|
47
47
|
return memoize(({ zoom, offsetLeft, offsetTop, scrollX, scrollY, height, width, editingElement, pendingImageElementId,
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
versionNonce: _versionNonce, }) => {
|
|
48
|
+
// cache-invalidation nonce
|
|
49
|
+
sceneNonce: _sceneNonce, }) => {
|
|
51
50
|
const elements = this.scene.getNonDeletedElements();
|
|
52
51
|
const elementsMap = getRenderableElements({
|
|
53
52
|
elements,
|
|
@@ -19,7 +19,14 @@ declare class Scene {
|
|
|
19
19
|
private frames;
|
|
20
20
|
private elementsMap;
|
|
21
21
|
private selectedElementsCache;
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Random integer regenerated each scene update.
|
|
24
|
+
*
|
|
25
|
+
* Does not relate to elements versions, it's only a renderer
|
|
26
|
+
* cache-invalidation nonce at the moment.
|
|
27
|
+
*/
|
|
28
|
+
private sceneNonce;
|
|
29
|
+
getSceneNonce(): number | undefined;
|
|
23
30
|
getNonDeletedElementsMap(): Map<string, Ordered<NonDeletedExcalidrawElement>> & import("../utility-types").MakeBrand<"NonDeletedSceneElementsMap">;
|
|
24
31
|
getElementsIncludingDeleted(): readonly OrderedExcalidrawElement[];
|
|
25
32
|
getElementsMapIncludingDeleted(): Map<string, Ordered<ExcalidrawElement>> & import("../utility-types").MakeBrand<"SceneElementsMap">;
|
|
@@ -38,7 +45,6 @@ declare class Scene {
|
|
|
38
45
|
}): NonDeleted<ExcalidrawElement>[];
|
|
39
46
|
getNonDeletedFramesLikes(): readonly NonDeleted<ExcalidrawFrameLikeElement>[];
|
|
40
47
|
getElement<T extends ExcalidrawElement>(id: T["id"]): T | null;
|
|
41
|
-
getVersionNonce(): number | undefined;
|
|
42
48
|
getNonDeletedElement(id: ExcalidrawElement["id"]): NonDeleted<ExcalidrawElement> | null;
|
|
43
49
|
/**
|
|
44
50
|
* A utility method to help with updating all scene elements, with the added
|
|
@@ -54,8 +60,8 @@ declare class Scene {
|
|
|
54
60
|
*/
|
|
55
61
|
mapElements(iteratee: (element: ExcalidrawElement) => ExcalidrawElement): boolean;
|
|
56
62
|
replaceAllElements(nextElements: ElementsMapOrArray): void;
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
triggerUpdate(): void;
|
|
64
|
+
onUpdate(cb: SceneStateCallback): SceneStateCallbackRemover;
|
|
59
65
|
destroy(): void;
|
|
60
66
|
insertElementAtIndex(element: ExcalidrawElement, index: number): void;
|
|
61
67
|
insertElementsAtIndex(elements: ExcalidrawElement[], index: number): void;
|
|
@@ -72,7 +72,16 @@ class Scene {
|
|
|
72
72
|
elements: null,
|
|
73
73
|
cache: new Map(),
|
|
74
74
|
};
|
|
75
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Random integer regenerated each scene update.
|
|
77
|
+
*
|
|
78
|
+
* Does not relate to elements versions, it's only a renderer
|
|
79
|
+
* cache-invalidation nonce at the moment.
|
|
80
|
+
*/
|
|
81
|
+
sceneNonce;
|
|
82
|
+
getSceneNonce() {
|
|
83
|
+
return this.sceneNonce;
|
|
84
|
+
}
|
|
76
85
|
getNonDeletedElementsMap() {
|
|
77
86
|
return this.nonDeletedElementsMap;
|
|
78
87
|
}
|
|
@@ -118,9 +127,6 @@ class Scene {
|
|
|
118
127
|
getElement(id) {
|
|
119
128
|
return this.elementsMap.get(id) || null;
|
|
120
129
|
}
|
|
121
|
-
getVersionNonce() {
|
|
122
|
-
return this.versionNonce;
|
|
123
|
-
}
|
|
124
130
|
getNonDeletedElement(id) {
|
|
125
131
|
const element = this.getElement(id);
|
|
126
132
|
if (element && isNonDeletedElement(element)) {
|
|
@@ -179,15 +185,15 @@ class Scene {
|
|
|
179
185
|
this.nonDeletedElementsMap = nonDeletedElements.elementsMap;
|
|
180
186
|
this.frames = nextFrameLikes;
|
|
181
187
|
this.nonDeletedFramesLikes = getNonDeletedElements(this.frames).elements;
|
|
182
|
-
this.
|
|
188
|
+
this.triggerUpdate();
|
|
183
189
|
}
|
|
184
|
-
|
|
185
|
-
this.
|
|
190
|
+
triggerUpdate() {
|
|
191
|
+
this.sceneNonce = randomInteger();
|
|
186
192
|
for (const callback of Array.from(this.callbacks)) {
|
|
187
193
|
callback();
|
|
188
194
|
}
|
|
189
195
|
}
|
|
190
|
-
|
|
196
|
+
onUpdate(cb) {
|
|
191
197
|
if (this.callbacks.has(cb)) {
|
|
192
198
|
throw new Error();
|
|
193
199
|
}
|
|
@@ -200,7 +200,7 @@ export const exportToSvg = async (elements, appState, files, opts) => {
|
|
|
200
200
|
if (import.meta.env.VITE_IS_EXCALIDRAW_NPM_PACKAGE) {
|
|
201
201
|
assetPath =
|
|
202
202
|
window.EXCALIDRAW_ASSET_PATH ||
|
|
203
|
-
`https://unpkg.com/${import.meta.env.VITE_PKG_NAME}@${import.meta.env.
|
|
203
|
+
`https://unpkg.com/${import.meta.env.VITE_PKG_NAME}@${import.meta.env.VITE_PKG_VERSION}`;
|
|
204
204
|
if (assetPath?.startsWith("/")) {
|
|
205
205
|
assetPath = assetPath.replace("/", `${window.location.origin}/`);
|
|
206
206
|
}
|
|
@@ -33,7 +33,7 @@ export type InteractiveCanvasRenderConfig = {
|
|
|
33
33
|
remotePointerUserStates: Map<SocketId, UserIdleState>;
|
|
34
34
|
remotePointerUsernames: Map<SocketId, string>;
|
|
35
35
|
remotePointerButton: Map<SocketId, string | undefined>;
|
|
36
|
-
selectionColor
|
|
36
|
+
selectionColor: string;
|
|
37
37
|
renderScrollbars?: boolean;
|
|
38
38
|
};
|
|
39
39
|
export type RenderInteractiveSceneCallback = {
|
|
@@ -56,6 +56,7 @@ export type InteractiveSceneRenderConfig = {
|
|
|
56
56
|
elementsMap: RenderableElementsMap;
|
|
57
57
|
visibleElements: readonly NonDeletedExcalidrawElement[];
|
|
58
58
|
selectedElements: readonly NonDeletedExcalidrawElement[];
|
|
59
|
+
allElementsMap: NonDeletedSceneElementsMap;
|
|
59
60
|
scale: number;
|
|
60
61
|
appState: InteractiveCanvasAppState;
|
|
61
62
|
renderConfig: InteractiveCanvasRenderConfig;
|
|
@@ -835,5 +835,6 @@ export const isActiveToolNonLinearSnappable = (activeToolType) => {
|
|
|
835
835
|
activeToolType === TOOL_TYPE.diamond ||
|
|
836
836
|
activeToolType === TOOL_TYPE.frame ||
|
|
837
837
|
activeToolType === TOOL_TYPE.magicframe ||
|
|
838
|
-
activeToolType === TOOL_TYPE.image
|
|
838
|
+
activeToolType === TOOL_TYPE.image ||
|
|
839
|
+
activeToolType === TOOL_TYPE.text);
|
|
839
840
|
};
|
|
@@ -2,11 +2,41 @@ import { AppStateChange, ElementsChange } from "./change";
|
|
|
2
2
|
import type { OrderedExcalidrawElement } from "./element/types";
|
|
3
3
|
import { Emitter } from "./emitter";
|
|
4
4
|
import type { AppState, ObservedAppState } from "./types";
|
|
5
|
+
import type { ValueOf } from "./utility-types";
|
|
5
6
|
export declare const getObservedAppState: (appState: AppState) => ObservedAppState;
|
|
6
|
-
export type StoreActionType = "capture" | "update" | "none";
|
|
7
7
|
export declare const StoreAction: {
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Immediately undoable.
|
|
10
|
+
*
|
|
11
|
+
* Use for updates which should be captured.
|
|
12
|
+
* Should be used for most of the local updates.
|
|
13
|
+
*
|
|
14
|
+
* These updates will _immediately_ make it to the local undo / redo stacks.
|
|
15
|
+
*/
|
|
16
|
+
readonly CAPTURE: "capture";
|
|
17
|
+
/**
|
|
18
|
+
* Never undoable.
|
|
19
|
+
*
|
|
20
|
+
* Use for updates which should never be recorded, such as remote updates
|
|
21
|
+
* or scene initialization.
|
|
22
|
+
*
|
|
23
|
+
* These updates will _never_ make it to the local undo / redo stacks.
|
|
24
|
+
*/
|
|
25
|
+
readonly UPDATE: "update";
|
|
26
|
+
/**
|
|
27
|
+
* Eventually undoable.
|
|
28
|
+
*
|
|
29
|
+
* Use for updates which should not be captured immediately - likely
|
|
30
|
+
* exceptions which are part of some async multi-step process. Otherwise, all
|
|
31
|
+
* such updates would end up being captured with the next
|
|
32
|
+
* `StoreAction.CAPTURE` - triggered either by the next `updateScene`
|
|
33
|
+
* or internally by the editor.
|
|
34
|
+
*
|
|
35
|
+
* These updates will _eventually_ make it to the local undo / redo stacks.
|
|
36
|
+
*/
|
|
37
|
+
readonly NONE: "none";
|
|
9
38
|
};
|
|
39
|
+
export type StoreActionType = ValueOf<typeof StoreAction>;
|
|
10
40
|
/**
|
|
11
41
|
* Represent an increment to the Store.
|
|
12
42
|
*/
|
package/dist/excalidraw/store.js
CHANGED
|
@@ -25,8 +25,35 @@ export const getObservedAppState = (appState) => {
|
|
|
25
25
|
};
|
|
26
26
|
const isObservedAppState = (appState) => !!Reflect.get(appState, hiddenObservedAppStateProp);
|
|
27
27
|
export const StoreAction = {
|
|
28
|
+
/**
|
|
29
|
+
* Immediately undoable.
|
|
30
|
+
*
|
|
31
|
+
* Use for updates which should be captured.
|
|
32
|
+
* Should be used for most of the local updates.
|
|
33
|
+
*
|
|
34
|
+
* These updates will _immediately_ make it to the local undo / redo stacks.
|
|
35
|
+
*/
|
|
28
36
|
CAPTURE: "capture",
|
|
37
|
+
/**
|
|
38
|
+
* Never undoable.
|
|
39
|
+
*
|
|
40
|
+
* Use for updates which should never be recorded, such as remote updates
|
|
41
|
+
* or scene initialization.
|
|
42
|
+
*
|
|
43
|
+
* These updates will _never_ make it to the local undo / redo stacks.
|
|
44
|
+
*/
|
|
29
45
|
UPDATE: "update",
|
|
46
|
+
/**
|
|
47
|
+
* Eventually undoable.
|
|
48
|
+
*
|
|
49
|
+
* Use for updates which should not be captured immediately - likely
|
|
50
|
+
* exceptions which are part of some async multi-step process. Otherwise, all
|
|
51
|
+
* such updates would end up being captured with the next
|
|
52
|
+
* `StoreAction.CAPTURE` - triggered either by the next `updateScene`
|
|
53
|
+
* or internally by the editor.
|
|
54
|
+
*
|
|
55
|
+
* These updates will _eventually_ make it to the local undo / redo stacks.
|
|
56
|
+
*/
|
|
30
57
|
NONE: "none",
|
|
31
58
|
};
|
|
32
59
|
/**
|
|
@@ -134,6 +134,7 @@ export type InteractiveCanvasAppState = Readonly<_CommonCanvasAppState & {
|
|
|
134
134
|
collaborators: AppState["collaborators"];
|
|
135
135
|
snapLines: AppState["snapLines"];
|
|
136
136
|
zenModeEnabled: AppState["zenModeEnabled"];
|
|
137
|
+
editingElement: AppState["editingElement"];
|
|
137
138
|
}>;
|
|
138
139
|
export type ObservedAppState = ObservedStandaloneAppState & ObservedElementsAppState;
|
|
139
140
|
export type ObservedStandaloneAppState = {
|