@myoc/excalidraw 0.19.537 → 0.19.539

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/dist/dev/{chunk-SZMFGT5M.js → chunk-2OVHIH4L.js} +3 -1
  3. package/dist/dev/chunk-2OVHIH4L.js.map +7 -0
  4. package/dist/dev/{chunk-7R7FDLAY.js → chunk-HJ2ALDN7.js} +30 -6
  5. package/dist/dev/chunk-HJ2ALDN7.js.map +7 -0
  6. package/dist/dev/{chunk-GMDJS52C.js → chunk-IJ2BHUZB.js} +2 -2
  7. package/dist/dev/data/{image-2QLYX6JM.js → image-2GHT4EI2.js} +3 -3
  8. package/dist/dev/index.js +387 -281
  9. package/dist/dev/index.js.map +4 -4
  10. package/dist/dev/locales/{en-FTXMBOG2.js → en-JINXO2V2.js} +2 -2
  11. package/dist/dev/subset-shared.chunk.js +1 -1
  12. package/dist/dev/subset-worker.chunk.js +1 -1
  13. package/dist/prod/chunk-5VYFU2RO.js +4 -0
  14. package/dist/prod/{chunk-5FNQLKFO.js → chunk-KGIBYNMP.js} +3 -3
  15. package/dist/prod/{chunk-U2M5DXIZ.js → chunk-U2CW5GZO.js} +1 -1
  16. package/dist/prod/data/image-VJFP4SPS.js +1 -0
  17. package/dist/prod/index.js +13 -13
  18. package/dist/prod/locales/{en-S77ABPIF.js → en-2ZA2LKRK.js} +1 -1
  19. package/dist/prod/subset-shared.chunk.js +1 -1
  20. package/dist/prod/subset-worker.chunk.js +1 -1
  21. package/dist/types/common/src/utils.d.ts +15 -12
  22. package/dist/types/excalidraw/actions/actionAlign.d.ts +1 -0
  23. package/dist/types/excalidraw/actions/actionBoundText.d.ts +2 -0
  24. package/dist/types/excalidraw/actions/actionCanvas.d.ts +6 -0
  25. package/dist/types/excalidraw/actions/actionClipboard.d.ts +2 -0
  26. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +1 -0
  27. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +3 -0
  28. package/dist/types/excalidraw/actions/actionDeselect.d.ts +1 -0
  29. package/dist/types/excalidraw/actions/actionElementLink.d.ts +1 -0
  30. package/dist/types/excalidraw/actions/actionElementLock.d.ts +2 -0
  31. package/dist/types/excalidraw/actions/actionExport.d.ts +2 -0
  32. package/dist/types/excalidraw/actions/actionFlipViewpoint.d.ts +43 -0
  33. package/dist/types/excalidraw/actions/actionFrame.d.ts +3 -0
  34. package/dist/types/excalidraw/actions/actionGroup.d.ts +2 -0
  35. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +1 -0
  36. package/dist/types/excalidraw/actions/actionLink.d.ts +1 -0
  37. package/dist/types/excalidraw/actions/actionMenu.d.ts +1 -0
  38. package/dist/types/excalidraw/actions/actionProperties.d.ts +2 -0
  39. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +1 -0
  40. package/dist/types/excalidraw/actions/actionStyles.d.ts +1 -0
  41. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +1 -0
  42. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +1 -0
  43. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +1 -0
  44. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +1 -0
  45. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +1 -0
  46. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +1 -0
  47. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +1 -0
  48. package/dist/types/excalidraw/actions/index.d.ts +1 -0
  49. package/dist/types/excalidraw/actions/shortcuts.d.ts +1 -1
  50. package/dist/types/excalidraw/actions/types.d.ts +1 -1
  51. package/dist/types/excalidraw/data/blob.d.ts +1 -0
  52. package/dist/types/excalidraw/data/json.d.ts +1 -0
  53. package/dist/types/excalidraw/index.d.ts +1 -1
  54. package/dist/types/excalidraw/renderer/viewpoint.d.ts +8 -0
  55. package/dist/types/excalidraw/types.d.ts +5 -1
  56. package/dist/types/excalidraw/viewport.d.ts +1 -0
  57. package/package.json +4 -4
  58. package/dist/dev/chunk-7R7FDLAY.js.map +0 -7
  59. package/dist/dev/chunk-SZMFGT5M.js.map +0 -7
  60. package/dist/prod/chunk-C4BFS67G.js +0 -4
  61. package/dist/prod/data/image-3GEOMH65.js +0 -1
  62. /package/dist/dev/{chunk-GMDJS52C.js.map → chunk-IJ2BHUZB.js.map} +0 -0
  63. /package/dist/dev/data/{image-2QLYX6JM.js.map → image-2GHT4EI2.js.map} +0 -0
  64. /package/dist/dev/locales/{en-FTXMBOG2.js.map → en-JINXO2V2.js.map} +0 -0
package/dist/dev/index.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  ImageURLToFile,
8
8
  SVGStringToFile,
9
9
  UnsupportedImageFileTypeError,
10
+ applyZoomAndViewpointFlip,
10
11
  bootstrapCanvas,
11
12
  canChangeRoundness,
12
13
  canHaveArrowheads,
@@ -63,13 +64,13 @@ import {
63
64
  serializeAsJSON,
64
65
  strokeRectWithRotation_simple,
65
66
  zoomToFitBounds
66
- } from "./chunk-7R7FDLAY.js";
67
+ } from "./chunk-HJ2ALDN7.js";
67
68
  import {
68
69
  define_import_meta_env_default
69
- } from "./chunk-GMDJS52C.js";
70
+ } from "./chunk-IJ2BHUZB.js";
70
71
  import {
71
72
  en_default
72
- } from "./chunk-SZMFGT5M.js";
73
+ } from "./chunk-2OVHIH4L.js";
73
74
  import {
74
75
  percentages_default
75
76
  } from "./chunk-72CYJXY3.js";
@@ -114,12 +115,12 @@ import {
114
115
  vectorNormalize as vectorNormalize6
115
116
  } from "@excalidraw/math";
