mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-10-24 16:34:24 +02:00
Merge branch 'master' into mtolmacs/feat/fixed-point-simple-arrow-binding
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
version: "3.8"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
excalidraw:
|
excalidraw:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -545,3 +545,8 @@ export const LINE_POLYGON_POINT_MERGE_DISTANCE = 20;
|
|||||||
export const DOUBLE_TAP_POSITION_THRESHOLD = 35;
|
export const DOUBLE_TAP_POSITION_THRESHOLD = 35;
|
||||||
|
|
||||||
export const BIND_MODE_TIMEOUT = 700; // ms
|
export const BIND_MODE_TIMEOUT = 700; // ms
|
||||||
|
|
||||||
|
// glass background for mobile action buttons
|
||||||
|
export const MOBILE_ACTION_BUTTON_BG = {
|
||||||
|
background: "var(--mobile-action-button-bg)",
|
||||||
|
} as const;
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ export const hasBackground = (type: ElementOrToolType) =>
|
|||||||
type === "freedraw";
|
type === "freedraw";
|
||||||
|
|
||||||
export const hasStrokeColor = (type: ElementOrToolType) =>
|
export const hasStrokeColor = (type: ElementOrToolType) =>
|
||||||
type !== "image" && type !== "frame" && type !== "magicframe";
|
type === "rectangle" ||
|
||||||
|
type === "ellipse" ||
|
||||||
|
type === "diamond" ||
|
||||||
|
type === "freedraw" ||
|
||||||
|
type === "arrow" ||
|
||||||
|
type === "line" ||
|
||||||
|
type === "text";
|
||||||
|
|
||||||
export const hasStrokeWidth = (type: ElementOrToolType) =>
|
export const hasStrokeWidth = (type: ElementOrToolType) =>
|
||||||
type === "rectangle" ||
|
type === "rectangle" ||
|
||||||
|
|||||||
@@ -122,7 +122,10 @@ export const actionClearCanvas = register({
|
|||||||
pasteDialog: appState.pasteDialog,
|
pasteDialog: appState.pasteDialog,
|
||||||
activeTool:
|
activeTool:
|
||||||
appState.activeTool.type === "image"
|
appState.activeTool.type === "image"
|
||||||
? { ...appState.activeTool, type: app.defaultSelectionTool }
|
? {
|
||||||
|
...appState.activeTool,
|
||||||
|
type: app.state.preferredSelectionTool.type,
|
||||||
|
}
|
||||||
: appState.activeTool,
|
: appState.activeTool,
|
||||||
},
|
},
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
@@ -502,7 +505,7 @@ export const actionToggleEraserTool = register({
|
|||||||
if (isEraserActive(appState)) {
|
if (isEraserActive(appState)) {
|
||||||
activeTool = updateActiveTool(appState, {
|
activeTool = updateActiveTool(appState, {
|
||||||
...(appState.activeTool.lastActiveTool || {
|
...(appState.activeTool.lastActiveTool || {
|
||||||
type: app.defaultSelectionTool,
|
type: app.state.preferredSelectionTool.type,
|
||||||
}),
|
}),
|
||||||
lastActiveToolBeforeEraser: null,
|
lastActiveToolBeforeEraser: null,
|
||||||
});
|
});
|
||||||
@@ -533,7 +536,7 @@ export const actionToggleLassoTool = register({
|
|||||||
icon: LassoIcon,
|
icon: LassoIcon,
|
||||||
trackEvent: { category: "toolbar" },
|
trackEvent: { category: "toolbar" },
|
||||||
predicate: (elements, appState, props, app) => {
|
predicate: (elements, appState, props, app) => {
|
||||||
return app.defaultSelectionTool !== "lasso";
|
return app.state.preferredSelectionTool.type !== "lasso";
|
||||||
},
|
},
|
||||||
perform: (elements, appState, _, app) => {
|
perform: (elements, appState, _, app) => {
|
||||||
let activeTool: AppState["activeTool"];
|
let activeTool: AppState["activeTool"];
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { KEYS, updateActiveTool } from "@excalidraw/common";
|
import {
|
||||||
|
KEYS,
|
||||||
|
MOBILE_ACTION_BUTTON_BG,
|
||||||
|
updateActiveTool,
|
||||||
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import { getNonDeletedElements } from "@excalidraw/element";
|
import { getNonDeletedElements } from "@excalidraw/element";
|
||||||
import { fixBindingsAfterDeletion } from "@excalidraw/element";
|
import { fixBindingsAfterDeletion } from "@excalidraw/element";
|
||||||
@@ -281,7 +285,7 @@ export const actionDeleteSelected = register({
|
|||||||
appState: {
|
appState: {
|
||||||
...nextAppState,
|
...nextAppState,
|
||||||
activeTool: updateActiveTool(appState, {
|
activeTool: updateActiveTool(appState, {
|
||||||
type: app.defaultSelectionTool,
|
type: app.state.preferredSelectionTool.type,
|
||||||
}),
|
}),
|
||||||
multiElement: null,
|
multiElement: null,
|
||||||
newElement: null,
|
newElement: null,
|
||||||
@@ -306,7 +310,15 @@ export const actionDeleteSelected = register({
|
|||||||
title={t("labels.delete")}
|
title={t("labels.delete")}
|
||||||
aria-label={t("labels.delete")}
|
aria-label={t("labels.delete")}
|
||||||
onClick={() => updateData(null)}
|
onClick={() => updateData(null)}
|
||||||
visible={isSomeElementSelected(getNonDeletedElements(elements), appState)}
|
disabled={
|
||||||
|
!isSomeElementSelected(getNonDeletedElements(elements), appState)
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
...(appState.stylesPanelMode === "mobile" &&
|
||||||
|
appState.openPopup !== "compactOtherProperties"
|
||||||
|
? MOBILE_ACTION_BUTTON_BG
|
||||||
|
: {}),
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
DEFAULT_GRID_SIZE,
|
DEFAULT_GRID_SIZE,
|
||||||
KEYS,
|
KEYS,
|
||||||
|
MOBILE_ACTION_BUTTON_BG,
|
||||||
arrayToMap,
|
arrayToMap,
|
||||||
getShortcutKey,
|
getShortcutKey,
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
@@ -115,7 +116,15 @@ export const actionDuplicateSelection = register({
|
|||||||
)}`}
|
)}`}
|
||||||
aria-label={t("labels.duplicateSelection")}
|
aria-label={t("labels.duplicateSelection")}
|
||||||
onClick={() => updateData(null)}
|
onClick={() => updateData(null)}
|
||||||
visible={isSomeElementSelected(getNonDeletedElements(elements), appState)}
|
disabled={
|
||||||
|
!isSomeElementSelected(getNonDeletedElements(elements), appState)
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
...(appState.stylesPanelMode === "mobile" &&
|
||||||
|
appState.openPopup !== "compactOtherProperties"
|
||||||
|
? MOBILE_ACTION_BUTTON_BG
|
||||||
|
: {}),
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -267,13 +267,13 @@ export const actionFinalize = register<FormData>({
|
|||||||
if (appState.activeTool.type === "eraser") {
|
if (appState.activeTool.type === "eraser") {
|
||||||
activeTool = updateActiveTool(appState, {
|
activeTool = updateActiveTool(appState, {
|
||||||
...(appState.activeTool.lastActiveTool || {
|
...(appState.activeTool.lastActiveTool || {
|
||||||
type: app.defaultSelectionTool,
|
type: app.state.preferredSelectionTool.type,
|
||||||
}),
|
}),
|
||||||
lastActiveToolBeforeEraser: null,
|
lastActiveToolBeforeEraser: null,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
activeTool = updateActiveTool(appState, {
|
activeTool = updateActiveTool(appState, {
|
||||||
type: app.defaultSelectionTool,
|
type: app.state.preferredSelectionTool.type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import { isWindows, KEYS, matchKey, arrayToMap } from "@excalidraw/common";
|
import {
|
||||||
|
isWindows,
|
||||||
|
KEYS,
|
||||||
|
matchKey,
|
||||||
|
arrayToMap,
|
||||||
|
MOBILE_ACTION_BUTTON_BG,
|
||||||
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import { CaptureUpdateAction } from "@excalidraw/element";
|
import { CaptureUpdateAction } from "@excalidraw/element";
|
||||||
|
|
||||||
@@ -67,7 +73,7 @@ export const createUndoAction: ActionCreator = (history) => ({
|
|||||||
),
|
),
|
||||||
keyTest: (event) =>
|
keyTest: (event) =>
|
||||||
event[KEYS.CTRL_OR_CMD] && matchKey(event, KEYS.Z) && !event.shiftKey,
|
event[KEYS.CTRL_OR_CMD] && matchKey(event, KEYS.Z) && !event.shiftKey,
|
||||||
PanelComponent: ({ updateData, data }) => {
|
PanelComponent: ({ appState, updateData, data }) => {
|
||||||
const { isUndoStackEmpty } = useEmitter<HistoryChangedEvent>(
|
const { isUndoStackEmpty } = useEmitter<HistoryChangedEvent>(
|
||||||
history.onHistoryChangedEmitter,
|
history.onHistoryChangedEmitter,
|
||||||
new HistoryChangedEvent(
|
new HistoryChangedEvent(
|
||||||
@@ -85,6 +91,11 @@ export const createUndoAction: ActionCreator = (history) => ({
|
|||||||
size={data?.size || "medium"}
|
size={data?.size || "medium"}
|
||||||
disabled={isUndoStackEmpty}
|
disabled={isUndoStackEmpty}
|
||||||
data-testid="button-undo"
|
data-testid="button-undo"
|
||||||
|
style={{
|
||||||
|
...(appState.stylesPanelMode === "mobile"
|
||||||
|
? MOBILE_ACTION_BUTTON_BG
|
||||||
|
: {}),
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -103,7 +114,7 @@ export const createRedoAction: ActionCreator = (history) => ({
|
|||||||
keyTest: (event) =>
|
keyTest: (event) =>
|
||||||
(event[KEYS.CTRL_OR_CMD] && event.shiftKey && matchKey(event, KEYS.Z)) ||
|
(event[KEYS.CTRL_OR_CMD] && event.shiftKey && matchKey(event, KEYS.Z)) ||
|
||||||
(isWindows && event.ctrlKey && !event.shiftKey && matchKey(event, KEYS.Y)),
|
(isWindows && event.ctrlKey && !event.shiftKey && matchKey(event, KEYS.Y)),
|
||||||
PanelComponent: ({ updateData, data }) => {
|
PanelComponent: ({ appState, updateData, data }) => {
|
||||||
const { isRedoStackEmpty } = useEmitter(
|
const { isRedoStackEmpty } = useEmitter(
|
||||||
history.onHistoryChangedEmitter,
|
history.onHistoryChangedEmitter,
|
||||||
new HistoryChangedEvent(
|
new HistoryChangedEvent(
|
||||||
@@ -121,6 +132,11 @@ export const createRedoAction: ActionCreator = (history) => ({
|
|||||||
size={data?.size || "medium"}
|
size={data?.size || "medium"}
|
||||||
disabled={isRedoStackEmpty}
|
disabled={isRedoStackEmpty}
|
||||||
data-testid="button-redo"
|
data-testid="button-redo"
|
||||||
|
style={{
|
||||||
|
...(appState.stylesPanelMode === "mobile"
|
||||||
|
? MOBILE_ACTION_BUTTON_BG
|
||||||
|
: {}),
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -352,7 +352,10 @@ export const actionChangeStrokeColor = register<
|
|||||||
elements={elements}
|
elements={elements}
|
||||||
appState={appState}
|
appState={appState}
|
||||||
updateData={updateData}
|
updateData={updateData}
|
||||||
compactMode={appState.stylesPanelMode === "compact"}
|
compactMode={
|
||||||
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile"
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@@ -434,7 +437,10 @@ export const actionChangeBackgroundColor = register<
|
|||||||
elements={elements}
|
elements={elements}
|
||||||
appState={appState}
|
appState={appState}
|
||||||
updateData={updateData}
|
updateData={updateData}
|
||||||
compactMode={appState.stylesPanelMode === "compact"}
|
compactMode={
|
||||||
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile"
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@@ -539,9 +545,7 @@ export const actionChangeStrokeWidth = register<
|
|||||||
},
|
},
|
||||||
PanelComponent: ({ elements, appState, updateData, app, data }) => (
|
PanelComponent: ({ elements, appState, updateData, app, data }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
{appState.stylesPanelMode === "full" && (
|
<legend>{t("labels.strokeWidth")}</legend>
|
||||||
<legend>{t("labels.strokeWidth")}</legend>
|
|
||||||
)}
|
|
||||||
<div className="buttonList">
|
<div className="buttonList">
|
||||||
<RadioSelection
|
<RadioSelection
|
||||||
group="stroke-width"
|
group="stroke-width"
|
||||||
@@ -598,9 +602,7 @@ export const actionChangeSloppiness = register<ExcalidrawElement["roughness"]>({
|
|||||||
},
|
},
|
||||||
PanelComponent: ({ elements, appState, updateData, app, data }) => (
|
PanelComponent: ({ elements, appState, updateData, app, data }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
{appState.stylesPanelMode === "full" && (
|
<legend>{t("labels.sloppiness")}</legend>
|
||||||
<legend>{t("labels.sloppiness")}</legend>
|
|
||||||
)}
|
|
||||||
<div className="buttonList">
|
<div className="buttonList">
|
||||||
<RadioSelection
|
<RadioSelection
|
||||||
group="sloppiness"
|
group="sloppiness"
|
||||||
@@ -655,9 +657,7 @@ export const actionChangeStrokeStyle = register<
|
|||||||
},
|
},
|
||||||
PanelComponent: ({ elements, appState, updateData, app, data }) => (
|
PanelComponent: ({ elements, appState, updateData, app, data }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
{appState.stylesPanelMode === "full" && (
|
<legend>{t("labels.strokeStyle")}</legend>
|
||||||
<legend>{t("labels.strokeStyle")}</legend>
|
|
||||||
)}
|
|
||||||
<div className="buttonList">
|
<div className="buttonList">
|
||||||
<RadioSelection
|
<RadioSelection
|
||||||
group="strokeStyle"
|
group="strokeStyle"
|
||||||
@@ -734,7 +734,7 @@ export const actionChangeFontSize = register<ExcalidrawTextElement["fontSize"]>(
|
|||||||
value,
|
value,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
PanelComponent: ({ elements, appState, updateData, app }) => (
|
PanelComponent: ({ elements, appState, updateData, app, data }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{t("labels.fontSize")}</legend>
|
<legend>{t("labels.fontSize")}</legend>
|
||||||
<div className="buttonList">
|
<div className="buttonList">
|
||||||
@@ -793,7 +793,15 @@ export const actionChangeFontSize = register<ExcalidrawTextElement["fontSize"]>(
|
|||||||
? null
|
? null
|
||||||
: appState.currentItemFontSize || DEFAULT_FONT_SIZE,
|
: appState.currentItemFontSize || DEFAULT_FONT_SIZE,
|
||||||
)}
|
)}
|
||||||
onChange={(value) => updateData(value)}
|
onChange={(value) => {
|
||||||
|
withCaretPositionPreservation(
|
||||||
|
() => updateData(value),
|
||||||
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile",
|
||||||
|
!!appState.editingTextElement,
|
||||||
|
data?.onPreventClose,
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -1059,7 +1067,7 @@ export const actionChangeFontFamily = register<{
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
PanelComponent: ({ elements, appState, app, updateData, data }) => {
|
PanelComponent: ({ elements, appState, app, updateData }) => {
|
||||||
const cachedElementsRef = useRef<ElementsMap>(new Map());
|
const cachedElementsRef = useRef<ElementsMap>(new Map());
|
||||||
const prevSelectedFontFamilyRef = useRef<number | null>(null);
|
const prevSelectedFontFamilyRef = useRef<number | null>(null);
|
||||||
// relying on state batching as multiple `FontPicker` handlers could be called in rapid succession and we want to combine them
|
// relying on state batching as multiple `FontPicker` handlers could be called in rapid succession and we want to combine them
|
||||||
@@ -1136,7 +1144,7 @@ export const actionChangeFontFamily = register<{
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<fieldset>
|
<>
|
||||||
{appState.stylesPanelMode === "full" && (
|
{appState.stylesPanelMode === "full" && (
|
||||||
<legend>{t("labels.fontFamily")}</legend>
|
<legend>{t("labels.fontFamily")}</legend>
|
||||||
)}
|
)}
|
||||||
@@ -1144,7 +1152,7 @@ export const actionChangeFontFamily = register<{
|
|||||||
isOpened={appState.openPopup === "fontFamily"}
|
isOpened={appState.openPopup === "fontFamily"}
|
||||||
selectedFontFamily={selectedFontFamily}
|
selectedFontFamily={selectedFontFamily}
|
||||||
hoveredFontFamily={appState.currentHoveredFontFamily}
|
hoveredFontFamily={appState.currentHoveredFontFamily}
|
||||||
compactMode={appState.stylesPanelMode === "compact"}
|
compactMode={appState.stylesPanelMode !== "full"}
|
||||||
onSelect={(fontFamily) => {
|
onSelect={(fontFamily) => {
|
||||||
withCaretPositionPreservation(
|
withCaretPositionPreservation(
|
||||||
() => {
|
() => {
|
||||||
@@ -1156,7 +1164,8 @@ export const actionChangeFontFamily = register<{
|
|||||||
// defensive clear so immediate close won't abuse the cached elements
|
// defensive clear so immediate close won't abuse the cached elements
|
||||||
cachedElementsRef.current.clear();
|
cachedElementsRef.current.clear();
|
||||||
},
|
},
|
||||||
appState.stylesPanelMode === "compact",
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile",
|
||||||
!!appState.editingTextElement,
|
!!appState.editingTextElement,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
@@ -1232,7 +1241,8 @@ export const actionChangeFontFamily = register<{
|
|||||||
|
|
||||||
// Refocus text editor when font picker closes if we were editing text
|
// Refocus text editor when font picker closes if we were editing text
|
||||||
if (
|
if (
|
||||||
appState.stylesPanelMode === "compact" &&
|
(appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile") &&
|
||||||
appState.editingTextElement
|
appState.editingTextElement
|
||||||
) {
|
) {
|
||||||
restoreCaretPosition(null); // Just refocus without saved position
|
restoreCaretPosition(null); // Just refocus without saved position
|
||||||
@@ -1240,7 +1250,7 @@ export const actionChangeFontFamily = register<{
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1333,7 +1343,8 @@ export const actionChangeTextAlign = register<TextAlign>({
|
|||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
withCaretPositionPreservation(
|
withCaretPositionPreservation(
|
||||||
() => updateData(value),
|
() => updateData(value),
|
||||||
appState.stylesPanelMode === "compact",
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile",
|
||||||
!!appState.editingTextElement,
|
!!appState.editingTextElement,
|
||||||
data?.onPreventClose,
|
data?.onPreventClose,
|
||||||
);
|
);
|
||||||
@@ -1432,7 +1443,8 @@ export const actionChangeVerticalAlign = register<VerticalAlign>({
|
|||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
withCaretPositionPreservation(
|
withCaretPositionPreservation(
|
||||||
() => updateData(value),
|
() => updateData(value),
|
||||||
appState.stylesPanelMode === "compact",
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile",
|
||||||
!!appState.editingTextElement,
|
!!appState.editingTextElement,
|
||||||
data?.onPreventClose,
|
data?.onPreventClose,
|
||||||
);
|
);
|
||||||
@@ -1698,8 +1710,8 @@ export const actionChangeArrowProperties = register({
|
|||||||
PanelComponent: ({ elements, appState, updateData, app, renderAction }) => {
|
PanelComponent: ({ elements, appState, updateData, app, renderAction }) => {
|
||||||
return (
|
return (
|
||||||
<div className="selected-shape-actions">
|
<div className="selected-shape-actions">
|
||||||
{renderAction("changeArrowType")}
|
|
||||||
{renderAction("changeArrowhead")}
|
{renderAction("changeArrowhead")}
|
||||||
|
{renderAction("changeArrowType")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ export const getDefaultAppState = (): Omit<
|
|||||||
fromSelection: false,
|
fromSelection: false,
|
||||||
lastActiveTool: null,
|
lastActiveTool: null,
|
||||||
},
|
},
|
||||||
|
preferredSelectionTool: {
|
||||||
|
type: "selection",
|
||||||
|
initialized: false,
|
||||||
|
},
|
||||||
penMode: false,
|
penMode: false,
|
||||||
penDetected: false,
|
penDetected: false,
|
||||||
errorMessage: null,
|
errorMessage: null,
|
||||||
@@ -177,6 +181,7 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
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 },
|
||||||
activeTool: { browser: true, export: false, server: false },
|
activeTool: { browser: true, export: false, server: false },
|
||||||
|
preferredSelectionTool: { 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 },
|
||||||
errorMessage: { browser: false, export: false, server: false },
|
errorMessage: { browser: false, export: false, server: false },
|
||||||
@@ -250,7 +255,7 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
lockedMultiSelections: { browser: true, export: true, server: true },
|
lockedMultiSelections: { browser: true, export: true, server: true },
|
||||||
activeLockedId: { browser: false, export: false, server: false },
|
activeLockedId: { browser: false, export: false, server: false },
|
||||||
bindMode: { browser: true, export: false, server: false },
|
bindMode: { browser: true, export: false, server: false },
|
||||||
stylesPanelMode: { browser: true, export: false, server: false },
|
stylesPanelMode: { browser: false, export: false, server: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const _clearAppStateForStorage = <
|
const _clearAppStateForStorage = <
|
||||||
|
|||||||
@@ -106,15 +106,15 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 2.5rem;
|
min-height: 2.5rem;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
--default-button-size: 2rem;
|
--default-button-size: 2rem;
|
||||||
|
|
||||||
.compact-action-button {
|
.compact-action-button {
|
||||||
width: 2rem;
|
width: var(--mobile-action-button-size);
|
||||||
height: 2rem;
|
height: var(--mobile-action-button-size);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: var(--border-radius-lg);
|
border-radius: var(--border-radius-lg);
|
||||||
background: transparent;
|
|
||||||
color: var(--color-on-surface);
|
color: var(--color-on-surface);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -122,24 +122,20 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
background: var(--mobile-action-button-bg);
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&.active {
|
||||||
background: var(--button-hover-bg, var(--island-bg-color));
|
background: var(
|
||||||
border-color: var(
|
--color-surface-primary-container,
|
||||||
--button-hover-border,
|
var(--mobile-action-button-bg)
|
||||||
var(--button-border, var(--default-border-color))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: var(--button-active-bg, var(--island-bg-color));
|
|
||||||
border-color: var(--button-active-border, var(--color-primary-darkest));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.compact-popover-content {
|
.compact-popover-content {
|
||||||
@@ -167,6 +163,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ToolIcon {
|
||||||
|
.ToolIcon__icon {
|
||||||
|
width: var(--mobile-action-button-size);
|
||||||
|
height: var(--mobile-action-button-size);
|
||||||
|
|
||||||
|
background: var(--mobile-action-button-bg);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.compact-shape-actions-island {
|
.compact-shape-actions-island {
|
||||||
@@ -174,29 +183,18 @@
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compact-popover-content {
|
.mobile-shape-actions {
|
||||||
.popover-section {
|
z-index: 999;
|
||||||
margin-bottom: 1rem;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
&:last-child {
|
justify-content: space-between;
|
||||||
margin-bottom: 0;
|
width: 100%;
|
||||||
}
|
background: transparent;
|
||||||
|
border-radius: var(--border-radius-lg);
|
||||||
.popover-section-title {
|
box-shadow: none;
|
||||||
font-size: 0.75rem;
|
overflow: none;
|
||||||
font-weight: 600;
|
scrollbar-width: none;
|
||||||
color: var(--color-text-secondary);
|
-ms-overflow-style: none;
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonList {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.shape-actions-theme-scope {
|
.shape-actions-theme-scope {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -672,14 +672,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
>();
|
>();
|
||||||
onRemoveEventListenersEmitter = new Emitter<[]>();
|
onRemoveEventListenersEmitter = new Emitter<[]>();
|
||||||
|
|
||||||
defaultSelectionTool: "selection" | "lasso" = "selection";
|
|
||||||
|
|
||||||
constructor(props: AppProps) {
|
constructor(props: AppProps) {
|
||||||
super(props);
|
super(props);
|
||||||
const defaultAppState = getDefaultAppState();
|
const defaultAppState = getDefaultAppState();
|
||||||
this.defaultSelectionTool = isMobileOrTablet()
|
|
||||||
? ("lasso" as const)
|
|
||||||
: ("selection" as const);
|
|
||||||
const {
|
const {
|
||||||
excalidrawAPI,
|
excalidrawAPI,
|
||||||
viewModeEnabled = false,
|
viewModeEnabled = false,
|
||||||
@@ -1871,7 +1866,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const selectedElements = this.scene.getSelectedElements(this.state);
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
||||||
const { renderTopRightUI, renderCustomStats } = this.props;
|
const { renderTopRightUI, renderTopLeftUI, renderCustomStats } = this.props;
|
||||||
|
|
||||||
const sceneNonce = this.scene.getSceneNonce();
|
const sceneNonce = this.scene.getSceneNonce();
|
||||||
const { elementsMap, visibleElements } =
|
const { elementsMap, visibleElements } =
|
||||||
@@ -1957,6 +1952,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
onPenModeToggle={this.togglePenMode}
|
onPenModeToggle={this.togglePenMode}
|
||||||
onHandToolToggle={this.onHandToolToggle}
|
onHandToolToggle={this.onHandToolToggle}
|
||||||
langCode={getLanguage().code}
|
langCode={getLanguage().code}
|
||||||
|
renderTopLeftUI={renderTopLeftUI}
|
||||||
renderTopRightUI={renderTopRightUI}
|
renderTopRightUI={renderTopRightUI}
|
||||||
renderCustomStats={renderCustomStats}
|
renderCustomStats={renderCustomStats}
|
||||||
showExitZenModeBtn={
|
showExitZenModeBtn={
|
||||||
@@ -1969,7 +1965,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
!this.state.isLoading &&
|
!this.state.isLoading &&
|
||||||
this.state.showWelcomeScreen &&
|
this.state.showWelcomeScreen &&
|
||||||
this.state.activeTool.type ===
|
this.state.activeTool.type ===
|
||||||
this.defaultSelectionTool &&
|
this.state.preferredSelectionTool.type &&
|
||||||
!this.state.zenModeEnabled &&
|
!this.state.zenModeEnabled &&
|
||||||
!this.scene.getElementsIncludingDeleted().length
|
!this.scene.getElementsIncludingDeleted().length
|
||||||
}
|
}
|
||||||
@@ -2715,6 +2711,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
deleteInvisibleElements: true,
|
deleteInvisibleElements: true,
|
||||||
});
|
});
|
||||||
const activeTool = scene.appState.activeTool;
|
const activeTool = scene.appState.activeTool;
|
||||||
|
|
||||||
|
if (!scene.appState.preferredSelectionTool.initialized) {
|
||||||
|
scene.appState.preferredSelectionTool = {
|
||||||
|
type: this.device.editor.isMobile ? "lasso" : "selection",
|
||||||
|
initialized: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
scene.appState = {
|
scene.appState = {
|
||||||
...scene.appState,
|
...scene.appState,
|
||||||
theme: this.props.theme || scene.appState.theme,
|
theme: this.props.theme || scene.appState.theme,
|
||||||
@@ -2729,12 +2733,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
activeTool.type === "selection"
|
activeTool.type === "selection"
|
||||||
? {
|
? {
|
||||||
...activeTool,
|
...activeTool,
|
||||||
type: this.defaultSelectionTool,
|
type: scene.appState.preferredSelectionTool.type,
|
||||||
}
|
}
|
||||||
: scene.appState.activeTool,
|
: scene.appState.activeTool,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
toast: this.state.toast,
|
toast: this.state.toast,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (initialData?.scrollToContent) {
|
if (initialData?.scrollToContent) {
|
||||||
scene.appState = {
|
scene.appState = {
|
||||||
...scene.appState,
|
...scene.appState,
|
||||||
@@ -2835,6 +2840,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// but not too narrow (> MQ_MAX_WIDTH_MOBILE)
|
// but not too narrow (> MQ_MAX_WIDTH_MOBILE)
|
||||||
this.isTabletBreakpoint(editorWidth, editorHeight) && isMobileOrTablet()
|
this.isTabletBreakpoint(editorWidth, editorHeight) && isMobileOrTablet()
|
||||||
? "compact"
|
? "compact"
|
||||||
|
: this.isMobileBreakpoint(editorWidth, editorHeight)
|
||||||
|
? "mobile"
|
||||||
: "full",
|
: "full",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3634,7 +3641,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
await this.insertClipboardContent(data, filesList, isPlainPaste);
|
await this.insertClipboardContent(data, filesList, isPlainPaste);
|
||||||
|
|
||||||
this.setActiveTool({ type: this.defaultSelectionTool }, true);
|
this.setActiveTool(
|
||||||
|
{ type: this.state.preferredSelectionTool.type },
|
||||||
|
true,
|
||||||
|
);
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -3780,7 +3790,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.setActiveTool({ type: this.defaultSelectionTool }, true);
|
this.setActiveTool({ type: this.state.preferredSelectionTool.type }, true);
|
||||||
|
|
||||||
if (opts.fitToContent) {
|
if (opts.fitToContent) {
|
||||||
this.scrollToContent(duplicatedElements, {
|
this.scrollToContent(duplicatedElements, {
|
||||||
@@ -3992,7 +4002,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
...updateActiveTool(
|
...updateActiveTool(
|
||||||
this.state,
|
this.state,
|
||||||
prevState.activeTool.locked
|
prevState.activeTool.locked
|
||||||
? { type: this.defaultSelectionTool }
|
? { type: this.state.preferredSelectionTool.type }
|
||||||
: prevState.activeTool,
|
: prevState.activeTool,
|
||||||
),
|
),
|
||||||
locked: !prevState.activeTool.locked,
|
locked: !prevState.activeTool.locked,
|
||||||
@@ -4334,7 +4344,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (appState) {
|
if (appState) {
|
||||||
this.setState(appState);
|
this.setState({
|
||||||
|
...appState,
|
||||||
|
// keep existing stylesPanelMode as it needs to be preserved
|
||||||
|
// or set at startup
|
||||||
|
stylesPanelMode: this.state.stylesPanelMode,
|
||||||
|
} as Pick<AppState, K> | null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elements) {
|
if (elements) {
|
||||||
@@ -4992,7 +5007,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
if (event.key === KEYS.K && !event.altKey && !event[KEYS.CTRL_OR_CMD]) {
|
if (event.key === KEYS.K && !event.altKey && !event[KEYS.CTRL_OR_CMD]) {
|
||||||
if (this.state.activeTool.type === "laser") {
|
if (this.state.activeTool.type === "laser") {
|
||||||
this.setActiveTool({ type: this.defaultSelectionTool });
|
this.setActiveTool({ type: this.state.preferredSelectionTool.type });
|
||||||
} else {
|
} else {
|
||||||
this.setActiveTool({ type: "laser" });
|
this.setActiveTool({ type: "laser" });
|
||||||
}
|
}
|
||||||
@@ -5914,7 +5929,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// we should only be able to double click when mode is selection
|
// we should only be able to double click when mode is selection
|
||||||
if (this.state.activeTool.type !== this.defaultSelectionTool) {
|
if (this.state.activeTool.type !== this.state.preferredSelectionTool.type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6930,6 +6945,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.setAppState({ snapLines: [] });
|
this.setAppState({ snapLines: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.state.openPopup) {
|
||||||
|
this.setState({ openPopup: null });
|
||||||
|
}
|
||||||
|
|
||||||
this.updateGestureOnPointerDown(event);
|
this.updateGestureOnPointerDown(event);
|
||||||
|
|
||||||
// if dragging element is freedraw and another pointerdown event occurs
|
// if dragging element is freedraw and another pointerdown event occurs
|
||||||
@@ -8154,7 +8173,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (!this.state.activeTool.locked) {
|
if (!this.state.activeTool.locked) {
|
||||||
this.setState({
|
this.setState({
|
||||||
activeTool: updateActiveTool(this.state, {
|
activeTool: updateActiveTool(this.state, {
|
||||||
type: this.defaultSelectionTool,
|
type: this.state.preferredSelectionTool.type,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -9986,7 +10005,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
newElement: null,
|
newElement: null,
|
||||||
activeTool: updateActiveTool(this.state, {
|
activeTool: updateActiveTool(this.state, {
|
||||||
type: this.defaultSelectionTool,
|
type: this.state.preferredSelectionTool.type,
|
||||||
}),
|
}),
|
||||||
selectedElementIds: makeNextSelectedElementIds(
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
{
|
{
|
||||||
@@ -10597,7 +10616,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
newElement: null,
|
newElement: null,
|
||||||
suggestedBinding: null,
|
suggestedBinding: null,
|
||||||
activeTool: updateActiveTool(this.state, {
|
activeTool: updateActiveTool(this.state, {
|
||||||
type: this.defaultSelectionTool,
|
type: this.state.preferredSelectionTool.type,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -10888,7 +10907,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
{
|
{
|
||||||
newElement: null,
|
newElement: null,
|
||||||
activeTool: updateActiveTool(this.state, {
|
activeTool: updateActiveTool(this.state, {
|
||||||
type: this.defaultSelectionTool,
|
type: this.state.preferredSelectionTool.type,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
@@ -11332,7 +11351,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
event.nativeEvent.pointerType === "pen" &&
|
event.nativeEvent.pointerType === "pen" &&
|
||||||
// always allow if user uses a pen secondary button
|
// always allow if user uses a pen secondary button
|
||||||
event.button !== POINTER_BUTTON.SECONDARY)) &&
|
event.button !== POINTER_BUTTON.SECONDARY)) &&
|
||||||
this.state.activeTool.type !== this.defaultSelectionTool
|
this.state.activeTool.type !== this.state.preferredSelectionTool.type
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-picker__title {
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.color-picker__heading {
|
.color-picker__heading {
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
@@ -157,6 +163,15 @@
|
|||||||
width: 1.625rem;
|
width: 1.625rem;
|
||||||
height: 1.625rem;
|
height: 1.625rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.compact-sizing {
|
||||||
|
width: var(--mobile-action-button-size);
|
||||||
|
height: var(--mobile-action-button-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mobile-border {
|
||||||
|
border: 1px solid var(--mobile-color-border);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-picker__button__hotkey-label {
|
.color-picker__button__hotkey-label {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { useExcalidrawContainer } from "../App";
|
|||||||
import { ButtonSeparator } from "../ButtonSeparator";
|
import { ButtonSeparator } from "../ButtonSeparator";
|
||||||
import { activeEyeDropperAtom } from "../EyeDropper";
|
import { activeEyeDropperAtom } from "../EyeDropper";
|
||||||
import { PropertiesPopover } from "../PropertiesPopover";
|
import { PropertiesPopover } from "../PropertiesPopover";
|
||||||
import { backgroundIcon, slashIcon, strokeIcon } from "../icons";
|
import { slashIcon, strokeIcon } from "../icons";
|
||||||
import {
|
import {
|
||||||
saveCaretPosition,
|
saveCaretPosition,
|
||||||
restoreCaretPosition,
|
restoreCaretPosition,
|
||||||
@@ -216,6 +216,11 @@ const ColorPickerPopupContent = ({
|
|||||||
type={type}
|
type={type}
|
||||||
elements={elements}
|
elements={elements}
|
||||||
updateData={updateData}
|
updateData={updateData}
|
||||||
|
showTitle={
|
||||||
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile"
|
||||||
|
}
|
||||||
|
showHotKey={appState.stylesPanelMode !== "mobile"}
|
||||||
>
|
>
|
||||||
{colorInputJSX}
|
{colorInputJSX}
|
||||||
</Picker>
|
</Picker>
|
||||||
@@ -230,7 +235,7 @@ const ColorPickerTrigger = ({
|
|||||||
label,
|
label,
|
||||||
color,
|
color,
|
||||||
type,
|
type,
|
||||||
compactMode = false,
|
stylesPanelMode,
|
||||||
mode = "background",
|
mode = "background",
|
||||||
onToggle,
|
onToggle,
|
||||||
editingTextElement,
|
editingTextElement,
|
||||||
@@ -238,7 +243,7 @@ const ColorPickerTrigger = ({
|
|||||||
color: string | null;
|
color: string | null;
|
||||||
label: string;
|
label: string;
|
||||||
type: ColorPickerType;
|
type: ColorPickerType;
|
||||||
compactMode?: boolean;
|
stylesPanelMode?: AppState["stylesPanelMode"];
|
||||||
mode?: "background" | "stroke";
|
mode?: "background" | "stroke";
|
||||||
onToggle: () => void;
|
onToggle: () => void;
|
||||||
editingTextElement?: boolean;
|
editingTextElement?: boolean;
|
||||||
@@ -263,6 +268,9 @@ const ColorPickerTrigger = ({
|
|||||||
"is-transparent": !color || color === "transparent",
|
"is-transparent": !color || color === "transparent",
|
||||||
"has-outline":
|
"has-outline":
|
||||||
!color || !isColorDark(color, COLOR_OUTLINE_CONTRAST_THRESHOLD),
|
!color || !isColorDark(color, COLOR_OUTLINE_CONTRAST_THRESHOLD),
|
||||||
|
"compact-sizing":
|
||||||
|
stylesPanelMode === "compact" || stylesPanelMode === "mobile",
|
||||||
|
"mobile-border": stylesPanelMode === "mobile",
|
||||||
})}
|
})}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
style={color ? { "--swatch-color": color } : undefined}
|
style={color ? { "--swatch-color": color } : undefined}
|
||||||
@@ -275,20 +283,10 @@ const ColorPickerTrigger = ({
|
|||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
<div className="color-picker__button-outline">{!color && slashIcon}</div>
|
<div className="color-picker__button-outline">{!color && slashIcon}</div>
|
||||||
{compactMode && color && (
|
{(stylesPanelMode === "compact" || stylesPanelMode === "mobile") &&
|
||||||
<div className="color-picker__button-background">
|
color &&
|
||||||
{mode === "background" ? (
|
mode === "stroke" && (
|
||||||
<span
|
<div className="color-picker__button-background">
|
||||||
style={{
|
|
||||||
color:
|
|
||||||
color && isColorDark(color, COLOR_OUTLINE_CONTRAST_THRESHOLD)
|
|
||||||
? "#fff"
|
|
||||||
: "#111",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{backgroundIcon}
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
@@ -299,9 +297,8 @@ const ColorPickerTrigger = ({
|
|||||||
>
|
>
|
||||||
{strokeIcon}
|
{strokeIcon}
|
||||||
</span>
|
</span>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
</Popover.Trigger>
|
</Popover.Trigger>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -316,12 +313,15 @@ export const ColorPicker = ({
|
|||||||
topPicks,
|
topPicks,
|
||||||
updateData,
|
updateData,
|
||||||
appState,
|
appState,
|
||||||
compactMode = false,
|
|
||||||
}: ColorPickerProps) => {
|
}: ColorPickerProps) => {
|
||||||
const openRef = useRef(appState.openPopup);
|
const openRef = useRef(appState.openPopup);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
openRef.current = appState.openPopup;
|
openRef.current = appState.openPopup;
|
||||||
}, [appState.openPopup]);
|
}, [appState.openPopup]);
|
||||||
|
const compactMode =
|
||||||
|
appState.stylesPanelMode === "compact" ||
|
||||||
|
appState.stylesPanelMode === "mobile";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
@@ -353,7 +353,7 @@ export const ColorPicker = ({
|
|||||||
color={color}
|
color={color}
|
||||||
label={label}
|
label={label}
|
||||||
type={type}
|
type={type}
|
||||||
compactMode={compactMode}
|
stylesPanelMode={appState.stylesPanelMode}
|
||||||
mode={type === "elementStroke" ? "stroke" : "background"}
|
mode={type === "elementStroke" ? "stroke" : "background"}
|
||||||
editingTextElement={!!appState.editingTextElement}
|
editingTextElement={!!appState.editingTextElement}
|
||||||
onToggle={() => {
|
onToggle={() => {
|
||||||
|
|||||||
@@ -37,8 +37,10 @@ interface PickerProps {
|
|||||||
palette: ColorPaletteCustom;
|
palette: ColorPaletteCustom;
|
||||||
updateData: (formData?: any) => void;
|
updateData: (formData?: any) => void;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
showTitle?: boolean;
|
||||||
onEyeDropperToggle: (force?: boolean) => void;
|
onEyeDropperToggle: (force?: boolean) => void;
|
||||||
onEscape: (event: React.KeyboardEvent | KeyboardEvent) => void;
|
onEscape: (event: React.KeyboardEvent | KeyboardEvent) => void;
|
||||||
|
showHotKey?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Picker = React.forwardRef(
|
export const Picker = React.forwardRef(
|
||||||
@@ -51,11 +53,21 @@ export const Picker = React.forwardRef(
|
|||||||
palette,
|
palette,
|
||||||
updateData,
|
updateData,
|
||||||
children,
|
children,
|
||||||
|
showTitle,
|
||||||
onEyeDropperToggle,
|
onEyeDropperToggle,
|
||||||
onEscape,
|
onEscape,
|
||||||
|
showHotKey = true,
|
||||||
}: PickerProps,
|
}: PickerProps,
|
||||||
ref,
|
ref,
|
||||||
) => {
|
) => {
|
||||||
|
const title = showTitle
|
||||||
|
? type === "elementStroke"
|
||||||
|
? t("labels.stroke")
|
||||||
|
: type === "elementBackground"
|
||||||
|
? t("labels.background")
|
||||||
|
: null
|
||||||
|
: null;
|
||||||
|
|
||||||
const [customColors] = React.useState(() => {
|
const [customColors] = React.useState(() => {
|
||||||
if (type === "canvasBackground") {
|
if (type === "canvasBackground") {
|
||||||
return [];
|
return [];
|
||||||
@@ -154,6 +166,8 @@ export const Picker = React.forwardRef(
|
|||||||
// to allow focusing by clicking but not by tabbing
|
// to allow focusing by clicking but not by tabbing
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
|
{title && <div className="color-picker__title">{title}</div>}
|
||||||
|
|
||||||
{!!customColors.length && (
|
{!!customColors.length && (
|
||||||
<div>
|
<div>
|
||||||
<PickerHeading>
|
<PickerHeading>
|
||||||
@@ -175,12 +189,18 @@ export const Picker = React.forwardRef(
|
|||||||
palette={palette}
|
palette={palette}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
activeShade={activeShade}
|
activeShade={activeShade}
|
||||||
|
showHotKey={showHotKey}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<PickerHeading>{t("colorPicker.shades")}</PickerHeading>
|
<PickerHeading>{t("colorPicker.shades")}</PickerHeading>
|
||||||
<ShadeList color={color} onChange={onChange} palette={palette} />
|
<ShadeList
|
||||||
|
color={color}
|
||||||
|
onChange={onChange}
|
||||||
|
palette={palette}
|
||||||
|
showHotKey={showHotKey}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ interface PickerColorListProps {
|
|||||||
color: string | null;
|
color: string | null;
|
||||||
onChange: (color: string) => void;
|
onChange: (color: string) => void;
|
||||||
activeShade: number;
|
activeShade: number;
|
||||||
|
showHotKey?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PickerColorList = ({
|
const PickerColorList = ({
|
||||||
@@ -27,6 +28,7 @@ const PickerColorList = ({
|
|||||||
color,
|
color,
|
||||||
onChange,
|
onChange,
|
||||||
activeShade,
|
activeShade,
|
||||||
|
showHotKey = true,
|
||||||
}: PickerColorListProps) => {
|
}: PickerColorListProps) => {
|
||||||
const colorObj = getColorNameAndShadeFromColor({
|
const colorObj = getColorNameAndShadeFromColor({
|
||||||
color,
|
color,
|
||||||
@@ -82,7 +84,7 @@ const PickerColorList = ({
|
|||||||
key={key}
|
key={key}
|
||||||
>
|
>
|
||||||
<div className="color-picker__button-outline" />
|
<div className="color-picker__button-outline" />
|
||||||
<HotkeyLabel color={color} keyLabel={keybinding} />
|
{showHotKey && <HotkeyLabel color={color} keyLabel={keybinding} />}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -16,9 +16,15 @@ interface ShadeListProps {
|
|||||||
color: string | null;
|
color: string | null;
|
||||||
onChange: (color: string) => void;
|
onChange: (color: string) => void;
|
||||||
palette: ColorPaletteCustom;
|
palette: ColorPaletteCustom;
|
||||||
|
showHotKey?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShadeList = ({ color, onChange, palette }: ShadeListProps) => {
|
export const ShadeList = ({
|
||||||
|
color,
|
||||||
|
onChange,
|
||||||
|
palette,
|
||||||
|
showHotKey,
|
||||||
|
}: ShadeListProps) => {
|
||||||
const colorObj = getColorNameAndShadeFromColor({
|
const colorObj = getColorNameAndShadeFromColor({
|
||||||
color: color || "transparent",
|
color: color || "transparent",
|
||||||
palette,
|
palette,
|
||||||
@@ -67,7 +73,9 @@ export const ShadeList = ({ color, onChange, palette }: ShadeListProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="color-picker__button-outline" />
|
<div className="color-picker__button-outline" />
|
||||||
<HotkeyLabel color={color} keyLabel={i + 1} isShade />
|
{showHotKey && (
|
||||||
|
<HotkeyLabel color={color} keyLabel={i + 1} isShade />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
.excalidraw {
|
.excalidraw {
|
||||||
.ExcalidrawLogo {
|
.ExcalidrawLogo {
|
||||||
|
--logo-icon--mobile: 1rem;
|
||||||
|
--logo-text--mobile: 0.75rem;
|
||||||
|
|
||||||
--logo-icon--xs: 2rem;
|
--logo-icon--xs: 2rem;
|
||||||
--logo-text--xs: 1.5rem;
|
--logo-text--xs: 1.5rem;
|
||||||
|
|
||||||
@@ -30,6 +33,17 @@
|
|||||||
color: var(--color-logo-text);
|
color: var(--color-logo-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-mobile {
|
||||||
|
.ExcalidrawLogo-icon {
|
||||||
|
height: var(--logo-icon--mobile);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ExcalidrawLogo-text {
|
||||||
|
height: var(--logo-text--mobile);
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.is-xs {
|
&.is-xs {
|
||||||
.ExcalidrawLogo-icon {
|
.ExcalidrawLogo-icon {
|
||||||
height: var(--logo-icon--xs);
|
height: var(--logo-icon--xs);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const LogoText = () => (
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
type LogoSize = "xs" | "small" | "normal" | "large" | "custom";
|
type LogoSize = "xs" | "small" | "normal" | "large" | "custom" | "mobile";
|
||||||
|
|
||||||
interface LogoProps {
|
interface LogoProps {
|
||||||
size?: LogoSize;
|
size?: LogoSize;
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ export const FontPicker = React.memo(
|
|||||||
<FontPickerTrigger
|
<FontPickerTrigger
|
||||||
selectedFontFamily={selectedFontFamily}
|
selectedFontFamily={selectedFontFamily}
|
||||||
isOpened={isOpened}
|
isOpened={isOpened}
|
||||||
|
compactMode={compactMode}
|
||||||
/>
|
/>
|
||||||
{isOpened && (
|
{isOpened && (
|
||||||
<FontPickerList
|
<FontPickerList
|
||||||
|
|||||||
@@ -338,11 +338,13 @@ export const FontPickerList = React.memo(
|
|||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
preventAutoFocusOnTouch={!!app.state.editingTextElement}
|
preventAutoFocusOnTouch={!!app.state.editingTextElement}
|
||||||
>
|
>
|
||||||
<QuickSearch
|
{app.state.stylesPanelMode === "full" && (
|
||||||
ref={inputRef}
|
<QuickSearch
|
||||||
placeholder={t("quickSearch.placeholder")}
|
ref={inputRef}
|
||||||
onChange={debounce(setSearchTerm, 20)}
|
placeholder={t("quickSearch.placeholder")}
|
||||||
/>
|
onChange={debounce(setSearchTerm, 20)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
className="dropdown-menu fonts manual-hover"
|
className="dropdown-menu fonts manual-hover"
|
||||||
placeholder={t("fontList.empty")}
|
placeholder={t("fontList.empty")}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import * as Popover from "@radix-ui/react-popover";
|
import * as Popover from "@radix-ui/react-popover";
|
||||||
|
|
||||||
|
import { MOBILE_ACTION_BUTTON_BG } from "@excalidraw/common";
|
||||||
|
|
||||||
import type { FontFamilyValues } from "@excalidraw/element/types";
|
import type { FontFamilyValues } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import { t } from "../../i18n";
|
import { t } from "../../i18n";
|
||||||
@@ -11,14 +13,24 @@ import { useExcalidrawSetAppState } from "../App";
|
|||||||
interface FontPickerTriggerProps {
|
interface FontPickerTriggerProps {
|
||||||
selectedFontFamily: FontFamilyValues | null;
|
selectedFontFamily: FontFamilyValues | null;
|
||||||
isOpened?: boolean;
|
isOpened?: boolean;
|
||||||
|
compactMode?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FontPickerTrigger = ({
|
export const FontPickerTrigger = ({
|
||||||
selectedFontFamily,
|
selectedFontFamily,
|
||||||
isOpened = false,
|
isOpened = false,
|
||||||
|
compactMode = false,
|
||||||
}: FontPickerTriggerProps) => {
|
}: FontPickerTriggerProps) => {
|
||||||
const setAppState = useExcalidrawSetAppState();
|
const setAppState = useExcalidrawSetAppState();
|
||||||
|
|
||||||
|
const compactStyle = compactMode
|
||||||
|
? {
|
||||||
|
...MOBILE_ACTION_BUTTON_BG,
|
||||||
|
width: "2rem",
|
||||||
|
height: "2rem",
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover.Trigger asChild>
|
<Popover.Trigger asChild>
|
||||||
<div data-openpopup="fontFamily" className="properties-trigger">
|
<div data-openpopup="fontFamily" className="properties-trigger">
|
||||||
@@ -37,6 +49,7 @@ export const FontPickerTrigger = ({
|
|||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
border: "none",
|
border: "none",
|
||||||
|
...compactStyle,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type LockIconProps = {
|
|||||||
export const HandButton = (props: LockIconProps) => {
|
export const HandButton = (props: LockIconProps) => {
|
||||||
return (
|
return (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
className={clsx("Shape", { fillable: false })}
|
className={clsx("Shape", { fillable: false, active: props.checked })}
|
||||||
type="radio"
|
type="radio"
|
||||||
icon={handIcon}
|
icon={handIcon}
|
||||||
name="editor-current-shape"
|
name="editor-current-shape"
|
||||||
|
|||||||
@@ -152,15 +152,13 @@ function Picker<T>({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isMobile = device.editor.isMobile;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover.Content
|
<Popover.Content
|
||||||
side={
|
side={isMobile ? "right" : "bottom"}
|
||||||
device.editor.isMobile && !device.viewport.isLandscape
|
|
||||||
? "top"
|
|
||||||
: "bottom"
|
|
||||||
}
|
|
||||||
align="start"
|
align="start"
|
||||||
sideOffset={12}
|
sideOffset={isMobile ? 8 : 12}
|
||||||
style={{ zIndex: "var(--zIndex-popup)" }}
|
style={{ zIndex: "var(--zIndex-popup)" }}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ interface LayerUIProps {
|
|||||||
onPenModeToggle: AppClassProperties["togglePenMode"];
|
onPenModeToggle: AppClassProperties["togglePenMode"];
|
||||||
showExitZenModeBtn: boolean;
|
showExitZenModeBtn: boolean;
|
||||||
langCode: Language["code"];
|
langCode: Language["code"];
|
||||||
|
renderTopLeftUI?: ExcalidrawProps["renderTopLeftUI"];
|
||||||
renderTopRightUI?: ExcalidrawProps["renderTopRightUI"];
|
renderTopRightUI?: ExcalidrawProps["renderTopRightUI"];
|
||||||
renderCustomStats?: ExcalidrawProps["renderCustomStats"];
|
renderCustomStats?: ExcalidrawProps["renderCustomStats"];
|
||||||
UIOptions: AppProps["UIOptions"];
|
UIOptions: AppProps["UIOptions"];
|
||||||
@@ -149,6 +150,7 @@ const LayerUI = ({
|
|||||||
onHandToolToggle,
|
onHandToolToggle,
|
||||||
onPenModeToggle,
|
onPenModeToggle,
|
||||||
showExitZenModeBtn,
|
showExitZenModeBtn,
|
||||||
|
renderTopLeftUI,
|
||||||
renderTopRightUI,
|
renderTopRightUI,
|
||||||
renderCustomStats,
|
renderCustomStats,
|
||||||
UIOptions,
|
UIOptions,
|
||||||
@@ -366,7 +368,7 @@ const LayerUI = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ShapesSwitcher
|
<ShapesSwitcher
|
||||||
appState={appState}
|
setAppState={setAppState}
|
||||||
activeTool={appState.activeTool}
|
activeTool={appState.activeTool}
|
||||||
UIOptions={UIOptions}
|
UIOptions={UIOptions}
|
||||||
app={app}
|
app={app}
|
||||||
@@ -582,13 +584,11 @@ const LayerUI = ({
|
|||||||
renderJSONExportDialog={renderJSONExportDialog}
|
renderJSONExportDialog={renderJSONExportDialog}
|
||||||
renderImageExportDialog={renderImageExportDialog}
|
renderImageExportDialog={renderImageExportDialog}
|
||||||
setAppState={setAppState}
|
setAppState={setAppState}
|
||||||
onLockToggle={onLockToggle}
|
|
||||||
onHandToolToggle={onHandToolToggle}
|
onHandToolToggle={onHandToolToggle}
|
||||||
onPenModeToggle={onPenModeToggle}
|
onPenModeToggle={onPenModeToggle}
|
||||||
|
renderTopLeftUI={renderTopLeftUI}
|
||||||
renderTopRightUI={renderTopRightUI}
|
renderTopRightUI={renderTopRightUI}
|
||||||
renderCustomStats={renderCustomStats}
|
|
||||||
renderSidebars={renderSidebars}
|
renderSidebars={renderSidebars}
|
||||||
device={device}
|
|
||||||
renderWelcomeScreen={renderWelcomeScreen}
|
renderWelcomeScreen={renderWelcomeScreen}
|
||||||
UIOptions={UIOptions}
|
UIOptions={UIOptions}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,32 +1,23 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { showSelectedShapeActions } from "@excalidraw/element";
|
|
||||||
|
|
||||||
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import { isHandToolActive } from "../appState";
|
|
||||||
import { useTunnels } from "../context/tunnels";
|
import { useTunnels } from "../context/tunnels";
|
||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
import { calculateScrollCenter } from "../scene";
|
import { calculateScrollCenter } from "../scene";
|
||||||
import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
|
import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
|
||||||
|
|
||||||
import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
import { MobileShapeActions } from "./Actions";
|
||||||
|
import { MobileToolBar } from "./MobileToolBar";
|
||||||
import { FixedSideContainer } from "./FixedSideContainer";
|
import { FixedSideContainer } from "./FixedSideContainer";
|
||||||
import { HandButton } from "./HandButton";
|
|
||||||
import { HintViewer } from "./HintViewer";
|
|
||||||
import { Island } from "./Island";
|
import { Island } from "./Island";
|
||||||
import { LockButton } from "./LockButton";
|
|
||||||
import { PenModeButton } from "./PenModeButton";
|
|
||||||
import { Section } from "./Section";
|
|
||||||
import Stack from "./Stack";
|
|
||||||
|
|
||||||
import type { ActionManager } from "../actions/manager";
|
import type { ActionManager } from "../actions/manager";
|
||||||
import type {
|
import type {
|
||||||
AppClassProperties,
|
AppClassProperties,
|
||||||
AppProps,
|
AppProps,
|
||||||
AppState,
|
AppState,
|
||||||
Device,
|
|
||||||
ExcalidrawProps,
|
|
||||||
UIAppState,
|
UIAppState,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import type { JSX } from "react";
|
import type { JSX } from "react";
|
||||||
@@ -38,7 +29,6 @@ type MobileMenuProps = {
|
|||||||
renderImageExportDialog: () => React.ReactNode;
|
renderImageExportDialog: () => React.ReactNode;
|
||||||
setAppState: React.Component<any, AppState>["setState"];
|
setAppState: React.Component<any, AppState>["setState"];
|
||||||
elements: readonly NonDeletedExcalidrawElement[];
|
elements: readonly NonDeletedExcalidrawElement[];
|
||||||
onLockToggle: () => void;
|
|
||||||
onHandToolToggle: () => void;
|
onHandToolToggle: () => void;
|
||||||
onPenModeToggle: AppClassProperties["togglePenMode"];
|
onPenModeToggle: AppClassProperties["togglePenMode"];
|
||||||
|
|
||||||
@@ -46,9 +36,11 @@ type MobileMenuProps = {
|
|||||||
isMobile: boolean,
|
isMobile: boolean,
|
||||||
appState: UIAppState,
|
appState: UIAppState,
|
||||||
) => JSX.Element | null;
|
) => JSX.Element | null;
|
||||||
renderCustomStats?: ExcalidrawProps["renderCustomStats"];
|
renderTopLeftUI?: (
|
||||||
|
isMobile: boolean,
|
||||||
|
appState: UIAppState,
|
||||||
|
) => JSX.Element | null;
|
||||||
renderSidebars: () => JSX.Element | null;
|
renderSidebars: () => JSX.Element | null;
|
||||||
device: Device;
|
|
||||||
renderWelcomeScreen: boolean;
|
renderWelcomeScreen: boolean;
|
||||||
UIOptions: AppProps["UIOptions"];
|
UIOptions: AppProps["UIOptions"];
|
||||||
app: AppClassProperties;
|
app: AppClassProperties;
|
||||||
@@ -59,14 +51,10 @@ export const MobileMenu = ({
|
|||||||
elements,
|
elements,
|
||||||
actionManager,
|
actionManager,
|
||||||
setAppState,
|
setAppState,
|
||||||
onLockToggle,
|
|
||||||
onHandToolToggle,
|
onHandToolToggle,
|
||||||
onPenModeToggle,
|
renderTopLeftUI,
|
||||||
|
|
||||||
renderTopRightUI,
|
renderTopRightUI,
|
||||||
renderCustomStats,
|
|
||||||
renderSidebars,
|
renderSidebars,
|
||||||
device,
|
|
||||||
renderWelcomeScreen,
|
renderWelcomeScreen,
|
||||||
UIOptions,
|
UIOptions,
|
||||||
app,
|
app,
|
||||||
@@ -76,141 +64,98 @@ export const MobileMenu = ({
|
|||||||
MainMenuTunnel,
|
MainMenuTunnel,
|
||||||
DefaultSidebarTriggerTunnel,
|
DefaultSidebarTriggerTunnel,
|
||||||
} = useTunnels();
|
} = useTunnels();
|
||||||
const renderToolbar = () => {
|
const renderAppTopBar = () => {
|
||||||
return (
|
const topRightUI = renderTopRightUI?.(true, appState) ?? (
|
||||||
<FixedSideContainer side="top" className="App-top-bar">
|
<DefaultSidebarTriggerTunnel.Out />
|
||||||
{renderWelcomeScreen && <WelcomeScreenCenterTunnel.Out />}
|
);
|
||||||
<Section heading="shapes">
|
|
||||||
{(heading: React.ReactNode) => (
|
const topLeftUI = (
|
||||||
<Stack.Col gap={4} align="center">
|
<div className="excalidraw-ui-top-left">
|
||||||
<Stack.Row gap={1} className="App-toolbar-container">
|
{renderTopLeftUI?.(true, appState)}
|
||||||
<Island padding={1} className="App-toolbar App-toolbar--mobile">
|
<MainMenuTunnel.Out />
|
||||||
{heading}
|
</div>
|
||||||
<Stack.Row gap={1}>
|
|
||||||
<ShapesSwitcher
|
|
||||||
appState={appState}
|
|
||||||
activeTool={appState.activeTool}
|
|
||||||
UIOptions={UIOptions}
|
|
||||||
app={app}
|
|
||||||
/>
|
|
||||||
</Stack.Row>
|
|
||||||
</Island>
|
|
||||||
{renderTopRightUI && renderTopRightUI(true, appState)}
|
|
||||||
<div className="mobile-misc-tools-container">
|
|
||||||
{!appState.viewModeEnabled &&
|
|
||||||
appState.openDialog?.name !== "elementLinkSelector" && (
|
|
||||||
<DefaultSidebarTriggerTunnel.Out />
|
|
||||||
)}
|
|
||||||
<PenModeButton
|
|
||||||
checked={appState.penMode}
|
|
||||||
onChange={() => onPenModeToggle(null)}
|
|
||||||
title={t("toolBar.penMode")}
|
|
||||||
isMobile
|
|
||||||
penDetected={appState.penDetected}
|
|
||||||
/>
|
|
||||||
<LockButton
|
|
||||||
checked={appState.activeTool.locked}
|
|
||||||
onChange={onLockToggle}
|
|
||||||
title={t("toolBar.lock")}
|
|
||||||
isMobile
|
|
||||||
/>
|
|
||||||
<HandButton
|
|
||||||
checked={isHandToolActive(appState)}
|
|
||||||
onChange={() => onHandToolToggle()}
|
|
||||||
title={t("toolBar.hand")}
|
|
||||||
isMobile
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Stack.Row>
|
|
||||||
</Stack.Col>
|
|
||||||
)}
|
|
||||||
</Section>
|
|
||||||
<HintViewer
|
|
||||||
appState={appState}
|
|
||||||
isMobile={true}
|
|
||||||
device={device}
|
|
||||||
app={app}
|
|
||||||
/>
|
|
||||||
</FixedSideContainer>
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
const renderAppToolbar = () => {
|
|
||||||
if (
|
if (
|
||||||
appState.viewModeEnabled ||
|
appState.viewModeEnabled ||
|
||||||
appState.openDialog?.name === "elementLinkSelector"
|
appState.openDialog?.name === "elementLinkSelector"
|
||||||
) {
|
) {
|
||||||
return (
|
return <div className="App-toolbar-content">{topLeftUI}</div>;
|
||||||
<div className="App-toolbar-content">
|
|
||||||
<MainMenuTunnel.Out />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App-toolbar-content">
|
<div
|
||||||
<MainMenuTunnel.Out />
|
className="App-toolbar-content"
|
||||||
{actionManager.renderAction("toggleEditMenu")}
|
style={{
|
||||||
{actionManager.renderAction(
|
display: "flex",
|
||||||
appState.multiElement ? "finalize" : "duplicateSelection",
|
flexDirection: "row",
|
||||||
)}
|
justifyContent: "space-between",
|
||||||
{actionManager.renderAction("deleteSelectedElements")}
|
}}
|
||||||
<div>
|
>
|
||||||
{actionManager.renderAction("undo")}
|
{topLeftUI}
|
||||||
{actionManager.renderAction("redo")}
|
{topRightUI}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderToolbar = () => {
|
||||||
|
return (
|
||||||
|
<MobileToolBar
|
||||||
|
app={app}
|
||||||
|
onHandToolToggle={onHandToolToggle}
|
||||||
|
setAppState={setAppState}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{renderSidebars()}
|
{renderSidebars()}
|
||||||
{!appState.viewModeEnabled &&
|
{/* welcome screen, bottom bar, and top bar all have the same z-index */}
|
||||||
appState.openDialog?.name !== "elementLinkSelector" &&
|
{/* ordered in this reverse order so that top bar is on top */}
|
||||||
renderToolbar()}
|
<div className="App-welcome-screen">
|
||||||
|
{renderWelcomeScreen && <WelcomeScreenCenterTunnel.Out />}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="App-bottom-bar"
|
className="App-bottom-bar"
|
||||||
style={{
|
style={{
|
||||||
marginBottom: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
|
marginBottom: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN,
|
||||||
marginLeft: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
|
|
||||||
marginRight: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Island padding={0}>
|
<MobileShapeActions
|
||||||
{appState.openMenu === "shape" &&
|
appState={appState}
|
||||||
!appState.viewModeEnabled &&
|
elementsMap={app.scene.getNonDeletedElementsMap()}
|
||||||
appState.openDialog?.name !== "elementLinkSelector" &&
|
renderAction={actionManager.renderAction}
|
||||||
showSelectedShapeActions(appState, elements) ? (
|
app={app}
|
||||||
<Section className="App-mobile-menu" heading="selectedShapeActions">
|
setAppState={setAppState}
|
||||||
<SelectedShapeActions
|
/>
|
||||||
appState={appState}
|
|
||||||
elementsMap={app.scene.getNonDeletedElementsMap()}
|
<Island className="App-toolbar">
|
||||||
renderAction={actionManager.renderAction}
|
{!appState.viewModeEnabled &&
|
||||||
app={app}
|
appState.openDialog?.name !== "elementLinkSelector" &&
|
||||||
/>
|
renderToolbar()}
|
||||||
</Section>
|
{appState.scrolledOutside &&
|
||||||
) : null}
|
!appState.openMenu &&
|
||||||
<footer className="App-toolbar">
|
!appState.openSidebar && (
|
||||||
{renderAppToolbar()}
|
<button
|
||||||
{appState.scrolledOutside &&
|
type="button"
|
||||||
!appState.openMenu &&
|
className="scroll-back-to-content"
|
||||||
!appState.openSidebar && (
|
onClick={() => {
|
||||||
<button
|
setAppState((appState) => ({
|
||||||
type="button"
|
...calculateScrollCenter(elements, appState),
|
||||||
className="scroll-back-to-content"
|
}));
|
||||||
onClick={() => {
|
}}
|
||||||
setAppState((appState) => ({
|
>
|
||||||
...calculateScrollCenter(elements, appState),
|
{t("buttons.scrollBackToContent")}
|
||||||
}));
|
</button>
|
||||||
}}
|
)}
|
||||||
>
|
|
||||||
{t("buttons.scrollBackToContent")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</footer>
|
|
||||||
</Island>
|
</Island>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<FixedSideContainer side="top" className="App-top-bar">
|
||||||
|
{renderAppTopBar()}
|
||||||
|
</FixedSideContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
78
packages/excalidraw/components/MobileToolBar.scss
Normal file
78
packages/excalidraw/components/MobileToolBar.scss
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
@import "open-color/open-color.scss";
|
||||||
|
@import "../css/variables.module.scss";
|
||||||
|
|
||||||
|
.excalidraw {
|
||||||
|
.mobile-toolbar {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0px;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: var(--space-factor);
|
||||||
|
overflow-x: auto;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-toolbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-toolbar .ToolIcon {
|
||||||
|
min-width: 2rem;
|
||||||
|
min-height: 2rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.ToolIcon__icon {
|
||||||
|
width: 2.25rem;
|
||||||
|
height: 2.25rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: var(
|
||||||
|
--color-surface-primary-container,
|
||||||
|
var(--island-bg-color)
|
||||||
|
);
|
||||||
|
border-color: var(--button-active-border, var(--color-primary-darkest));
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-toolbar .App-toolbar__extra-tools-dropdown {
|
||||||
|
min-width: 160px;
|
||||||
|
z-index: var(--zIndex-layerUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-toolbar-separator {
|
||||||
|
width: 1px;
|
||||||
|
height: 24px;
|
||||||
|
background: var(--default-border-color);
|
||||||
|
margin: 0 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-toolbar-undo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-toolbar-undo .ToolIcon {
|
||||||
|
min-width: 32px;
|
||||||
|
min-height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
471
packages/excalidraw/components/MobileToolBar.tsx
Normal file
471
packages/excalidraw/components/MobileToolBar.tsx
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
import { useState, useEffect, useRef } from "react";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
|
import { KEYS, capitalizeString } from "@excalidraw/common";
|
||||||
|
|
||||||
|
import { trackEvent } from "../analytics";
|
||||||
|
|
||||||
|
import { t } from "../i18n";
|
||||||
|
|
||||||
|
import { isHandToolActive } from "../appState";
|
||||||
|
|
||||||
|
import { useTunnels } from "../context/tunnels";
|
||||||
|
|
||||||
|
import { HandButton } from "./HandButton";
|
||||||
|
import { ToolButton } from "./ToolButton";
|
||||||
|
import DropdownMenu from "./dropdownMenu/DropdownMenu";
|
||||||
|
import { ToolPopover } from "./ToolPopover";
|
||||||
|
|
||||||
|
import {
|
||||||
|
SelectionIcon,
|
||||||
|
FreedrawIcon,
|
||||||
|
EraserIcon,
|
||||||
|
RectangleIcon,
|
||||||
|
ArrowIcon,
|
||||||
|
extraToolsIcon,
|
||||||
|
DiamondIcon,
|
||||||
|
EllipseIcon,
|
||||||
|
LineIcon,
|
||||||
|
TextIcon,
|
||||||
|
ImageIcon,
|
||||||
|
frameToolIcon,
|
||||||
|
EmbedIcon,
|
||||||
|
laserPointerToolIcon,
|
||||||
|
LassoIcon,
|
||||||
|
mermaidLogoIcon,
|
||||||
|
MagicIcon,
|
||||||
|
} from "./icons";
|
||||||
|
|
||||||
|
import "./ToolIcon.scss";
|
||||||
|
import "./MobileToolBar.scss";
|
||||||
|
|
||||||
|
import type { AppClassProperties, ToolType, UIAppState } from "../types";
|
||||||
|
|
||||||
|
const SHAPE_TOOLS = [
|
||||||
|
{
|
||||||
|
type: "rectangle",
|
||||||
|
icon: RectangleIcon,
|
||||||
|
title: capitalizeString(t("toolBar.rectangle")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "diamond",
|
||||||
|
icon: DiamondIcon,
|
||||||
|
title: capitalizeString(t("toolBar.diamond")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "ellipse",
|
||||||
|
icon: EllipseIcon,
|
||||||
|
title: capitalizeString(t("toolBar.ellipse")),
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const SELECTION_TOOLS = [
|
||||||
|
{
|
||||||
|
type: "selection",
|
||||||
|
icon: SelectionIcon,
|
||||||
|
title: capitalizeString(t("toolBar.selection")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lasso",
|
||||||
|
icon: LassoIcon,
|
||||||
|
title: capitalizeString(t("toolBar.lasso")),
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const LINEAR_ELEMENT_TOOLS = [
|
||||||
|
{
|
||||||
|
type: "arrow",
|
||||||
|
icon: ArrowIcon,
|
||||||
|
title: capitalizeString(t("toolBar.arrow")),
|
||||||
|
},
|
||||||
|
{ type: "line", icon: LineIcon, title: capitalizeString(t("toolBar.line")) },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
type MobileToolBarProps = {
|
||||||
|
app: AppClassProperties;
|
||||||
|
onHandToolToggle: () => void;
|
||||||
|
setAppState: React.Component<any, UIAppState>["setState"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MobileToolBar = ({
|
||||||
|
app,
|
||||||
|
onHandToolToggle,
|
||||||
|
setAppState,
|
||||||
|
}: MobileToolBarProps) => {
|
||||||
|
const activeTool = app.state.activeTool;
|
||||||
|
const [isOtherShapesMenuOpen, setIsOtherShapesMenuOpen] = useState(false);
|
||||||
|
const [lastActiveGenericShape, setLastActiveGenericShape] = useState<
|
||||||
|
"rectangle" | "diamond" | "ellipse"
|
||||||
|
>("rectangle");
|
||||||
|
const [lastActiveLinearElement, setLastActiveLinearElement] = useState<
|
||||||
|
"arrow" | "line"
|
||||||
|
>("arrow");
|
||||||
|
|
||||||
|
const toolbarRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// keep lastActiveGenericShape in sync with active tool if user switches via other UI
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
activeTool.type === "rectangle" ||
|
||||||
|
activeTool.type === "diamond" ||
|
||||||
|
activeTool.type === "ellipse"
|
||||||
|
) {
|
||||||
|
setLastActiveGenericShape(activeTool.type);
|
||||||
|
}
|
||||||
|
}, [activeTool.type]);
|
||||||
|
|
||||||
|
// keep lastActiveLinearElement in sync with active tool if user switches via other UI
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeTool.type === "arrow" || activeTool.type === "line") {
|
||||||
|
setLastActiveLinearElement(activeTool.type);
|
||||||
|
}
|
||||||
|
}, [activeTool.type]);
|
||||||
|
|
||||||
|
const frameToolSelected = activeTool.type === "frame";
|
||||||
|
const laserToolSelected = activeTool.type === "laser";
|
||||||
|
const embeddableToolSelected = activeTool.type === "embeddable";
|
||||||
|
|
||||||
|
const { TTDDialogTriggerTunnel } = useTunnels();
|
||||||
|
|
||||||
|
const handleToolChange = (toolType: string, pointerType?: string) => {
|
||||||
|
if (app.state.activeTool.type !== toolType) {
|
||||||
|
trackEvent("toolbar", toolType, "ui");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toolType === "selection") {
|
||||||
|
if (app.state.activeTool.type === "selection") {
|
||||||
|
// Toggle selection tool behavior if needed
|
||||||
|
} else {
|
||||||
|
app.setActiveTool({ type: "selection" });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
app.setActiveTool({ type: toolType as ToolType });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toolbarWidth =
|
||||||
|
toolbarRef.current?.getBoundingClientRect()?.width ?? 0 - 8;
|
||||||
|
const WIDTH = 36;
|
||||||
|
const GAP = 4;
|
||||||
|
|
||||||
|
// hand, selection, freedraw, eraser, rectangle, arrow, others
|
||||||
|
const MIN_TOOLS = 7;
|
||||||
|
const MIN_WIDTH = MIN_TOOLS * WIDTH + (MIN_TOOLS - 1) * GAP;
|
||||||
|
const ADDITIONAL_WIDTH = WIDTH + GAP;
|
||||||
|
|
||||||
|
const showTextToolOutside = toolbarWidth >= MIN_WIDTH + 1 * ADDITIONAL_WIDTH;
|
||||||
|
const showImageToolOutside = toolbarWidth >= MIN_WIDTH + 2 * ADDITIONAL_WIDTH;
|
||||||
|
const showFrameToolOutside = toolbarWidth >= MIN_WIDTH + 3 * ADDITIONAL_WIDTH;
|
||||||
|
|
||||||
|
const extraTools = [
|
||||||
|
"text",
|
||||||
|
"frame",
|
||||||
|
"embeddable",
|
||||||
|
"laser",
|
||||||
|
"magicframe",
|
||||||
|
].filter((tool) => {
|
||||||
|
if (showImageToolOutside && tool === "image") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (showFrameToolOutside && tool === "frame") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
const extraToolSelected = extraTools.includes(activeTool.type);
|
||||||
|
const extraIcon = extraToolSelected
|
||||||
|
? activeTool.type === "frame"
|
||||||
|
? frameToolIcon
|
||||||
|
: activeTool.type === "embeddable"
|
||||||
|
? EmbedIcon
|
||||||
|
: activeTool.type === "laser"
|
||||||
|
? laserPointerToolIcon
|
||||||
|
: activeTool.type === "text"
|
||||||
|
? TextIcon
|
||||||
|
: activeTool.type === "magicframe"
|
||||||
|
? MagicIcon
|
||||||
|
: extraToolsIcon
|
||||||
|
: extraToolsIcon;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mobile-toolbar" ref={toolbarRef}>
|
||||||
|
{/* Hand Tool */}
|
||||||
|
<HandButton
|
||||||
|
checked={isHandToolActive(app.state)}
|
||||||
|
onChange={onHandToolToggle}
|
||||||
|
title={t("toolBar.hand")}
|
||||||
|
isMobile
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Selection Tool */}
|
||||||
|
<ToolPopover
|
||||||
|
app={app}
|
||||||
|
options={SELECTION_TOOLS}
|
||||||
|
activeTool={activeTool}
|
||||||
|
defaultOption={app.state.preferredSelectionTool.type}
|
||||||
|
namePrefix="selectionType"
|
||||||
|
title={capitalizeString(t("toolBar.selection"))}
|
||||||
|
data-testid="toolbar-selection"
|
||||||
|
onToolChange={(type: string) => {
|
||||||
|
if (type === "selection" || type === "lasso") {
|
||||||
|
app.setActiveTool({ type });
|
||||||
|
setAppState({
|
||||||
|
preferredSelectionTool: { type, initialized: true },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
displayedOption={
|
||||||
|
SELECTION_TOOLS.find(
|
||||||
|
(tool) => tool.type === app.state.preferredSelectionTool.type,
|
||||||
|
) || SELECTION_TOOLS[0]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Free Draw */}
|
||||||
|
<ToolButton
|
||||||
|
className={clsx({
|
||||||
|
active: activeTool.type === "freedraw",
|
||||||
|
})}
|
||||||
|
type="radio"
|
||||||
|
icon={FreedrawIcon}
|
||||||
|
checked={activeTool.type === "freedraw"}
|
||||||
|
name="editor-current-shape"
|
||||||
|
title={`${capitalizeString(t("toolBar.freedraw"))}`}
|
||||||
|
aria-label={capitalizeString(t("toolBar.freedraw"))}
|
||||||
|
data-testid="toolbar-freedraw"
|
||||||
|
onChange={() => handleToolChange("freedraw")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Eraser */}
|
||||||
|
<ToolButton
|
||||||
|
className={clsx({
|
||||||
|
active: activeTool.type === "eraser",
|
||||||
|
})}
|
||||||
|
type="radio"
|
||||||
|
icon={EraserIcon}
|
||||||
|
checked={activeTool.type === "eraser"}
|
||||||
|
name="editor-current-shape"
|
||||||
|
title={`${capitalizeString(t("toolBar.eraser"))}`}
|
||||||
|
aria-label={capitalizeString(t("toolBar.eraser"))}
|
||||||
|
data-testid="toolbar-eraser"
|
||||||
|
onChange={() => handleToolChange("eraser")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Rectangle */}
|
||||||
|
<ToolPopover
|
||||||
|
app={app}
|
||||||
|
options={SHAPE_TOOLS}
|
||||||
|
activeTool={activeTool}
|
||||||
|
defaultOption={lastActiveGenericShape}
|
||||||
|
namePrefix="shapeType"
|
||||||
|
title={capitalizeString(
|
||||||
|
t(
|
||||||
|
lastActiveGenericShape === "rectangle"
|
||||||
|
? "toolBar.rectangle"
|
||||||
|
: lastActiveGenericShape === "diamond"
|
||||||
|
? "toolBar.diamond"
|
||||||
|
: lastActiveGenericShape === "ellipse"
|
||||||
|
? "toolBar.ellipse"
|
||||||
|
: "toolBar.rectangle",
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
data-testid="toolbar-rectangle"
|
||||||
|
onToolChange={(type: string) => {
|
||||||
|
if (
|
||||||
|
type === "rectangle" ||
|
||||||
|
type === "diamond" ||
|
||||||
|
type === "ellipse"
|
||||||
|
) {
|
||||||
|
setLastActiveGenericShape(type);
|
||||||
|
app.setActiveTool({ type });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
displayedOption={
|
||||||
|
SHAPE_TOOLS.find((tool) => tool.type === lastActiveGenericShape) ||
|
||||||
|
SHAPE_TOOLS[0]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Arrow/Line */}
|
||||||
|
<ToolPopover
|
||||||
|
app={app}
|
||||||
|
options={LINEAR_ELEMENT_TOOLS}
|
||||||
|
activeTool={activeTool}
|
||||||
|
defaultOption={lastActiveLinearElement}
|
||||||
|
namePrefix="linearElementType"
|
||||||
|
title={capitalizeString(
|
||||||
|
t(
|
||||||
|
lastActiveLinearElement === "arrow"
|
||||||
|
? "toolBar.arrow"
|
||||||
|
: "toolBar.line",
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
data-testid="toolbar-arrow"
|
||||||
|
fillable={true}
|
||||||
|
onToolChange={(type: string) => {
|
||||||
|
if (type === "arrow" || type === "line") {
|
||||||
|
setLastActiveLinearElement(type);
|
||||||
|
app.setActiveTool({ type });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
displayedOption={
|
||||||
|
LINEAR_ELEMENT_TOOLS.find(
|
||||||
|
(tool) => tool.type === lastActiveLinearElement,
|
||||||
|
) || LINEAR_ELEMENT_TOOLS[0]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Text Tool */}
|
||||||
|
{showTextToolOutside && (
|
||||||
|
<ToolButton
|
||||||
|
className={clsx({
|
||||||
|
active: activeTool.type === "text",
|
||||||
|
})}
|
||||||
|
type="radio"
|
||||||
|
icon={TextIcon}
|
||||||
|
checked={activeTool.type === "text"}
|
||||||
|
name="editor-current-shape"
|
||||||
|
title={`${capitalizeString(t("toolBar.text"))}`}
|
||||||
|
aria-label={capitalizeString(t("toolBar.text"))}
|
||||||
|
data-testid="toolbar-text"
|
||||||
|
onChange={() => handleToolChange("text")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Image */}
|
||||||
|
{showImageToolOutside && (
|
||||||
|
<ToolButton
|
||||||
|
className={clsx({
|
||||||
|
active: activeTool.type === "image",
|
||||||
|
})}
|
||||||
|
type="radio"
|
||||||
|
icon={ImageIcon}
|
||||||
|
checked={activeTool.type === "image"}
|
||||||
|
name="editor-current-shape"
|
||||||
|
title={`${capitalizeString(t("toolBar.image"))}`}
|
||||||
|
aria-label={capitalizeString(t("toolBar.image"))}
|
||||||
|
data-testid="toolbar-image"
|
||||||
|
onChange={() => handleToolChange("image")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Frame Tool */}
|
||||||
|
{showFrameToolOutside && (
|
||||||
|
<ToolButton
|
||||||
|
className={clsx({ active: frameToolSelected })}
|
||||||
|
type="radio"
|
||||||
|
icon={frameToolIcon}
|
||||||
|
checked={frameToolSelected}
|
||||||
|
name="editor-current-shape"
|
||||||
|
title={`${capitalizeString(t("toolBar.frame"))}`}
|
||||||
|
aria-label={capitalizeString(t("toolBar.frame"))}
|
||||||
|
data-testid="toolbar-frame"
|
||||||
|
onChange={() => handleToolChange("frame")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Other Shapes */}
|
||||||
|
<DropdownMenu open={isOtherShapesMenuOpen} placement="top">
|
||||||
|
<DropdownMenu.Trigger
|
||||||
|
className={clsx(
|
||||||
|
"App-toolbar__extra-tools-trigger App-toolbar__extra-tools-trigger--mobile",
|
||||||
|
{
|
||||||
|
"App-toolbar__extra-tools-trigger--selected":
|
||||||
|
extraToolSelected || isOtherShapesMenuOpen,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
onToggle={() => setIsOtherShapesMenuOpen(!isOtherShapesMenuOpen)}
|
||||||
|
title={t("toolBar.extraTools")}
|
||||||
|
style={{
|
||||||
|
width: WIDTH,
|
||||||
|
height: WIDTH,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{extraIcon}
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
<DropdownMenu.Content
|
||||||
|
onClickOutside={() => setIsOtherShapesMenuOpen(false)}
|
||||||
|
onSelect={() => setIsOtherShapesMenuOpen(false)}
|
||||||
|
className="App-toolbar__extra-tools-dropdown"
|
||||||
|
>
|
||||||
|
{!showTextToolOutside && (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
onSelect={() => app.setActiveTool({ type: "text" })}
|
||||||
|
icon={TextIcon}
|
||||||
|
shortcut={KEYS.T.toLocaleUpperCase()}
|
||||||
|
data-testid="toolbar-text"
|
||||||
|
selected={activeTool.type === "text"}
|
||||||
|
>
|
||||||
|
{t("toolBar.text")}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!showImageToolOutside && (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
onSelect={() => app.setActiveTool({ type: "image" })}
|
||||||
|
icon={ImageIcon}
|
||||||
|
data-testid="toolbar-image"
|
||||||
|
selected={activeTool.type === "image"}
|
||||||
|
>
|
||||||
|
{t("toolBar.image")}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)}
|
||||||
|
{!showFrameToolOutside && (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
onSelect={() => app.setActiveTool({ type: "frame" })}
|
||||||
|
icon={frameToolIcon}
|
||||||
|
shortcut={KEYS.F.toLocaleUpperCase()}
|
||||||
|
data-testid="toolbar-frame"
|
||||||
|
selected={frameToolSelected}
|
||||||
|
>
|
||||||
|
{t("toolBar.frame")}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)}
|
||||||
|
<DropdownMenu.Item
|
||||||
|
onSelect={() => app.setActiveTool({ type: "embeddable" })}
|
||||||
|
icon={EmbedIcon}
|
||||||
|
data-testid="toolbar-embeddable"
|
||||||
|
selected={embeddableToolSelected}
|
||||||
|
>
|
||||||
|
{t("toolBar.embeddable")}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
onSelect={() => app.setActiveTool({ type: "laser" })}
|
||||||
|
icon={laserPointerToolIcon}
|
||||||
|
data-testid="toolbar-laser"
|
||||||
|
selected={laserToolSelected}
|
||||||
|
shortcut={KEYS.K.toLocaleUpperCase()}
|
||||||
|
>
|
||||||
|
{t("toolBar.laser")}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<div style={{ margin: "6px 0", fontSize: 14, fontWeight: 600 }}>
|
||||||
|
Generate
|
||||||
|
</div>
|
||||||
|
{app.props.aiEnabled !== false && <TTDDialogTriggerTunnel.Out />}
|
||||||
|
<DropdownMenu.Item
|
||||||
|
onSelect={() => app.setOpenDialog({ name: "ttd", tab: "mermaid" })}
|
||||||
|
icon={mermaidLogoIcon}
|
||||||
|
data-testid="toolbar-embeddable"
|
||||||
|
>
|
||||||
|
{t("toolBar.mermaidToExcalidraw")}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
{app.props.aiEnabled !== false && app.plugins.diagramToCode && (
|
||||||
|
<>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
onSelect={() => app.onMagicframeToolSelect()}
|
||||||
|
icon={MagicIcon}
|
||||||
|
data-testid="toolbar-magicframe"
|
||||||
|
>
|
||||||
|
{t("toolBar.magicframe")}
|
||||||
|
<DropdownMenu.Item.Badge>AI</DropdownMenu.Item.Badge>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import { trackEvent } from "../../analytics";
|
import { trackEvent } from "../../analytics";
|
||||||
import { useTunnels } from "../../context/tunnels";
|
import { useTunnels } from "../../context/tunnels";
|
||||||
import { t } from "../../i18n";
|
import { useI18n } from "../../i18n";
|
||||||
import { useExcalidrawSetAppState } from "../App";
|
import { useExcalidrawSetAppState } from "../App";
|
||||||
import DropdownMenu from "../dropdownMenu/DropdownMenu";
|
import DropdownMenu from "../dropdownMenu/DropdownMenu";
|
||||||
import { brainIcon } from "../icons";
|
import { brainIcon } from "../icons";
|
||||||
|
|
||||||
import type { ReactNode } from "react";
|
import type { JSX, ReactNode } from "react";
|
||||||
import type { JSX } from "react";
|
|
||||||
|
|
||||||
export const TTDDialogTrigger = ({
|
export const TTDDialogTrigger = ({
|
||||||
children,
|
children,
|
||||||
@@ -15,6 +14,7 @@ export const TTDDialogTrigger = ({
|
|||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
icon?: JSX.Element;
|
icon?: JSX.Element;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useI18n();
|
||||||
const { TTDDialogTriggerTunnel } = useTunnels();
|
const { TTDDialogTriggerTunnel } = useTunnels();
|
||||||
const setAppState = useExcalidrawSetAppState();
|
const setAppState = useExcalidrawSetAppState();
|
||||||
|
|
||||||
|
|||||||
18
packages/excalidraw/components/ToolPopover.scss
Normal file
18
packages/excalidraw/components/ToolPopover.scss
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
@import "../css/variables.module.scss";
|
||||||
|
|
||||||
|
.excalidraw {
|
||||||
|
.tool-popover-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 0.25rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: var(--island-bg-color);
|
||||||
|
box-shadow: var(--shadow-island);
|
||||||
|
padding: 0.5rem;
|
||||||
|
z-index: var(--zIndex-layerUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
120
packages/excalidraw/components/ToolPopover.tsx
Normal file
120
packages/excalidraw/components/ToolPopover.tsx
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
|
import { capitalizeString } from "@excalidraw/common";
|
||||||
|
|
||||||
|
import * as Popover from "@radix-ui/react-popover";
|
||||||
|
|
||||||
|
import { trackEvent } from "../analytics";
|
||||||
|
|
||||||
|
import { ToolButton } from "./ToolButton";
|
||||||
|
|
||||||
|
import "./ToolPopover.scss";
|
||||||
|
|
||||||
|
import type { AppClassProperties } from "../types";
|
||||||
|
|
||||||
|
type ToolOption = {
|
||||||
|
type: string;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
title?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ToolPopoverProps = {
|
||||||
|
app: AppClassProperties;
|
||||||
|
options: readonly ToolOption[];
|
||||||
|
activeTool: { type: string };
|
||||||
|
defaultOption: string;
|
||||||
|
className?: string;
|
||||||
|
namePrefix: string;
|
||||||
|
title: string;
|
||||||
|
"data-testid": string;
|
||||||
|
onToolChange: (type: string) => void;
|
||||||
|
displayedOption: ToolOption;
|
||||||
|
fillable?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ToolPopover = ({
|
||||||
|
app,
|
||||||
|
options,
|
||||||
|
activeTool,
|
||||||
|
defaultOption,
|
||||||
|
className = "Shape",
|
||||||
|
namePrefix,
|
||||||
|
title,
|
||||||
|
"data-testid": dataTestId,
|
||||||
|
onToolChange,
|
||||||
|
displayedOption,
|
||||||
|
fillable = false,
|
||||||
|
}: ToolPopoverProps) => {
|
||||||
|
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
||||||
|
const currentType = activeTool.type;
|
||||||
|
const isActive = displayedOption.type === currentType;
|
||||||
|
const SIDE_OFFSET = 32 / 2 + 10;
|
||||||
|
|
||||||
|
// if currentType is not in options, close popup
|
||||||
|
if (!options.some((o) => o.type === currentType) && isPopupOpen) {
|
||||||
|
setIsPopupOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close popover when user starts interacting with the canvas (pointer down)
|
||||||
|
useEffect(() => {
|
||||||
|
// app.onPointerDownEmitter emits when pointer down happens on canvas area
|
||||||
|
const unsubscribe = app.onPointerDownEmitter.on(() => {
|
||||||
|
setIsPopupOpen(false);
|
||||||
|
});
|
||||||
|
return () => unsubscribe?.();
|
||||||
|
}, [app]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover.Root open={isPopupOpen}>
|
||||||
|
<Popover.Trigger asChild>
|
||||||
|
<ToolButton
|
||||||
|
className={clsx(className, {
|
||||||
|
fillable,
|
||||||
|
active: options.some((o) => o.type === activeTool.type),
|
||||||
|
})}
|
||||||
|
type="radio"
|
||||||
|
icon={displayedOption.icon}
|
||||||
|
checked={isActive}
|
||||||
|
name="editor-current-shape"
|
||||||
|
title={title}
|
||||||
|
aria-label={title}
|
||||||
|
data-testid={dataTestId}
|
||||||
|
onPointerDown={() => {
|
||||||
|
setIsPopupOpen((v) => !v);
|
||||||
|
onToolChange(defaultOption);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popover.Trigger>
|
||||||
|
|
||||||
|
<Popover.Content
|
||||||
|
className="tool-popover-content"
|
||||||
|
sideOffset={SIDE_OFFSET}
|
||||||
|
>
|
||||||
|
{options.map(({ type, icon, title }) => (
|
||||||
|
<ToolButton
|
||||||
|
className={clsx(className, {
|
||||||
|
active: currentType === type,
|
||||||
|
})}
|
||||||
|
key={type}
|
||||||
|
type="radio"
|
||||||
|
icon={icon}
|
||||||
|
checked={currentType === type}
|
||||||
|
name={`${namePrefix}-option`}
|
||||||
|
title={title || capitalizeString(type)}
|
||||||
|
keyBindingLabel=""
|
||||||
|
aria-label={title || capitalizeString(type)}
|
||||||
|
data-testid={`toolbar-${type}`}
|
||||||
|
onChange={() => {
|
||||||
|
if (app.state.activeTool.type !== type) {
|
||||||
|
trackEvent("toolbar", type, "ui");
|
||||||
|
}
|
||||||
|
app.setActiveTool({ type: type as any });
|
||||||
|
onToolChange?.(type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -44,6 +44,10 @@
|
|||||||
var(--button-active-border, var(--color-primary-darkest)) inset;
|
var(--button-active-border, var(--color-primary-darkest)) inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
&--selected,
|
&--selected,
|
||||||
&--selected:hover {
|
&--selected:hover {
|
||||||
background: var(--color-primary-light);
|
background: var(--color-primary-light);
|
||||||
|
|||||||
@@ -3,24 +3,46 @@
|
|||||||
.excalidraw {
|
.excalidraw {
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 2.5rem;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
|
|
||||||
|
&--placement-top {
|
||||||
|
top: auto;
|
||||||
|
bottom: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
&--mobile {
|
&--mobile {
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
row-gap: 0.75rem;
|
row-gap: 0.75rem;
|
||||||
|
|
||||||
|
// When main menu is in the top toolbar, position relative to trigger
|
||||||
|
&.main-menu-dropdown {
|
||||||
|
min-width: 232px;
|
||||||
|
max-width: calc(100vw - var(--editor-container-padding) * 2);
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
z-index: var(--zIndex-layerUI);
|
||||||
|
|
||||||
|
@media screen and (orientation: landscape) {
|
||||||
|
max-width: 232px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown-menu-container {
|
.dropdown-menu-container {
|
||||||
padding: 8px 8px;
|
padding: 8px 8px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
// background-color: var(--island-bg-color);
|
max-height: calc(
|
||||||
|
100svh - var(--editor-container-padding) * 2 - 2.25rem
|
||||||
|
);
|
||||||
box-shadow: var(--shadow-island);
|
box-shadow: var(--shadow-island);
|
||||||
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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
&.zen-mode {
|
&.zen-mode {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@@ -30,7 +52,7 @@
|
|||||||
|
|
||||||
.dropdown-menu-container {
|
.dropdown-menu-container {
|
||||||
background-color: var(--island-bg-color);
|
background-color: var(--island-bg-color);
|
||||||
max-height: calc(100vh - 150px);
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
--gap: 2;
|
--gap: 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,27 @@ import "./DropdownMenu.scss";
|
|||||||
const DropdownMenu = ({
|
const DropdownMenu = ({
|
||||||
children,
|
children,
|
||||||
open,
|
open,
|
||||||
|
placement,
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
placement?: "top" | "bottom";
|
||||||
}) => {
|
}) => {
|
||||||
const MenuTriggerComp = getMenuTriggerComponent(children);
|
const MenuTriggerComp = getMenuTriggerComponent(children);
|
||||||
const MenuContentComp = getMenuContentComponent(children);
|
const MenuContentComp = getMenuContentComponent(children);
|
||||||
|
|
||||||
|
// clone the MenuContentComp to pass the placement prop
|
||||||
|
const MenuContentCompWithPlacement =
|
||||||
|
MenuContentComp && React.isValidElement(MenuContentComp)
|
||||||
|
? React.cloneElement(MenuContentComp as React.ReactElement<any>, {
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
: MenuContentComp;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{MenuTriggerComp}
|
{MenuTriggerComp}
|
||||||
{open && MenuContentComp}
|
{open && MenuContentCompWithPlacement}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const MenuContent = ({
|
|||||||
className = "",
|
className = "",
|
||||||
onSelect,
|
onSelect,
|
||||||
style,
|
style,
|
||||||
|
placement = "bottom",
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
onClickOutside?: () => void;
|
onClickOutside?: () => void;
|
||||||
@@ -26,6 +27,7 @@ const MenuContent = ({
|
|||||||
*/
|
*/
|
||||||
onSelect?: (event: Event) => void;
|
onSelect?: (event: Event) => void;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
|
placement?: "top" | "bottom";
|
||||||
}) => {
|
}) => {
|
||||||
const device = useDevice();
|
const device = useDevice();
|
||||||
const menuRef = useRef<HTMLDivElement>(null);
|
const menuRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -58,6 +60,7 @@ const MenuContent = ({
|
|||||||
|
|
||||||
const classNames = clsx(`dropdown-menu ${className}`, {
|
const classNames = clsx(`dropdown-menu ${className}`, {
|
||||||
"dropdown-menu--mobile": device.editor.isMobile,
|
"dropdown-menu--mobile": device.editor.isMobile,
|
||||||
|
"dropdown-menu--placement-top": placement === "top",
|
||||||
}).trim();
|
}).trim();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2319,22 +2319,10 @@ export const adjustmentsIcon = createIcon(
|
|||||||
tablerIconProps,
|
tablerIconProps,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const backgroundIcon = createIcon(
|
|
||||||
<g strokeWidth={1}>
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path d="M6 10l4 -4" />
|
|
||||||
<path d="M6 14l8 -8" />
|
|
||||||
<path d="M6 18l12 -12" />
|
|
||||||
<path d="M10 18l8 -8" />
|
|
||||||
<path d="M14 18l4 -4" />
|
|
||||||
</g>,
|
|
||||||
tablerIconProps,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const strokeIcon = createIcon(
|
export const strokeIcon = createIcon(
|
||||||
<g strokeWidth={1}>
|
<g strokeWidth={1}>
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
<rect x="6" y="6" width="12" height="12" fill="none" />
|
<path d="M6 10l4 -4 L6 14l8 -8 L6 18l12 -12 L10 18l8 -8 L14 18l4 -4" />
|
||||||
</g>,
|
</g>,
|
||||||
tablerIconProps,
|
tablerIconProps,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ const MainMenu = Object.assign(
|
|||||||
onSelect={composeEventHandlers(onSelect, () => {
|
onSelect={composeEventHandlers(onSelect, () => {
|
||||||
setAppState({ openMenu: null });
|
setAppState({ openMenu: null });
|
||||||
})}
|
})}
|
||||||
|
placement="bottom"
|
||||||
|
className={device.editor.isMobile ? "main-menu-dropdown" : ""}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
{device.editor.isMobile && appState.collaborators.size > 0 && (
|
{device.editor.isMobile && appState.collaborators.size > 0 && (
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export const SHAPES = [
|
|||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const getToolbarTools = (app: AppClassProperties) => {
|
export const getToolbarTools = (app: AppClassProperties) => {
|
||||||
return app.defaultSelectionTool === "lasso"
|
return app.state.preferredSelectionTool.type === "lasso"
|
||||||
? ([
|
? ([
|
||||||
{
|
{
|
||||||
value: "lasso",
|
value: "lasso",
|
||||||
|
|||||||
@@ -252,16 +252,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 599px) {
|
&.excalidraw--mobile {
|
||||||
.welcome-screen-center {
|
.welcome-screen-center {
|
||||||
margin-top: 4rem;
|
margin-bottom: 2rem;
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 600px) and (max-height: 900px) {
|
|
||||||
.welcome-screen-center {
|
|
||||||
margin-top: 8rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 500px), (max-width: 320px) {
|
@media (max-height: 500px), (max-width: 320px) {
|
||||||
.welcome-screen-center {
|
.welcome-screen-center {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ body.excalidraw-cursor-resize * {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
button,
|
||||||
|
label {
|
||||||
|
@include buttonNoHighlight;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -235,27 +240,32 @@ body.excalidraw-cursor-resize * {
|
|||||||
z-index: var(--zIndex-layerUI);
|
z-index: var(--zIndex-layerUI);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
}
|
||||||
|
|
||||||
|
.App-welcome-screen {
|
||||||
|
z-index: var(--zIndex-layerUI);
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-bottom-bar {
|
.App-bottom-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
// account for margins
|
||||||
|
width: calc(100% - 28px);
|
||||||
|
max-width: 450px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 50%;
|
||||||
right: 0;
|
transform: translateX(-50%);
|
||||||
--bar-padding: calc(4 * var(--space-factor));
|
--bar-padding: calc(4 * var(--space-factor));
|
||||||
z-index: 4;
|
z-index: var(--zIndex-layerUI);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
flex-direction: column;
|
||||||
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
> .Island {
|
> .Island {
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
min-width: 100%;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
padding: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
pointer-events: var(--ui-pointerEvents);
|
pointer-events: var(--ui-pointerEvents);
|
||||||
@@ -263,7 +273,8 @@ body.excalidraw-cursor-resize * {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.App-toolbar {
|
.App-toolbar {
|
||||||
width: 100%;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
.eraser {
|
.eraser {
|
||||||
&.ToolIcon:hover {
|
&.ToolIcon:hover {
|
||||||
@@ -276,16 +287,15 @@ body.excalidraw-cursor-resize * {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-toolbar-content {
|
.excalidraw-ui-top-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
gap: 0.5rem;
|
||||||
padding: 8px;
|
}
|
||||||
|
|
||||||
.dropdown-menu--mobile {
|
.App-toolbar-content {
|
||||||
bottom: 55px;
|
display: flex;
|
||||||
top: auto;
|
flex-direction: column;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-mobile-menu {
|
.App-mobile-menu {
|
||||||
@@ -506,7 +516,7 @@ body.excalidraw-cursor-resize * {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.scroll-back-to-content {
|
.scroll-back-to-content {
|
||||||
bottom: calc(80px + var(--sab, 0));
|
bottom: calc(100px + var(--sab, 0));
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
--button-gray-1: #{$oc-gray-2};
|
--button-gray-1: #{$oc-gray-2};
|
||||||
--button-gray-2: #{$oc-gray-4};
|
--button-gray-2: #{$oc-gray-4};
|
||||||
--button-gray-3: #{$oc-gray-5};
|
--button-gray-3: #{$oc-gray-5};
|
||||||
|
--mobile-action-button-bg: rgba(255, 255, 255, 0.35);
|
||||||
|
--mobile-color-border: var(--default-border-color);
|
||||||
--button-special-active-bg-color: #{$oc-green-0};
|
--button-special-active-bg-color: #{$oc-green-0};
|
||||||
--dialog-border-color: var(--color-gray-20);
|
--dialog-border-color: var(--color-gray-20);
|
||||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||||
@@ -42,6 +44,11 @@
|
|||||||
--lg-button-size: 2.25rem;
|
--lg-button-size: 2.25rem;
|
||||||
--lg-icon-size: 1rem;
|
--lg-icon-size: 1rem;
|
||||||
--editor-container-padding: 1rem;
|
--editor-container-padding: 1rem;
|
||||||
|
--mobile-action-button-size: 2rem;
|
||||||
|
|
||||||
|
@include isMobile {
|
||||||
|
--editor-container-padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (min-device-width: 1921px) {
|
@media screen and (min-device-width: 1921px) {
|
||||||
--lg-button-size: 2.5rem;
|
--lg-button-size: 2.5rem;
|
||||||
@@ -177,6 +184,8 @@
|
|||||||
--button-gray-1: #363636;
|
--button-gray-1: #363636;
|
||||||
--button-gray-2: #272727;
|
--button-gray-2: #272727;
|
||||||
--button-gray-3: #222;
|
--button-gray-3: #222;
|
||||||
|
--mobile-action-button-bg: var(--island-bg-color);
|
||||||
|
--mobile-color-border: rgba(255, 255, 255, 0.85);
|
||||||
--button-special-active-bg-color: #204624;
|
--button-special-active-bg-color: #204624;
|
||||||
--dialog-border-color: var(--color-gray-80);
|
--dialog-border-color: var(--color-gray-80);
|
||||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||||
|
|||||||
@@ -122,6 +122,17 @@
|
|||||||
color: var(--button-color, var(--color-on-primary-container));
|
color: var(--button-color, var(--color-on-primary-container));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include isMobile() {
|
||||||
|
width: var(--mobile-action-button-size, var(--default-button-size));
|
||||||
|
height: var(--mobile-action-button-size, var(--default-button-size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin buttonNoHighlight {
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin outlineButtonIconStyles {
|
@mixin outlineButtonIconStyles {
|
||||||
@@ -187,4 +198,9 @@
|
|||||||
&:active {
|
&:active {
|
||||||
box-shadow: 0 0 0 1px var(--color-brand-active);
|
box-shadow: 0 0 0 1px var(--color-brand-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include isMobile() {
|
||||||
|
width: var(--mobile-action-button-size, 2rem);
|
||||||
|
height: var(--mobile-action-button-size, 2rem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
|||||||
excalidrawAPI,
|
excalidrawAPI,
|
||||||
isCollaborating = false,
|
isCollaborating = false,
|
||||||
onPointerUpdate,
|
onPointerUpdate,
|
||||||
|
renderTopLeftUI,
|
||||||
renderTopRightUI,
|
renderTopRightUI,
|
||||||
langCode = defaultLang.code,
|
langCode = defaultLang.code,
|
||||||
viewModeEnabled,
|
viewModeEnabled,
|
||||||
@@ -120,6 +121,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
|||||||
excalidrawAPI={excalidrawAPI}
|
excalidrawAPI={excalidrawAPI}
|
||||||
isCollaborating={isCollaborating}
|
isCollaborating={isCollaborating}
|
||||||
onPointerUpdate={onPointerUpdate}
|
onPointerUpdate={onPointerUpdate}
|
||||||
|
renderTopLeftUI={renderTopLeftUI}
|
||||||
renderTopRightUI={renderTopRightUI}
|
renderTopRightUI={renderTopRightUI}
|
||||||
langCode={langCode}
|
langCode={langCode}
|
||||||
viewModeEnabled={viewModeEnabled}
|
viewModeEnabled={viewModeEnabled}
|
||||||
|
|||||||
@@ -957,6 +957,10 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -1153,6 +1157,10 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -1367,6 +1375,10 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -1698,6 +1710,10 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -2029,6 +2045,10 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -2243,6 +2263,10 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -2484,6 +2508,10 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -2782,6 +2810,10 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
},
|
},
|
||||||
@@ -3154,6 +3186,10 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -3647,6 +3683,10 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -3970,6 +4010,10 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -4293,6 +4337,10 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
},
|
},
|
||||||
@@ -5578,6 +5626,10 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -6795,6 +6847,10 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -7733,6 +7789,10 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -8730,6 +8790,10 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9724,6 +9788,10 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
},
|
},
|
||||||
@@ -712,6 +716,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
},
|
},
|
||||||
@@ -1276,6 +1284,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -1636,6 +1648,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -1998,6 +2014,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -2258,6 +2278,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -2714,6 +2738,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -3017,6 +3045,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -3336,6 +3368,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -3630,6 +3666,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -3916,6 +3956,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -4151,6 +4195,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -4408,6 +4456,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -4679,6 +4731,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -4908,6 +4964,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -5137,6 +5197,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -5384,6 +5448,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -5640,6 +5708,10 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -5895,6 +5967,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
},
|
},
|
||||||
@@ -6215,7 +6291,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
"offsetTop": 0,
|
"offsetTop": 0,
|
||||||
"openDialog": null,
|
"openDialog": null,
|
||||||
"openMenu": null,
|
"openMenu": null,
|
||||||
"openPopup": "elementBackground",
|
"openPopup": null,
|
||||||
"openSidebar": null,
|
"openSidebar": null,
|
||||||
"originSnapOffset": null,
|
"originSnapOffset": null,
|
||||||
"pasteDialog": {
|
"pasteDialog": {
|
||||||
@@ -6224,6 +6300,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id8": true,
|
"id8": true,
|
||||||
},
|
},
|
||||||
@@ -6651,6 +6731,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
},
|
},
|
||||||
@@ -7028,6 +7112,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -7337,6 +7425,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -7629,6 +7721,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -7859,6 +7955,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -8211,6 +8311,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -8563,6 +8667,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -8969,6 +9077,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9248,6 +9360,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9512,6 +9628,10 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9777,6 +9897,10 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -10012,6 +10136,10 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -10306,6 +10434,10 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -10623,6 +10755,10 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -10862,6 +10998,10 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -11301,6 +11441,10 @@ exports[`history > multiplayer undo/redo > should update history entries after r
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -11561,6 +11705,10 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -11796,6 +11944,10 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -12024,7 +12176,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
|||||||
"offsetTop": 0,
|
"offsetTop": 0,
|
||||||
"openDialog": null,
|
"openDialog": null,
|
||||||
"openMenu": null,
|
"openMenu": null,
|
||||||
"openPopup": "elementStroke",
|
"openPopup": null,
|
||||||
"openSidebar": null,
|
"openSidebar": null,
|
||||||
"originSnapOffset": null,
|
"originSnapOffset": null,
|
||||||
"pasteDialog": {
|
"pasteDialog": {
|
||||||
@@ -12033,6 +12185,10 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -12427,6 +12583,10 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -12634,6 +12794,10 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -12844,6 +13008,10 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -13142,6 +13310,10 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -13443,6 +13615,10 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": -50,
|
"scrollX": -50,
|
||||||
@@ -13685,6 +13861,10 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -13922,6 +14102,10 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -14159,6 +14343,10 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -14406,6 +14594,10 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -14740,6 +14932,10 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -14907,6 +15103,10 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -15194,6 +15394,10 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -15457,6 +15661,10 @@ exports[`history > singleplayer undo/redo > should not modify anything on unrela
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -15598,7 +15806,7 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
|||||||
"offsetTop": 0,
|
"offsetTop": 0,
|
||||||
"openDialog": null,
|
"openDialog": null,
|
||||||
"openMenu": null,
|
"openMenu": null,
|
||||||
"openPopup": "elementBackground",
|
"openPopup": null,
|
||||||
"openSidebar": null,
|
"openSidebar": null,
|
||||||
"originSnapOffset": null,
|
"originSnapOffset": null,
|
||||||
"pasteDialog": {
|
"pasteDialog": {
|
||||||
@@ -15607,6 +15815,10 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -15892,6 +16104,10 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -16051,6 +16267,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -16799,6 +17019,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -17445,6 +17669,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -18091,6 +18319,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -18840,6 +19072,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -19608,6 +19844,10 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -20088,6 +20328,10 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
},
|
},
|
||||||
@@ -20599,6 +20843,10 @@ exports[`history > singleplayer undo/redo > should support element creation, del
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
},
|
},
|
||||||
@@ -21058,6 +21306,10 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ exports[`given element A and group of elements B and given both are selected whe
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -506,6 +510,10 @@ exports[`given element A and group of elements B and given both are selected whe
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -922,6 +930,10 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -1488,6 +1500,10 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -1695,6 +1711,10 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -2079,6 +2099,10 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -2324,6 +2348,10 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -2504,6 +2532,10 @@ exports[`regression tests > can drag element that covers another element, while
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id6": true,
|
"id6": true,
|
||||||
},
|
},
|
||||||
@@ -2829,6 +2861,10 @@ exports[`regression tests > change the properties of a shape > [end of test] app
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -3084,6 +3120,10 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -3325,6 +3365,10 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -3561,6 +3605,10 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
},
|
},
|
||||||
@@ -3819,6 +3867,10 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id6": true,
|
"id6": true,
|
||||||
},
|
},
|
||||||
@@ -4133,6 +4185,10 @@ exports[`regression tests > deleting last but one element in editing group shoul
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -4569,6 +4625,10 @@ exports[`regression tests > deselects group of selected elements on pointer down
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -4852,6 +4912,10 @@ exports[`regression tests > deselects group of selected elements on pointer up w
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -5128,6 +5192,10 @@ exports[`regression tests > deselects selected element on pointer down when poin
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -5336,6 +5404,10 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -5536,6 +5608,10 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -5929,6 +6005,10 @@ exports[`regression tests > drags selected elements from point inside common bou
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -6226,6 +6306,10 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -7036,6 +7120,10 @@ exports[`regression tests > given a group of selected elements with an element t
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id6": true,
|
"id6": true,
|
||||||
@@ -7361,7 +7449,7 @@ exports[`regression tests > given a selected element A and a not selected elemen
|
|||||||
"offsetTop": 0,
|
"offsetTop": 0,
|
||||||
"openDialog": null,
|
"openDialog": null,
|
||||||
"openMenu": null,
|
"openMenu": null,
|
||||||
"openPopup": "elementBackground",
|
"openPopup": null,
|
||||||
"openSidebar": null,
|
"openSidebar": null,
|
||||||
"originSnapOffset": null,
|
"originSnapOffset": null,
|
||||||
"pasteDialog": {
|
"pasteDialog": {
|
||||||
@@ -7370,6 +7458,10 @@ exports[`regression tests > given a selected element A and a not selected elemen
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -7649,6 +7741,10 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -7884,6 +7980,10 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -8124,6 +8224,10 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -8304,6 +8408,10 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -8484,6 +8592,10 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -8664,6 +8776,10 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -8893,6 +9009,10 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9120,6 +9240,10 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9312,6 +9436,10 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9541,6 +9669,10 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9721,6 +9853,10 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -9948,6 +10084,10 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -10128,6 +10268,10 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -10320,6 +10464,10 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -10500,6 +10648,10 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -11031,6 +11183,10 @@ exports[`regression tests > noop interaction after undo shouldn't create history
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -11311,6 +11467,10 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": "-6.25000",
|
"scrollX": "-6.25000",
|
||||||
@@ -11434,6 +11594,10 @@ exports[`regression tests > shift click on selected element should deselect it o
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -11634,6 +11798,10 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -11953,6 +12121,10 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@@ -12382,6 +12554,10 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id15": true,
|
"id15": true,
|
||||||
@@ -13025,6 +13201,10 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 60,
|
"scrollX": 60,
|
||||||
@@ -13148,6 +13328,10 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
},
|
},
|
||||||
@@ -13779,6 +13963,10 @@ exports[`regression tests > switches from group of selected elements to another
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
"id6": true,
|
"id6": true,
|
||||||
@@ -14118,6 +14306,10 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {
|
"previousSelectedElementIds": {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
},
|
},
|
||||||
@@ -14382,6 +14574,10 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 20,
|
"scrollX": 20,
|
||||||
@@ -14505,6 +14701,10 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -14869,6 +15069,10 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@@ -14995,6 +15199,10 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": true,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
|
|||||||
@@ -322,6 +322,10 @@ export interface AppState {
|
|||||||
// indicates if the current tool is temporarily switched on from the selection tool
|
// indicates if the current tool is temporarily switched on from the selection tool
|
||||||
fromSelection: boolean;
|
fromSelection: boolean;
|
||||||
} & ActiveTool;
|
} & ActiveTool;
|
||||||
|
preferredSelectionTool: {
|
||||||
|
type: "selection" | "lasso";
|
||||||
|
initialized: boolean;
|
||||||
|
};
|
||||||
penMode: boolean;
|
penMode: boolean;
|
||||||
penDetected: boolean;
|
penDetected: boolean;
|
||||||
exportBackground: boolean;
|
exportBackground: boolean;
|
||||||
@@ -370,7 +374,6 @@ export interface AppState {
|
|||||||
| { name: "ttd"; tab: "text-to-diagram" | "mermaid" }
|
| { name: "ttd"; tab: "text-to-diagram" | "mermaid" }
|
||||||
| { name: "commandPalette" }
|
| { name: "commandPalette" }
|
||||||
| { name: "elementLinkSelector"; sourceElementId: ExcalidrawElement["id"] };
|
| { name: "elementLinkSelector"; sourceElementId: ExcalidrawElement["id"] };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reflects user preference for whether the default sidebar should be docked.
|
* Reflects user preference for whether the default sidebar should be docked.
|
||||||
*
|
*
|
||||||
@@ -455,7 +458,7 @@ export interface AppState {
|
|||||||
bindMode: BindMode;
|
bindMode: BindMode;
|
||||||
|
|
||||||
/** properties sidebar mode - determines whether to show compact or complete sidebar */
|
/** properties sidebar mode - determines whether to show compact or complete sidebar */
|
||||||
stylesPanelMode: "compact" | "full";
|
stylesPanelMode: "compact" | "full" | "mobile";
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SearchMatch = {
|
export type SearchMatch = {
|
||||||
@@ -578,6 +581,10 @@ export interface ExcalidrawProps {
|
|||||||
/** excludes the duplicated elements */
|
/** excludes the duplicated elements */
|
||||||
prevElements: readonly ExcalidrawElement[],
|
prevElements: readonly ExcalidrawElement[],
|
||||||
) => ExcalidrawElement[] | void;
|
) => ExcalidrawElement[] | void;
|
||||||
|
renderTopLeftUI?: (
|
||||||
|
isMobile: boolean,
|
||||||
|
appState: UIAppState,
|
||||||
|
) => JSX.Element | null;
|
||||||
renderTopRightUI?: (
|
renderTopRightUI?: (
|
||||||
isMobile: boolean,
|
isMobile: boolean,
|
||||||
appState: UIAppState,
|
appState: UIAppState,
|
||||||
@@ -745,8 +752,7 @@ export type AppClassProperties = {
|
|||||||
|
|
||||||
onPointerUpEmitter: App["onPointerUpEmitter"];
|
onPointerUpEmitter: App["onPointerUpEmitter"];
|
||||||
updateEditorAtom: App["updateEditorAtom"];
|
updateEditorAtom: App["updateEditorAtom"];
|
||||||
|
onPointerDownEmitter: App["onPointerDownEmitter"];
|
||||||
defaultSelectionTool: "selection" | "lasso";
|
|
||||||
|
|
||||||
bindModeHandler: App["bindModeHandler"];
|
bindModeHandler: App["bindModeHandler"];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -226,22 +226,6 @@ export const textWysiwyg = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const [viewportX, viewportY] = getViewportCoords(coordX, coordY);
|
const [viewportX, viewportY] = getViewportCoords(coordX, coordY);
|
||||||
const initialSelectionStart = editable.selectionStart;
|
|
||||||
const initialSelectionEnd = editable.selectionEnd;
|
|
||||||
const initialLength = editable.value.length;
|
|
||||||
|
|
||||||
// restore cursor position after value updated so it doesn't
|
|
||||||
// go to the end of text when container auto expanded
|
|
||||||
if (
|
|
||||||
initialSelectionStart === initialSelectionEnd &&
|
|
||||||
initialSelectionEnd !== initialLength
|
|
||||||
) {
|
|
||||||
// get diff between length and selection end and shift
|
|
||||||
// the cursor by "diff" times to position correctly
|
|
||||||
const diff = initialLength - initialSelectionEnd;
|
|
||||||
editable.selectionStart = editable.value.length - diff;
|
|
||||||
editable.selectionEnd = editable.value.length - diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!container) {
|
if (!container) {
|
||||||
maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
|
maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ exports[`exportToSvg > with default arguments 1`] = `
|
|||||||
},
|
},
|
||||||
"penDetected": false,
|
"penDetected": false,
|
||||||
"penMode": false,
|
"penMode": false,
|
||||||
|
"preferredSelectionTool": {
|
||||||
|
"initialized": false,
|
||||||
|
"type": "selection",
|
||||||
|
},
|
||||||
"previousSelectedElementIds": {},
|
"previousSelectedElementIds": {},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user