ソースを参照

improve clipboard handling (#596)

* improve clipboard handling

* fix regression of not defocusing tool icons
David Luzar 5 年 前
コミット
26048ee469
4 ファイル変更38 行追加21 行削除
  1. 1 1
      src/actions/manager.tsx
  2. 1 1
      src/actions/types.ts
  3. 20 14
      src/index.tsx
  4. 16 5
      src/utils.ts

+ 1 - 1
src/actions/manager.tsx

@@ -37,7 +37,7 @@ export class ActionManager implements ActionsManagerInterface {
         action => action.keyTest && action.keyTest(event, elements, appState),
       );
 
-    if (data.length === 0) return {};
+    if (data.length === 0) return null;
 
     event.preventDefault();
     return data[0].perform(elements, appState, null);

+ 1 - 1
src/actions/types.ts

@@ -45,7 +45,7 @@ export interface ActionsManagerInterface {
     event: KeyboardEvent,
     elements: readonly ExcalidrawElement[],
     appState: AppState,
-  ) => ActionResult | {};
+  ) => ActionResult | null;
   getContextMenuItems: (
     elements: readonly ExcalidrawElement[],
     appState: AppState,

+ 20 - 14
src/index.tsx

@@ -307,11 +307,15 @@ export class App extends React.Component<any, AppState> {
     }
     if (isInputLike(event.target)) return;
 
-    const data = this.actionManager.handleKeyDown(event, elements, this.state);
-    this.syncActionResult(data);
+    const actionResult = this.actionManager.handleKeyDown(
+      event,
+      elements,
+      this.state,
+    );
 
-    if (data.elements !== undefined || data.appState !== undefined) {
-      return;
+    if (actionResult) {
+      this.syncActionResult(actionResult);
+      if (actionResult) return;
     }
 
     const shape = findShapeByKey(event.key);
@@ -371,18 +375,20 @@ export class App extends React.Component<any, AppState> {
   private removeWheelEventListener: (() => void) | undefined;
 
   private copyToClipboard = () => {
-    if (navigator.clipboard) {
-      const text = JSON.stringify(
-        elements
-          .filter(element => element.isSelected)
-          .map(({ shape, ...el }) => el),
-      );
+    const text = JSON.stringify(
+      elements
+        .filter(element => element.isSelected)
+        .map(({ shape, ...el }) => el),
+    );
+    if ("clipboard" in navigator && "writeText" in navigator.clipboard) {
       navigator.clipboard.writeText(text);
+    } else {
+      document.execCommand("copy");
     }
   };
 
   private pasteFromClipboard = () => {
-    if (navigator.clipboard) {
+    if ("clipboard" in navigator && "readText" in navigator.clipboard) {
       navigator.clipboard
         .readText()
         .then(text => this.addElementsFromPaste(text));
@@ -790,9 +796,9 @@ export class App extends React.Component<any, AppState> {
               // fixes mousemove causing selection of UI texts #32
               e.preventDefault();
               // Preventing the event above disables default behavior
-              //  of defocusing potentially focused input, which is what we want
-              //  when clicking inside the canvas.
-              if (isInputLike(document.activeElement)) {
+              //  of defocusing potentially focused element, which is what we
+              //  want when clicking inside the canvas.
+              if (document.activeElement instanceof HTMLElement) {
                 document.activeElement.blur();
               }
 

+ 16 - 5
src/utils.ts

@@ -14,14 +14,25 @@ export function capitalizeString(str: string) {
   return str.charAt(0).toUpperCase() + str.slice(1);
 }
 
+export function isToolIcon(
+  target: Element | EventTarget | null,
+): target is HTMLElement {
+  return target instanceof HTMLElement && target.className.includes("ToolIcon");
+}
+
 export function isInputLike(
   target: Element | EventTarget | null,
-): target is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement {
+): target is
+  | HTMLInputElement
+  | HTMLTextAreaElement
+  | HTMLSelectElement
+  | HTMLDivElement {
   return (
-    (target instanceof HTMLElement && target.dataset.type === "wysiwyg") ||
-    target instanceof HTMLInputElement ||
-    target instanceof HTMLTextAreaElement ||
-    target instanceof HTMLSelectElement
+    ((target instanceof HTMLElement && target.dataset.type === "wysiwyg") ||
+      target instanceof HTMLInputElement ||
+      target instanceof HTMLTextAreaElement ||
+      target instanceof HTMLSelectElement) &&
+    !isToolIcon(target)
   );
 }