116
117
  import {
117
- CODES as CODES11,
118
+ CODES as CODES12,
118
119
  shouldResizeFromCenter,
119
120
  shouldMaintainAspectRatio,
120
121
  shouldRotateWithDiscreteAngle as shouldRotateWithDiscreteAngle4,
121
122
  isArrowKey as isArrowKey3,
122
- KEYS as KEYS52,
123
+ KEYS as KEYS53,
123
124
  APP_NAME,
124
125
  CURSOR_TYPE as CURSOR_TYPE2,
125
126
  DEFAULT_STROKE_STREAMLINE as DEFAULT_STROKE_STREAMLINE3,
@@ -202,7 +203,8 @@ import {
202
203
  setDesktopUIMode,
203
204
  isSelectionLikeTool,
204
205
  oneOf,
205
- getStrokeWidthByKey as getStrokeWidthByKey5
206
+ getStrokeWidthByKey as getStrokeWidthByKey5,
207
+ getViewpointFlipSign as getViewpointFlipSign2
206
208
  } from "@excalidraw/common";
207
209
  import {
208
210
  getObservedAppState as getObservedAppState2,
@@ -319,7 +321,7 @@ import {
319
321
  getDragOffsetXY,
320
322
  Scene as Scene2,
321
323
  Store,
322
- CaptureUpdateAction as CaptureUpdateAction39,
324
+ CaptureUpdateAction as CaptureUpdateAction40,
323
325
  hitElementBoundingBox as hitElementBoundingBox2,
324
326
  isLineElement as isLineElement9,
325
327
  isSimpleArrow,
@@ -396,7 +398,7 @@ var globImport_locales_json = __glob({
396
398
  "./locales/de-CH.json": () => import("./locales/de-CH-KLWBYLGC.js"),
397
399
  "./locales/de-DE.json": () => import("./locales/de-DE-UB755M7G.js"),
398
400
  "./locales/el-GR.json": () => import("./locales/el-GR-J2BFDAEA.js"),
399
- "./locales/en.json": () => import("./locales/en-FTXMBOG2.js"),
401
+ "./locales/en.json": () => import("./locales/en-JINXO2V2.js"),
400
402
  "./locales/es-ES.json": () => import("./locales/es-ES-GL35U3D6.js"),
401
403
  "./locales/eu-ES.json": () => import("./locales/eu-ES-5LL7P4G7.js"),
402
404
  "./locales/fa-IR.json": () => import("./locales/fa-IR-2D6AXPSB.js"),
@@ -10968,7 +10970,7 @@ var exportCanvas = async (type, elements, appState, files, {
10968
10970
  let blob = canvasToBlob(tempCanvas);
10969
10971
  if (appState.exportEmbedScene) {
10970
10972
  blob = blob.then(
10971
- (blob2) => import("./data/image-2QLYX6JM.js").then(
10973
+ (blob2) => import("./data/image-2GHT4EI2.js").then(
10972
10974
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
10973
10975
  blob: blob2,
10974
10976
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -12621,14 +12623,14 @@ var actionArrangeElements = register({
12621
12623
  captureUpdate: CaptureUpdateAction16.IMMEDIATELY
12622
12624
  };
12623
12625
  },
12624
- keyTest: (event) => event.shiftKey && matchKey(event, KEYS22.R),
12626
+ keyTest: (event) => event.shiftKey && matchKey(event, KEYS22.A),
12625
12627
  PanelComponent: ({ updateData }) => /* @__PURE__ */ jsx51(
12626
12628
  "button",
12627
12629
  {
12628
12630
  type: "button",
12629
12631
  className: "arrangeButton",
12630
12632
  onClick: () => updateData(null),
12631
- title: `${t("labels.arrangeElements")} \u2014 ${getShortcutKey("Shift+R")}`,
12633
+ title: `${t("labels.arrangeElements")} \u2014 ${getShortcutKey("Shift+A")}`,
12632
12634
  children: TableCellsIcon
12633
12635
  }
12634
12636
  )
@@ -12825,11 +12827,42 @@ var flipElements = (selectedElements, elementsMap, flipDirection, app) => {
12825
12827
  return selectedElements;
12826
12828
  };
12827
12829
 
12830
+ // actions/actionFlipViewpoint.ts
12831
+ import { CODES as CODES5, KEYS as KEYS24 } from "@excalidraw/common";
12832
+ import { CaptureUpdateAction as CaptureUpdateAction19 } from "@excalidraw/element";
12833
+ var toggleViewpointFlip = (appState, axis) => ({
12834
+ appState: {
12835
+ viewpointFlip: {
12836
+ ...appState.viewpointFlip,
12837
+ [axis]: !appState.viewpointFlip[axis]
12838
+ }
12839
+ },
12840
+ captureUpdate: CaptureUpdateAction19.NEVER
12841
+ });
12842
+ var actionFlipViewpointHorizontal = register({
12843
+ name: "flipViewpointHorizontal",
12844
+ label: "labels.flipViewpointHorizontal",
12845
+ viewMode: true,
12846
+ trackEvent: { category: "canvas" },
12847
+ perform: (_elements, appState) => toggleViewpointFlip(appState, "horizontal"),
12848
+ checked: (appState) => appState.viewpointFlip.horizontal,
12849
+ keyTest: (event) => !event[KEYS24.CTRL_OR_CMD] && !event.altKey && event.shiftKey && event.code === CODES5.R
12850
+ });
12851
+ var actionFlipViewpointVertical = register({
12852
+ name: "flipViewpointVertical",
12853
+ label: "labels.flipViewpointVertical",
12854
+ viewMode: true,
12855
+ trackEvent: { category: "canvas" },
12856
+ perform: (_elements, appState) => toggleViewpointFlip(appState, "vertical"),
12857
+ checked: (appState) => appState.viewpointFlip.vertical,
12858
+ keyTest: (event) => !event[KEYS24.CTRL_OR_CMD] && event.altKey && event.shiftKey && event.code === CODES5.R
12859
+ });
12860
+
12828
12861
  // actions/actionClipboard.tsx
12829
12862
  import { isTextElement as isTextElement4 } from "@excalidraw/element";
12830
12863
  import { getTextFromElements } from "@excalidraw/element";
12831
- import { CODES as CODES5, KEYS as KEYS24, isFirefox as isFirefox2 } from "@excalidraw/common";
12832
- import { CaptureUpdateAction as CaptureUpdateAction19 } from "@excalidraw/element";
12864
+ import { CODES as CODES6, KEYS as KEYS25, isFirefox as isFirefox2 } from "@excalidraw/common";
12865
+ import { CaptureUpdateAction as CaptureUpdateAction20 } from "@excalidraw/element";
12833
12866
  var actionCopy = register({
12834
12867
  name: "copy",
12835
12868
  label: "labels.copy",
@@ -12845,7 +12878,7 @@ var actionCopy = register({
12845
12878
  await copyToClipboard(elementsToCopy, app.files, event);
12846
12879
  } catch (error) {
12847
12880
  return {
12848
- captureUpdate: CaptureUpdateAction19.EVENTUALLY,
12881
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY,
12849
12882
  appState: {
12850
12883
  ...appState,
12851
12884
  errorMessage: error.message
@@ -12853,7 +12886,7 @@ var actionCopy = register({
12853
12886
  };
12854
12887
  }
12855
12888
  return {
12856
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
12889
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
12857
12890
  };
12858
12891
  },
12859
12892
  // don't supply a shortcut since we handle this conditionally via onCopy event
@@ -12874,7 +12907,7 @@ var actionPaste = register({
12874
12907
  console.error(`actionPaste ${error.name}: ${error.message}`);
12875
12908
  if (isFirefox2) {
12876
12909
  return {
12877
- captureUpdate: CaptureUpdateAction19.EVENTUALLY,
12910
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY,
12878
12911
  appState: {
12879
12912
  ...appState,
12880
12913
  errorMessage: t("hints.firefox_clipboard_write")
@@ -12882,7 +12915,7 @@ var actionPaste = register({
12882
12915
  };
12883
12916
  }
12884
12917
  return {
12885
- captureUpdate: CaptureUpdateAction19.EVENTUALLY,
12918
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY,
12886
12919
  appState: {
12887
12920
  ...appState,
12888
12921
  errorMessage: t("errors.asyncPasteFailedOnRead")
@@ -12894,7 +12927,7 @@ var actionPaste = register({
12894
12927
  } catch (error) {
12895
12928
  console.error(error);
12896
12929
  return {
12897
- captureUpdate: CaptureUpdateAction19.EVENTUALLY,
12930
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY,
12898
12931
  appState: {
12899
12932
  ...appState,
12900
12933
  errorMessage: t("errors.asyncPasteFailedOnParse")
@@ -12902,7 +12935,7 @@ var actionPaste = register({
12902
12935
  };
12903
12936
  }
12904
12937
  return {
12905
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
12938
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
12906
12939
  };
12907
12940
  },
12908
12941
  // don't supply a shortcut since we handle this conditionally via onCopy event
@@ -12917,7 +12950,7 @@ var actionCut = register({
12917
12950
  actionCopy.perform(elements, appState, event, app);
12918
12951
  return actionDeleteSelected.perform(elements, appState, null, app);
12919
12952
  },
12920
- keyTest: (event) => event[KEYS24.CTRL_OR_CMD] && event.key === KEYS24.X
12953
+ keyTest: (event) => event[KEYS25.CTRL_OR_CMD] && event.key === KEYS25.X
12921
12954
  });
12922
12955
  var actionCopyAsSvg = register({
12923
12956
  name: "copyAsSvg",
@@ -12927,7 +12960,7 @@ var actionCopyAsSvg = register({
12927
12960
  perform: async (elements, appState, _data, app) => {
12928
12961
  if (!app.canvas) {
12929
12962
  return {
12930
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
12963
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
12931
12964
  };
12932
12965
  }
12933
12966
  const { exportedElements, exportingFrame } = prepareElementsForExport(
@@ -12961,7 +12994,7 @@ var actionCopyAsSvg = register({
12961
12994
  })
12962
12995
  }
12963
12996
  },
12964
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
12997
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
12965
12998
  };
12966
12999
  } catch (error) {
12967
13000
  console.error(error);
@@ -12969,7 +13002,7 @@ var actionCopyAsSvg = register({
12969
13002
  appState: {
12970
13003
  errorMessage: error.message
12971
13004
  },
12972
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
13005
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
12973
13006
  };
12974
13007
  }
12975
13008
  },
@@ -12986,7 +13019,7 @@ var actionCopyAsPng = register({
12986
13019
  perform: async (elements, appState, _data, app) => {
12987
13020
  if (!app.canvas) {
12988
13021
  return {
12989
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
13022
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
12990
13023
  };
12991
13024
  }
12992
13025
  const selectedElements = app.scene.getSelectedElements({
@@ -13015,7 +13048,7 @@ var actionCopyAsPng = register({
13015
13048
  })
13016
13049
  }
13017
13050
  },
13018
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
13051
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
13019
13052
  };
13020
13053
  } catch (error) {
13021
13054
  console.error(error);
@@ -13024,14 +13057,14 @@ var actionCopyAsPng = register({
13024
13057
  ...appState,
13025
13058
  errorMessage: error.message
13026
13059
  },
13027
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
13060
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
13028
13061
  };
13029
13062
  }
13030
13063
  },
13031
13064
  predicate: (elements) => {
13032
13065
  return probablySupportsClipboardBlob && elements.length > 0;
13033
13066
  },
13034
- keyTest: (event) => event.code === CODES5.C && event.altKey && event.shiftKey,
13067
+ keyTest: (event) => event.code === CODES6.C && event.altKey && event.shiftKey,
13035
13068
  keywords: ["png", "clipboard", "copy"]
13036
13069
  });
13037
13070
  var copyText = register({
@@ -13049,7 +13082,7 @@ var copyText = register({
13049
13082
  throw new Error(t("errors.copyToSystemClipboardFailed"));
13050
13083
  }
13051
13084
  return {
13052
- captureUpdate: CaptureUpdateAction19.EVENTUALLY
13085
+ captureUpdate: CaptureUpdateAction20.EVENTUALLY
13053
13086
  };
13054
13087
  },
13055
13088
  predicate: (elements, appState, _, app) => {
@@ -13062,8 +13095,8 @@ var copyText = register({
13062
13095
  });
13063
13096
 
13064
13097
  // actions/actionToggleGridMode.tsx
13065
- import { CODES as CODES6, KEYS as KEYS25 } from "@excalidraw/common";
13066
- import { CaptureUpdateAction as CaptureUpdateAction20 } from "@excalidraw/element";
13098
+ import { CODES as CODES7, KEYS as KEYS26 } from "@excalidraw/common";
13099
+ import { CaptureUpdateAction as CaptureUpdateAction21 } from "@excalidraw/element";
13067
13100
  var actionToggleGridMode = register({
13068
13101
  name: "gridMode",
13069
13102
  icon: gridIcon,
@@ -13081,19 +13114,19 @@ var actionToggleGridMode = register({
13081
13114
  gridModeEnabled: !this.checked(appState),
13082
13115
  objectsSnapModeEnabled: false
13083
13116
  },
13084
- captureUpdate: CaptureUpdateAction20.EVENTUALLY
13117
+ captureUpdate: CaptureUpdateAction21.EVENTUALLY
13085
13118
  };
13086
13119
  },
13087
13120
  checked: (appState) => appState.gridModeEnabled,
13088
13121
  predicate: (element, appState, props) => {
13089
13122
  return props.gridModeEnabled === void 0;
13090
13123
  },
13091
- keyTest: (event) => event[KEYS25.CTRL_OR_CMD] && event.code === CODES6.QUOTE
13124
+ keyTest: (event) => event[KEYS26.CTRL_OR_CMD] && event.code === CODES7.QUOTE
13092
13125
  });
13093
13126
 
13094
13127
  // actions/actionSmartZoom.tsx
13095
- import { KEYS as KEYS26 } from "@excalidraw/common";
13096
- import { CaptureUpdateAction as CaptureUpdateAction21 } from "@excalidraw/element/store";
13128
+ import { KEYS as KEYS27 } from "@excalidraw/common";
13129
+ import { CaptureUpdateAction as CaptureUpdateAction22 } from "@excalidraw/element/store";
13097
13130
  import { jsx as jsx53 } from "react/jsx-runtime";
13098
13131
  var actionSmartZoom = register({
13099
13132
  name: "smartZoom",
@@ -13115,28 +13148,28 @@ var actionSmartZoom = register({
13115
13148
  viewportZoomFactor: settings.viewportZoomFactor
13116
13149
  });
13117
13150
  return {
13118
- captureUpdate: CaptureUpdateAction21.NEVER
13151
+ captureUpdate: CaptureUpdateAction22.NEVER
13119
13152
  };
13120
13153
  },
13121
- keyTest: (event) => !event[KEYS26.CTRL_OR_CMD] && !event.shiftKey && !event.altKey && event.key.toLocaleLowerCase() === KEYS26.F,
13154
+ keyTest: (event) => !event[KEYS27.CTRL_OR_CMD] && !event.shiftKey && !event.altKey && event.key.toLocaleLowerCase() === KEYS27.F,
13122
13155
  PanelComponent: ({ data, updateData }) => /* @__PURE__ */ jsx53(
13123
13156
  IconButton,
13124
13157
  {
13125
13158
  type: "button",
13126
13159
  icon: arrowsToEyeIcon,
13127
13160
  "aria-label": t("labels.smartZoom"),
13128
- title: `${t("labels.smartZoom")} - ${KEYS26.F.toLocaleUpperCase()}`,
13161
+ title: `${t("labels.smartZoom")} - ${KEYS27.F.toLocaleUpperCase()}`,
13129
13162
  onClick: () => updateData(null),
13130
13163
  size: data?.size || "medium",
13131
13164
  "data-testid": "button-smart-zoom",
13132
- keyBindingLabel: KEYS26.F.toLocaleUpperCase()
13165
+ keyBindingLabel: KEYS27.F.toLocaleUpperCase()
13133
13166
  }
13134
13167
  )
13135
13168
  });
13136
13169
 
13137
13170
  // actions/actionToggleObjectsSnapMode.tsx
13138
- import { CODES as CODES7, KEYS as KEYS27 } from "@excalidraw/common";
13139
- import { CaptureUpdateAction as CaptureUpdateAction22 } from "@excalidraw/element";
13171
+ import { CODES as CODES8, KEYS as KEYS28 } from "@excalidraw/common";
13172
+ import { CaptureUpdateAction as CaptureUpdateAction23 } from "@excalidraw/element";
13140
13173
  var actionToggleObjectsSnapMode = register({
13141
13174
  name: "objectsSnapMode",
13142
13175
  label: "buttons.objectsSnapMode",
@@ -13153,18 +13186,18 @@ var actionToggleObjectsSnapMode = register({
13153
13186
  objectsSnapModeEnabled: !this.checked(appState),
13154
13187
  gridModeEnabled: false
13155
13188
  },
13156
- captureUpdate: CaptureUpdateAction22.EVENTUALLY
13189
+ captureUpdate: CaptureUpdateAction23.EVENTUALLY
13157
13190
  };
13158
13191
  },
13159
13192
  checked: (appState) => appState.objectsSnapModeEnabled,
13160
13193
  predicate: (elements, appState, appProps) => {
13161
13194
  return typeof appProps.objectsSnapModeEnabled === "undefined";
13162
13195
  },
13163
- keyTest: (event) => !event[KEYS27.CTRL_OR_CMD] && event.altKey && event.code === CODES7.S
13196
+ keyTest: (event) => !event[KEYS28.CTRL_OR_CMD] && event.altKey && event.code === CODES8.S
13164
13197
  });
13165
13198
 
13166
13199
  // actions/actionToggleArrowBinding.tsx
13167
- import { CaptureUpdateAction as CaptureUpdateAction23 } from "@excalidraw/element";
13200
+ import { CaptureUpdateAction as CaptureUpdateAction24 } from "@excalidraw/element";
13168
13201
  var actionToggleArrowBinding = register({
13169
13202
  name: "arrowBinding",
13170
13203
  label: "labels.arrowBinding",
@@ -13181,14 +13214,14 @@ var actionToggleArrowBinding = register({
13181
13214
  bindingPreference: newPreference,
13182
13215
  isBindingEnabled: newPreference === "enabled"
13183
13216
  },
13184
- captureUpdate: CaptureUpdateAction23.NEVER
13217
+ captureUpdate: CaptureUpdateAction24.NEVER
13185
13218
  };
13186
13219
  },
13187
13220
  checked: (appState) => appState.bindingPreference === "enabled"
13188
13221
  });
13189
13222
 
13190
13223
  // actions/actionToggleMidpointSnapping.tsx
13191
- import { CaptureUpdateAction as CaptureUpdateAction24 } from "@excalidraw/element";
13224
+ import { CaptureUpdateAction as CaptureUpdateAction25 } from "@excalidraw/element";
13192
13225
  var actionToggleMidpointSnapping = register({
13193
13226
  name: "midpointSnapping",
13194
13227
  label: "labels.midpointSnapping",
@@ -13203,15 +13236,15 @@ var actionToggleMidpointSnapping = register({
13203
13236
  ...appState,
13204
13237
  isMidpointSnappingEnabled: !this.checked(appState)
13205
13238
  },
13206
- captureUpdate: CaptureUpdateAction24.NEVER
13239
+ captureUpdate: CaptureUpdateAction25.NEVER
13207
13240
  };
13208
13241
  },
13209
13242
  checked: (appState) => appState.isMidpointSnappingEnabled
13210
13243
  });
13211
13244
 
13212
13245
  // actions/actionToggleStats.tsx
13213
- import { CODES as CODES8, KEYS as KEYS28 } from "@excalidraw/common";
13214
- import { CaptureUpdateAction as CaptureUpdateAction25 } from "@excalidraw/element";
13246
+ import { CODES as CODES9, KEYS as KEYS29 } from "@excalidraw/common";
13247
+ import { CaptureUpdateAction as CaptureUpdateAction26 } from "@excalidraw/element";
13215
13248
  var actionToggleStats = register({
13216
13249
  name: "stats",
13217
13250
  label: "stats.fullTitle",
@@ -13225,11 +13258,11 @@ var actionToggleStats = register({
13225
13258
  ...appState,
13226
13259
  stats: { ...appState.stats, open: !this.checked(appState) }
13227
13260
  },
13228
- captureUpdate: CaptureUpdateAction25.EVENTUALLY
13261
+ captureUpdate: CaptureUpdateAction26.EVENTUALLY
13229
13262
  };
13230
13263
  },
13231
13264
  checked: (appState) => appState.stats.open,
13232
- keyTest: (event) => !event[KEYS28.CTRL_OR_CMD] && event.altKey && event.code === CODES8.SLASH
13265
+ keyTest: (event) => !event[KEYS29.CTRL_OR_CMD] && event.altKey && event.code === CODES9.SLASH
13233
13266
  });
13234
13267
 
13235
13268
  // actions/actionBoundText.tsx
@@ -13264,7 +13297,7 @@ import {
13264
13297
  import { measureText } from "@excalidraw/element";
13265
13298
  import { syncMovedIndices as syncMovedIndices3 } from "@excalidraw/element";
13266
13299
  import { newElement } from "@excalidraw/element";
13267
- import { CaptureUpdateAction as CaptureUpdateAction26 } from "@excalidraw/element";
13300
+ import { CaptureUpdateAction as CaptureUpdateAction27 } from "@excalidraw/element";
13268
13301
  var actionUnbindText = register({
13269
13302
  name: "unbindText",
13270
13303
  label: "labels.unbindText",
@@ -13312,7 +13345,7 @@ var actionUnbindText = register({
13312
13345
  return {
13313
13346
  elements,
13314
13347
  appState,
13315
- captureUpdate: CaptureUpdateAction26.IMMEDIATELY
13348
+ captureUpdate: CaptureUpdateAction27.IMMEDIATELY
13316
13349
  };
13317
13350
  }
13318
13351
  });
@@ -13369,7 +13402,7 @@ var actionBindText = register({
13369
13402
  return {
13370
13403
  elements: pushTextAboveContainer(elements, container, textElement),
13371
13404
  appState: { ...appState, selectedElementIds: { [container.id]: true } },
13372
- captureUpdate: CaptureUpdateAction26.IMMEDIATELY
13405
+ captureUpdate: CaptureUpdateAction27.IMMEDIATELY
13373
13406
  };
13374
13407
  }
13375
13408
  });
@@ -13497,7 +13530,7 @@ var actionWrapTextInContainer = register({
13497
13530
  ...appState,
13498
13531
  selectedElementIds: containerIds
13499
13532
  },
13500
- captureUpdate: CaptureUpdateAction26.IMMEDIATELY
13533
+ captureUpdate: CaptureUpdateAction27.IMMEDIATELY
13501
13534
  };
13502
13535
  }
13503
13536
  });
@@ -13507,8 +13540,8 @@ import {
13507
13540
  getNonDeletedElements as getNonDeletedElements11,
13508
13541
  isEmbeddableElement as isEmbeddableElement2
13509
13542
  } from "@excalidraw/element";
13510
- import { KEYS as KEYS30 } from "@excalidraw/common";
13511
- import { CaptureUpdateAction as CaptureUpdateAction27 } from "@excalidraw/element";
13543
+ import { KEYS as KEYS31 } from "@excalidraw/common";
13544
+ import { CaptureUpdateAction as CaptureUpdateAction28 } from "@excalidraw/element";
13512
13545
 
13513
13546
  // components/hyperlink/Hyperlink.tsx
13514
13547
  import { pointFrom as pointFrom3 } from "@excalidraw/math";
@@ -13520,7 +13553,7 @@ import {
13520
13553
  useRef as useRef14,
13521
13554
  useState as useState14
13522
13555
  } from "react";
13523
- import { EVENT as EVENT5, HYPERLINK_TOOLTIP_DELAY, KEYS as KEYS29 } from "@excalidraw/common";
13556
+ import { EVENT as EVENT5, HYPERLINK_TOOLTIP_DELAY, KEYS as KEYS30 } from "@excalidraw/common";
13524
13557
  import { getElementAbsoluteCoords } from "@excalidraw/element";
13525
13558
  import { hitElementBoundingBox } from "@excalidraw/element";
13526
13559
  import { isElementLink } from "@excalidraw/element";
@@ -13694,10 +13727,10 @@ var Hyperlink = ({
13694
13727
  autoFocus: true,
13695
13728
  onKeyDown: (event) => {
13696
13729
  event.stopPropagation();
13697
- if (event[KEYS29.CTRL_OR_CMD] && event.key === KEYS29.K) {
13730
+ if (event[KEYS30.CTRL_OR_CMD] && event.key === KEYS30.K) {
13698
13731
  event.preventDefault();
13699
13732
  }
13700
- if (event.key === KEYS29.ENTER || event.key === KEYS29.ESCAPE) {
13733
+ if (event.key === KEYS30.ENTER || event.key === KEYS30.ESCAPE) {
13701
13734
  handleSubmit();
13702
13735
  setAppState({ showHyperlinkPopup: "info" });
13703
13736
  }
@@ -13885,11 +13918,11 @@ var actionLink = register({
13885
13918
  showHyperlinkPopup: "editor",
13886
13919
  openMenu: null
13887
13920
  },
13888
- captureUpdate: CaptureUpdateAction27.IMMEDIATELY
13921
+ captureUpdate: CaptureUpdateAction28.IMMEDIATELY
13889
13922
  };
13890
13923
  },
13891
13924
  trackEvent: { category: "hyperlink", action: "click" },
13892
- keyTest: (event) => event[KEYS30.CTRL_OR_CMD] && event.key === KEYS30.K,
13925
+ keyTest: (event) => event[KEYS31.CTRL_OR_CMD] && event.key === KEYS31.K,
13893
13926
  predicate: (elements, appState) => {
13894
13927
  const selectedElements = getSelectedElements(elements, appState);
13895
13928
  return selectedElements.length === 1;
@@ -13913,14 +13946,14 @@ var actionLink = register({
13913
13946
  });
13914
13947
 
13915
13948
  // actions/actionElementLock.ts
13916
- import { KEYS as KEYS31, arrayToMap as arrayToMap14, randomId as randomId2 } from "@excalidraw/common";
13949
+ import { KEYS as KEYS32, arrayToMap as arrayToMap14, randomId as randomId2 } from "@excalidraw/common";
13917
13950
  import {
13918
13951
  elementsAreInSameGroup,
13919
13952
  getNonDeletedElements as getNonDeletedElements12,
13920
13953
  newElementWith as newElementWith7,
13921
13954
  selectGroupsFromGivenElements
13922
13955
  } from "@excalidraw/element";
13923
- import { CaptureUpdateAction as CaptureUpdateAction28 } from "@excalidraw/element";
13956
+ import { CaptureUpdateAction as CaptureUpdateAction29 } from "@excalidraw/element";
13924
13957
  var shouldLock = (elements) => elements.every((el) => !el.locked);
13925
13958
  var actionToggleElementLock = register({
13926
13959
  name: "toggleElementLock",
@@ -14004,11 +14037,11 @@ var actionToggleElementLock = register({
14004
14037
  lockedMultiSelections: nextLockedMultiSelections,
14005
14038
  activeLockedId
14006
14039
  },
14007
- captureUpdate: CaptureUpdateAction28.IMMEDIATELY
14040
+ captureUpdate: CaptureUpdateAction29.IMMEDIATELY
14008
14041
  };
14009
14042
  },
14010
14043
  keyTest: (event, appState, elements, app) => {
14011
- return event.key.toLocaleLowerCase() === KEYS31.L && event[KEYS31.CTRL_OR_CMD] && event.shiftKey && app.scene.getSelectedElements({
14044
+ return event.key.toLocaleLowerCase() === KEYS32.L && event[KEYS32.CTRL_OR_CMD] && event.shiftKey && app.scene.getSelectedElements({
14012
14045
  selectedElementIds: appState.selectedElementIds,
14013
14046
  includeBoundTextElement: false
14014
14047
  }).length > 0;
@@ -14059,7 +14092,7 @@ var actionUnlockAllElements = register({
14059
14092
  lockedMultiSelections: {},
14060
14093
  activeLockedId: null
14061
14094
  },
14062
- captureUpdate: CaptureUpdateAction28.IMMEDIATELY
14095
+ captureUpdate: CaptureUpdateAction29.IMMEDIATELY
14063
14096
  };
14064
14097
  },
14065
14098
  label: "labels.elementLock.unlockAll"
@@ -14074,7 +14107,7 @@ import {
14074
14107
  import { arrayToMap as arrayToMap27, invariant as invariant16 } from "@excalidraw/common";
14075
14108
  import {
14076
14109
  toggleLinePolygonState as toggleLinePolygonState3,
14077
- CaptureUpdateAction as CaptureUpdateAction29
14110
+ CaptureUpdateAction as CaptureUpdateAction30
14078
14111
  } from "@excalidraw/element";
14079
14112
 
14080
14113
  // ../element/src/mutateElement.ts
@@ -14543,7 +14576,7 @@ import {
14543
14576
  } from "@excalidraw/math";
14544
14577
  import {
14545
14578
  DRAGGING_THRESHOLD as DRAGGING_THRESHOLD2,
14546
- KEYS as KEYS33,
14579
+ KEYS as KEYS34,
14547
14580
  shouldRotateWithDiscreteAngle as shouldRotateWithDiscreteAngle2,
14548
14581
  getGridPoint as getGridPoint3,
14549
14582
  invariant as invariant13,
@@ -15190,12 +15223,12 @@ import {
15190
15223
  import { pointFrom as pointFrom14, pointRotateRads as pointRotateRads8 } from "@excalidraw/math";
15191
15224
 
15192
15225
  // ../element/src/shapes.ts
15193
- import { KEYS as KEYS32 } from "@excalidraw/common";
15226
+ import { KEYS as KEYS33 } from "@excalidraw/common";
15194
15227
  var SHAPES = [
15195
15228
  {
15196
15229
  icon: SelectionIcon,
15197
15230
  value: "selection",
15198
- key: KEYS32.V,
15231
+ key: KEYS33.V,
15199
15232
  numericKey: void 0,
15200
15233
  fillable: true,
15201
15234
  myocSimplifiedMode: true
@@ -15203,7 +15236,7 @@ var SHAPES = [
15203
15236
  {
15204
15237
  icon: RectangleIcon,
15205
15238
  value: "rectangle",
15206
- key: KEYS32.R,
15239
+ key: KEYS33.R,
15207
15240
  numericKey: void 0,
15208
15241
  fillable: true,
15209
15242
  myocSimplifiedMode: false
@@ -15211,7 +15244,7 @@ var SHAPES = [
15211
15244
  {
15212
15245
  icon: DiamondIcon,
15213
15246
  value: "diamond",
15214
- key: KEYS32.D,
15247
+ key: KEYS33.D,
15215
15248
  numericKey: void 0,
15216
15249
  fillable: true,
15217
15250
  myocSimplifiedMode: false
@@ -15219,7 +15252,7 @@ var SHAPES = [
15219
15252
  {
15220
15253
  icon: EllipseIcon,
15221
15254
  value: "ellipse",
15222
- key: KEYS32.O,
15255
+ key: KEYS33.O,
15223
15256
  numericKey: void 0,
15224
15257
  fillable: true,
15225
15258
  myocSimplifiedMode: false
@@ -15227,7 +15260,7 @@ var SHAPES = [
15227
15260
  {
15228
15261
  icon: ArrowIcon,
15229
15262
  value: "arrow",
15230
- key: KEYS32.A,
15263
+ key: KEYS33.A,
15231
15264
  numericKey: void 0,
15232
15265
  fillable: true,
15233
15266
  myocSimplifiedMode: false
@@ -15235,7 +15268,7 @@ var SHAPES = [
15235
15268
  {
15236
15269
  icon: LineIcon,
15237
15270
  value: "line",
15238
- key: KEYS32.L,
15271
+ key: KEYS33.L,
15239
15272
  numericKey: void 0,
15240
15273
  fillable: true,
15241
15274
  myocSimplifiedMode: false
@@ -15243,7 +15276,7 @@ var SHAPES = [
15243
15276
  {
15244
15277
  icon: FreedrawIcon,
15245
15278
  value: "freedraw",
15246
- key: [KEYS32.P, KEYS32.X],
15279
+ key: [KEYS33.P, KEYS33.X],
15247
15280
  numericKey: void 0,
15248
15281
  fillable: false,
15249
15282
  myocSimplifiedMode: true
@@ -15251,7 +15284,7 @@ var SHAPES = [
15251
15284
  {
15252
15285
  icon: TextIcon,
15253
15286
  value: "text",
15254
- key: KEYS32.T,
15287
+ key: KEYS33.T,
15255
15288
  numericKey: void 0,
15256
15289
  fillable: false,
15257
15290
  myocSimplifiedMode: true
@@ -15259,7 +15292,7 @@ var SHAPES = [
15259
15292
  {
15260
15293
  icon: ImageIcon,
15261
15294
  value: "image",
15262
- key: [KEYS32.I],
15295
+ key: [KEYS33.I],
15263
15296
  numericKey: void 0,
15264
15297
  fillable: false,
15265
15298
  myocSimplifiedMode: true
@@ -15267,7 +15300,7 @@ var SHAPES = [
15267
15300
  {
15268
15301
  icon: EraserIcon,
15269
15302
  value: "eraser",
15270
- key: KEYS32.E,
15303
+ key: KEYS33.E,
15271
15304
  numericKey: void 0,
15272
15305
  fillable: false,
15273
15306
  myocSimplifiedMode: true
@@ -16222,7 +16255,7 @@ var actionToggleLinearEditor = register({
16222
16255
  ...appState,
16223
16256
  selectedLinearElement
16224
16257
  },
16225
- captureUpdate: CaptureUpdateAction29.IMMEDIATELY
16258
+ captureUpdate: CaptureUpdateAction30.IMMEDIATELY
16226
16259
  };
16227
16260
  },
16228
16261
  PanelComponent: ({ appState, updateData, app }) => {
@@ -16290,7 +16323,7 @@ var actionTogglePolygon = register({
16290
16323
  });
16291
16324
  }),
16292
16325
  appState,
16293
- captureUpdate: CaptureUpdateAction29.IMMEDIATELY
16326
+ captureUpdate: CaptureUpdateAction30.IMMEDIATELY
16294
16327
  };
16295
16328
  },
16296
16329
  PanelComponent: ({ appState, updateData, app }) => {
@@ -16328,12 +16361,12 @@ var actionTogglePolygon = register({
16328
16361
 
16329
16362
  // actions/actionToggleSearchMenu.ts
16330
16363
  import {
16331
- KEYS as KEYS34,
16364
+ KEYS as KEYS35,
16332
16365
  CANVAS_SEARCH_TAB,
16333
16366
  CLASSES,
16334
16367
  DEFAULT_SIDEBAR
16335
16368
  } from "@excalidraw/common";
16336
- import { CaptureUpdateAction as CaptureUpdateAction30 } from "@excalidraw/element";
16369
+ import { CaptureUpdateAction as CaptureUpdateAction31 } from "@excalidraw/element";
16337
16370
  var actionToggleSearchMenu = register({
16338
16371
  name: "searchMenu",
16339
16372
  icon: searchIcon,
@@ -16363,19 +16396,19 @@ var actionToggleSearchMenu = register({
16363
16396
  openSidebar: { name: DEFAULT_SIDEBAR.name, tab: CANVAS_SEARCH_TAB },
16364
16397
  openDialog: null
16365
16398
  },
16366
- captureUpdate: CaptureUpdateAction30.EVENTUALLY
16399
+ captureUpdate: CaptureUpdateAction31.EVENTUALLY
16367
16400
  };
16368
16401
  },
16369
16402
  checked: (appState) => appState.gridModeEnabled,
16370
16403
  predicate: (element, appState, props) => {
16371
16404
  return props.gridModeEnabled === void 0;
16372
16405
  },
16373
- keyTest: (event) => event[KEYS34.CTRL_OR_CMD] && event.key === KEYS34.F
16406
+ keyTest: (event) => event[KEYS35.CTRL_OR_CMD] && event.key === KEYS35.F
16374
16407
  });
16375
16408
 
16376
16409
  // actions/actionCropEditor.tsx
16377
16410
  import { isImageElement as isImageElement2 } from "@excalidraw/element";
16378
- import { CaptureUpdateAction as CaptureUpdateAction31 } from "@excalidraw/element";
16411
+ import { CaptureUpdateAction as CaptureUpdateAction32 } from "@excalidraw/element";
16379
16412
  import { jsx as jsx57 } from "react/jsx-runtime";
16380
16413
  var actionToggleCropEditor = register({
16381
16414
  name: "cropEditor",
@@ -16395,7 +16428,7 @@ var actionToggleCropEditor = register({
16395
16428
  isCropping: false,
16396
16429
  croppingElementId: selectedElement.id
16397
16430
  },
16398
- captureUpdate: CaptureUpdateAction31.IMMEDIATELY
16431
+ captureUpdate: CaptureUpdateAction32.IMMEDIATELY
16399
16432
  };
16400
16433
  },
16401
16434
  predicate: (elements, appState, _, app) => {
@@ -16432,7 +16465,7 @@ import {
16432
16465
  import { getFrameChildren as getFrameChildren3 } from "@excalidraw/element";
16433
16466
  import { getElementsInGroup as getElementsInGroup6 } from "@excalidraw/element";
16434
16467
  import { getCommonBounds as getCommonBounds3 } from "@excalidraw/element";
16435
- import { CaptureUpdateAction as CaptureUpdateAction32 } from "@excalidraw/element";
16468
+ import { CaptureUpdateAction as CaptureUpdateAction33 } from "@excalidraw/element";
16436
16469
  var isSingleFrameSelected = (appState, app) => {
16437
16470
  const selectedElements = app.scene.getSelectedElements(appState);
16438
16471
  return selectedElements.length === 1 && isFrameLikeElement9(selectedElements[0]);
@@ -16457,13 +16490,13 @@ var actionSelectAllElementsInFrame = register({
16457
16490
  return acc;
16458
16491
  }, {})
16459
16492
  },
16460
- captureUpdate: CaptureUpdateAction32.IMMEDIATELY
16493
+ captureUpdate: CaptureUpdateAction33.IMMEDIATELY
16461
16494
  };
16462
16495
  }
16463
16496
  return {
16464
16497
  elements,
16465
16498
  appState,
16466
- captureUpdate: CaptureUpdateAction32.EVENTUALLY
16499
+ captureUpdate: CaptureUpdateAction33.EVENTUALLY
16467
16500
  };
16468
16501
  },
16469
16502
  predicate: (elements, appState, _, app) => isSingleFrameSelected(appState, app)
@@ -16483,13 +16516,13 @@ var actionRemoveAllElementsFromFrame = register({
16483
16516
  [selectedElement.id]: true
16484
16517
  }
16485
16518
  },
16486
- captureUpdate: CaptureUpdateAction32.IMMEDIATELY
16519
+ captureUpdate: CaptureUpdateAction33.IMMEDIATELY
16487
16520
  };
16488
16521
  }
16489
16522
  return {
16490
16523
  elements,
16491
16524
  appState,
16492
- captureUpdate: CaptureUpdateAction32.EVENTUALLY
16525
+ captureUpdate: CaptureUpdateAction33.EVENTUALLY
16493
16526
  };
16494
16527
  },
16495
16528
  predicate: (elements, appState, _, app) => isSingleFrameSelected(appState, app)
@@ -16509,7 +16542,7 @@ var actionupdateFrameRendering = register({
16509
16542
  enabled: !appState.frameRendering.enabled
16510
16543
  }
16511
16544
  },
16512
- captureUpdate: CaptureUpdateAction32.EVENTUALLY
16545
+ captureUpdate: CaptureUpdateAction33.EVENTUALLY
16513
16546
  };
16514
16547
  },
16515
16548
  checked: (appState) => appState.frameRendering.enabled
@@ -16555,25 +16588,25 @@ var actionWrapSelectionInFrame = register({
16555
16588
  appState: {
16556
16589
  selectedElementIds: { [frame.id]: true }
16557
16590
  },
16558
- captureUpdate: CaptureUpdateAction32.IMMEDIATELY
16591
+ captureUpdate: CaptureUpdateAction33.IMMEDIATELY
16559
16592
  };
16560
16593
  }
16561
16594
  });
16562
16595
 
16563
16596
  // actions/actionHistory.tsx
16564
16597
  import {
16565
- KEYS as KEYS35,
16598
+ KEYS as KEYS36,
16566
16599
  matchKey as matchKey2,
16567
16600
  arrayToMap as arrayToMap28,
16568
16601
  MOBILE_ACTION_BUTTON_BG as MOBILE_ACTION_BUTTON_BG4
16569
16602
  } from "@excalidraw/common";
16570
- import { CaptureUpdateAction as CaptureUpdateAction34 } from "@excalidraw/element";
16603
+ import { CaptureUpdateAction as CaptureUpdateAction35 } from "@excalidraw/element";
16571
16604
  import { orderByFractionalIndex as orderByFractionalIndex2 } from "@excalidraw/element";
16572
16605
 
16573
16606
  // history.ts
16574
16607
  import { Emitter as Emitter2 } from "@excalidraw/common";
16575
16608
  import {
16576
- CaptureUpdateAction as CaptureUpdateAction33,
16609
+ CaptureUpdateAction as CaptureUpdateAction34,
16577
16610
  StoreChange,
16578
16611
  StoreDelta
16579
16612
  } from "@excalidraw/element";
@@ -16687,7 +16720,7 @@ var History = class _History {
16687
16720
  if (historyDelta === null) {
16688
16721
  return;
16689
16722
  }
16690
- const action = CaptureUpdateAction33.IMMEDIATELY;
16723
+ const action = CaptureUpdateAction34.IMMEDIATELY;
16691
16724
  let prevSnapshot = this.store.snapshot;
16692
16725
  let nextElements = elements;
16693
16726
  let nextAppState = appState;
@@ -16771,7 +16804,7 @@ var executeHistoryAction = (app, appState, updater) => {
16771
16804
  !app.drawShape.hasPendingGesture()) {
16772
16805
  const result = updater();
16773
16806
  if (!result) {
16774
- return { captureUpdate: CaptureUpdateAction34.EVENTUALLY };
16807
+ return { captureUpdate: CaptureUpdateAction35.EVENTUALLY };
16775
16808
  }
16776
16809
  const [nextElementsMap, nextAppState] = result;
16777
16810
  const nextElements = orderByFractionalIndex2(
@@ -16780,10 +16813,10 @@ var executeHistoryAction = (app, appState, updater) => {
16780
16813
  return {
16781
16814
  appState: nextAppState,
16782
16815
  elements: nextElements,
16783
- captureUpdate: CaptureUpdateAction34.NEVER
16816
+ captureUpdate: CaptureUpdateAction35.NEVER
16784
16817
  };
16785
16818
  }
16786
- return { captureUpdate: CaptureUpdateAction34.EVENTUALLY };
16819
+ return { captureUpdate: CaptureUpdateAction35.EVENTUALLY };
16787
16820
  };
16788
16821
  var createUndoAction = (history) => ({
16789
16822
  name: "undo",
@@ -16796,7 +16829,7 @@ var createUndoAction = (history) => ({
16796
16829
  appState,
16797
16830
  () => history.undo(arrayToMap28(elements), appState)
16798
16831
  ),
16799
- keyTest: (event) => event[KEYS35.CTRL_OR_CMD] && matchKey2(event, KEYS35.Z) && !event.shiftKey,
16832
+ keyTest: (event) => event[KEYS36.CTRL_OR_CMD] && matchKey2(event, KEYS36.Z) && !event.shiftKey,
16800
16833
  PanelComponent: ({ appState, updateData, data, app }) => {
16801
16834
  const { isUndoStackEmpty } = useEmitter(
16802
16835
  history.onHistoryChangedEmitter,
@@ -16834,7 +16867,7 @@ var createRedoAction = (history) => ({
16834
16867
  appState,
16835
16868
  () => history.redo(arrayToMap28(elements), appState)
16836
16869
  ),
16837
- keyTest: (event) => event[KEYS35.CTRL_OR_CMD] && event.shiftKey && matchKey2(event, KEYS35.Z) || event[KEYS35.CTRL_OR_CMD] && !event.shiftKey && matchKey2(event, KEYS35.Y),
16870
+ keyTest: (event) => event[KEYS36.CTRL_OR_CMD] && event.shiftKey && matchKey2(event, KEYS36.Z) || event[KEYS36.CTRL_OR_CMD] && !event.shiftKey && matchKey2(event, KEYS36.Y),
16838
16871
  PanelComponent: ({ appState, updateData, data, app }) => {
16839
16872
  const { isRedoStackEmpty } = useEmitter(
16840
16873
  history.onHistoryChangedEmitter,
@@ -16873,7 +16906,7 @@ import {
16873
16906
  } from "@excalidraw/element";
16874
16907
  import { measureText as measureText3 } from "@excalidraw/element";
16875
16908
  import { isTextElement as isTextElement7 } from "@excalidraw/element";
16876
- import { CaptureUpdateAction as CaptureUpdateAction35 } from "@excalidraw/element";
16909
+ import { CaptureUpdateAction as CaptureUpdateAction36 } from "@excalidraw/element";
16877
16910
  var actionTextAutoResize = register({
16878
16911
  name: "autoResize",
16879
16912
  label: "labels.autoResize",
@@ -16916,15 +16949,15 @@ var actionTextAutoResize = register({
16916
16949
  elements: elements.map(
16917
16950
  (element) => element.id === resized.id ? resized : element
16918
16951
  ),
16919
- captureUpdate: CaptureUpdateAction35.IMMEDIATELY
16952
+ captureUpdate: CaptureUpdateAction36.IMMEDIATELY
16920
16953
  };
16921
16954
  }
16922
16955
  });
16923
16956
 
16924
16957
  // actions/actionToggleViewMode.tsx
16925
- import { CODES as CODES9, KEYS as KEYS36 } from "@excalidraw/common";
16958
+ import { CODES as CODES10, KEYS as KEYS37 } from "@excalidraw/common";
16926
16959
  import clsx24 from "clsx";
16927
- import { CaptureUpdateAction as CaptureUpdateAction36 } from "@excalidraw/element";
16960
+ import { CaptureUpdateAction as CaptureUpdateAction37 } from "@excalidraw/element";
16928
16961
  import { jsx as jsx59 } from "react/jsx-runtime";
16929
16962
  var actionToggleViewMode = register({
16930
16963
  name: "viewMode",
@@ -16944,14 +16977,14 @@ var actionToggleViewMode = register({
16944
16977
  ...appState,
16945
16978
  viewModeEnabled: !this.checked(appState)
16946
16979
  },
16947
- captureUpdate: CaptureUpdateAction36.EVENTUALLY
16980
+ captureUpdate: CaptureUpdateAction37.EVENTUALLY
16948
16981
  };
16949
16982
  },
16950
16983
  checked: (appState) => appState.viewModeEnabled,
16951
16984
  predicate: (elements, appState, appProps, app) => {
16952
16985
  return !appState.viewModeOnly && !appProps.viewModeOnly && typeof appProps.viewModeEnabled === "undefined" && app.isInteractionEnabled();
16953
16986
  },
16954
- keyTest: (event) => !event[KEYS36.CTRL_OR_CMD] && event.altKey && event.code === CODES9.R,
16987
+ keyTest: (event) => !event[KEYS37.CTRL_OR_CMD] && event.altKey && !event.shiftKey && event.code === CODES10.R,
16955
16988
  PanelComponent: ({ data, updateData, appState, appProps }) => {
16956
16989
  if (appState.viewModeOnly || appProps.viewModeOnly) {
16957
16990
  return null;
@@ -17145,7 +17178,7 @@ import {
17145
17178
  rangeIntersection,
17146
17179
  rangesOverlap
17147
17180
  } from "@excalidraw/math";
17148
- import { TOOL_TYPE, KEYS as KEYS37 } from "@excalidraw/common";
17181
+ import { TOOL_TYPE, KEYS as KEYS38 } from "@excalidraw/common";
17149
17182
  import {
17150
17183
  getCommonBounds as getCommonBounds4,
17151
17184
  getDraggedElementsBounds,
@@ -17191,7 +17224,7 @@ var isSnappingEnabled = ({
17191
17224
  }) => {
17192
17225
  if (event) {
17193
17226
  const isLassoDragging = app.state.activeTool.type === "lasso" && app.state.selectedElementsAreBeingDragged;
17194
- return (app.state.activeTool.type !== "lasso" || isLassoDragging) && (app.state.objectsSnapModeEnabled && !event[KEYS37.CTRL_OR_CMD] || !app.state.objectsSnapModeEnabled && event[KEYS37.CTRL_OR_CMD] && !isGridModeEnabled(app));
17227
+ return (app.state.activeTool.type !== "lasso" || isLassoDragging) && (app.state.objectsSnapModeEnabled && !event[KEYS38.CTRL_OR_CMD] || !app.state.objectsSnapModeEnabled && event[KEYS38.CTRL_OR_CMD] && !isGridModeEnabled(app));
17195
17228
  }
17196
17229
  if (selectedElements.length === 1 && selectedElements[0].type === "arrow") {
17197
17230
  return false;
@@ -18742,8 +18775,8 @@ var isPointHittingTextAutoResizeHandle = (point, textElement, zoomValue, formFac
18742
18775
 
18743
18776
  // wysiwyg/textWysiwyg.tsx
18744
18777
  import {
18745
- CODES as CODES10,
18746
- KEYS as KEYS38,
18778
+ CODES as CODES11,
18779
+ KEYS as KEYS39,
18747
18780
  CLASSES as CLASSES2,
18748
18781
  POINTER_BUTTON,
18749
18782
  THEME as THEME16,
@@ -18753,7 +18786,8 @@ import {
18753
18786
  isTestEnv as isTestEnv8,
18754
18787
  MIME_TYPES as MIME_TYPES6,
18755
18788
  applyDarkModeFilter as applyDarkModeFilter8,
18756
- isRTL as isRTL2
18789
+ isRTL as isRTL2,
18790
+ getViewpointFlipSign
18757
18791
  } from "@excalidraw/common";
18758
18792
  import { pointFrom as pointFrom27, pointRotateRads as pointRotateRads19 } from "@excalidraw/math";
18759
18793
  import {
@@ -18797,7 +18831,7 @@ var getTransform = (width, height, angle2, appState, maxWidth, maxHeight) => {
18797
18831
  if (height > maxHeight && zoom.value !== 1) {
18798
18832
  translateY = maxHeight * (zoom.value - 1) / 2;
18799
18833
  }
18800
- return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
18834
+ return `translate(${translateX}px, ${translateY}px) scale(${zoom.value * getViewpointFlipSign(appState.viewpointFlip.horizontal)}, ${zoom.value * getViewpointFlipSign(appState.viewpointFlip.vertical)}) rotate(${degree}deg)`;
18801
18835
  };
18802
18836
  var getLineDirection = (text, offset) => {
18803
18837
  const hardLineStart = text.lastIndexOf("\n", Math.max(0, offset - 1)) + 1;
@@ -18983,7 +19017,7 @@ var textWysiwyg = ({
18983
19017
  }
18984
19018
  const [viewportX, viewportY] = getViewportCoords(coordX, coordY);
18985
19019
  if (!container) {
18986
- maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
19020
+ maxWidth = (appState.viewpointFlip.horizontal ? viewportX - 8 : appState.width - 8 - viewportX) / appState.zoom.value;
18987
19021
  width = Math.min(width, maxWidth);
18988
19022
  } else {
18989
19023
  width += 0.5;
@@ -18991,7 +19025,7 @@ var textWysiwyg = ({
18991
19025
  height *= 1.05;
18992
19026
  const font = getFontString11(updatedTextElement);
18993
19027
  const angle2 = getTextElementAngle(updatedTextElement, container);
18994
- const editorMaxHeight = (appState.height - viewportY) / appState.zoom.value;
19028
+ const editorMaxHeight = (appState.viewpointFlip.vertical ? viewportY : appState.height - viewportY) / appState.zoom.value;
18995
19029
  Object.assign(editable.style, {
18996
19030
  font,
18997
19031
  // must be defined *after* font ¯\_(ツ)_/¯
@@ -19206,7 +19240,7 @@ var textWysiwyg = ({
19206
19240
  app.actionManager.executeAction(actionDecreaseFontSize);
19207
19241
  } else if (actionIncreaseFontSize.keyTest(event)) {
19208
19242
  app.actionManager.executeAction(actionIncreaseFontSize);
19209
- } else if (event.key === KEYS38.ESCAPE) {
19243
+ } else if (event.key === KEYS39.ESCAPE) {
19210
19244
  event.preventDefault();
19211
19245
  submittedViaKeyboard = true;
19212
19246
  handleSubmit();
@@ -19214,18 +19248,18 @@ var textWysiwyg = ({
19214
19248
  event.preventDefault();
19215
19249
  handleSubmit();
19216
19250
  app.actionManager.executeAction(actionSaveToActiveFile);
19217
- } else if (event.key === KEYS38.ENTER && event[KEYS38.CTRL_OR_CMD]) {
19251
+ } else if (event.key === KEYS39.ENTER && event[KEYS39.CTRL_OR_CMD]) {
19218
19252
  event.preventDefault();
19219
19253
  if (event.isComposing || event.keyCode === 229) {
19220
19254
  return;
19221
19255
  }
19222
19256
  submittedViaKeyboard = true;
19223
19257
  handleSubmit();
19224
- } else if (event.key === KEYS38.TAB || event[KEYS38.CTRL_OR_CMD] && (event.code === CODES10.BRACKET_LEFT || event.code === CODES10.BRACKET_RIGHT)) {
19258
+ } else if (event.key === KEYS39.TAB || event[KEYS39.CTRL_OR_CMD] && (event.code === CODES11.BRACKET_LEFT || event.code === CODES11.BRACKET_RIGHT)) {
19225
19259
  event.preventDefault();
19226
19260
  if (event.isComposing) {
19227
19261
  return;
19228
- } else if (event.shiftKey || event.code === CODES10.BRACKET_LEFT) {
19262
+ } else if (event.shiftKey || event.code === CODES11.BRACKET_LEFT) {
19229
19263
  outdent();
19230
19264
  } else {
19231
19265
  indent();
@@ -19365,6 +19399,7 @@ var textWysiwyg = ({
19365
19399
  unbindUpdate();
19366
19400
  unsubOnChange();
19367
19401
  unbindOnScroll();
19402
+ unbindViewpointFlip();
19368
19403
  editable.remove();
19369
19404
  };
19370
19405
  const bindBlurEvent = (event) => {
@@ -19434,6 +19469,9 @@ var textWysiwyg = ({
19434
19469
  const unbindOnScroll = app.onScrollChangeEmitter.on(() => {
19435
19470
  updateWysiwygStyle();
19436
19471
  });
19472
+ const unbindViewpointFlip = app.onStateChange("viewpointFlip", () => {
19473
+ updateWysiwygStyle();
19474
+ });
19437
19475
  let isDestroyed = false;
19438
19476
  if (autoSelect && !pendingInitialSelection) {
19439
19477
  editable.select();
@@ -22679,7 +22717,7 @@ var _renderInteractiveScene = ({
22679
22717
  normalizedHeight
22680
22718
  });
22681
22719
  context.save();
22682
- context.scale(appState.zoom.value, appState.zoom.value);
22720
+ applyZoomAndViewpointFlip(context, appState);
22683
22721
  let editingLinearElement = void 0;
22684
22722
  visibleElements.forEach((element) => {
22685
22723
  if (appState.selectedLinearElement?.isEditing && appState.selectedLinearElement.elementId === element.id) {
@@ -24408,10 +24446,10 @@ var AppDrawShape = class {
24408
24446
  };
24409
24447
 
24410
24448
  // components/App.flowchart.ts
24411
- import { isArrowKey as isArrowKey2, KEYS as KEYS39 } from "@excalidraw/common";
24449
+ import { isArrowKey as isArrowKey2, KEYS as KEYS40 } from "@excalidraw/common";
24412
24450
  import {
24413
24451
  makeNextSelectedElementIds as makeNextSelectedElementIds3,
24414
- CaptureUpdateAction as CaptureUpdateAction37,
24452
+ CaptureUpdateAction as CaptureUpdateAction38,
24415
24453
  FlowChartCreator,
24416
24454
  FlowChartNavigator,
24417
24455
  getSelectedElements as getSelectedElements6,
@@ -24475,14 +24513,14 @@ var AppFlowchart = class _AppFlowchart {
24475
24513
  resolveKeyboardEventToOperation(event) {
24476
24514
  const { creator, navigator: navigator2, app } = this;
24477
24515
  if (event.type === "keydown") {
24478
- if (event.key === KEYS39.ESCAPE && creator.isCreatingChart) {
24516
+ if (event.key === KEYS40.ESCAPE && creator.isCreatingChart) {
24479
24517
  creator.clear();
24480
24518
  return { type: "canceled" };
24481
24519
  }
24482
24520
  if (!isArrowKey2(event.key)) {
24483
24521
  return { type: "none" };
24484
24522
  }
24485
- if (event[KEYS39.CTRL_OR_CMD] && !event.shiftKey) {
24523
+ if (event[KEYS40.CTRL_OR_CMD] && !event.shiftKey) {
24486
24524
  const selectedElements = getSelectedElements6(
24487
24525
  app.scene.getNonDeletedElementsMap(),
24488
24526
  app.state
@@ -24517,7 +24555,7 @@ var AppFlowchart = class _AppFlowchart {
24517
24555
  if (navigationEnded) {
24518
24556
  navigator2.clear();
24519
24557
  }
24520
- if (!event[KEYS39.CTRL_OR_CMD] && creator.isCreatingChart) {
24558
+ if (!event[KEYS40.CTRL_OR_CMD] && creator.isCreatingChart) {
24521
24559
  const nodes = creator.pendingNodes ?? [];
24522
24560
  creator.clear();
24523
24561
  return { type: "committed", nodes };
@@ -24535,18 +24573,18 @@ var AppFlowchart = class _AppFlowchart {
24535
24573
  }
24536
24574
  captureUpdate() {
24537
24575
  this.app.syncActionResult({
24538
- captureUpdate: CaptureUpdateAction37.IMMEDIATELY
24576
+ captureUpdate: CaptureUpdateAction38.IMMEDIATELY
24539
24577
  });
24540
24578
  }
24541
24579
  static getLinkDirectionFromKey(key) {
24542
24580
  switch (key) {
24543
- case KEYS39.ARROW_UP:
24581
+ case KEYS40.ARROW_UP:
24544
24582
  return "up";
24545
- case KEYS39.ARROW_DOWN:
24583
+ case KEYS40.ARROW_DOWN:
24546
24584
  return "down";
24547
- case KEYS39.ARROW_RIGHT:
24585
+ case KEYS40.ARROW_RIGHT:
24548
24586
  return "right";
24549
- case KEYS39.ARROW_LEFT:
24587
+ case KEYS40.ARROW_LEFT:
24550
24588
  return "left";
24551
24589
  default:
24552
24590
  return "right";
@@ -25333,6 +25371,8 @@ var shortcutMap = {
25333
25371
  stats: [getShortcutKey("Alt+/")],
25334
25372
  flipHorizontal: [getShortcutKey("Shift+H")],
25335
25373
  flipVertical: [getShortcutKey("Shift+V")],
25374
+ flipViewpointHorizontal: [getShortcutKey("Shift+R")],
25375
+ flipViewpointVertical: [getShortcutKey("Alt+Shift+R")],
25336
25376
  viewMode: [getShortcutKey("Alt+R")],
25337
25377
  hyperlink: [getShortcutKey("CtrlOrCmd+K")],
25338
25378
  toggleElementLock: [getShortcutKey("CtrlOrCmd+Shift+L")],
@@ -25348,7 +25388,7 @@ var shortcutMap = {
25348
25388
  toggleShortcuts: [getShortcutKey("?")],
25349
25389
  searchMenu: [getShortcutKey("CtrlOrCmd+F")],
25350
25390
  wrapSelectionInFrame: [],
25351
- arrangeElements: [getShortcutKey("Shift+R")],
25391
+ arrangeElements: [getShortcutKey("Shift+A")],
25352
25392
  toolLock: [getShortcutKey("Q")]
25353
25393
  };
25354
25394
  var getShortcutFromShortcutName = (name, idx = 0) => {
@@ -25359,7 +25399,7 @@ var getShortcutFromShortcutName = (name, idx = 0) => {
25359
25399
  // components/Popover.tsx
25360
25400
  import { useLayoutEffect as useLayoutEffect4, useRef as useRef16, useEffect as useEffect23 } from "react";
25361
25401
  import { unstable_batchedUpdates as unstable_batchedUpdates2 } from "react-dom";
25362
- import { KEYS as KEYS40, queryFocusableElements } from "@excalidraw/common";
25402
+ import { KEYS as KEYS41, queryFocusableElements } from "@excalidraw/common";
25363
25403
  import { clamp as clamp10 } from "@excalidraw/math";
25364
25404
  import clsx25 from "clsx";
25365
25405
  import { jsx as jsx63 } from "react/jsx-runtime";
@@ -25384,7 +25424,7 @@ var Popover7 = ({
25384
25424
  container.focus();
25385
25425
  }
25386
25426
  const handleKeyDown = (event) => {
25387
- if (event.key === KEYS40.TAB) {
25427
+ if (event.key === KEYS41.TAB) {
25388
25428
  const focusableElements = queryFocusableElements(container);
25389
25429
  const { activeElement } = document;
25390
25430
  const currentIndex = focusableElements.findIndex(
@@ -26535,7 +26575,7 @@ var LoadingMessage = ({
26535
26575
  // components/MobileToolbar.tsx
26536
26576
  import { useState as useState19, useEffect as useEffect26 } from "react";
26537
26577
  import clsx34 from "clsx";
26538
- import { KEYS as KEYS42, capitalizeString as capitalizeString3 } from "@excalidraw/common";
26578
+ import { KEYS as KEYS43, capitalizeString as capitalizeString3 } from "@excalidraw/common";
26539
26579
 
26540
26580
  // components/dropdownMenu/DropdownMenu.tsx
26541
26581
  import React25 from "react";
@@ -26545,7 +26585,7 @@ import { CLASSES as CLASSES6 } from "@excalidraw/common";
26545
26585
  // components/dropdownMenu/DropdownMenuContent.tsx
26546
26586
  import clsx31 from "clsx";
26547
26587
  import { useCallback as useCallback7, useEffect as useEffect25, useRef as useRef18 } from "react";
26548
- import { CLASSES as CLASSES5, EVENT as EVENT6, KEYS as KEYS41 } from "@excalidraw/common";
26588
+ import { CLASSES as CLASSES5, EVENT as EVENT6, KEYS as KEYS42 } from "@excalidraw/common";
26549
26589
  import { DropdownMenu as DropdownMenuPrimitive2 } from "radix-ui";
26550
26590
  import { jsx as jsx69 } from "react/jsx-runtime";
26551
26591
  var MenuContent = ({
@@ -26576,7 +26616,7 @@ var MenuContent = ({
26576
26616
  return;
26577
26617
  }
26578
26618
  const onKeyDown = (event) => {
26579
- if (event.key === KEYS41.ESCAPE) {
26619
+ if (event.key === KEYS42.ESCAPE) {
26580
26620
  event.preventDefault();
26581
26621
  event.stopImmediatePropagation();
26582
26622
  callbacksRef.onClickOutside?.();
@@ -27119,7 +27159,7 @@ var MobileToolbar = ({
27119
27159
  icon: app.state.activeTool.locked ? LockedIcon : UnlockedIcon,
27120
27160
  "data-testid": "toolbar-lock",
27121
27161
  selected: app.state.activeTool.locked,
27122
- shortcut: KEYS42.Q.toLocaleUpperCase(),
27162
+ shortcut: KEYS43.Q.toLocaleUpperCase(),
27123
27163
  children: t("toolBar.lock-short")
27124
27164
  }
27125
27165
  )
@@ -27129,7 +27169,7 @@ var MobileToolbar = ({
27129
27169
  {
27130
27170
  onSelect: () => app.setActiveTool({ type: "text" }),
27131
27171
  icon: TextIcon,
27132
- shortcut: KEYS42.T.toLocaleUpperCase(),
27172
+ shortcut: KEYS43.T.toLocaleUpperCase(),
27133
27173
  "data-testid": "toolbar-text",
27134
27174
  selected: activeTool.type === "text",
27135
27175
  disabled: isToolButtonDisabled(app, "text"),
@@ -27152,7 +27192,7 @@ var MobileToolbar = ({
27152
27192
  {
27153
27193
  onSelect: () => app.setActiveTool({ type: "frame" }),
27154
27194
  icon: frameToolIcon,
27155
- shortcut: KEYS42.F.toLocaleUpperCase(),
27195
+ shortcut: KEYS43.F.toLocaleUpperCase(),
27156
27196
  "data-testid": "toolbar-frame",
27157
27197
  selected: frameToolSelected,
27158
27198
  disabled: isToolButtonDisabled(app, "frame"),
@@ -27406,7 +27446,7 @@ import { newTextElement as newTextElement4 } from "@excalidraw/element";
27406
27446
  // components/Dialog.tsx
27407
27447
  import clsx38 from "clsx";
27408
27448
  import { useEffect as useEffect27, useState as useState21 } from "react";
27409
- import { KEYS as KEYS44, queryFocusableElements as queryFocusableElements2 } from "@excalidraw/common";
27449
+ import { KEYS as KEYS45, queryFocusableElements as queryFocusableElements2 } from "@excalidraw/common";
27410
27450
 
27411
27451
  // hooks/useCallbackRefState.ts
27412
27452
  import { useCallback as useCallback9, useState as useState20 } from "react";
@@ -27420,7 +27460,7 @@ var useCallbackRefState = () => {
27420
27460
  import clsx37 from "clsx";
27421
27461
  import { useRef as useRef19 } from "react";
27422
27462
  import { createPortal as createPortal2 } from "react-dom";
27423
- import { KEYS as KEYS43 } from "@excalidraw/common";
27463
+ import { KEYS as KEYS44 } from "@excalidraw/common";
27424
27464
  import { jsx as jsx82, jsxs as jsxs41 } from "react/jsx-runtime";
27425
27465
  var Modal = (props) => {
27426
27466
  const { closeOnClickOutside = true } = props;
@@ -27437,7 +27477,7 @@ var Modal = (props) => {
27437
27477
  return null;
27438
27478
  }
27439
27479
  const handleKeydown = (event) => {
27440
- if (event.key === KEYS43.ESCAPE) {
27480
+ if (event.key === KEYS44.ESCAPE) {
27441
27481
  event.preventDefault();
27442
27482
  event.nativeEvent.stopImmediatePropagation();
27443
27483
  event.stopPropagation();
@@ -27511,7 +27551,7 @@ var Dialog = (props) => {
27511
27551
  }
27512
27552
  });
27513
27553
  const handleKeyDown = (event) => {
27514
- if (event.key === KEYS44.TAB) {
27554
+ if (event.key === KEYS45.TAB) {
27515
27555
  const focusableElements2 = queryFocusableElements2(islandNode);
27516
27556
  const { activeElement } = document;
27517
27557
  const currentIndex = focusableElements2.findIndex(
@@ -29011,9 +29051,9 @@ import { updateBindings as updateBindings3 } from "@excalidraw/element";
29011
29051
  // components/Stats/DragInput.tsx
29012
29052
  import clsx44 from "clsx";
29013
29053
  import { useEffect as useEffect28, useRef as useRef22, useState as useState24 } from "react";
29014
- import { EVENT as EVENT7, KEYS as KEYS45, cloneJSON as cloneJSON3 } from "@excalidraw/common";
29054
+ import { EVENT as EVENT7, KEYS as KEYS46, cloneJSON as cloneJSON3 } from "@excalidraw/common";
29015
29055
  import { deepCopyElement as deepCopyElement4 } from "@excalidraw/element";
29016
- import { CaptureUpdateAction as CaptureUpdateAction38 } from "@excalidraw/element";
29056
+ import { CaptureUpdateAction as CaptureUpdateAction39 } from "@excalidraw/element";
29017
29057
 
29018
29058
  // components/Stats/utils.ts
29019
29059
  import { pointFrom as pointFrom40, pointRotateRads as pointRotateRads22 } from "@excalidraw/math";
@@ -29224,7 +29264,7 @@ var StatsDragInput = ({
29224
29264
  setAppState
29225
29265
  });
29226
29266
  app.syncActionResult({
29227
- captureUpdate: CaptureUpdateAction38.IMMEDIATELY
29267
+ captureUpdate: CaptureUpdateAction39.IMMEDIATELY
29228
29268
  });
29229
29269
  }
29230
29270
  };
@@ -29332,7 +29372,7 @@ var StatsDragInput = ({
29332
29372
  false
29333
29373
  );
29334
29374
  app.syncActionResult({
29335
- captureUpdate: CaptureUpdateAction38.IMMEDIATELY
29375
+ captureUpdate: CaptureUpdateAction39.IMMEDIATELY
29336
29376
  });
29337
29377
  dragFinishedCallback?.({
29338
29378
  app,
@@ -29371,7 +29411,7 @@ var StatsDragInput = ({
29371
29411
  onKeyDown: (event) => {
29372
29412
  if (editable) {
29373
29413
  const eventTarget = event.target;
29374
- if (eventTarget instanceof HTMLInputElement && event.key === KEYS45.ENTER) {
29414
+ if (eventTarget instanceof HTMLInputElement && event.key === KEYS46.ENTER) {
29375
29415
  handleInputValue(eventTarget.value, elements, appState);
29376
29416
  app.focusContainer();
29377
29417
  }
@@ -31233,7 +31273,7 @@ var StatsInner = memo2(
31233
31273
 
31234
31274
  // components/ElementLinkDialog.tsx
31235
31275
  import { useCallback as useCallback10, useEffect as useEffect30, useState as useState27 } from "react";
31236
- import { normalizeLink as normalizeLink3, KEYS as KEYS46 } from "@excalidraw/common";
31276
+ import { normalizeLink as normalizeLink3, KEYS as KEYS47 } from "@excalidraw/common";
31237
31277
  import {
31238
31278
  defaultGetElementLinkFromSelection,
31239
31279
  getLinkIdAndTypeFromSelection
@@ -31438,10 +31478,10 @@ var ElementLinkDialog = ({
31438
31478
  }, [sourceElementId, nextLink, elementsMap, linkEdited, scene, onClose]);
31439
31479
  useEffect30(() => {
31440
31480
  const handleKeyDown = (event) => {
31441
- if (appState.openDialog?.name === "elementLinkSelector" && event.key === KEYS46.ENTER) {
31481
+ if (appState.openDialog?.name === "elementLinkSelector" && event.key === KEYS47.ENTER) {
31442
31482
  handleConfirm();
31443
31483
  }
31444
- if (appState.openDialog?.name === "elementLinkSelector" && event.key === KEYS46.ESCAPE) {
31484
+ if (appState.openDialog?.name === "elementLinkSelector" && event.key === KEYS47.ESCAPE) {
31445
31485
  onClose?.();
31446
31486
  }
31447
31487
  };
@@ -31467,7 +31507,7 @@ var ElementLinkDialog = ({
31467
31507
  setNextLink(value);
31468
31508
  },
31469
31509
  onKeyDown: (event) => {
31470
- if (event.key === KEYS46.ENTER) {
31510
+ if (event.key === KEYS47.ENTER) {
31471
31511
  handleConfirm();
31472
31512
  }
31473
31513
  },
@@ -32083,11 +32123,11 @@ var GifPlaybackControls = ({
32083
32123
  import React33, { useMemo as useMemo10 } from "react";
32084
32124
  import clsx50 from "clsx";
32085
32125
  import { isDarwin as isDarwin4, isFirefox as isFirefox4, isWindows } from "@excalidraw/common";
32086
- import { KEYS as KEYS48 } from "@excalidraw/common";
32126
+ import { KEYS as KEYS49 } from "@excalidraw/common";
32087
32127
  import { SHAPES as SHAPES3 } from "@excalidraw/element/shapes";
32088
32128
 
32089
32129
  // components/HelpDialog/BasicHelpDialog.tsx
32090
- import { isFirefox as isFirefox3, KEYS as KEYS47 } from "@excalidraw/common";
32130
+ import { isFirefox as isFirefox3, KEYS as KEYS48 } from "@excalidraw/common";
32091
32131
  import { SHAPES as SHAPES2 } from "@excalidraw/element/shapes";
32092
32132
  import { Fragment as Fragment19, jsx as jsx114, jsxs as jsxs60 } from "react/jsx-runtime";
32093
32133
  var Section2 = (props) => /* @__PURE__ */ jsxs60(Fragment19, { children: [
@@ -32134,7 +32174,7 @@ function BasicHelpDialog() {
32134
32174
  className: "HelpDialog__island--tools",
32135
32175
  caption: t("helpDialog.tools"),
32136
32176
  children: [
32137
- /* @__PURE__ */ jsx114(Shortcut, { label: t("toolBar.hand"), shortcuts: [KEYS47.H] }),
32177
+ /* @__PURE__ */ jsx114(Shortcut, { label: t("toolBar.hand"), shortcuts: [KEYS48.H] }),
32138
32178
  SHAPES2.filter(({ myocSimplifiedMode }) => myocSimplifiedMode).map(
32139
32179
  ({ value, key }) => /* @__PURE__ */ jsx114(
32140
32180
  Shortcut,
@@ -32170,12 +32210,26 @@ function BasicHelpDialog() {
32170
32210
  className: "HelpDialog__island--view",
32171
32211
  caption: t("helpDialog.view"),
32172
32212
  children: [
32173
- /* @__PURE__ */ jsx114(Shortcut, { label: t("helpDialog.smartZoom"), shortcuts: [KEYS47.F] }),
32213
+ /* @__PURE__ */ jsx114(Shortcut, { label: t("helpDialog.smartZoom"), shortcuts: [KEYS48.F] }),
32214
+ /* @__PURE__ */ jsx114(
32215
+ Shortcut,
32216
+ {
32217
+ label: t("labels.flipViewpointHorizontal"),
32218
+ shortcuts: [getShortcutKey("Shift+R")]
32219
+ }
32220
+ ),
32221
+ /* @__PURE__ */ jsx114(
32222
+ Shortcut,
32223
+ {
32224
+ label: t("labels.flipViewpointVertical"),
32225
+ shortcuts: [getShortcutKey("Alt+Shift+R")]
32226
+ }
32227
+ ),
32174
32228
  /* @__PURE__ */ jsx114(
32175
32229
  Shortcut,
32176
32230
  {
32177
32231
  label: t("helpDialog.dragToZoom"),
32178
- shortcuts: [`${KEYS47.Z}+${t("helpDialog.drag")}`]
32232
+ shortcuts: [`${KEYS48.Z}+${t("helpDialog.drag")}`]
32179
32233
  }
32180
32234
  ),
32181
32235
  /* @__PURE__ */ jsx114(
@@ -32348,7 +32402,7 @@ var HelpDialog = ({ onClose }) => {
32348
32402
  className: "HelpDialog__island--tools",
32349
32403
  caption: t("helpDialog.tools"),
32350
32404
  children: [
32351
- /* @__PURE__ */ jsx115(Shortcut2, { label: t("toolBar.hand"), shortcuts: [KEYS48.H] }),
32405
+ /* @__PURE__ */ jsx115(Shortcut2, { label: t("toolBar.hand"), shortcuts: [KEYS49.H] }),
32352
32406
  SHAPES3.map(({ value, key }) => /* @__PURE__ */ jsx115(
32353
32407
  Shortcut2,
32354
32408
  {
@@ -32357,12 +32411,12 @@ var HelpDialog = ({ onClose }) => {
32357
32411
  },
32358
32412
  value
32359
32413
  )),
32360
- /* @__PURE__ */ jsx115(Shortcut2, { label: t("toolBar.frame"), shortcuts: [KEYS48.F] }),
32414
+ /* @__PURE__ */ jsx115(Shortcut2, { label: t("toolBar.frame"), shortcuts: [KEYS49.F] }),
32361
32415
  /* @__PURE__ */ jsx115(
32362
32416
  Shortcut2,
32363
32417
  {
32364
32418
  label: t("labels.eyeDropper"),
32365
- shortcuts: [KEYS48.I, "Shift+S", "Shift+I"]
32419
+ shortcuts: [KEYS49.I, "Shift+S", "Shift+I"]
32366
32420
  }
32367
32421
  ),
32368
32422
  /* @__PURE__ */ jsx115(
@@ -32444,7 +32498,7 @@ var HelpDialog = ({ onClose }) => {
32444
32498
  isOr: true
32445
32499
  }
32446
32500
  ),
32447
- /* @__PURE__ */ jsx115(Shortcut2, { label: t("toolBar.lock"), shortcuts: [KEYS48.Q] }),
32501
+ /* @__PURE__ */ jsx115(Shortcut2, { label: t("toolBar.lock"), shortcuts: [KEYS49.Q] }),
32448
32502
  /* @__PURE__ */ jsx115(
32449
32503
  Shortcut2,
32450
32504
  {
@@ -32480,14 +32534,14 @@ var HelpDialog = ({ onClose }) => {
32480
32534
  Shortcut2,
32481
32535
  {
32482
32536
  label: t("helpDialog.smartZoom"),
32483
- shortcuts: [KEYS48.F]
32537
+ shortcuts: [KEYS49.F]
32484
32538
  }
32485
32539
  ),
32486
32540
  /* @__PURE__ */ jsx115(
32487
32541
  Shortcut2,
32488
32542
  {
32489
32543
  label: t("helpDialog.dragToZoom"),
32490
- shortcuts: [`${KEYS48.Z}+${t("helpDialog.drag")}`]
32544
+ shortcuts: [`${KEYS49.Z}+${t("helpDialog.drag")}`]
32491
32545
  }
32492
32546
  ),
32493
32547
  /* @__PURE__ */ jsx115(
@@ -32546,6 +32600,20 @@ var HelpDialog = ({ onClose }) => {
32546
32600
  shortcuts: [getShortcutKey("Alt+R")]
32547
32601
  }
32548
32602
  ),
32603
+ /* @__PURE__ */ jsx115(
32604
+ Shortcut2,
32605
+ {
32606
+ label: t("labels.flipViewpointHorizontal"),
32607
+ shortcuts: [getShortcutKey("Shift+R")]
32608
+ }
32609
+ ),
32610
+ /* @__PURE__ */ jsx115(
32611
+ Shortcut2,
32612
+ {
32613
+ label: t("labels.flipViewpointVertical"),
32614
+ shortcuts: [getShortcutKey("Alt+Shift+R")]
32615
+ }
32616
+ ),
32549
32617
  /* @__PURE__ */ jsx115(
32550
32618
  Shortcut2,
32551
32619
  {
@@ -32718,7 +32786,7 @@ var HelpDialog = ({ onClose }) => {
32718
32786
  Shortcut2,
32719
32787
  {
32720
32788
  label: t("labels.arrangeElements"),
32721
- shortcuts: [getShortcutKey("Shift+R")]
32789
+ shortcuts: [getShortcutKey("Shift+A")]
32722
32790
  }
32723
32791
  ),
32724
32792
  /* @__PURE__ */ jsx115(
@@ -33228,7 +33296,7 @@ import {
33228
33296
  } from "@excalidraw/element";
33229
33297
  import { measureText as measureText7 } from "@excalidraw/element";
33230
33298
  import {
33231
- KEYS as KEYS49,
33299
+ KEYS as KEYS50,
33232
33300
  randomInteger as randomInteger8,
33233
33301
  addEventListener,
33234
33302
  getFontString as getFontString15
@@ -33388,7 +33456,7 @@ var SearchMenu2 = () => {
33388
33456
  });
33389
33457
  useEffect32(() => {
33390
33458
  const eventHandler = (event) => {
33391
- if (event.key === KEYS49.ESCAPE && !app.state.openDialog && !app.state.openPopup) {
33459
+ if (event.key === KEYS50.ESCAPE && !app.state.openDialog && !app.state.openPopup) {
33392
33460
  event.preventDefault();
33393
33461
  event.stopPropagation();
33394
33462
  setAppState({
@@ -33396,7 +33464,7 @@ var SearchMenu2 = () => {
33396
33464
  });
33397
33465
  return;
33398
33466
  }
33399
- if (event[KEYS49.CTRL_OR_CMD] && event.key === KEYS49.F) {
33467
+ if (event[KEYS50.CTRL_OR_CMD] && event.key === KEYS50.F) {
33400
33468
  event.preventDefault();
33401
33469
  event.stopPropagation();
33402
33470
  if (app.state.openDialog) {
@@ -33414,14 +33482,14 @@ var SearchMenu2 = () => {
33414
33482
  }
33415
33483
  if (event.target instanceof HTMLElement && event.target.closest(".layer-ui__search")) {
33416
33484
  if (stableState.searchMatches.items.length) {
33417
- if (event.key === KEYS49.ENTER) {
33485
+ if (event.key === KEYS50.ENTER) {
33418
33486
  event.stopPropagation();
33419
33487
  stableState.goToNextItem();
33420
33488
  }
33421
- if (event.key === KEYS49.ARROW_UP) {
33489
+ if (event.key === KEYS50.ARROW_UP) {
33422
33490
  event.stopPropagation();
33423
33491
  stableState.goToPreviousItem();
33424
- } else if (event.key === KEYS49.ARROW_DOWN) {
33492
+ } else if (event.key === KEYS50.ARROW_DOWN) {
33425
33493
  event.stopPropagation();
33426
33494
  stableState.goToNextItem();
33427
33495
  }
@@ -33845,7 +33913,7 @@ import {
33845
33913
  CLASSES as CLASSES8,
33846
33914
  EVENT as EVENT9,
33847
33915
  isDevEnv as isDevEnv12,
33848
- KEYS as KEYS50,
33916
+ KEYS as KEYS51,
33849
33917
  updateObject
33850
33918
  } from "@excalidraw/common";
33851
33919
 
@@ -34085,7 +34153,7 @@ var SidebarInner = forwardRef5(
34085
34153
  );
34086
34154
  useEffect33(() => {
34087
34155
  const handleKeyDown = (event) => {
34088
- if (event.key === KEYS50.ESCAPE && (!docked || !editorInterface.canFitSidebar)) {
34156
+ if (event.key === KEYS51.ESCAPE && (!docked || !editorInterface.canFitSidebar)) {
34089
34157
  closeSidebar();
34090
34158
  }
34091
34159
  };
@@ -34381,7 +34449,7 @@ var LaserPointerButton = (props) => {
34381
34449
  // components/Toolbar.tsx
34382
34450
  import clsx58 from "clsx";
34383
34451
  import { useState as useState33 } from "react";
34384
- import { CANVAS_SEARCH_TAB as CANVAS_SEARCH_TAB4, DEFAULT_SIDEBAR as DEFAULT_SIDEBAR4, KEYS as KEYS51 } from "@excalidraw/common";
34452
+ import { CANVAS_SEARCH_TAB as CANVAS_SEARCH_TAB4, DEFAULT_SIDEBAR as DEFAULT_SIDEBAR4, KEYS as KEYS52 } from "@excalidraw/common";
34385
34453
 
34386
34454
  // components/HintViewer.tsx
34387
34455
  import { CANVAS_SEARCH_TAB as CANVAS_SEARCH_TAB3, DEFAULT_SIDEBAR as DEFAULT_SIDEBAR3 } from "@excalidraw/common";
@@ -34626,7 +34694,7 @@ var LockActiveToolDropdownItem = ({ app }) => /* @__PURE__ */ jsx131(
34626
34694
  icon: app.state.activeTool.locked ? LockedIcon : UnlockedIcon,
34627
34695
  "data-testid": "toolbar-lock",
34628
34696
  selected: app.state.activeTool.locked,
34629
- shortcut: KEYS51.Q.toLocaleUpperCase(),
34697
+ shortcut: KEYS52.Q.toLocaleUpperCase(),
34630
34698
  children: t("toolBar.lock-short")
34631
34699
  }
34632
34700
  );
@@ -34696,10 +34764,10 @@ var StrokeEyeDropperButton2 = ({ app }) => /* @__PURE__ */ jsx131(
34696
34764
  {
34697
34765
  type: "button",
34698
34766
  icon: eyeDropperIcon,
34699
- title: `${t("labels.eyeDropper")} - ${KEYS51.I.toLocaleUpperCase()}`,
34767
+ title: `${t("labels.eyeDropper")} - ${KEYS52.I.toLocaleUpperCase()}`,
34700
34768
  "aria-label": t("labels.eyeDropper"),
34701
- "aria-keyshortcuts": KEYS51.I.toLocaleUpperCase(),
34702
- keyBindingLabel: KEYS51.I.toLocaleUpperCase(),
34769
+ "aria-keyshortcuts": KEYS52.I.toLocaleUpperCase(),
34770
+ keyBindingLabel: KEYS52.I.toLocaleUpperCase(),
34703
34771
  "data-testid": "toolbar-eyedropper",
34704
34772
  onClick: () => app.openEyeDropper({ type: "stroke", swapPreviewOnAlt: false })
34705
34773
  }
@@ -34785,7 +34853,7 @@ var ExtraToolsDropdown = ({
34785
34853
  {
34786
34854
  onSelect: () => app.setActiveTool({ type: "frame" }),
34787
34855
  icon: frameToolIcon,
34788
- shortcut: KEYS51.F.toLocaleUpperCase(),
34856
+ shortcut: KEYS52.F.toLocaleUpperCase(),
34789
34857
  "data-testid": "toolbar-frame",
34790
34858
  selected: frameToolSelected,
34791
34859
  disabled: isToolButtonDisabled(app, "frame"),
@@ -35644,6 +35712,7 @@ var getRelevantAppStateProps = (appState) => ({
35644
35712
  scrollY: appState.scrollY,
35645
35713
  width: appState.width,
35646
35714
  height: appState.height,
35715
+ viewpointFlip: appState.viewpointFlip,
35647
35716
  viewModeEnabled: appState.viewModeEnabled,
35648
35717
  activeTool: appState.activeTool,
35649
35718
  openDialog: appState.openDialog,
@@ -35811,6 +35880,7 @@ var getRelevantAppStateProps2 = (appState) => {
35811
35880
  scrollY: appState.scrollY,
35812
35881
  width: appState.width,
35813
35882
  height: appState.height,
35883
+ viewpointFlip: appState.viewpointFlip,
35814
35884
  viewModeEnabled: appState.viewModeEnabled,
35815
35885
  openDialog: appState.openDialog,
35816
35886
  hoveredElementIds: appState.hoveredElementIds,
@@ -35882,7 +35952,7 @@ var _renderNewElementScene = ({
35882
35952
  normalizedHeight
35883
35953
  });
35884
35954
  context.save();
35885
- context.scale(appState.zoom.value, appState.zoom.value);
35955
+ applyZoomAndViewpointFlip(context, appState);
35886
35956
  if (newElement9 && newElement9.type !== "selection") {
35887
35957
  if (isInvisiblySmallElement3(newElement9)) {
35888
35958
  return;
@@ -36340,6 +36410,18 @@ var touchTimeout = 0;
36340
36410
  var invalidateContextMenu = false;
36341
36411
  var YOUTUBE_VIDEO_STATES = /* @__PURE__ */ new Map();
36342
36412
  var MAX_EMBEDDABLE_VIEWPORT_SCALE = 4;
36413
+ var getViewpointAwareResizeCursor = (cursor, viewpointFlip) => {
36414
+ if (viewpointFlip.horizontal === viewpointFlip.vertical) {
36415
+ return cursor;
36416
+ }
36417
+ if (cursor === "nwse-resize") {
36418
+ return "nesw-resize";
36419
+ }
36420
+ if (cursor === "nesw-resize") {
36421
+ return "nwse-resize";
36422
+ }
36423
+ return cursor;
36424
+ };
36343
36425
  var IS_PLAIN_PASTE = false;
36344
36426
  var IS_PLAIN_PASTE_TIMER = 0;
36345
36427
  var PLAIN_PASTE_TOAST_SHOWN = false;
@@ -36562,7 +36644,7 @@ var App = class _App extends React41.Component {
36562
36644
  __publicField(this, "frameNameBoundsCache", {
36563
36645
  get: (frameElement) => {
36564
36646
  let bounds = this.frameNameBoundsCache._cache.get(frameElement.id);
36565
- if (!bounds || bounds.zoom !== this.state.zoom.value || bounds.versionNonce !== frameElement.versionNonce) {
36647
+ if (!bounds || bounds.zoom !== this.state.zoom.value || bounds.viewpointFlip !== this.state.viewpointFlip || bounds.versionNonce !== frameElement.versionNonce) {
36566
36648
  const frameNameDiv = document.getElementById(
36567
36649
  this.getFrameNameDOMId(frameElement)
36568
36650
  );
@@ -36577,11 +36659,12 @@ var App = class _App extends React41.Component {
36577
36659
  this.state
36578
36660
  );
36579
36661
  bounds = {
36580
- x: boxSceneTopLeft.x,
36581
- y: boxSceneTopLeft.y,
36582
- width: boxSceneBottomRight.x - boxSceneTopLeft.x,
36583
- height: boxSceneBottomRight.y - boxSceneTopLeft.y,
36662
+ x: Math.min(boxSceneTopLeft.x, boxSceneBottomRight.x),
36663
+ y: Math.min(boxSceneTopLeft.y, boxSceneBottomRight.y),
36664
+ width: Math.abs(boxSceneBottomRight.x - boxSceneTopLeft.x),
36665
+ height: Math.abs(boxSceneBottomRight.y - boxSceneTopLeft.y),
36584
36666
  zoom: this.state.zoom.value,
36667
+ viewpointFlip: this.state.viewpointFlip,
36585
36668
  versionNonce: frameElement.versionNonce
36586
36669
  };
36587
36670
  this.frameNameBoundsCache._cache.set(frameElement.id, bounds);
@@ -36634,7 +36717,10 @@ var App = class _App extends React41.Component {
36634
36717
  return null;
36635
36718
  }
36636
36719
  const { x: x1, y: y1 } = sceneCoordsToViewportCoords7(
36637
- { sceneX: f.x, sceneY: f.y },
36720
+ {
36721
+ sceneX: f.x + (this.state.viewpointFlip.horizontal ? f.width : 0),
36722
+ sceneY: f.y + (this.state.viewpointFlip.vertical ? f.height : 0)
36723
+ },
36638
36724
  this.state
36639
36725
  );
36640
36726
  const FRAME_NAME_EDIT_PADDING = 6;
@@ -36655,7 +36741,7 @@ var App = class _App extends React41.Component {
36655
36741
  onFocus: (e) => e.target.select(),
36656
36742
  onBlur: () => this.resetEditingFrame(f),
36657
36743
  onKeyDown: (event) => {
36658
- if (event.key === KEYS52.ESCAPE || event.key === KEYS52.ENTER) {
36744
+ if (event.key === KEYS53.ESCAPE || event.key === KEYS53.ENTER) {
36659
36745
  this.resetEditingFrame(f);
36660
36746
  }
36661
36747
  },
@@ -36781,12 +36867,12 @@ var App = class _App extends React41.Component {
36781
36867
  if (shouldUpdateStrokeColor) {
36782
36868
  this.syncActionResult({
36783
36869
  appState: { ...this.state, currentItemStrokeColor: color },
36784
- captureUpdate: CaptureUpdateAction39.IMMEDIATELY
36870
+ captureUpdate: CaptureUpdateAction40.IMMEDIATELY
36785
36871
  });
36786
36872
  } else {
36787
36873
  this.syncActionResult({
36788
36874
  appState: { ...this.state, currentItemBackgroundColor: color },
36789
- captureUpdate: CaptureUpdateAction39.IMMEDIATELY
36875
+ captureUpdate: CaptureUpdateAction40.IMMEDIATELY
36790
36876
  });
36791
36877
  }
36792
36878
  } else {
@@ -36799,7 +36885,7 @@ var App = class _App extends React41.Component {
36799
36885
  }
36800
36886
  return el;
36801
36887
  }),
36802
- captureUpdate: CaptureUpdateAction39.IMMEDIATELY
36888
+ captureUpdate: CaptureUpdateAction40.IMMEDIATELY
36803
36889
  });
36804
36890
  }
36805
36891
  },
@@ -36876,7 +36962,7 @@ var App = class _App extends React41.Component {
36876
36962
  }
36877
36963
  }));
36878
36964
  __publicField(this, "scheduleCapture", () => this.store.scheduleCapture());
36879
- __publicField(this, "scheduleUpdate", () => this.store.scheduleAction(CaptureUpdateAction39.NEVER));
36965
+ __publicField(this, "scheduleUpdate", () => this.store.scheduleAction(CaptureUpdateAction40.NEVER));
36880
36966
  // Lifecycle
36881
36967
  __publicField(this, "onBlur", withBatchedUpdates(() => {
36882
36968
  isHoldingSpace = false;
@@ -36894,7 +36980,7 @@ var App = class _App extends React41.Component {
36894
36980
  // letting regular scroll through (trackpad pinch is delivered as
36895
36981
  // ctrl+wheel)
36896
36982
  __publicField(this, "preventBrowserZoomWheel", (event) => {
36897
- if (event[KEYS52.CTRL_OR_CMD]) {
36983
+ if (event[KEYS53.CTRL_OR_CMD]) {
36898
36984
  event.preventDefault();
36899
36985
  }
36900
36986
  });
@@ -36915,11 +37001,11 @@ var App = class _App extends React41.Component {
36915
37001
  * (via `viewport.translate`).
36916
37002
  */
36917
37003
  __publicField(this, "maybeHandlePageScrollKeyDown", (event) => {
36918
- if (event.key !== KEYS52.PAGE_UP && event.key !== KEYS52.PAGE_DOWN) {
37004
+ if (event.key !== KEYS53.PAGE_UP && event.key !== KEYS53.PAGE_DOWN) {
36919
37005
  return false;
36920
37006
  }
36921
37007
  let offset = (event.shiftKey ? this.state.width : this.state.height) / this.state.zoom.value;
36922
- if (event.key === KEYS52.PAGE_DOWN) {
37008
+ if (event.key === KEYS53.PAGE_DOWN) {
36923
37009
  offset = -offset;
36924
37010
  }
36925
37011
  if (event.shiftKey) {
@@ -36934,7 +37020,7 @@ var App = class _App extends React41.Component {
36934
37020
  return true;
36935
37021
  });
36936
37022
  __publicField(this, "preventBrowserZoomKeyDown", (event) => {
36937
- if (event[KEYS52.CTRL_OR_CMD] && (event.code === CODES11.EQUAL || event.code === CODES11.MINUS || event.code === CODES11.ZERO || event.code === CODES11.NUM_ADD || event.code === CODES11.NUM_SUBTRACT || event.code === CODES11.NUM_ZERO)) {
37023
+ if (event[KEYS53.CTRL_OR_CMD] && (event.code === CODES12.EQUAL || event.code === CODES12.MINUS || event.code === CODES12.ZERO || event.code === CODES12.NUM_ADD || event.code === CODES12.NUM_SUBTRACT || event.code === CODES12.NUM_ZERO)) {
36938
37024
  event.preventDefault();
36939
37025
  }
36940
37026
  });
@@ -37218,7 +37304,7 @@ var App = class _App extends React41.Component {
37218
37304
  elements: restoredElements,
37219
37305
  appState: restoredAppState,
37220
37306
  files: initialData?.files,
37221
- captureUpdate: CaptureUpdateAction39.NEVER
37307
+ captureUpdate: CaptureUpdateAction40.NEVER
37222
37308
  });
37223
37309
  this.clearImageShapeCache();
37224
37310
  this.fonts.loadSceneFonts().then((fontFaces) => {
@@ -38044,7 +38130,7 @@ var App = class _App extends React41.Component {
38044
38130
  });
38045
38131
  }
38046
38132
  if (!isInputLike(event.target)) {
38047
- if ((event.key === KEYS52.ESCAPE || event.key === KEYS52.ENTER) && this.state.croppingElementId) {
38133
+ if ((event.key === KEYS53.ESCAPE || event.key === KEYS53.ENTER) && this.state.croppingElementId) {
38048
38134
  this.finishImageCropping();
38049
38135
  return;
38050
38136
  }
@@ -38052,13 +38138,13 @@ var App = class _App extends React41.Component {
38052
38138
  this.scene.getNonDeletedElementsMap(),
38053
38139
  this.state
38054
38140
  );
38055
- if (selectedElements.length === 1 && isImageElement9(selectedElements[0]) && event.key === KEYS52.ENTER) {
38141
+ if (selectedElements.length === 1 && isImageElement9(selectedElements[0]) && event.key === KEYS53.ENTER) {
38056
38142
  this.startImageCropping(selectedElements[0]);
38057
38143
  return;
38058
38144
  }
38059
- if (event.key === KEYS52.ESCAPE) {
38145
+ if (event.key === KEYS53.ESCAPE) {
38060
38146
  this.updateEditorAtom(convertElementTypePopupAtom, null);
38061
- } else if (event.key === KEYS52.TAB && (document.activeElement === this.excalidrawContainerRef?.current || document.activeElement?.classList.contains(
38147
+ } else if (event.key === KEYS53.TAB && (document.activeElement === this.excalidrawContainerRef?.current || document.activeElement?.classList.contains(
38062
38148
  CLASSES10.CONVERT_ELEMENT_TYPE_POPUP
38063
38149
  ))) {
38064
38150
  event.preventDefault();
@@ -38081,15 +38167,15 @@ var App = class _App extends React41.Component {
38081
38167
  return;
38082
38168
  }
38083
38169
  }
38084
- if (event[KEYS52.CTRL_OR_CMD] && event.key.toLowerCase() === KEYS52.V) {
38170
+ if (event[KEYS53.CTRL_OR_CMD] && event.key.toLowerCase() === KEYS53.V) {
38085
38171
  IS_PLAIN_PASTE = event.shiftKey;
38086
38172
  clearTimeout(IS_PLAIN_PASTE_TIMER);
38087
38173
  IS_PLAIN_PASTE_TIMER = window.setTimeout(() => {
38088
38174
  IS_PLAIN_PASTE = false;
38089
38175
  }, 100);
38090
38176
  }
38091
- if (event[KEYS52.CTRL_OR_CMD] && isWritableElement4(event.target)) {
38092
- if (event.code === CODES11.MINUS || event.code === CODES11.EQUAL) {
38177
+ if (event[KEYS53.CTRL_OR_CMD] && isWritableElement4(event.target)) {
38178
+ if (event.code === CODES12.MINUS || event.code === CODES12.EQUAL) {
38093
38179
  event.preventDefault();
38094
38180
  return;
38095
38181
  }
@@ -38097,17 +38183,17 @@ var App = class _App extends React41.Component {
38097
38183
  if (
38098
38184
  // inside an input
38099
38185
  isWritableElement4(event.target) && // unless pressing escape (finalize action)
38100
- event.key !== KEYS52.ESCAPE || // or unless using arrows (to move between buttons)
38186
+ event.key !== KEYS53.ESCAPE || // or unless using arrows (to move between buttons)
38101
38187
  isArrowKey3(event.key) && isInputLike(event.target)
38102
38188
  ) {
38103
38189
  return;
38104
38190
  }
38105
- if (event.key === KEYS52.QUESTION_MARK) {
38191
+ if (event.key === KEYS53.QUESTION_MARK) {
38106
38192
  this.setState({
38107
38193
  openDialog: { name: "help" }
38108
38194
  });
38109
38195
  return;
38110
- } else if (event.key.toLowerCase() === KEYS52.E && event.shiftKey && event[KEYS52.CTRL_OR_CMD]) {
38196
+ } else if (event.key.toLowerCase() === KEYS53.E && event.shiftKey && event[KEYS53.CTRL_OR_CMD]) {
38111
38197
  event.preventDefault();
38112
38198
  this.setState({ openDialog: { name: "imageExport" } });
38113
38199
  return;
@@ -38119,7 +38205,7 @@ var App = class _App extends React41.Component {
38119
38205
  if (this.state.openDialog?.name === "elementLinkSelector") {
38120
38206
  return;
38121
38207
  }
38122
- if (event.key === KEYS52.ALT) {
38208
+ if (event.key === KEYS53.ALT) {
38123
38209
  if (this.state.activeTool.type === "bucketfill") {
38124
38210
  this.bucketFill.openTemporaryEyeDropper();
38125
38211
  event.preventDefault();
@@ -38134,7 +38220,7 @@ var App = class _App extends React41.Component {
38134
38220
  return;
38135
38221
  }
38136
38222
  const shouldPreventToolSwitching = this.props.viewModeEnabled === true;
38137
- if (!shouldPreventToolSwitching && this.state.viewModeEnabled && event.key === KEYS52.ESCAPE) {
38223
+ if (!shouldPreventToolSwitching && this.state.viewModeEnabled && event.key === KEYS53.ESCAPE) {
38138
38224
  this.setActiveTool({ type: "selection" });
38139
38225
  return;
38140
38226
  }
@@ -38172,7 +38258,7 @@ var App = class _App extends React41.Component {
38172
38258
  }
38173
38259
  event.stopPropagation();
38174
38260
  return;
38175
- } else if (event.key === KEYS52.Q) {
38261
+ } else if (event.key === KEYS53.Q) {
38176
38262
  this.toggleLock("keyboard");
38177
38263
  event.stopPropagation();
38178
38264
  return;
@@ -38181,7 +38267,7 @@ var App = class _App extends React41.Component {
38181
38267
  if (this.state.viewModeEnabled) {
38182
38268
  return;
38183
38269
  }
38184
- if (event[KEYS52.CTRL_OR_CMD] && !event.repeat) {
38270
+ if (event[KEYS53.CTRL_OR_CMD] && !event.repeat) {
38185
38271
  if (getFeatureFlag4("COMPLEX_BINDINGS")) {
38186
38272
  this.resetDelayedBindMode();
38187
38273
  }
@@ -38217,15 +38303,17 @@ var App = class _App extends React41.Component {
38217
38303
  const step = this.getEffectiveGridSize() && (event.shiftKey ? ELEMENT_TRANSLATE_AMOUNT : this.getEffectiveGridSize()) || (event.shiftKey ? ELEMENT_SHIFT_TRANSLATE_AMOUNT : ELEMENT_TRANSLATE_AMOUNT);
38218
38304
  let offsetX = 0;
38219
38305
  let offsetY = 0;
38220
- if (event.key === KEYS52.ARROW_LEFT) {
38306
+ if (event.key === KEYS53.ARROW_LEFT) {
38221
38307
  offsetX = -step;
38222
- } else if (event.key === KEYS52.ARROW_RIGHT) {
38308
+ } else if (event.key === KEYS53.ARROW_RIGHT) {
38223
38309
  offsetX = step;
38224
- } else if (event.key === KEYS52.ARROW_UP) {
38310
+ } else if (event.key === KEYS53.ARROW_UP) {
38225
38311
  offsetY = -step;
38226
- } else if (event.key === KEYS52.ARROW_DOWN) {
38312
+ } else if (event.key === KEYS53.ARROW_DOWN) {
38227
38313
  offsetY = step;
38228
38314
  }
38315
+ offsetX *= getViewpointFlipSign2(this.state.viewpointFlip.horizontal);
38316
+ offsetY *= getViewpointFlipSign2(this.state.viewpointFlip.vertical);
38229
38317
  selectedElements.forEach((element) => {
38230
38318
  this.scene.mutateElement(
38231
38319
  element,
@@ -38241,11 +38329,11 @@ var App = class _App extends React41.Component {
38241
38329
  });
38242
38330
  this.scene.triggerUpdate();
38243
38331
  event.preventDefault();
38244
- } else if (event.key === KEYS52.ENTER) {
38332
+ } else if (event.key === KEYS53.ENTER) {
38245
38333
  const selectedElements = this.scene.getSelectedElements(this.state);
38246
38334
  if (selectedElements.length === 1) {
38247
38335
  const selectedElement = selectedElements[0];
38248
- if (event[KEYS52.CTRL_OR_CMD] || isLineElement9(selectedElement)) {
38336
+ if (event[KEYS53.CTRL_OR_CMD] || isLineElement9(selectedElement)) {
38249
38337
  if (isLinearElement11(selectedElement)) {
38250
38338
  if (!this.state.selectedLinearElement?.isEditing || this.state.selectedLinearElement.elementId !== selectedElement.id) {
38251
38339
  this.store.scheduleCapture();
@@ -38279,31 +38367,31 @@ var App = class _App extends React41.Component {
38279
38367
  }
38280
38368
  }
38281
38369
  }
38282
- if (event.key === KEYS52.SPACE && gesture.pointers.size === 0) {
38370
+ if (event.key === KEYS53.SPACE && gesture.pointers.size === 0) {
38283
38371
  isHoldingSpace = true;
38284
38372
  this.cursor.set(CURSOR_TYPE2.GRAB);
38285
38373
  event.preventDefault();
38286
38374
  }
38287
- if (event.key.toLowerCase() === KEYS52.Z && !event[KEYS52.CTRL_OR_CMD] && !event.altKey && !event.shiftKey) {
38375
+ if (event.key.toLowerCase() === KEYS53.Z && !event[KEYS53.CTRL_OR_CMD] && !event.altKey && !event.shiftKey) {
38288
38376
  isHoldingZ = true;
38289
38377
  this.cursor.set("zoom-in");
38290
38378
  event.preventDefault();
38291
38379
  }
38292
- if ((event.key === KEYS52.G || event.key === KEYS52.S) && !event.altKey && !event[KEYS52.CTRL_OR_CMD]) {
38380
+ if ((event.key === KEYS53.G || event.key === KEYS53.S) && !event.altKey && !event[KEYS53.CTRL_OR_CMD]) {
38293
38381
  const selectedElements = this.scene.getSelectedElements(this.state);
38294
38382
  if (this.state.activeTool.type === "selection" && !selectedElements.length) {
38295
38383
  return;
38296
38384
  }
38297
- if (event.key === KEYS52.G && (hasBackground(this.state.activeTool.type) || selectedElements.some((element) => hasBackground(element.type)))) {
38385
+ if (event.key === KEYS53.G && (hasBackground(this.state.activeTool.type) || selectedElements.some((element) => hasBackground(element.type)))) {
38298
38386
  this.setState({ openPopup: "elementBackground" });
38299
38387
  event.stopPropagation();
38300
38388
  }
38301
- if (event.key === KEYS52.S) {
38389
+ if (event.key === KEYS53.S) {
38302
38390
  this.setState({ openPopup: "elementStroke" });
38303
38391
  event.stopPropagation();
38304
38392
  }
38305
38393
  }
38306
- if (!event[KEYS52.CTRL_OR_CMD] && event.shiftKey && event.key.toLowerCase() === KEYS52.F) {
38394
+ if (!event[KEYS53.CTRL_OR_CMD] && event.shiftKey && event.key.toLowerCase() === KEYS53.F) {
38307
38395
  const selectedElements = this.scene.getSelectedElements(this.state);
38308
38396
  if (this.state.activeTool.type === "selection" && !selectedElements.length) {
38309
38397
  return;
@@ -38319,9 +38407,9 @@ var App = class _App extends React41.Component {
38319
38407
  }
38320
38408
  }
38321
38409
  const lowerCased = event.key.toLocaleLowerCase();
38322
- const isPlainStrokeEyeDropper = lowerCased === KEYS52.I && !event.shiftKey && !event[KEYS52.CTRL_OR_CMD];
38323
- const isPickingStroke = lowerCased === KEYS52.S && event.shiftKey && !event[KEYS52.CTRL_OR_CMD] || isPlainStrokeEyeDropper;
38324
- const isPickingBackground = lowerCased === KEYS52.I && event.shiftKey && !event[KEYS52.CTRL_OR_CMD];
38410
+ const isPlainStrokeEyeDropper = lowerCased === KEYS53.I && !event.shiftKey && !event[KEYS53.CTRL_OR_CMD];
38411
+ const isPickingStroke = lowerCased === KEYS53.S && event.shiftKey && !event[KEYS53.CTRL_OR_CMD] || isPlainStrokeEyeDropper;
38412
+ const isPickingBackground = lowerCased === KEYS53.I && event.shiftKey && !event[KEYS53.CTRL_OR_CMD];
38325
38413
  if (isPickingStroke || isPickingBackground) {
38326
38414
  this.openEyeDropper({
38327
38415
  type: isPickingStroke ? "stroke" : "background",
@@ -38334,7 +38422,7 @@ var App = class _App extends React41.Component {
38334
38422
  if (!this.isInteractionEnabled()) {
38335
38423
  return;
38336
38424
  }
38337
- if (event.key === KEYS52.SPACE) {
38425
+ if (event.key === KEYS53.SPACE) {
38338
38426
  if (this.state.viewModeEnabled && this.state.activeTool.type !== "laser" || this.state.openDialog?.name === "elementLinkSelector") {
38339
38427
  this.cursor.set(CURSOR_TYPE2.GRAB);
38340
38428
  } else if (isSelectionLikeTool(this.state.activeTool.type)) {
@@ -38350,15 +38438,15 @@ var App = class _App extends React41.Component {
38350
38438
  }
38351
38439
  isHoldingSpace = false;
38352
38440
  }
38353
- if (event.key.toLowerCase() === KEYS52.Z) {
38441
+ if (event.key.toLowerCase() === KEYS53.Z) {
38354
38442
  isHoldingZ = false;
38355
38443
  this.cursor.reset();
38356
38444
  }
38357
- if (event.key === KEYS52.ALT) {
38445
+ if (event.key === KEYS53.ALT) {
38358
38446
  this.bucketFill.closeTemporaryEyeDropper();
38359
38447
  maybeHandleArrowPointlikeDrag({ app: this, event });
38360
38448
  }
38361
- if (event.key === KEYS52.ALT && this.state.bindMode === "skip" || !event[KEYS52.CTRL_OR_CMD] && !isBindingEnabled3(this.state)) {
38449
+ if (event.key === KEYS53.ALT && this.state.bindMode === "skip" || !event[KEYS53.CTRL_OR_CMD] && !isBindingEnabled3(this.state)) {
38362
38450
  this.setState({
38363
38451
  bindMode: "orbit"
38364
38452
  });
@@ -38386,7 +38474,7 @@ var App = class _App extends React41.Component {
38386
38474
  }
38387
38475
  }
38388
38476
  }
38389
- if (!event[KEYS52.CTRL_OR_CMD]) {
38477
+ if (!event[KEYS53.CTRL_OR_CMD]) {
38390
38478
  const preferenceEnabled = this.state.bindingPreference === "enabled";
38391
38479
  if (this.state.isBindingEnabled !== preferenceEnabled) {
38392
38480
  flushSync2(() => {
@@ -38833,7 +38921,7 @@ var App = class _App extends React41.Component {
38833
38921
  );
38834
38922
  if (selectedElements.length === 1 && isLinearElement11(selectedElements[0])) {
38835
38923
  const selectedLinearElement = selectedElements[0];
38836
- if ((event[KEYS52.CTRL_OR_CMD] && isSimpleArrow(selectedLinearElement) || isLineElement9(selectedLinearElement)) && (!this.state.selectedLinearElement?.isEditing || this.state.selectedLinearElement.elementId !== selectedLinearElement.id)) {
38924
+ if ((event[KEYS53.CTRL_OR_CMD] && isSimpleArrow(selectedLinearElement) || isLineElement9(selectedLinearElement)) && (!this.state.selectedLinearElement?.isEditing || this.state.selectedLinearElement.elementId !== selectedLinearElement.id)) {
38837
38925
  this.actionManager.executeAction(actionToggleLinearEditor);
38838
38926
  return;
38839
38927
  } else if (this.state.selectedLinearElement && isElbowArrow10(selectedElements[0])) {
@@ -38929,7 +39017,7 @@ var App = class _App extends React41.Component {
38929
39017
  if (!this.state.selectedLinearElement?.isEditing) {
38930
39018
  const container = (
38931
39019
  // skip binding to container on dblclick when holding ctrl
38932
- !event[KEYS52.CTRL_OR_CMD] && this.getTextBindableContainerAtPosition(sceneX, sceneY)
39020
+ !event[KEYS53.CTRL_OR_CMD] && this.getTextBindableContainerAtPosition(sceneX, sceneY)
38933
39021
  );
38934
39022
  if (container) {
38935
39023
  if (
@@ -39633,7 +39721,10 @@ var App = class _App extends React41.Component {
39633
39721
  );
39634
39722
  if (elementWithTransformHandleType && elementWithTransformHandleType.transformHandleType) {
39635
39723
  this.cursor.set(
39636
- getCursorForResizingElement(elementWithTransformHandleType)
39724
+ getViewpointAwareResizeCursor(
39725
+ getCursorForResizingElement(elementWithTransformHandleType),
39726
+ this.state.viewpointFlip
39727
+ )
39637
39728
  );
39638
39729
  return;
39639
39730
  }
@@ -39649,9 +39740,12 @@ var App = class _App extends React41.Component {
39649
39740
  );
39650
39741
  if (transformHandleType) {
39651
39742
  this.cursor.set(
39652
- getCursorForResizingElement({
39653
- transformHandleType
39654
- })
39743
+ getViewpointAwareResizeCursor(
39744
+ getCursorForResizingElement({
39745
+ transformHandleType
39746
+ }),
39747
+ this.state.viewpointFlip
39748
+ )
39655
39749
  );
39656
39750
  return;
39657
39751
  }
@@ -39694,7 +39788,7 @@ var App = class _App extends React41.Component {
39694
39788
  this.cursor.set(
39695
39789
  hoveredArrowTextAnchor ? CURSOR_TYPE2.POINTER : isTextElement18(hitElement) ? CURSOR_TYPE2.TEXT : CURSOR_TYPE2.CROSSHAIR
39696
39790
  );
39697
- } else if (!event[KEYS52.CTRL_OR_CMD] && this.isHittingCommonBoundingBoxOfSelectedElements(
39791
+ } else if (!event[KEYS53.CTRL_OR_CMD] && this.isHittingCommonBoundingBoxOfSelectedElements(
39698
39792
  scenePointer,
39699
39793
  selectedElements
39700
39794
  )) {
@@ -39707,7 +39801,7 @@ var App = class _App extends React41.Component {
39707
39801
  this.cursor.set(CURSOR_TYPE2.AUTO);
39708
39802
  } else if (
39709
39803
  // if using cmd/ctrl, we're not dragging
39710
- !event[KEYS52.CTRL_OR_CMD] && // editing text -> don't show move cursor when hovering over its bbox
39804
+ !event[KEYS53.CTRL_OR_CMD] && // editing text -> don't show move cursor when hovering over its bbox
39711
39805
  hitElement?.id !== this.state.editingTextElement?.id
39712
39806
  ) {
39713
39807
  if ((hitElement || this.isHittingCommonBoundingBoxOfSelectedElements(
@@ -39860,7 +39954,7 @@ var App = class _App extends React41.Component {
39860
39954
  this.state
39861
39955
  )
39862
39956
  },
39863
- captureUpdate: this.state.openDialog?.name === "elementLinkSelector" ? CaptureUpdateAction39.EVENTUALLY : CaptureUpdateAction39.NEVER
39957
+ captureUpdate: this.state.openDialog?.name === "elementLinkSelector" ? CaptureUpdateAction40.EVENTUALLY : CaptureUpdateAction40.NEVER
39864
39958
  });
39865
39959
  return;
39866
39960
  }
@@ -39967,7 +40061,7 @@ var App = class _App extends React41.Component {
39967
40061
  }
39968
40062
  if (this.state.activeTool.type === "lasso") {
39969
40063
  const hitSelectedElement = pointerDownState.hit.element && this.isASelectedElement(pointerDownState.hit.element);
39970
- const shouldForceLassoReselect = event.altKey && event[KEYS52.CTRL_OR_CMD] && !pointerDownState.resize.handleType;
40064
+ const shouldForceLassoReselect = event.altKey && event[KEYS53.CTRL_OR_CMD] && !pointerDownState.resize.handleType;
39971
40065
  const shouldStartLassoSelection = shouldForceLassoReselect || !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements && !pointerDownState.resize.handleType && !hitSelectedElement;
39972
40066
  if (shouldStartLassoSelection) {
39973
40067
  if (!this.lassoTrail.hasCurrentTrail) {
@@ -40219,8 +40313,8 @@ var App = class _App extends React41.Component {
40219
40313
  window.addEventListener(EVENT11.POINTER_UP, enableNextPaste);
40220
40314
  }
40221
40315
  this.viewport.translate({
40222
- scrollX: this.state.scrollX - deltaX / this.state.zoom.value,
40223
- scrollY: this.state.scrollY - deltaY / this.state.zoom.value
40316
+ scrollX: this.state.scrollX - deltaX * getViewpointFlipSign2(this.state.viewpointFlip.horizontal) / this.state.zoom.value,
40317
+ scrollY: this.state.scrollY - deltaY * getViewpointFlipSign2(this.state.viewpointFlip.vertical) / this.state.zoom.value
40224
40318
  });
40225
40319
  });
40226
40320
  const teardown = withBatchedUpdates(
@@ -40288,8 +40382,8 @@ var App = class _App extends React41.Component {
40288
40382
  // 2x multiplier is just a magic number that makes this work correctly
40289
40383
  // on touchscreen devices (note: if we get report that panning is slower/faster
40290
40384
  // than actual movement, consider swapping with devicePixelRatio)
40291
- scrollX: zoomedViewport.scrollX + 2 * deltaX / zoomValue,
40292
- scrollY: zoomedViewport.scrollY + 2 * deltaY / zoomValue,
40385
+ scrollX: zoomedViewport.scrollX + 2 * deltaX * getViewpointFlipSign2(state.viewpointFlip.horizontal) / zoomValue,
40386
+ scrollY: zoomedViewport.scrollY + 2 * deltaY * getViewpointFlipSign2(state.viewpointFlip.vertical) / zoomValue,
40293
40387
  shouldCacheIgnoreZoom: true
40294
40388
  },
40295
40389
  { zoomPreConstrained: true }
@@ -40501,7 +40595,7 @@ var App = class _App extends React41.Component {
40501
40595
  ) : makeNextSelectedElementIds4({}, prevState)
40502
40596
  }));
40503
40597
  } else if (hitElement != null) {
40504
- if (event[KEYS52.CTRL_OR_CMD]) {
40598
+ if (event[KEYS53.CTRL_OR_CMD]) {
40505
40599
  if (event.altKey) {
40506
40600
  if (this.state.openDialog?.name === "elementLinkSelector") {
40507
40601
  this.setOpenDialog(null);
@@ -40729,7 +40823,7 @@ var App = class _App extends React41.Component {
40729
40823
  const [gridX, gridY] = getGridPoint4(
40730
40824
  sceneX,
40731
40825
  sceneY,
40732
- this.lastPointerDownEvent?.[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
40826
+ this.lastPointerDownEvent?.[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
40733
40827
  );
40734
40828
  const element = newIframeElement({
40735
40829
  type: "iframe",
@@ -40759,7 +40853,7 @@ var App = class _App extends React41.Component {
40759
40853
  const [gridX, gridY] = getGridPoint4(
40760
40854
  sceneX,
40761
40855
  sceneY,
40762
- this.lastPointerDownEvent?.[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
40856
+ this.lastPointerDownEvent?.[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
40763
40857
  );
40764
40858
  const embedLink = getEmbedLink2(link);
40765
40859
  if (!embedLink) {
@@ -40800,7 +40894,7 @@ var App = class _App extends React41.Component {
40800
40894
  const [gridX, gridY] = getGridPoint4(
40801
40895
  sceneX,
40802
40896
  sceneY,
40803
- this.lastPointerDownEvent?.[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
40897
+ this.lastPointerDownEvent?.[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
40804
40898
  );
40805
40899
  const topLayerFrame = addToFrameUnderCursor ? this.getTopLayerFrameAtSceneCoords({
40806
40900
  x: gridX,
@@ -40927,7 +41021,7 @@ var App = class _App extends React41.Component {
40927
41021
  const [gridX, gridY] = getGridPoint4(
40928
41022
  pointerDownState.origin.x,
40929
41023
  pointerDownState.origin.y,
40930
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41024
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
40931
41025
  );
40932
41026
  const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
40933
41027
  x: gridX,
@@ -41062,7 +41156,7 @@ var App = class _App extends React41.Component {
41062
41156
  const [gridX, gridY] = getGridPoint4(
41063
41157
  pointerDownState.origin.x,
41064
41158
  pointerDownState.origin.y,
41065
- this.lastPointerDownEvent?.[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41159
+ this.lastPointerDownEvent?.[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41066
41160
  );
41067
41161
  const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
41068
41162
  x: gridX,
@@ -41110,7 +41204,7 @@ var App = class _App extends React41.Component {
41110
41204
  const [gridX, gridY] = getGridPoint4(
41111
41205
  pointerDownState.origin.x,
41112
41206
  pointerDownState.origin.y,
41113
- this.lastPointerDownEvent?.[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41207
+ this.lastPointerDownEvent?.[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41114
41208
  );
41115
41209
  const constructorOpts = {
41116
41210
  x: gridX,
@@ -41437,7 +41531,7 @@ var App = class _App extends React41.Component {
41437
41531
  });
41438
41532
  }
41439
41533
  if (erroredFiles.size || updatedFiles.size) {
41440
- this.store.scheduleAction(CaptureUpdateAction39.NEVER);
41534
+ this.store.scheduleAction(CaptureUpdateAction40.NEVER);
41441
41535
  this.scene.replaceAllElements(
41442
41536
  this.scene.getElementsIncludingDeleted().map((element) => {
41443
41537
  if (isInitializedImageElement5(element)) {
@@ -41583,7 +41677,7 @@ var App = class _App extends React41.Component {
41583
41677
  )
41584
41678
  },
41585
41679
  elements: nextElements,
41586
- captureUpdate: CaptureUpdateAction39.IMMEDIATELY
41680
+ captureUpdate: CaptureUpdateAction40.IMMEDIATELY
41587
41681
  });
41588
41682
  this.setState({}, () => {
41589
41683
  this.actionManager.executeAction(actionFinalize);
@@ -41640,7 +41734,7 @@ var App = class _App extends React41.Component {
41640
41734
  isLoading: false
41641
41735
  },
41642
41736
  replaceFiles: true,
41643
- captureUpdate: CaptureUpdateAction39.IMMEDIATELY
41737
+ captureUpdate: CaptureUpdateAction40.IMMEDIATELY
41644
41738
  });
41645
41739
  return;
41646
41740
  } catch (error) {
@@ -41712,7 +41806,7 @@ var App = class _App extends React41.Component {
41712
41806
  {
41713
41807
  syncInvalidIndices3(elements.concat(ret.elements));
41714
41808
  this.store.scheduleMicroAction({
41715
- action: CaptureUpdateAction39.NEVER,
41809
+ action: CaptureUpdateAction40.NEVER,
41716
41810
  elements,
41717
41811
  appState: void 0
41718
41812
  });
@@ -41725,7 +41819,7 @@ var App = class _App extends React41.Component {
41725
41819
  isLoading: false
41726
41820
  },
41727
41821
  replaceFiles: true,
41728
- captureUpdate: CaptureUpdateAction39.IMMEDIATELY
41822
+ captureUpdate: CaptureUpdateAction40.IMMEDIATELY
41729
41823
  });
41730
41824
  }
41731
41825
  } catch (error) {
@@ -41823,7 +41917,7 @@ var App = class _App extends React41.Component {
41823
41917
  let [gridX, gridY] = getGridPoint4(
41824
41918
  pointerCoords.x,
41825
41919
  pointerCoords.y,
41826
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41920
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41827
41921
  );
41828
41922
  const image = isInitializedImageElement5(newElement9) && this.imageCache.get(newElement9.fileId)?.image;
41829
41923
  const aspectRatio = image && !(image instanceof Promise) ? image.width / image.height : null;
@@ -41890,7 +41984,7 @@ var App = class _App extends React41.Component {
41890
41984
  const [x, y] = getGridPoint4(
41891
41985
  pointerCoords.x - pointerDownState.resize.offset.x,
41892
41986
  pointerCoords.y - pointerDownState.resize.offset.y,
41893
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41987
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41894
41988
  );
41895
41989
  const croppingElement = this.scene.getNonDeletedElementsMap().get(this.state.croppingElementId);
41896
41990
  if (transformHandleType && croppingElement && isImageElement9(croppingElement)) {
@@ -41902,7 +41996,7 @@ var App = class _App extends React41.Component {
41902
41996
  const [gridX, gridY] = getGridPoint4(
41903
41997
  pointerCoords.x,
41904
41998
  pointerCoords.y,
41905
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41999
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41906
42000
  );
41907
42001
  const dragOffset = {
41908
42002
  x: gridX - pointerDownState.originInGrid.x,
@@ -41964,7 +42058,7 @@ var App = class _App extends React41.Component {
41964
42058
  let [resizeX, resizeY] = getGridPoint4(
41965
42059
  pointerCoords.x - pointerDownState.resize.offset.x,
41966
42060
  pointerCoords.y - pointerDownState.resize.offset.y,
41967
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
42061
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41968
42062
  );
41969
42063
  const frameElementsOffsetsMap = /* @__PURE__ */ new Map();
41970
42064
  selectedFrames.forEach((frame) => {
@@ -41983,7 +42077,7 @@ var App = class _App extends React41.Component {
41983
42077
  const [gridX, gridY] = getGridPoint4(
41984
42078
  pointerCoords.x,
41985
42079
  pointerCoords.y,
41986
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
42080
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
41987
42081
  );
41988
42082
  const dragOffset = {
41989
42083
  x: gridX - pointerDownState.originInGrid.x,
@@ -42098,6 +42192,9 @@ var App = class _App extends React41.Component {
42098
42192
  if (this.state.viewModeEnabled) {
42099
42193
  return [
42100
42194
  actionSmartZoom,
42195
+ actionFlipViewpointHorizontal,
42196
+ actionFlipViewpointVertical,
42197
+ CONTEXT_MENU_SEPARATOR,
42101
42198
  actionToggleGridMode,
42102
42199
  actionToggleViewMode,
42103
42200
  actionToggleStats
@@ -42113,6 +42210,10 @@ var App = class _App extends React41.Component {
42113
42210
  actionToggleObjectsSnapMode,
42114
42211
  actionToggleArrowBinding,
42115
42212
  actionToggleMidpointSnapping,
42213
+ CONTEXT_MENU_SEPARATOR,
42214
+ actionFlipViewpointHorizontal,
42215
+ actionFlipViewpointVertical,
42216
+ CONTEXT_MENU_SEPARATOR,
42116
42217
  actionToggleViewMode,
42117
42218
  actionToggleStats
42118
42219
  ];
@@ -42122,6 +42223,9 @@ var App = class _App extends React41.Component {
42122
42223
  ...elementLinkContextMenuItems,
42123
42224
  elementLinkContextMenuItems.length > 0 && CONTEXT_MENU_SEPARATOR,
42124
42225
  actionSmartZoom,
42226
+ actionFlipViewpointHorizontal,
42227
+ actionFlipViewpointVertical,
42228
+ CONTEXT_MENU_SEPARATOR,
42125
42229
  actionCopy,
42126
42230
  imageContextMenuItems.length > 0 && CONTEXT_MENU_SEPARATOR,
42127
42231
  ...imageContextMenuItems
@@ -42137,6 +42241,8 @@ var App = class _App extends React41.Component {
42137
42241
  return [
42138
42242
  CONTEXT_MENU_SEPARATOR,
42139
42243
  actionSmartZoom,
42244
+ actionFlipViewpointHorizontal,
42245
+ actionFlipViewpointVertical,
42140
42246
  CONTEXT_MENU_SEPARATOR,
42141
42247
  actionCut,
42142
42248
  actionCopy,
@@ -42184,7 +42290,7 @@ var App = class _App extends React41.Component {
42184
42290
  if (!(event.target instanceof HTMLCanvasElement || event.target instanceof HTMLTextAreaElement || event.target instanceof HTMLIFrameElement || event.target instanceof HTMLElement && (event.target.classList.contains(CLASSES10.FRAME_NAME) || event.target.classList.contains(
42185
42291
  "excalidraw-eye-dropper-backdrop"
42186
42292
  )))) {
42187
- if (event[KEYS52.CTRL_OR_CMD]) {
42293
+ if (event[KEYS53.CTRL_OR_CMD]) {
42188
42294
  event.preventDefault();
42189
42295
  }
42190
42296
  return;
@@ -42230,15 +42336,15 @@ var App = class _App extends React41.Component {
42230
42336
  return;
42231
42337
  }
42232
42338
  if (event.shiftKey) {
42233
- this.viewport.translate(({ zoom, scrollX }) => ({
42339
+ this.viewport.translate(({ zoom, scrollX, viewpointFlip }) => ({
42234
42340
  // on Mac, shift+wheel tends to result in deltaX
42235
- scrollX: scrollX - (deltaY || deltaX) / zoom.value
42341
+ scrollX: scrollX - (deltaY || deltaX) * getViewpointFlipSign2(viewpointFlip.horizontal) / zoom.value
42236
42342
  }));
42237
42343
  return;
42238
42344
  }
42239
- this.viewport.translate(({ zoom, scrollX, scrollY }) => ({
42240
- scrollX: scrollX - deltaX / zoom.value,
42241
- scrollY: scrollY - deltaY / zoom.value
42345
+ this.viewport.translate(({ zoom, scrollX, scrollY, viewpointFlip }) => ({
42346
+ scrollX: scrollX - deltaX * getViewpointFlipSign2(viewpointFlip.horizontal) / zoom.value,
42347
+ scrollY: scrollY - deltaY * getViewpointFlipSign2(viewpointFlip.vertical) / zoom.value
42242
42348
  }));
42243
42349
  }
42244
42350
  ));
@@ -42945,7 +43051,7 @@ var App = class _App extends React41.Component {
42945
43051
  "is-hovered": isHovered
42946
43052
  }),
42947
43053
  style: {
42948
- transform: isVisible ? `translate(${x - this.state.offsetLeft}px, ${y - this.state.offsetTop}px) scale(${scale})` : "none",
43054
+ transform: isVisible ? `translate(${x - this.state.offsetLeft}px, ${y - this.state.offsetTop}px) scale(${scale * getViewpointFlipSign2(this.state.viewpointFlip.horizontal)}, ${scale * getViewpointFlipSign2(this.state.viewpointFlip.vertical)})` : "none",
42949
43055
  display: isVisible ? "block" : "none",
42950
43056
  opacity: getRenderOpacity(
42951
43057
  el,
@@ -44416,12 +44522,12 @@ var App = class _App extends React41.Component {
44416
44522
  const isElbowArrowOnly = selectedElements.findIndex(isElbowArrow10) === 0;
44417
44523
  return {
44418
44524
  origin,
44419
- withCmdOrCtrl: event[KEYS52.CTRL_OR_CMD],
44525
+ withCmdOrCtrl: event[KEYS53.CTRL_OR_CMD],
44420
44526
  originInGrid: tupleToCoors(
44421
44527
  getGridPoint4(
44422
44528
  origin.x,
44423
44529
  origin.y,
44424
- event[KEYS52.CTRL_OR_CMD] || isElbowArrowOnly ? null : this.getEffectiveGridSize()
44530
+ event[KEYS53.CTRL_OR_CMD] || isElbowArrowOnly ? null : this.getEffectiveGridSize()
44425
44531
  )
44426
44532
  ),
44427
44533
  scrollbars: isOverScrollBars(
@@ -44569,7 +44675,7 @@ var App = class _App extends React41.Component {
44569
44675
  }
44570
44676
  onKeyUpFromPointerDownHandler(pointerDownState) {
44571
44677
  return withBatchedUpdates((event) => {
44572
- event.key === KEYS52.ALT && event.preventDefault();
44678
+ event.key === KEYS53.ALT && event.preventDefault();
44573
44679
  if (this.maybeHandleResize(pointerDownState, event)) {
44574
44680
  return;
44575
44681
  }
@@ -44591,7 +44697,7 @@ var App = class _App extends React41.Component {
44591
44697
  const [gridX2, gridY2] = getGridPoint4(
44592
44698
  pointerCoords.x,
44593
44699
  pointerCoords.y,
44594
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
44700
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
44595
44701
  );
44596
44702
  let index = this.state.selectedLinearElement.initialState.segmentMidpoint.index;
44597
44703
  if (index < 0) {
@@ -44659,7 +44765,7 @@ var App = class _App extends React41.Component {
44659
44765
  const [gridX, gridY] = getGridPoint4(
44660
44766
  pointerCoords.x,
44661
44767
  pointerCoords.y,
44662
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
44768
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
44663
44769
  );
44664
44770
  if (pointerDownState.resize.isResizing) {
44665
44771
  pointerDownState.lastCoords.x = pointerCoords.x;
@@ -44707,7 +44813,7 @@ var App = class _App extends React41.Component {
44707
44813
  this.state.selectedLinearElement,
44708
44814
  pointerCoords,
44709
44815
  this,
44710
- !event[KEYS52.CTRL_OR_CMD],
44816
+ !event[KEYS53.CTRL_OR_CMD],
44711
44817
  this.scene
44712
44818
  );
44713
44819
  if (!ret) {
@@ -44904,7 +45010,7 @@ var App = class _App extends React41.Component {
44904
45010
  dragOffset,
44905
45011
  this.scene,
44906
45012
  snapOffset,
44907
- event[KEYS52.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
45013
+ event[KEYS53.CTRL_OR_CMD] ? null : this.getEffectiveGridSize()
44908
45014
  );
44909
45015
  }
44910
45016
  this.setState({
@@ -45534,7 +45640,7 @@ var App = class _App extends React41.Component {
45534
45640
  appState: {
45535
45641
  newElement: null
45536
45642
  },
45537
- captureUpdate: CaptureUpdateAction39.NEVER
45643
+ captureUpdate: CaptureUpdateAction40.NEVER
45538
45644
  });
45539
45645
  return;
45540
45646
  }
@@ -45665,7 +45771,7 @@ var App = class _App extends React41.Component {
45665
45771
  if (resizingElement && isInvisiblySmallElement4(resizingElement)) {
45666
45772
  this.updateScene({
45667
45773
  elements: this.scene.getElementsIncludingDeleted().filter((el) => el.id !== resizingElement.id),
45668
- captureUpdate: CaptureUpdateAction39.NEVER
45774
+ captureUpdate: CaptureUpdateAction40.NEVER
45669
45775
  });
45670
45776
  }
45671
45777
  if (pointerDownState.resize.isResizing) {
@@ -45888,7 +45994,7 @@ var App = class _App extends React41.Component {
45888
45994
  return;
45889
45995
  }
45890
45996
  const selectedTextEditingContainer = this.getSelectedTextEditingContainerAtPosition(hitElement, sceneCoords);
45891
- if (activeTool.type === this.state.preferredSelectionTool.type && !this.state.editingTextElement && !pointerDownState.drag.hasOccurred && !pointerDownState.hit.wasAddedToSelection && !childEvent.shiftKey && !childEvent[KEYS52.CTRL_OR_CMD] && !childEvent.altKey && childEvent.pointerType !== "touch" && hitElement && (isTextElement18(hitElement) && this.state.selectedElementIds[hitElement.id] && this.scene.getSelectedElements(this.state).length === 1 || selectedTextEditingContainer)) {
45997
+ if (activeTool.type === this.state.preferredSelectionTool.type && !this.state.editingTextElement && !pointerDownState.drag.hasOccurred && !pointerDownState.hit.wasAddedToSelection && !childEvent.shiftKey && !childEvent[KEYS53.CTRL_OR_CMD] && !childEvent.altKey && childEvent.pointerType !== "touch" && hitElement && (isTextElement18(hitElement) && this.state.selectedElementIds[hitElement.id] && this.scene.getSelectedElements(this.state).length === 1 || selectedTextEditingContainer)) {
45892
45998
  this.startTextEditing({
45893
45999
  sceneX: sceneCoords.x,
45894
46000
  sceneY: sceneCoords.y,
@@ -46535,7 +46641,7 @@ import {
46535
46641
  newElementWith as newElementWith12,
46536
46642
  bumpVersion as bumpVersion4
46537
46643
  } from "@excalidraw/element";
46538
- import { CaptureUpdateAction as CaptureUpdateAction40 } from "@excalidraw/element";
46644
+ import { CaptureUpdateAction as CaptureUpdateAction41 } from "@excalidraw/element";
46539
46645
  import {
46540
46646
  getCommonBounds as getCommonBounds15,
46541
46647
  getVisibleSceneBounds as getVisibleSceneBounds2,
@@ -46796,7 +46902,7 @@ function useExcalidrawStateValue(selector) {
46796
46902
  }
46797
46903
  export {
46798
46904
  Button,
46799
- CaptureUpdateAction40 as CaptureUpdateAction,
46905
+ CaptureUpdateAction41 as CaptureUpdateAction,
46800
46906
  DEFAULT_LASER_COLOR2 as DEFAULT_LASER_COLOR,
46801
46907
  DEFAULT_OVERSCROLL,
46802
46908
  DefaultSidebar,