Переглянути джерело

feat: Copy to clipboard all text nodes as text (#5013)

* Copy to clipboard all text nodes as text

* fix: only show the option for text elements
Faustino Kialungila 3 роки тому
батько
коміт
670ceafc84

+ 17 - 1
src/actions/actionClipboard.tsx

@@ -1,11 +1,12 @@
 import { CODES, KEYS } from "../keys";
 import { register } from "./register";
-import { copyToClipboard } from "../clipboard";
+import { copyTextToSystemClipboard, copyToClipboard } from "../clipboard";
 import { actionDeleteSelected } from "./actionDeleteSelected";
 import { getSelectedElements } from "../scene/selection";
 import { exportCanvas } from "../data/index";
 import { getNonDeletedElements } from "../element";
 import { t } from "../i18n";
+import { ExcalidrawTextElement } from "../element/types";
 
 export const actionCopy = register({
   name: "copy",
@@ -126,3 +127,18 @@ export const actionCopyAsPng = register({
   contextItemLabel: "labels.copyAsPng",
   keyTest: (event) => event.code === CODES.C && event.altKey && event.shiftKey,
 });
+
+export const copyAllTextNodesAsText = register({
+  name: "copyAllTextNodesAsText",
+  trackEvent: { category: "element" },
+  perform: (elements) => {
+    const text = (
+      getNonDeletedElements(elements) as ExcalidrawTextElement[]
+    ).reduce((acc, element) => `${acc}${element.text}\n`, "");
+    copyTextToSystemClipboard(text);
+    return {
+      commitToHistory: false,
+    };
+  },
+  contextItemLabel: "labels.copyAllTextNodesAsText",
+});

+ 1 - 0
src/actions/index.ts

@@ -75,6 +75,7 @@ export {
   actionCut,
   actionCopyAsPng,
   actionCopyAsSvg,
+  copyAllTextNodesAsText,
 } from "./actionClipboard";
 
 export { actionToggleGridMode } from "./actionToggleGridMode";

+ 1 - 0
src/actions/types.ts

@@ -41,6 +41,7 @@ export type ActionName =
   | "paste"
   | "copyAsPng"
   | "copyAsSvg"
+  | "copyAllTextNodesAsText"
   | "sendBackward"
   | "bringForward"
   | "sendToBack"

+ 15 - 0
src/components/App.tsx

@@ -11,6 +11,7 @@ import {
   actionCopy,
   actionCopyAsPng,
   actionCopyAsSvg,
+  copyAllTextNodesAsText,
   actionCopyStyles,
   actionCut,
   actionDeleteSelected,
@@ -5475,6 +5476,8 @@ class App extends React.Component<AppProps, AppState> {
 
     const elements = this.scene.getElements();
 
+    const isTextNodesOnly = elements.every((element) => isTextElement(element));
+
     const options: ContextMenuOption[] = [];
     if (probablySupportsClipboardBlob && elements.length > 0) {
       options.push(actionCopyAsPng);
@@ -5483,6 +5486,14 @@ class App extends React.Component<AppProps, AppState> {
     if (probablySupportsClipboardWriteText && elements.length > 0) {
       options.push(actionCopyAsSvg);
     }
+
+    if (
+      probablySupportsClipboardWriteText &&
+      elements.length > 0 &&
+      isTextNodesOnly
+    ) {
+      options.push(copyAllTextNodesAsText);
+    }
     if (type === "canvas") {
       const viewModeOptions = [
         ...options,
@@ -5526,6 +5537,10 @@ class App extends React.Component<AppProps, AppState> {
             probablySupportsClipboardWriteText &&
               elements.length > 0 &&
               actionCopyAsSvg,
+            probablySupportsClipboardWriteText &&
+              elements.length > 0 &&
+              isTextNodesOnly &&
+              copyAllTextNodesAsText,
             ((probablySupportsClipboardBlob && elements.length > 0) ||
               (probablySupportsClipboardWriteText && elements.length > 0)) &&
               separator,

+ 1 - 0
src/locales/en.json

@@ -9,6 +9,7 @@
     "copy": "Copy",
     "copyAsPng": "Copy to clipboard as PNG",
     "copyAsSvg": "Copy to clipboard as SVG",
+    "copyAllTextNodesAsText": "Copy to clipboard as a single text element",
     "bringForward": "Bring forward",
     "sendToBack": "Send to back",
     "bringToFront": "Bring to front",