actionCanvas.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import React from "react";
  2. import { ColorPicker } from "../components/ColorPicker";
  3. import { getDefaultAppState } from "../appState";
  4. import { trash, zoomIn, zoomOut, resetZoom } from "../components/icons";
  5. import { ToolButton } from "../components/ToolButton";
  6. import { t } from "../i18n";
  7. import { getNormalizedZoom } from "../scene";
  8. import { KEYS } from "../keys";
  9. import { getShortcutKey } from "../utils";
  10. import useIsMobile from "../is-mobile";
  11. import { register } from "./register";
  12. import { newElementWith } from "../element/mutateElement";
  13. export const actionChangeViewBackgroundColor = register({
  14. name: "changeViewBackgroundColor",
  15. perform: (_, appState, value) => {
  16. return { appState: { ...appState, viewBackgroundColor: value } };
  17. },
  18. PanelComponent: ({ appState, updateData }) => {
  19. return (
  20. <div style={{ position: "relative" }}>
  21. <ColorPicker
  22. label={t("labels.canvasBackground")}
  23. type="canvasBackground"
  24. color={appState.viewBackgroundColor}
  25. onChange={color => updateData(color)}
  26. />
  27. </div>
  28. );
  29. },
  30. commitToHistory: () => true,
  31. });
  32. export const actionClearCanvas = register({
  33. name: "clearCanvas",
  34. commitToHistory: () => true,
  35. perform: elements => {
  36. return {
  37. elements: elements.map(element =>
  38. newElementWith(element, { isDeleted: true }),
  39. ),
  40. appState: getDefaultAppState(),
  41. };
  42. },
  43. PanelComponent: ({ updateData }) => (
  44. <ToolButton
  45. type="button"
  46. icon={trash}
  47. title={t("buttons.clearReset")}
  48. aria-label={t("buttons.clearReset")}
  49. showAriaLabel={useIsMobile()}
  50. onClick={() => {
  51. if (window.confirm(t("alerts.clearReset"))) {
  52. // TODO: Defined globally, since file handles aren't yet serializable.
  53. // Once `FileSystemFileHandle` can be serialized, make this
  54. // part of `AppState`.
  55. (window as any).handle = null;
  56. updateData(null);
  57. }
  58. }}
  59. />
  60. ),
  61. });
  62. const ZOOM_STEP = 0.1;
  63. const KEY_CODES = {
  64. MINUS: "Minus",
  65. EQUAL: "Equal",
  66. ZERO: "Digit0",
  67. NUM_SUBTRACT: "NumpadSubtract",
  68. NUM_ADD: "NumpadAdd",
  69. NUM_ZERO: "Numpad0",
  70. };
  71. export const actionZoomIn = register({
  72. name: "zoomIn",
  73. perform: (_elements, appState) => {
  74. return {
  75. appState: {
  76. ...appState,
  77. zoom: getNormalizedZoom(appState.zoom + ZOOM_STEP),
  78. },
  79. };
  80. },
  81. PanelComponent: ({ updateData }) => (
  82. <ToolButton
  83. type="button"
  84. icon={zoomIn}
  85. title={`${t("buttons.zoomIn")} ${getShortcutKey("CtrlOrCmd++")}`}
  86. aria-label={t("buttons.zoomIn")}
  87. onClick={() => {
  88. updateData(null);
  89. }}
  90. />
  91. ),
  92. keyTest: event =>
  93. (event.code === KEY_CODES.EQUAL || event.code === KEY_CODES.NUM_ADD) &&
  94. (event[KEYS.CTRL_OR_CMD] || event.shiftKey),
  95. });
  96. export const actionZoomOut = register({
  97. name: "zoomOut",
  98. perform: (_elements, appState) => {
  99. return {
  100. appState: {
  101. ...appState,
  102. zoom: getNormalizedZoom(appState.zoom - ZOOM_STEP),
  103. },
  104. };
  105. },
  106. PanelComponent: ({ updateData }) => (
  107. <ToolButton
  108. type="button"
  109. icon={zoomOut}
  110. title={`${t("buttons.zoomOut")} ${getShortcutKey("CtrlOrCmd+-")}`}
  111. aria-label={t("buttons.zoomOut")}
  112. onClick={() => {
  113. updateData(null);
  114. }}
  115. />
  116. ),
  117. keyTest: event =>
  118. (event.code === KEY_CODES.MINUS || event.code === KEY_CODES.NUM_SUBTRACT) &&
  119. (event[KEYS.CTRL_OR_CMD] || event.shiftKey),
  120. });
  121. export const actionResetZoom = register({
  122. name: "resetZoom",
  123. perform: (_elements, appState) => {
  124. return {
  125. appState: {
  126. ...appState,
  127. zoom: 1,
  128. },
  129. };
  130. },
  131. PanelComponent: ({ updateData }) => (
  132. <ToolButton
  133. type="button"
  134. icon={resetZoom}
  135. title={t("buttons.resetZoom")}
  136. aria-label={t("buttons.resetZoom")}
  137. onClick={() => {
  138. updateData(null);
  139. }}
  140. />
  141. ),
  142. keyTest: event =>
  143. (event.code === KEY_CODES.ZERO || event.code === KEY_CODES.NUM_ZERO) &&
  144. (event[KEYS.CTRL_OR_CMD] || event.shiftKey),
  145. });