actionDuplicateSelection.tsx 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import React from "react";
  2. import { KEYS } from "../keys";
  3. import { register } from "./register";
  4. import { ExcalidrawElement } from "../element/types";
  5. import { duplicateElement, getNonDeletedElements } from "../element";
  6. import { isSomeElementSelected } from "../scene";
  7. import { ToolButton } from "../components/ToolButton";
  8. import { clone } from "../components/icons";
  9. import { t } from "../i18n";
  10. import { getShortcutKey } from "../utils";
  11. export const actionDuplicateSelection = register({
  12. name: "duplicateSelection",
  13. perform: (elements, appState) => {
  14. const groupIdMap = new Map();
  15. return {
  16. appState,
  17. elements: elements.reduce(
  18. (acc: Array<ExcalidrawElement>, element: ExcalidrawElement) => {
  19. if (appState.selectedElementIds[element.id]) {
  20. const newElement = duplicateElement(
  21. appState.editingGroupId,
  22. groupIdMap,
  23. element,
  24. {
  25. x: element.x + 10,
  26. y: element.y + 10,
  27. },
  28. );
  29. appState.selectedElementIds[newElement.id] = true;
  30. delete appState.selectedElementIds[element.id];
  31. return acc.concat([element, newElement]);
  32. }
  33. return acc.concat(element);
  34. },
  35. [],
  36. ),
  37. commitToHistory: true,
  38. };
  39. },
  40. contextItemLabel: "labels.duplicateSelection",
  41. keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.key === "d",
  42. PanelComponent: ({ elements, appState, updateData }) => (
  43. <ToolButton
  44. type="button"
  45. icon={clone}
  46. title={`${t("labels.duplicateSelection")} — ${getShortcutKey(
  47. "CtrlOrCmd+D",
  48. )}`}
  49. aria-label={t("labels.duplicateSelection")}
  50. onClick={() => updateData(null)}
  51. visible={isSomeElementSelected(getNonDeletedElements(elements), appState)}
  52. />
  53. ),
  54. });