mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
fix: Add multiElement-edit finalize action to Desktop (currently only visible in Mobile view) (#4764)
* add finalize action to Desktop UI * Update LayerUI.tsx * add size to panel component * finzalize button style * add finalize button * changed isMobile to DeviceInfo, added isTouchScreen * cleanup * rename deviceInfo to deviceType * rename deviceInfo to deviceType * added updateObject * Update App.tsx
This commit is contained in:
parent
1cfb4dfd8b
commit
192debd829
17 changed files with 138 additions and 61 deletions
|
@ -195,6 +195,7 @@ import {
|
|||
LibraryItems,
|
||||
PointerDownState,
|
||||
SceneData,
|
||||
DeviceType,
|
||||
} from "../types";
|
||||
import {
|
||||
debounce,
|
||||
|
@ -214,6 +215,7 @@ import {
|
|||
withBatchedUpdates,
|
||||
wrapEvent,
|
||||
withBatchedUpdatesThrottled,
|
||||
updateObject,
|
||||
setEraserCursor,
|
||||
} from "../utils";
|
||||
import ContextMenu, { ContextMenuOption } from "./ContextMenu";
|
||||
|
@ -253,8 +255,12 @@ import {
|
|||
isLocalLink,
|
||||
} from "../element/Hyperlink";
|
||||
|
||||
const IsMobileContext = React.createContext(false);
|
||||
export const useIsMobile = () => useContext(IsMobileContext);
|
||||
const defaultDeviceTypeContext: DeviceType = {
|
||||
isMobile: false,
|
||||
isTouchScreen: false,
|
||||
};
|
||||
const DeviceTypeContext = React.createContext(defaultDeviceTypeContext);
|
||||
export const useDeviceType = () => useContext(DeviceTypeContext);
|
||||
const ExcalidrawContainerContext = React.createContext<{
|
||||
container: HTMLDivElement | null;
|
||||
id: string | null;
|
||||
|
@ -286,7 +292,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||
rc: RoughCanvas | null = null;
|
||||
unmounted: boolean = false;
|
||||
actionManager: ActionManager;
|
||||
isMobile = false;
|
||||
deviceType: DeviceType = {
|
||||
isMobile: false,
|
||||
isTouchScreen: false,
|
||||
};
|
||||
detachIsMobileMqHandler?: () => void;
|
||||
|
||||
private excalidrawContainerRef = React.createRef<HTMLDivElement>();
|
||||
|
@ -468,7 +477,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
<div
|
||||
className={clsx("excalidraw excalidraw-container", {
|
||||
"excalidraw--view-mode": viewModeEnabled,
|
||||
"excalidraw--mobile": this.isMobile,
|
||||
"excalidraw--mobile": this.deviceType.isMobile,
|
||||
})}
|
||||
ref={this.excalidrawContainerRef}
|
||||
onDrop={this.handleAppOnDrop}
|
||||
|
@ -480,7 +489,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
<ExcalidrawContainerContext.Provider
|
||||
value={this.excalidrawContainerValue}
|
||||
>
|
||||
<IsMobileContext.Provider value={this.isMobile}>
|
||||
<DeviceTypeContext.Provider value={this.deviceType}>
|
||||
<LayerUI
|
||||
canvas={this.canvas}
|
||||
appState={this.state}
|
||||
|
@ -547,7 +556,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
/>
|
||||
)}
|
||||
<main>{this.renderCanvas()}</main>
|
||||
</IsMobileContext.Provider>
|
||||
</DeviceTypeContext.Provider>
|
||||
</ExcalidrawContainerContext.Provider>
|
||||
</div>
|
||||
);
|
||||
|
@ -891,9 +900,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||
// ---------------------------------------------------------------------
|
||||
const { width, height } =
|
||||
this.excalidrawContainerRef.current!.getBoundingClientRect();
|
||||
this.isMobile =
|
||||
width < MQ_MAX_WIDTH_PORTRAIT ||
|
||||
(height < MQ_MAX_HEIGHT_LANDSCAPE && width < MQ_MAX_WIDTH_LANDSCAPE);
|
||||
this.deviceType = updateObject(this.deviceType, {
|
||||
isMobile:
|
||||
width < MQ_MAX_WIDTH_PORTRAIT ||
|
||||
(height < MQ_MAX_HEIGHT_LANDSCAPE &&
|
||||
width < MQ_MAX_WIDTH_LANDSCAPE),
|
||||
});
|
||||
// refresh offsets
|
||||
// ---------------------------------------------------------------------
|
||||
this.updateDOMRect();
|
||||
|
@ -903,7 +915,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||
const mediaQuery = window.matchMedia(
|
||||
`(max-width: ${MQ_MAX_WIDTH_PORTRAIT}px), (max-height: ${MQ_MAX_HEIGHT_LANDSCAPE}px) and (max-width: ${MQ_MAX_WIDTH_LANDSCAPE}px)`,
|
||||
);
|
||||
const handler = () => (this.isMobile = mediaQuery.matches);
|
||||
const handler = () => {
|
||||
this.deviceType = updateObject(this.deviceType, {
|
||||
isMobile: mediaQuery.matches,
|
||||
});
|
||||
};
|
||||
mediaQuery.addListener(handler);
|
||||
this.detachIsMobileMqHandler = () => mediaQuery.removeListener(handler);
|
||||
}
|
||||
|
@ -1205,7 +1221,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
theme: this.state.theme,
|
||||
imageCache: this.imageCache,
|
||||
isExporting: false,
|
||||
renderScrollbars: !this.isMobile,
|
||||
renderScrollbars: !this.deviceType.isMobile,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -2391,7 +2407,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
element,
|
||||
this.state,
|
||||
[scenePointer.x, scenePointer.y],
|
||||
this.isMobile,
|
||||
this.deviceType.isMobile,
|
||||
) &&
|
||||
index <= hitElementIndex
|
||||
);
|
||||
|
@ -2424,7 +2440,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.hitLinkElement!,
|
||||
this.state,
|
||||
[lastPointerDownCoords.x, lastPointerDownCoords.y],
|
||||
this.isMobile,
|
||||
this.deviceType.isMobile,
|
||||
);
|
||||
const lastPointerUpCoords = viewportCoordsToSceneCoords(
|
||||
this.lastPointerUp!,
|
||||
|
@ -2434,7 +2450,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.hitLinkElement!,
|
||||
this.state,
|
||||
[lastPointerUpCoords.x, lastPointerUpCoords.y],
|
||||
this.isMobile,
|
||||
this.deviceType.isMobile,
|
||||
);
|
||||
if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {
|
||||
const url = this.hitLinkElement.link;
|
||||
|
@ -2856,6 +2872,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||
});
|
||||
}
|
||||
|
||||
if (
|
||||
!this.deviceType.isTouchScreen &&
|
||||
["pen", "touch"].includes(event.pointerType)
|
||||
) {
|
||||
this.deviceType = updateObject(this.deviceType, { isTouchScreen: true });
|
||||
}
|
||||
|
||||
if (isPanning) {
|
||||
return;
|
||||
}
|
||||
|
@ -2986,9 +3009,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
event: React.PointerEvent<HTMLCanvasElement>,
|
||||
) => {
|
||||
this.lastPointerUp = event;
|
||||
const isTouchScreen = ["pen", "touch"].includes(event.pointerType);
|
||||
|
||||
if (isTouchScreen) {
|
||||
if (this.deviceType.isTouchScreen) {
|
||||
const scenePointer = viewportCoordsToSceneCoords(
|
||||
{ clientX: event.clientX, clientY: event.clientY },
|
||||
this.state,
|
||||
|
@ -3006,7 +3027,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
this.hitLinkElement &&
|
||||
!this.state.selectedElementIds[this.hitLinkElement.id]
|
||||
) {
|
||||
this.redirectToLink(event, isTouchScreen);
|
||||
this.redirectToLink(event, this.deviceType.isTouchScreen);
|
||||
}
|
||||
|
||||
this.removePointer(event);
|
||||
|
@ -3376,7 +3397,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
pointerDownState.hit.element,
|
||||
this.state,
|
||||
[pointerDownState.origin.x, pointerDownState.origin.y],
|
||||
this.isMobile,
|
||||
this.deviceType.isMobile,
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
|
@ -5407,7 +5428,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
} else {
|
||||
ContextMenu.push({
|
||||
options: [
|
||||
this.isMobile &&
|
||||
this.deviceType.isMobile &&
|
||||
navigator.clipboard && {
|
||||
name: "paste",
|
||||
perform: (elements, appStates) => {
|
||||
|
@ -5418,7 +5439,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
},
|
||||
contextItemLabel: "labels.paste",
|
||||
},
|
||||
this.isMobile && navigator.clipboard && separator,
|
||||
this.deviceType.isMobile && navigator.clipboard && separator,
|
||||
probablySupportsClipboardBlob &&
|
||||
elements.length > 0 &&
|
||||
actionCopyAsPng,
|
||||
|
@ -5464,9 +5485,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||
} else {
|
||||
ContextMenu.push({
|
||||
options: [
|
||||
this.isMobile && actionCut,
|
||||
this.isMobile && navigator.clipboard && actionCopy,
|
||||
this.isMobile &&
|
||||
this.deviceType.isMobile && actionCut,
|
||||
this.deviceType.isMobile && navigator.clipboard && actionCopy,
|
||||
this.deviceType.isMobile &&
|
||||
navigator.clipboard && {
|
||||
name: "paste",
|
||||
perform: (elements, appStates) => {
|
||||
|
@ -5477,7 +5498,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
},
|
||||
contextItemLabel: "labels.paste",
|
||||
},
|
||||
this.isMobile && separator,
|
||||
this.deviceType.isMobile && separator,
|
||||
...options,
|
||||
separator,
|
||||
actionCopyStyles,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue