mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-11-03 20:34:40 +01:00 
			
		
		
		
	More mobile tweaks (#790)
* Disable text selection * Set content-editable=plaintext-only to disable Touch Bar formatting buttons * Enlarge resize handle tap targets for pen/touch * Make the lock button a button in mobile mode * Use icons instead of Unicode characters; add an alternate toolbar for creating multipoint lines * Allow buttons to hide themselves * Fix heuristic for showing shape actions * Refactor icons * Fix label for edit button * Switch edit button icon * Remove lock button on mobile * Add language selector on mobile * Fix showing edit button on mobile * Fix showing edit button on mobile, part 2 * Fix handle touch regions * Fix scroll-back button position * Allow using the text tool on a text object to start editing it * Fix deletion of last point in line
This commit is contained in:
		@@ -1,15 +1,26 @@
 | 
			
		||||
import { ExcalidrawElement } from "./types";
 | 
			
		||||
import { ExcalidrawElement, PointerType } from "./types";
 | 
			
		||||
 | 
			
		||||
import { getElementAbsoluteCoords } from "./bounds";
 | 
			
		||||
 | 
			
		||||
type Sides = "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se";
 | 
			
		||||
 | 
			
		||||
export function handlerRectangles(element: ExcalidrawElement, zoom: number) {
 | 
			
		||||
  const handlerWidth = 8 / zoom;
 | 
			
		||||
  const handlerHeight = 8 / zoom;
 | 
			
		||||
const handleSizes: { [k in PointerType]: number } = {
 | 
			
		||||
  mouse: 8,
 | 
			
		||||
  pen: 16,
 | 
			
		||||
  touch: 28,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
  const handlerMarginX = 8 / zoom;
 | 
			
		||||
  const handlerMarginY = 8 / zoom;
 | 
			
		||||
export function handlerRectangles(
 | 
			
		||||
  element: ExcalidrawElement,
 | 
			
		||||
  zoom: number,
 | 
			
		||||
  pointerType: PointerType = "mouse",
 | 
			
		||||
) {
 | 
			
		||||
  const size = handleSizes[pointerType];
 | 
			
		||||
  const handlerWidth = size / zoom;
 | 
			
		||||
  const handlerHeight = size / zoom;
 | 
			
		||||
 | 
			
		||||
  const handlerMarginX = size / zoom;
 | 
			
		||||
  const handlerMarginY = size / zoom;
 | 
			
		||||
 | 
			
		||||
  const [elementX1, elementY1, elementX2, elementY2] = getElementAbsoluteCoords(
 | 
			
		||||
    element,
 | 
			
		||||
@@ -20,59 +31,61 @@ export function handlerRectangles(element: ExcalidrawElement, zoom: number) {
 | 
			
		||||
 | 
			
		||||
  const dashedLineMargin = 4 / zoom;
 | 
			
		||||
 | 
			
		||||
  const centeringOffset = (size - 8) / (2 * zoom);
 | 
			
		||||
 | 
			
		||||
  const handlers = {
 | 
			
		||||
    nw: [
 | 
			
		||||
      elementX1 - dashedLineMargin - handlerMarginX,
 | 
			
		||||
      elementY1 - dashedLineMargin - handlerMarginY,
 | 
			
		||||
      elementX1 - dashedLineMargin - handlerMarginX + centeringOffset,
 | 
			
		||||
      elementY1 - dashedLineMargin - handlerMarginY + centeringOffset,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ],
 | 
			
		||||
    ne: [
 | 
			
		||||
      elementX2 + dashedLineMargin,
 | 
			
		||||
      elementY1 - dashedLineMargin - handlerMarginY,
 | 
			
		||||
      elementX2 + dashedLineMargin - centeringOffset,
 | 
			
		||||
      elementY1 - dashedLineMargin - handlerMarginY + centeringOffset,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ],
 | 
			
		||||
    sw: [
 | 
			
		||||
      elementX1 - dashedLineMargin - handlerMarginX,
 | 
			
		||||
      elementY2 + dashedLineMargin,
 | 
			
		||||
      elementX1 - dashedLineMargin - handlerMarginX + centeringOffset,
 | 
			
		||||
      elementY2 + dashedLineMargin - centeringOffset,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ],
 | 
			
		||||
    se: [
 | 
			
		||||
      elementX2 + dashedLineMargin,
 | 
			
		||||
      elementY2 + dashedLineMargin,
 | 
			
		||||
      elementX2 + dashedLineMargin - centeringOffset,
 | 
			
		||||
      elementY2 + dashedLineMargin - centeringOffset,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ],
 | 
			
		||||
  } as { [T in Sides]: number[] };
 | 
			
		||||
 | 
			
		||||
  // We only want to show height handlers (all cardinal directions)  above a certain size
 | 
			
		||||
  const minimumSizeForEightHandlers = 40 / zoom;
 | 
			
		||||
  const minimumSizeForEightHandlers = (5 * size) / zoom;
 | 
			
		||||
  if (Math.abs(elementWidth) > minimumSizeForEightHandlers) {
 | 
			
		||||
    handlers["n"] = [
 | 
			
		||||
      elementX1 + elementWidth / 2,
 | 
			
		||||
      elementY1 - dashedLineMargin - handlerMarginY,
 | 
			
		||||
      elementX1 + elementWidth / 2 - handlerWidth / 2,
 | 
			
		||||
      elementY1 - dashedLineMargin - handlerMarginY + centeringOffset,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ];
 | 
			
		||||
    handlers["s"] = [
 | 
			
		||||
      elementX1 + elementWidth / 2,
 | 
			
		||||
      elementY2 + dashedLineMargin,
 | 
			
		||||
      elementX1 + elementWidth / 2 - handlerWidth / 2,
 | 
			
		||||
      elementY2 + dashedLineMargin - centeringOffset,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
  if (Math.abs(elementHeight) > minimumSizeForEightHandlers) {
 | 
			
		||||
    handlers["w"] = [
 | 
			
		||||
      elementX1 - dashedLineMargin - handlerMarginX,
 | 
			
		||||
      elementY1 + elementHeight / 2,
 | 
			
		||||
      elementX1 - dashedLineMargin - handlerMarginX + centeringOffset,
 | 
			
		||||
      elementY1 + elementHeight / 2 - handlerHeight / 2,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ];
 | 
			
		||||
    handlers["e"] = [
 | 
			
		||||
      elementX2 + dashedLineMargin,
 | 
			
		||||
      elementY1 + elementHeight / 2,
 | 
			
		||||
      elementX2 + dashedLineMargin - centeringOffset,
 | 
			
		||||
      elementY1 + elementHeight / 2 - handlerHeight / 2,
 | 
			
		||||
      handlerWidth,
 | 
			
		||||
      handlerHeight,
 | 
			
		||||
    ];
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { ExcalidrawElement } from "./types";
 | 
			
		||||
import { ExcalidrawElement, PointerType } from "./types";
 | 
			
		||||
 | 
			
		||||
import { handlerRectangles } from "./handlerRectangles";
 | 
			
		||||
 | 
			
		||||
@@ -9,12 +9,13 @@ export function resizeTest(
 | 
			
		||||
  x: number,
 | 
			
		||||
  y: number,
 | 
			
		||||
  zoom: number,
 | 
			
		||||
  pointerType: PointerType,
 | 
			
		||||
): HandlerRectanglesRet | false {
 | 
			
		||||
  if (!element.isSelected || element.type === "text") {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const handlers = handlerRectangles(element, zoom);
 | 
			
		||||
  const handlers = handlerRectangles(element, zoom, pointerType);
 | 
			
		||||
 | 
			
		||||
  const filter = Object.keys(handlers).filter(key => {
 | 
			
		||||
    const handler = handlers[key as HandlerRectanglesRet]!;
 | 
			
		||||
@@ -41,12 +42,13 @@ export function getElementWithResizeHandler(
 | 
			
		||||
  elements: readonly ExcalidrawElement[],
 | 
			
		||||
  { x, y }: { x: number; y: number },
 | 
			
		||||
  zoom: number,
 | 
			
		||||
  pointerType: PointerType,
 | 
			
		||||
) {
 | 
			
		||||
  return elements.reduce((result, element) => {
 | 
			
		||||
    if (result) {
 | 
			
		||||
      return result;
 | 
			
		||||
    }
 | 
			
		||||
    const resizeHandle = resizeTest(element, x, y, zoom);
 | 
			
		||||
    const resizeHandle = resizeTest(element, x, y, zoom, pointerType);
 | 
			
		||||
    return resizeHandle ? { element, resizeHandle } : null;
 | 
			
		||||
  }, null as { element: ExcalidrawElement; resizeHandle: ReturnType<typeof resizeTest> } | null);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ export function textWysiwyg({
 | 
			
		||||
  // But this solution has an issue — it allows to paste
 | 
			
		||||
  // multiline text, which is not currently supported
 | 
			
		||||
  const editable = document.createElement("div");
 | 
			
		||||
  editable.contentEditable = "true";
 | 
			
		||||
  editable.contentEditable = "plaintext-only";
 | 
			
		||||
  editable.tabIndex = 0;
 | 
			
		||||
  editable.innerText = initText;
 | 
			
		||||
  editable.dataset.type = "wysiwyg";
 | 
			
		||||
 
 | 
			
		||||
@@ -9,3 +9,5 @@ export type ExcalidrawTextElement = ExcalidrawElement & {
 | 
			
		||||
  actualBoundingBoxAscent?: number;
 | 
			
		||||
  baseline: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type PointerType = "mouse" | "pen" | "touch";
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user