@nous-excalidraw/excalidraw 0.18.9-beta.2 → 0.18.9-beta.21

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 (94) hide show
  1. package/dist/dev/{chunk-DSYRTCAK.js → chunk-6PNL5SR6.js} +34 -14
  2. package/dist/dev/chunk-6PNL5SR6.js.map +7 -0
  3. package/dist/dev/{chunk-CYLA22NC.js → chunk-FGNDYJ2B.js} +2 -2
  4. package/dist/dev/{chunk-CYLA22NC.js.map → chunk-FGNDYJ2B.js.map} +1 -1
  5. package/dist/dev/{chunk-4JOINNOK.js → chunk-IXBA2ET3.js} +3 -1
  6. package/dist/dev/chunk-IXBA2ET3.js.map +7 -0
  7. package/dist/dev/components/TTDDialog/{CodeMirrorEditor-T4CL43BJ.js → CodeMirrorEditor-LUWBT76B.js} +2 -2
  8. package/dist/dev/data/{image-OB55CB4R.js → image-5IO6LC6F.js} +3 -3
  9. package/dist/dev/index.css +2 -2
  10. package/dist/dev/index.css.map +1 -1
  11. package/dist/dev/index.js +1598 -1039
  12. package/dist/dev/index.js.map +4 -4
  13. package/dist/dev/locales/{en-WD25OMHJ.js → en-FKZ7NP7W.js} +2 -2
  14. package/dist/dev/locales/{zh-CN-SZ37453H.js → zh-CN-MQID2QWX.js} +3 -1
  15. package/dist/dev/locales/zh-CN-MQID2QWX.js.map +7 -0
  16. package/dist/dev/subset-shared.chunk.js +1 -1
  17. package/dist/dev/subset-worker.chunk.js +1 -1
  18. package/dist/prod/{chunk-LOOWOR4L.js → chunk-KGPK36EJ.js} +1 -1
  19. package/dist/prod/{chunk-CR4SD7AI.js → chunk-TFET7NMD.js} +1 -1
  20. package/dist/prod/chunk-YAGSAM37.js +4 -0
  21. package/dist/prod/components/TTDDialog/{CodeMirrorEditor-KIQDCIKP.js → CodeMirrorEditor-QL4RYZUZ.js} +1 -1
  22. package/dist/prod/data/image-LRQMDLTI.js +1 -0
  23. package/dist/prod/index.css +1 -1
  24. package/dist/prod/index.js +41 -36
  25. package/dist/prod/locales/{en-CMP6EMR6.js → en-QIAUJ35X.js} +1 -1
  26. package/dist/prod/locales/{zh-CN-MVX3E32U.js → zh-CN-3F3C6RA5.js} +1 -1
  27. package/dist/prod/subset-shared.chunk.js +1 -1
  28. package/dist/prod/subset-worker.chunk.js +1 -1
  29. package/dist/types/common/src/constants.d.ts +12 -20
  30. package/dist/types/common/src/fontSize.d.ts +27 -0
  31. package/dist/types/common/src/index.d.ts +2 -0
  32. package/dist/types/common/src/strokeWidth.d.ts +68 -0
  33. package/dist/types/common/src/zoomDisplay.d.ts +3 -0
  34. package/dist/types/common/src/zoomStep.d.ts +15 -0
  35. package/dist/types/element/src/Scene.d.ts +1 -1
  36. package/dist/types/element/src/bounds.d.ts +6 -1
  37. package/dist/types/element/src/comparisons.d.ts +5 -5
  38. package/dist/types/element/src/frame.d.ts +2 -5
  39. package/dist/types/element/src/index.d.ts +1 -0
  40. package/dist/types/element/src/renderElement.d.ts +1 -0
  41. package/dist/types/element/src/resizeElements.d.ts +1 -2
  42. package/dist/types/element/src/selection.d.ts +1 -1
  43. package/dist/types/element/src/shape.d.ts +5 -3
  44. package/dist/types/element/src/strokeWidth.d.ts +11 -0
  45. package/dist/types/element/src/typeChecks.d.ts +3 -1
  46. package/dist/types/element/src/types.d.ts +8 -5
  47. package/dist/types/element/src/utils.d.ts +3 -1
  48. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +3 -0
  49. package/dist/types/excalidraw/actions/actionBoundText.d.ts +2 -0
  50. package/dist/types/excalidraw/actions/actionCanvas.d.ts +59 -31
  51. package/dist/types/excalidraw/actions/actionClipboard.d.ts +2 -0
  52. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +1 -0
  53. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +3 -0
  54. package/dist/types/excalidraw/actions/actionDeselect.d.ts +1 -0
  55. package/dist/types/excalidraw/actions/actionElementLink.d.ts +1 -0
  56. package/dist/types/excalidraw/actions/actionElementLock.d.ts +2 -0
  57. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +1 -0
  58. package/dist/types/excalidraw/actions/actionExport.d.ts +8 -6
  59. package/dist/types/excalidraw/actions/actionFrame.d.ts +38 -0
  60. package/dist/types/excalidraw/actions/actionGroup.d.ts +2 -0
  61. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +35 -0
  62. package/dist/types/excalidraw/actions/actionLink.d.ts +1 -0
  63. package/dist/types/excalidraw/actions/actionMenu.d.ts +1 -0
  64. package/dist/types/excalidraw/actions/actionProperties.d.ts +2 -0
  65. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +1 -0
  66. package/dist/types/excalidraw/actions/actionStyles.d.ts +1 -0
  67. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +1 -0
  68. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +1 -0
  69. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +1 -0
  70. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +1 -0
  71. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +1 -0
  72. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +1 -0
  73. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +1 -0
  74. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +1 -0
  75. package/dist/types/excalidraw/appState.d.ts +5 -5
  76. package/dist/types/excalidraw/components/App.d.ts +28 -3
  77. package/dist/types/excalidraw/components/icons.d.ts +1 -0
  78. package/dist/types/excalidraw/components/shapes.d.ts +22 -1
  79. package/dist/types/excalidraw/data/blob.d.ts +14 -12
  80. package/dist/types/excalidraw/data/json.d.ts +7 -6
  81. package/dist/types/excalidraw/scene/types.d.ts +7 -0
  82. package/dist/types/excalidraw/scene/zoom.d.ts +2 -0
  83. package/dist/types/excalidraw/snapping.d.ts +1 -1
  84. package/dist/types/excalidraw/types.d.ts +7 -2
  85. package/dist/types/utils/src/shape.d.ts +2 -2
  86. package/package.json +4 -4
  87. package/dist/dev/chunk-4JOINNOK.js.map +0 -7
  88. package/dist/dev/chunk-DSYRTCAK.js.map +0 -7
  89. package/dist/dev/locales/zh-CN-SZ37453H.js.map +0 -7
  90. package/dist/prod/chunk-HFHOWOFT.js +0 -4
  91. package/dist/prod/data/image-5LSIY7YB.js +0 -1
  92. /package/dist/dev/components/TTDDialog/{CodeMirrorEditor-T4CL43BJ.js.map → CodeMirrorEditor-LUWBT76B.js.map} +0 -0
  93. /package/dist/dev/data/{image-OB55CB4R.js.map → image-5IO6LC6F.js.map} +0 -0
  94. /package/dist/dev/locales/{en-WD25OMHJ.js.map → en-FKZ7NP7W.js.map} +0 -0
package/dist/dev/index.js CHANGED
@@ -65,13 +65,13 @@ import {
65
65
  serializeAsJSON,
66
66
  serializeLibraryAsJSON,
67
67
  strokeRectWithRotation_simple
68
- } from "./chunk-DSYRTCAK.js";
68
+ } from "./chunk-6PNL5SR6.js";
69
69
  import {
70
70
  define_import_meta_env_default
71
- } from "./chunk-CYLA22NC.js";
71
+ } from "./chunk-FGNDYJ2B.js";
72
72
  import {
73
73
  en_default
74
- } from "./chunk-4JOINNOK.js";
74
+ } from "./chunk-IXBA2ET3.js";
75
75
  import {
76
76
  percentages_default
77
77
  } from "./chunk-URPEKBQ3.js";
@@ -85,7 +85,7 @@ import {
85
85
  import React48, {
86
86
  useCallback as useCallback21,
87
87
  useContext as useContext4,
88
- useEffect as useEffect51,
88
+ useEffect as useEffect50,
89
89
  useRef as useRef46,
90
90
  useState as useState44
91
91
  } from "react";
@@ -119,6 +119,7 @@ import {
119
119
  KEYS as KEYS55,
120
120
  APP_NAME as APP_NAME2,
121
121
  CURSOR_TYPE as CURSOR_TYPE4,
122
+ DEFAULT_TRANSFORM_HANDLE_SPACING as DEFAULT_TRANSFORM_HANDLE_SPACING3,
122
123
  DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT,
123
124
  DEFAULT_VERTICAL_ALIGN,
124
125
  DRAGGING_THRESHOLD as DRAGGING_THRESHOLD3,
@@ -143,6 +144,12 @@ import {
143
144
  YOUTUBE_STATES,
144
145
  getInteractiveZoomStep as getInteractiveZoomStep2,
145
146
  INITIAL_CANVAS_ZOOM,
147
+ scaleFontSizeForZoomChange,
148
+ normalizeSceneFontSizeForZoom,
149
+ scaleStrokeWidthForZoomChange as scaleStrokeWidthForZoomChange3,
150
+ getDisplaySceneStrokeWidth as getDisplaySceneStrokeWidth3,
151
+ STROKE_WIDTH_CUSTOM_DATA_KEY as STROKE_WIDTH_CUSTOM_DATA_KEY4,
152
+ getDefaultSceneFontSizeForZoom as getDefaultSceneFontSizeForZoom3,
146
153
  POINTER_EVENTS,
147
154
  TOOL_TYPE as TOOL_TYPE3,
148
155
  supportsResizeObserver as supportsResizeObserver2,
@@ -168,7 +175,7 @@ import {
168
175
  wrapEvent as wrapEvent2,
169
176
  updateObject as updateObject2,
170
177
  updateActiveTool as updateActiveTool8,
171
- isTransparent as isTransparent6,
178
+ isTransparent as isTransparent7,
172
179
  easeToValuesRAF,
173
180
  muteFSAbortError as muteFSAbortError2,
174
181
  isTestEnv as isTestEnv5,
@@ -204,7 +211,6 @@ import {
204
211
  import {
205
212
  getObservedAppState,
206
213
  getCommonBounds as getCommonBounds11,
207
- getCommonSelectionBounds as getCommonSelectionBounds2,
208
214
  getElementAbsoluteCoords as getElementAbsoluteCoords9,
209
215
  bindOrUnbindBindingElements as bindOrUnbindBindingElements2,
210
216
  fixBindingsAfterDeletion as fixBindingsAfterDeletion2,
@@ -235,6 +241,7 @@ import {
235
241
  isHoverNativeOutlineShapeElement as isHoverNativeOutlineShapeElement2,
236
242
  isImageElement as isImageElement9,
237
243
  isEmbeddableElement as isEmbeddableElement5,
244
+ shouldForceMaintainAspectRatio as shouldForceMaintainAspectRatio2,
238
245
  isInitializedImageElement as isInitializedImageElement3,
239
246
  isLinearElement as isLinearElement12,
240
247
  isLinearElementType as isLinearElementType2,
@@ -345,7 +352,8 @@ import {
345
352
  handleFocusPointPointerUp,
346
353
  maybeHandleArrowPointlikeDrag,
347
354
  getUncroppedWidthAndHeight as getUncroppedWidthAndHeight4,
348
- getActiveTextElement as getActiveTextElement2
355
+ getActiveTextElement as getActiveTextElement2,
356
+ syncElementsStrokeWidthForZoom as syncElementsStrokeWidthForZoom2
349
357
  } from "@nous-excalidraw/element";
350
358
 
351
359
  // actions/actionDeleteSelected.tsx
@@ -398,7 +406,7 @@ var globImport_locales_json = __glob({
398
406
  "./locales/de-CH.json": () => import("./locales/de-CH-GCXOD4LK.js"),
399
407
  "./locales/de-DE.json": () => import("./locales/de-DE-CGDBECYD.js"),
400
408
  "./locales/el-GR.json": () => import("./locales/el-GR-G5QZC24A.js"),
401
- "./locales/en.json": () => import("./locales/en-WD25OMHJ.js"),
409
+ "./locales/en.json": () => import("./locales/en-FKZ7NP7W.js"),
402
410
  "./locales/es-ES.json": () => import("./locales/es-ES-UMEOH76W.js"),
403
411
  "./locales/eu-ES.json": () => import("./locales/eu-ES-IWRZXJC5.js"),
404
412
  "./locales/fa-IR.json": () => import("./locales/fa-IR-QOYVIIJA.js"),
@@ -442,7 +450,7 @@ var globImport_locales_json = __glob({
442
450
  "./locales/uk-UA.json": () => import("./locales/uk-UA-XYAFHHJW.js"),
443
451
  "./locales/uz-UZ.json": () => import("./locales/uz-UZ-LF3CBRYE.js"),
444
452
  "./locales/vi-VN.json": () => import("./locales/vi-VN-WDPZEUOJ.js"),
445
- "./locales/zh-CN.json": () => import("./locales/zh-CN-SZ37453H.js"),
453
+ "./locales/zh-CN.json": () => import("./locales/zh-CN-MQID2QWX.js"),
446
454
  "./locales/zh-HK.json": () => import("./locales/zh-HK-QDQ5QNBC.js"),
447
455
  "./locales/zh-TW.json": () => import("./locales/zh-TW-CYU6GFBV.js")
448
456
  });
@@ -901,6 +909,13 @@ var DiamondIcon = createIcon(
901
909
  ] }),
902
910
  tablerIconProps
903
911
  );
912
+ var TriangleIcon = createIcon(
913
+ /* @__PURE__ */ jsxs("g", { strokeWidth: "1.5", children: [
914
+ /* @__PURE__ */ jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
915
+ /* @__PURE__ */ jsx("path", { d: "M12 4l8 16h-16z" })
916
+ ] }),
917
+ tablerIconProps
918
+ );
904
919
  var EllipseIcon = createIcon(
905
920
  /* @__PURE__ */ jsxs("g", { strokeWidth: "1.5", children: [
906
921
  /* @__PURE__ */ jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
@@ -3671,10 +3686,11 @@ import {
3671
3686
  DEFAULT_ELEMENT_STROKE_PICKS as DEFAULT_ELEMENT_STROKE_PICKS2,
3672
3687
  ARROW_TYPE,
3673
3688
  DEFAULT_FONT_FAMILY,
3674
- DEFAULT_FONT_SIZE,
3675
3689
  FONT_FAMILY as FONT_FAMILY3,
3676
3690
  ROUNDNESS,
3677
- STROKE_WIDTH,
3691
+ STROKE_WIDTH_CUSTOM_DATA_KEY,
3692
+ getStrokeWidthPresetsForZoom,
3693
+ getFontSizePresetsForZoom,
3678
3694
  VERTICAL_ALIGN,
3679
3695
  KEYS as KEYS11,
3680
3696
  randomInteger,
@@ -3683,8 +3699,7 @@ import {
3683
3699
  getLineHeight,
3684
3700
  isTransparent,
3685
3701
  reduceToCommonValue,
3686
- invariant,
3687
- FONT_SIZES
3702
+ invariant
3688
3703
  } from "@nous-excalidraw/common";
3689
3704
  import { canBecomePolygon, getNonDeletedElements as getNonDeletedElements4 } from "@nous-excalidraw/element";
3690
3705
  import {
@@ -6612,50 +6627,63 @@ var actionChangeStrokeWidth = register({
6612
6627
  elements,
6613
6628
  appState,
6614
6629
  (el) => newElementWith2(el, {
6615
- strokeWidth: value
6630
+ strokeWidth: value,
6631
+ customData: {
6632
+ ...el.customData,
6633
+ [STROKE_WIDTH_CUSTOM_DATA_KEY]: true
6634
+ }
6616
6635
  })
6617
6636
  ),
6618
- appState: { ...appState, currentItemStrokeWidth: value },
6637
+ appState: {
6638
+ ...appState,
6639
+ currentItemStrokeWidth: value,
6640
+ currentItemStrokeWidthCustom: true
6641
+ },
6619
6642
  captureUpdate: CaptureUpdateAction5.IMMEDIATELY
6620
6643
  };
6621
6644
  },
6622
- PanelComponent: ({ elements, appState, updateData, app, data }) => /* @__PURE__ */ jsxs20("fieldset", { children: [
6623
- /* @__PURE__ */ jsx34("legend", { children: t("labels.strokeWidth") }),
6624
- /* @__PURE__ */ jsx34("div", { className: "buttonList", children: /* @__PURE__ */ jsx34(
6625
- RadioSelection,
6626
- {
6627
- group: "stroke-width",
6628
- options: [
6629
- {
6630
- value: STROKE_WIDTH.thin,
6631
- text: t("labels.thin"),
6632
- icon: StrokeWidthBaseIcon,
6633
- testId: "strokeWidth-thin"
6634
- },
6635
- {
6636
- value: STROKE_WIDTH.bold,
6637
- text: t("labels.bold"),
6638
- icon: StrokeWidthBoldIcon,
6639
- testId: "strokeWidth-bold"
6640
- },
6641
- {
6642
- value: STROKE_WIDTH.extraBold,
6643
- text: t("labels.extraBold"),
6644
- icon: StrokeWidthExtraBoldIcon,
6645
- testId: "strokeWidth-extraBold"
6646
- }
6647
- ],
6648
- value: getFormValue(
6649
- elements,
6650
- app,
6651
- (element) => element.strokeWidth,
6652
- (element) => element.hasOwnProperty("strokeWidth"),
6653
- (hasSelection) => hasSelection ? null : appState.currentItemStrokeWidth
6654
- ),
6655
- onChange: (value) => updateData(value)
6656
- }
6657
- ) })
6658
- ] })
6645
+ PanelComponent: ({ elements, appState, updateData, app, data }) => {
6646
+ const strokeWidthPresets = getStrokeWidthPresetsForZoom(
6647
+ appState.zoom.value
6648
+ );
6649
+ return /* @__PURE__ */ jsxs20("fieldset", { children: [
6650
+ /* @__PURE__ */ jsx34("legend", { children: t("labels.strokeWidth") }),
6651
+ /* @__PURE__ */ jsx34("div", { className: "buttonList", children: /* @__PURE__ */ jsx34(
6652
+ RadioSelection,
6653
+ {
6654
+ group: "stroke-width",
6655
+ options: [
6656
+ {
6657
+ value: strokeWidthPresets.thin,
6658
+ text: t("labels.thin"),
6659
+ icon: StrokeWidthBaseIcon,
6660
+ testId: "strokeWidth-thin"
6661
+ },
6662
+ {
6663
+ value: strokeWidthPresets.bold,
6664
+ text: t("labels.bold"),
6665
+ icon: StrokeWidthBoldIcon,
6666
+ testId: "strokeWidth-bold"
6667
+ },
6668
+ {
6669
+ value: strokeWidthPresets.extraBold,
6670
+ text: t("labels.extraBold"),
6671
+ icon: StrokeWidthExtraBoldIcon,
6672
+ testId: "strokeWidth-extraBold"
6673
+ }
6674
+ ],
6675
+ value: getFormValue(
6676
+ elements,
6677
+ app,
6678
+ (element) => element.strokeWidth,
6679
+ (element) => element.hasOwnProperty("strokeWidth"),
6680
+ (hasSelection) => hasSelection ? null : appState.currentItemStrokeWidth
6681
+ ),
6682
+ onChange: (value) => updateData(value)
6683
+ }
6684
+ ) })
6685
+ ] });
6686
+ }
6659
6687
  });
6660
6688
  var actionChangeSloppiness = register({
6661
6689
  name: "changeSloppiness",
@@ -6822,6 +6850,7 @@ var actionChangeFontSize = register(
6822
6850
  },
6823
6851
  PanelComponent: ({ elements, appState, updateData, app, data }) => {
6824
6852
  const { isCompact } = getStylesPanelInfo(app);
6853
+ const fontSizePresets = getFontSizePresetsForZoom(appState.zoom.value);
6825
6854
  return /* @__PURE__ */ jsxs20("fieldset", { children: [
6826
6855
  /* @__PURE__ */ jsx34("legend", { children: t("labels.fontSize") }),
6827
6856
  /* @__PURE__ */ jsx34("div", { className: "buttonList", children: /* @__PURE__ */ jsx34(
@@ -6830,25 +6859,25 @@ var actionChangeFontSize = register(
6830
6859
  group: "font-size",
6831
6860
  options: [
6832
6861
  {
6833
- value: FONT_SIZES.sm,
6862
+ value: fontSizePresets.sm,
6834
6863
  text: t("labels.small"),
6835
6864
  icon: FontSizeSmallIcon,
6836
6865
  testId: "fontSize-small"
6837
6866
  },
6838
6867
  {
6839
- value: FONT_SIZES.md,
6868
+ value: fontSizePresets.md,
6840
6869
  text: t("labels.medium"),
6841
6870
  icon: FontSizeMediumIcon,
6842
6871
  testId: "fontSize-medium"
6843
6872
  },
6844
6873
  {
6845
- value: FONT_SIZES.lg,
6874
+ value: fontSizePresets.lg,
6846
6875
  text: t("labels.large"),
6847
6876
  icon: FontSizeLargeIcon,
6848
6877
  testId: "fontSize-large"
6849
6878
  },
6850
6879
  {
6851
- value: FONT_SIZES.xl,
6880
+ value: fontSizePresets.xl,
6852
6881
  text: t("labels.veryLarge"),
6853
6882
  icon: FontSizeExtraLargeIcon,
6854
6883
  testId: "fontSize-veryLarge"
@@ -6874,7 +6903,7 @@ var actionChangeFontSize = register(
6874
6903
  element,
6875
6904
  app.scene.getNonDeletedElementsMap()
6876
6905
  ) !== null,
6877
- (hasSelection) => hasSelection ? null : appState.currentItemFontSize || DEFAULT_FONT_SIZE
6906
+ (hasSelection) => hasSelection ? null : appState.currentItemFontSize || fontSizePresets.md
6878
6907
  ),
6879
6908
  onChange: (value) => {
6880
6909
  withCaretPositionPreservation(
@@ -7882,11 +7911,13 @@ import {
7882
7911
  ZOOM_STEP,
7883
7912
  getInteractiveZoomStep,
7884
7913
  getDisplayedZoomValue,
7914
+ getDefaultSceneFontSizeForZoom as getDefaultSceneFontSizeForZoom2,
7915
+ scaleStrokeWidthForZoomChange as scaleStrokeWidthForZoomChange2,
7885
7916
  updateActiveTool as updateActiveTool2,
7886
7917
  CODES as CODES2,
7887
7918
  KEYS as KEYS12
7888
7919
  } from "@nous-excalidraw/common";
7889
- import { getNonDeletedElements as getNonDeletedElements5 } from "@nous-excalidraw/element";
7920
+ import { getNonDeletedElements as getNonDeletedElements5, syncElementsStrokeWidthForZoom } from "@nous-excalidraw/element";
7890
7921
  import { newElementWith as newElementWith3 } from "@nous-excalidraw/element";
7891
7922
  import { getCommonBounds } from "@nous-excalidraw/element";
7892
7923
  import { CaptureUpdateAction as CaptureUpdateAction6 } from "@nous-excalidraw/element";
@@ -8048,6 +8079,10 @@ var setCursorForShape = (interactiveCanvas, appState) => {
8048
8079
  };
8049
8080
 
8050
8081
  // scene/zoom.ts
8082
+ import {
8083
+ getDefaultSceneFontSizeForZoom,
8084
+ scaleStrokeWidthForZoomChange
8085
+ } from "@nous-excalidraw/common";
8051
8086
  var getStateForZoom = ({
8052
8087
  viewportX,
8053
8088
  viewportY,
@@ -8065,7 +8100,14 @@ var getStateForZoom = ({
8065
8100
  scrollY: baseScrollY + zoomOffsetScrollY,
8066
8101
  zoom: {
8067
8102
  value: nextZoom
8068
- }
8103
+ },
8104
+ currentItemStrokeWidth: scaleStrokeWidthForZoomChange(
8105
+ appState.currentItemStrokeWidth,
8106
+ currentZoom,
8107
+ nextZoom,
8108
+ appState.currentItemStrokeWidthCustom
8109
+ ),
8110
+ currentItemFontSize: getDefaultSceneFontSizeForZoom(nextZoom)
8069
8111
  };
8070
8112
  };
8071
8113
 
@@ -8143,21 +8185,27 @@ var actionZoomIn = register({
8143
8185
  viewMode: true,
8144
8186
  icon: ZoomInIcon,
8145
8187
  trackEvent: { category: "canvas" },
8146
- perform: (_elements, appState, _, app) => {
8188
+ perform: (elements, appState, _, app) => {
8147
8189
  const displayedZoomValue = getDisplayedZoomValue(appState.zoom.value);
8190
+ const zoomState = getStateForZoom(
8191
+ {
8192
+ viewportX: appState.width / 2 + appState.offsetLeft,
8193
+ viewportY: appState.height / 2 + appState.offsetTop,
8194
+ nextZoom: getNormalizedZoom(
8195
+ displayedZoomValue + getInteractiveZoomStep(appState.zoom.value, "in")
8196
+ )
8197
+ },
8198
+ appState
8199
+ );
8148
8200
  return {
8201
+ elements: syncElementsStrokeWidthForZoom(
8202
+ elements,
8203
+ appState.zoom.value,
8204
+ zoomState.zoom.value
8205
+ ),
8149
8206
  appState: {
8150
8207
  ...appState,
8151
- ...getStateForZoom(
8152
- {
8153
- viewportX: appState.width / 2 + appState.offsetLeft,
8154
- viewportY: appState.height / 2 + appState.offsetTop,
8155
- nextZoom: getNormalizedZoom(
8156
- displayedZoomValue + getInteractiveZoomStep(appState.zoom.value, "in")
8157
- )
8158
- },
8159
- appState
8160
- ),
8208
+ ...zoomState,
8161
8209
  userToFollow: null
8162
8210
  },
8163
8211
  captureUpdate: CaptureUpdateAction6.EVENTUALLY
@@ -8185,21 +8233,27 @@ var actionZoomOut = register({
8185
8233
  icon: ZoomOutIcon,
8186
8234
  viewMode: true,
8187
8235
  trackEvent: { category: "canvas" },
8188
- perform: (_elements, appState, _, app) => {
8236
+ perform: (elements, appState, _, app) => {
8189
8237
  const displayedZoomValue = getDisplayedZoomValue(appState.zoom.value);
8238
+ const zoomState = getStateForZoom(
8239
+ {
8240
+ viewportX: appState.width / 2 + appState.offsetLeft,
8241
+ viewportY: appState.height / 2 + appState.offsetTop,
8242
+ nextZoom: getNormalizedZoom(
8243
+ displayedZoomValue - getInteractiveZoomStep(appState.zoom.value, "out")
8244
+ )
8245
+ },
8246
+ appState
8247
+ );
8190
8248
  return {
8249
+ elements: syncElementsStrokeWidthForZoom(
8250
+ elements,
8251
+ appState.zoom.value,
8252
+ zoomState.zoom.value
8253
+ ),
8191
8254
  appState: {
8192
8255
  ...appState,
8193
- ...getStateForZoom(
8194
- {
8195
- viewportX: appState.width / 2 + appState.offsetLeft,
8196
- viewportY: appState.height / 2 + appState.offsetTop,
8197
- nextZoom: getNormalizedZoom(
8198
- displayedZoomValue - getInteractiveZoomStep(appState.zoom.value, "out")
8199
- )
8200
- },
8201
- appState
8202
- ),
8256
+ ...zoomState,
8203
8257
  userToFollow: null
8204
8258
  },
8205
8259
  captureUpdate: CaptureUpdateAction6.EVENTUALLY
@@ -8227,18 +8281,24 @@ var actionResetZoom = register({
8227
8281
  icon: ZoomResetIcon,
8228
8282
  viewMode: true,
8229
8283
  trackEvent: { category: "canvas" },
8230
- perform: (_elements, appState, _, app) => {
8284
+ perform: (elements, appState, _, app) => {
8285
+ const zoomState = getStateForZoom(
8286
+ {
8287
+ viewportX: appState.width / 2 + appState.offsetLeft,
8288
+ viewportY: appState.height / 2 + appState.offsetTop,
8289
+ nextZoom: getNormalizedZoom(1)
8290
+ },
8291
+ appState
8292
+ );
8231
8293
  return {
8294
+ elements: syncElementsStrokeWidthForZoom(
8295
+ elements,
8296
+ appState.zoom.value,
8297
+ zoomState.zoom.value
8298
+ ),
8232
8299
  appState: {
8233
8300
  ...appState,
8234
- ...getStateForZoom(
8235
- {
8236
- viewportX: appState.width / 2 + appState.offsetLeft,
8237
- viewportY: appState.height / 2 + appState.offsetTop,
8238
- nextZoom: getNormalizedZoom(1)
8239
- },
8240
- appState
8241
- ),
8301
+ ...zoomState,
8242
8302
  userToFollow: null
8243
8303
  },
8244
8304
  captureUpdate: CaptureUpdateAction6.EVENTUALLY
@@ -8276,19 +8336,24 @@ var zoomToFitBounds = ({
8276
8336
  bounds,
8277
8337
  appState,
8278
8338
  canvasOffsets,
8339
+ fitCanvasOffsets,
8340
+ scrollCanvasOffsets,
8279
8341
  fitToViewport = false,
8280
8342
  viewportZoomFactor = 1,
8281
8343
  minZoom = -Infinity,
8282
- maxZoom = Infinity
8344
+ maxZoom = Infinity,
8345
+ elements
8283
8346
  }) => {
8284
8347
  viewportZoomFactor = clamp(viewportZoomFactor, MIN_ZOOM, MAX_ZOOM);
8285
8348
  const [x1, y1, x2, y2] = bounds;
8286
8349
  const centerX = (x1 + x2) / 2;
8287
8350
  const centerY = (y1 + y2) / 2;
8288
- const canvasOffsetLeft = canvasOffsets?.left ?? 0;
8289
- const canvasOffsetTop = canvasOffsets?.top ?? 0;
8290
- const canvasOffsetRight = canvasOffsets?.right ?? 0;
8291
- const canvasOffsetBottom = canvasOffsets?.bottom ?? 0;
8351
+ const fitOffsets = fitCanvasOffsets ?? canvasOffsets;
8352
+ const scrollOffsets = scrollCanvasOffsets ?? fitOffsets ?? canvasOffsets;
8353
+ const canvasOffsetLeft = fitOffsets?.left ?? 0;
8354
+ const canvasOffsetTop = fitOffsets?.top ?? 0;
8355
+ const canvasOffsetRight = fitOffsets?.right ?? 0;
8356
+ const canvasOffsetBottom = fitOffsets?.bottom ?? 0;
8292
8357
  const effectiveCanvasWidth = appState.width - canvasOffsetLeft - canvasOffsetRight;
8293
8358
  const effectiveCanvasHeight = appState.height - canvasOffsetTop - canvasOffsetBottom;
8294
8359
  let adjustedZoomValue;
@@ -8318,37 +8383,54 @@ var zoomToFitBounds = ({
8318
8383
  width: appState.width,
8319
8384
  height: appState.height
8320
8385
  },
8321
- offsets: canvasOffsets,
8386
+ offsets: scrollOffsets,
8322
8387
  zoom: { value: newZoomValue }
8323
8388
  });
8389
+ const fromZoom = appState.zoom.value;
8324
8390
  return {
8325
8391
  appState: {
8326
8392
  ...appState,
8327
8393
  scrollX: centerScroll.scrollX,
8328
8394
  scrollY: centerScroll.scrollY,
8329
- zoom: { value: newZoomValue }
8395
+ zoom: { value: newZoomValue },
8396
+ currentItemStrokeWidth: scaleStrokeWidthForZoomChange2(
8397
+ appState.currentItemStrokeWidth,
8398
+ fromZoom,
8399
+ newZoomValue,
8400
+ appState.currentItemStrokeWidthCustom
8401
+ ),
8402
+ currentItemFontSize: getDefaultSceneFontSizeForZoom2(newZoomValue)
8403
+ },
8404
+ ...elements && {
8405
+ elements: syncElementsStrokeWidthForZoom(elements, fromZoom, newZoomValue)
8330
8406
  },
8331
8407
  captureUpdate: CaptureUpdateAction6.EVENTUALLY
8332
8408
  };
8333
8409
  };
8334
8410
  var zoomToFit = ({
8335
8411
  canvasOffsets,
8412
+ fitCanvasOffsets,
8413
+ scrollCanvasOffsets,
8336
8414
  targetElements,
8337
8415
  appState,
8338
8416
  fitToViewport,
8339
8417
  viewportZoomFactor,
8340
8418
  minZoom,
8341
- maxZoom
8419
+ maxZoom,
8420
+ elements
8342
8421
  }) => {
8343
8422
  const commonBounds = getCommonBounds(getNonDeletedElements5(targetElements));
8344
8423
  return zoomToFitBounds({
8345
8424
  canvasOffsets,
8425
+ fitCanvasOffsets,
8426
+ scrollCanvasOffsets,
8346
8427
  bounds: commonBounds,
8347
8428
  appState,
8348
8429
  fitToViewport,
8349
8430
  viewportZoomFactor,
8350
8431
  minZoom,
8351
- maxZoom
8432
+ maxZoom,
8433
+ elements
8352
8434
  });
8353
8435
  };
8354
8436
  var actionZoomToFitSelectionInViewport = register({
@@ -8360,6 +8442,7 @@ var actionZoomToFitSelectionInViewport = register({
8360
8442
  const selectedElements = app.scene.getSelectedElements(appState);
8361
8443
  return zoomToFit({
8362
8444
  targetElements: selectedElements.length ? selectedElements : elements,
8445
+ elements,
8363
8446
  appState: {
8364
8447
  ...appState,
8365
8448
  userToFollow: null
@@ -8381,6 +8464,7 @@ var actionZoomToFitSelection = register({
8381
8464
  const selectedElements = app.scene.getSelectedElements(appState);
8382
8465
  return zoomToFit({
8383
8466
  targetElements: selectedElements.length ? selectedElements : elements,
8467
+ elements,
8384
8468
  appState: {
8385
8469
  ...appState,
8386
8470
  userToFollow: null
@@ -8400,6 +8484,7 @@ var actionZoomToFit = register({
8400
8484
  trackEvent: { category: "canvas" },
8401
8485
  perform: (elements, appState, _, app) => zoomToFit({
8402
8486
  targetElements: elements,
8487
+ elements,
8403
8488
  appState: {
8404
8489
  ...appState,
8405
8490
  userToFollow: null
@@ -9640,7 +9725,7 @@ var exportCanvas = async (type, elements, appState, files, {
9640
9725
  let blob = canvasToBlob(tempCanvas);
9641
9726
  if (appState.exportEmbedScene) {
9642
9727
  blob = blob.then(
9643
- (blob2) => import("./data/image-OB55CB4R.js").then(
9728
+ (blob2) => import("./data/image-5IO6LC6F.js").then(
9644
9729
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
9645
9730
  blob: blob2,
9646
9731
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -10086,11 +10171,12 @@ var actionExportWithDarkMode = register({
10086
10171
 
10087
10172
  // actions/actionStyles.ts
10088
10173
  import {
10089
- DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE2,
10174
+ DEFAULT_FONT_SIZE,
10090
10175
  DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY2,
10091
10176
  DEFAULT_TEXT_ALIGN,
10092
10177
  CODES as CODES3,
10093
10178
  KEYS as KEYS17,
10179
+ STROKE_WIDTH_CUSTOM_DATA_KEY as STROKE_WIDTH_CUSTOM_DATA_KEY2,
10094
10180
  getLineHeight as getLineHeight2
10095
10181
  } from "@nous-excalidraw/common";
10096
10182
  import { newElementWith as newElementWith5 } from "@nous-excalidraw/element";
@@ -10164,6 +10250,12 @@ var actionPasteStyles = register({
10164
10250
  if (!elementStylesToCopyFrom) {
10165
10251
  return element;
10166
10252
  }
10253
+ const customData = { ...element.customData };
10254
+ if (elementStylesToCopyFrom?.customData?.[STROKE_WIDTH_CUSTOM_DATA_KEY2]) {
10255
+ customData[STROKE_WIDTH_CUSTOM_DATA_KEY2] = true;
10256
+ } else {
10257
+ delete customData[STROKE_WIDTH_CUSTOM_DATA_KEY2];
10258
+ }
10167
10259
  let newElement7 = newElementWith5(element, {
10168
10260
  backgroundColor: elementStylesToCopyFrom?.backgroundColor,
10169
10261
  strokeWidth: elementStylesToCopyFrom?.strokeWidth,
@@ -10172,13 +10264,14 @@ var actionPasteStyles = register({
10172
10264
  fillStyle: elementStylesToCopyFrom?.fillStyle,
10173
10265
  opacity: elementStylesToCopyFrom?.opacity,
10174
10266
  roughness: elementStylesToCopyFrom?.roughness,
10267
+ customData,
10175
10268
  roundness: elementStylesToCopyFrom.roundness ? canApplyRoundnessTypeToElement(
10176
10269
  elementStylesToCopyFrom.roundness.type,
10177
10270
  element
10178
10271
  ) ? elementStylesToCopyFrom.roundness : getDefaultRoundnessTypeForElement(element) : null
10179
10272
  });
10180
10273
  if (isTextElement3(newElement7)) {
10181
- const fontSize = elementStylesToCopyFrom.fontSize || DEFAULT_FONT_SIZE2;
10274
+ const fontSize = elementStylesToCopyFrom.fontSize || DEFAULT_FONT_SIZE;
10182
10275
  const fontFamily = elementStylesToCopyFrom.fontFamily || DEFAULT_FONT_FAMILY2;
10183
10276
  newElement7 = newElementWith5(newElement7, {
10184
10277
  fontSize,
@@ -12650,7 +12743,7 @@ import { updateBindings } from "@nous-excalidraw/element";
12650
12743
  import { jsx as jsx50 } from "react/jsx-runtime";
12651
12744
  var GAP_HORIZONTAL = 8;
12652
12745
  var GAP_VERTICAL = 10;
12653
- var GENERIC_TYPES = ["rectangle", "diamond", "ellipse"];
12746
+ var GENERIC_TYPES = ["rectangle", "diamond", "triangle", "ellipse"];
12654
12747
  var LINEAR_TYPES = [
12655
12748
  "line",
12656
12749
  "sharpArrow",
@@ -12776,6 +12869,7 @@ var Panel = ({
12776
12869
  ] : conversionType === "generic" ? [
12777
12870
  ["rectangle", RectangleIcon],
12778
12871
  ["diamond", DiamondIcon],
12872
+ ["triangle", TriangleIcon],
12779
12873
  ["ellipse", EllipseIcon]
12780
12874
  ] : [];
12781
12875
  return /* @__PURE__ */ jsx50(
@@ -13130,7 +13224,7 @@ var convertElementType = (element, targetType, app) => {
13130
13224
  newElement2({
13131
13225
  ...element,
13132
13226
  type: targetType,
13133
- roundness: targetType === "diamond" && element.roundness ? {
13227
+ roundness: (targetType === "diamond" || targetType === "triangle") && element.roundness ? {
13134
13228
  type: isUsingAdaptiveRadius3(targetType) ? ROUNDNESS3.ADAPTIVE_RADIUS : ROUNDNESS3.PROPORTIONAL_RADIUS
13135
13229
  } : element.roundness
13136
13230
  })
@@ -16802,6 +16896,14 @@ var SHAPES = [
16802
16896
  fillable: true,
16803
16897
  toolbar: true
16804
16898
  },
16899
+ {
16900
+ icon: TriangleIcon,
16901
+ value: "triangle",
16902
+ key: KEYS35.G,
16903
+ numericKey: null,
16904
+ fillable: true,
16905
+ toolbar: true
16906
+ },
16805
16907
  {
16806
16908
  icon: EllipseIcon,
16807
16909
  value: "ellipse",
@@ -18826,9 +18928,49 @@ import {
18826
18928
  getUpdatedTimestamp
18827
18929
  } from "@nous-excalidraw/common";
18828
18930
 
18829
- // ../element/src/shape.ts
18830
- import { simplify } from "points-on-curve";
18831
- import { getStroke } from "perfect-freehand";
18931
+ // ../element/src/renderElement.ts
18932
+ import rough2 from "roughjs/bin/rough";
18933
+ import {
18934
+ isRightAngleRads,
18935
+ lineSegment as lineSegment7,
18936
+ pointFrom as pointFrom18,
18937
+ pointRotateRads as pointRotateRads14
18938
+ } from "@nous-excalidraw/math";
18939
+ import {
18940
+ BOUND_TEXT_PADDING as BOUND_TEXT_PADDING4,
18941
+ DEFAULT_REDUCED_GLOBAL_ALPHA,
18942
+ ELEMENT_READY_TO_ERASE_OPACITY,
18943
+ FRAME_STYLE,
18944
+ DARK_THEME_FILTER,
18945
+ MIME_TYPES as MIME_TYPES7,
18946
+ THEME as THEME10,
18947
+ distance,
18948
+ getFontString as getFontString5,
18949
+ isRTL,
18950
+ getVerticalOffset,
18951
+ invariant as invariant13,
18952
+ applyDarkModeFilter as applyDarkModeFilter2,
18953
+ isSafari,
18954
+ isTransparent as isTransparent6
18955
+ } from "@nous-excalidraw/common";
18956
+
18957
+ // ../element/src/bounds.ts
18958
+ import rough from "roughjs/bin/rough";
18959
+ import {
18960
+ arrayToMap as arrayToMap17,
18961
+ invariant as invariant12,
18962
+ rescalePoints,
18963
+ sizeOf,
18964
+ STROKE_WIDTH
18965
+ } from "@nous-excalidraw/common";
18966
+ import {
18967
+ degreesToRadians,
18968
+ lineSegment as lineSegment5,
18969
+ pointDistance as pointDistance7,
18970
+ pointFrom as pointFrom14,
18971
+ pointFromArray as pointFromArray3,
18972
+ pointRotateRads as pointRotateRads11
18973
+ } from "@nous-excalidraw/math";
18832
18974
 
18833
18975
  // ../utils/src/shape.ts
18834
18976
  import { pointsOnBezierCurves } from "points-on-curve";
@@ -18863,162 +19005,30 @@ var getCurvePathOps = (shape) => {
18863
19005
  return shape.sets[0].ops;
18864
19006
  };
18865
19007
 
19008
+ // ../element/src/bounds.ts
19009
+ import { pointsOnBezierCurves as pointsOnBezierCurves2 } from "points-on-curve";
19010
+ import { getDisplaySceneStrokeWidth as getDisplaySceneStrokeWidth2 } from "@nous-excalidraw/common";
19011
+
18866
19012
  // ../element/src/shape.ts
19013
+ import { simplify } from "points-on-curve";
19014
+ import { getStroke } from "perfect-freehand";
18867
19015
  import {
18868
- pointFrom as pointFrom18,
18869
- pointDistance as pointDistance7,
18870
- pointRotateRads as pointRotateRads14
19016
+ pointFrom as pointFrom13,
19017
+ pointDistance as pointDistance6,
19018
+ pointRotateRads as pointRotateRads10
18871
19019
  } from "@nous-excalidraw/math";
18872
19020
  import {
18873
19021
  ROUGHNESS,
18874
- THEME as THEME10,
19022
+ THEME as THEME9,
18875
19023
  isTransparent as isTransparent5,
18876
19024
  assertNever as assertNever3,
18877
19025
  COLOR_PALETTE as COLOR_PALETTE4,
18878
19026
  LINE_POLYGON_POINT_MERGE_DISTANCE,
18879
- applyDarkModeFilter as applyDarkModeFilter2
18880
- } from "@nous-excalidraw/common";
18881
- import { RoughGenerator } from "roughjs/bin/generator";
18882
-
18883
- // ../element/src/renderElement.ts
18884
- import rough2 from "roughjs/bin/rough";
18885
- import {
18886
- isRightAngleRads,
18887
- lineSegment as lineSegment7,
18888
- pointFrom as pointFrom17,
18889
- pointRotateRads as pointRotateRads13
18890
- } from "@nous-excalidraw/math";
18891
- import {
18892
- BOUND_TEXT_PADDING as BOUND_TEXT_PADDING4,
18893
- DEFAULT_REDUCED_GLOBAL_ALPHA,
18894
- ELEMENT_READY_TO_ERASE_OPACITY,
18895
- FRAME_STYLE,
18896
- DARK_THEME_FILTER,
18897
- MIME_TYPES as MIME_TYPES7,
18898
- THEME as THEME9,
18899
- distance,
18900
- getFontString as getFontString5,
18901
- isRTL,
18902
- getVerticalOffset,
18903
- invariant as invariant13,
18904
19027
  applyDarkModeFilter,
18905
- isSafari
18906
- } from "@nous-excalidraw/common";
18907
-
18908
- // ../element/src/bounds.ts
18909
- import rough from "roughjs/bin/rough";
18910
- import {
18911
- arrayToMap as arrayToMap17,
18912
- invariant as invariant12,
18913
- rescalePoints,
18914
- sizeOf
18915
- } from "@nous-excalidraw/common";
18916
- import {
18917
- degreesToRadians,
18918
- lineSegment as lineSegment5,
18919
- pointDistance as pointDistance6,
18920
- pointFrom as pointFrom13,
18921
- pointFromArray as pointFromArray3,
18922
- pointRotateRads as pointRotateRads10
18923
- } from "@nous-excalidraw/math";
18924
- import { pointsOnBezierCurves as pointsOnBezierCurves2 } from "points-on-curve";
18925
-
18926
- // ../element/src/linearElementEditor.ts
18927
- import {
18928
- pointCenter,
18929
- pointFrom as pointFrom12,
18930
- pointRotateRads as pointRotateRads9,
18931
- pointsEqual as pointsEqual7,
18932
- pointDistance as pointDistance5,
18933
- vectorFromPoint as vectorFromPoint7,
18934
- curveLength,
18935
- curvePointAtLength
18936
- } from "@nous-excalidraw/math";
18937
- import {
18938
- DRAGGING_THRESHOLD,
18939
- KEYS as KEYS39,
18940
- shouldRotateWithDiscreteAngle as shouldRotateWithDiscreteAngle2,
18941
- getGridPoint,
18942
- invariant as invariant11,
18943
- isShallowEqual as isShallowEqual2,
18944
- getFeatureFlag as getFeatureFlag2
19028
+ isCrispScreenStroke,
19029
+ getTierScreenStrokeWidth as getTierScreenStrokeWidth2
18945
19030
  } from "@nous-excalidraw/common";
18946
- import {
18947
- deconstructLinearOrFreeDrawElement as deconstructLinearOrFreeDrawElement2,
18948
- getSnapOutlineMidPoint,
18949
- isPathALoop as isPathALoop3,
18950
- moveArrowAboveBindable,
18951
- projectFixedPointOntoDiagonal as projectFixedPointOntoDiagonal2
18952
- } from "@nous-excalidraw/element";
18953
-
18954
- // ../element/src/binding.ts
18955
- import {
18956
- arrayToMap as arrayToMap16,
18957
- getFeatureFlag,
18958
- invariant as invariant10,
18959
- isTransparent as isTransparent4
18960
- } from "@nous-excalidraw/common";
18961
- import {
18962
- PRECISION as PRECISION2,
18963
- clamp as clamp3,
18964
- lineSegment as lineSegment4,
18965
- pointDistance as pointDistance4,
18966
- pointDistanceSq,
18967
- pointFrom as pointFrom11,
18968
- pointFromVector as pointFromVector5,
18969
- pointRotateRads as pointRotateRads8,
18970
- pointsEqual as pointsEqual5,
18971
- vectorFromPoint as vectorFromPoint6,
18972
- vectorNormalize as vectorNormalize3,
18973
- vectorScale as vectorScale6
18974
- } from "@nous-excalidraw/math";
18975
-
18976
- // ../element/src/collision.ts
18977
- import { invariant as invariant7, isTransparent as isTransparent3 } from "@nous-excalidraw/common";
18978
- import {
18979
- curveIntersectLineSegment,
18980
- isPointWithinBounds,
18981
- lineSegment as lineSegment3,
18982
- lineSegmentIntersectionPoints as lineSegmentIntersectionPoints2,
18983
- pointFrom as pointFrom8,
18984
- pointFromVector as pointFromVector3,
18985
- pointRotateRads as pointRotateRads6,
18986
- pointsEqual as pointsEqual2,
18987
- vectorFromPoint as vectorFromPoint3,
18988
- vectorNormalize as vectorNormalize2,
18989
- vectorScale as vectorScale3
18990
- } from "@nous-excalidraw/math";
18991
- import {
18992
- ellipse as ellipse2,
18993
- ellipseSegmentInterceptPoints
18994
- } from "@nous-excalidraw/math/ellipse";
18995
-
18996
- // ../element/src/utils.ts
18997
- import {
18998
- DEFAULT_ADAPTIVE_RADIUS,
18999
- DEFAULT_PROPORTIONAL_RADIUS,
19000
- invariant as invariant5,
19001
- LINE_CONFIRM_THRESHOLD,
19002
- ROUNDNESS as ROUNDNESS5
19003
- } from "@nous-excalidraw/common";
19004
- import {
19005
- bezierEquation,
19006
- curve as curve2,
19007
- curveCatmullRomCubicApproxPoints,
19008
- curveOffsetPoints,
19009
- lineSegment as lineSegment2,
19010
- lineSegmentIntersectionPoints,
19011
- pointDistance as pointDistance2,
19012
- pointFrom as pointFrom6,
19013
- pointFromArray as pointFromArray2,
19014
- pointFromVector as pointFromVector2,
19015
- pointRotateRads as pointRotateRads3,
19016
- pointTranslate,
19017
- rectangle,
19018
- vectorFromPoint as vectorFromPoint2,
19019
- vectorNormalize,
19020
- vectorScale as vectorScale2
19021
- } from "@nous-excalidraw/math";
19031
+ import { RoughGenerator } from "roughjs/bin/generator";
19022
19032
 
19023
19033
  // ../element/src/typeChecks.ts
19024
19034
  import { ROUNDNESS as ROUNDNESS4, assertNever as assertNever2 } from "@nous-excalidraw/common";
@@ -19055,81 +19065,156 @@ var isBoundToContainer5 = (element) => {
19055
19065
  };
19056
19066
 
19057
19067
  // ../element/src/utils.ts
19058
- var isPathALoop2 = (points, zoomValue = 1) => {
19059
- if (points.length >= 3) {
19060
- const [first, last] = [points[0], points[points.length - 1]];
19061
- const distance3 = pointDistance2(first, last);
19062
- return distance3 <= LINE_CONFIRM_THRESHOLD / zoomValue;
19063
- }
19064
- return false;
19065
- };
19066
- var getCornerRadius = (x, element) => {
19067
- if (element.roundness?.type === ROUNDNESS5.PROPORTIONAL_RADIUS || element.roundness?.type === ROUNDNESS5.LEGACY) {
19068
- return x * DEFAULT_PROPORTIONAL_RADIUS;
19069
- }
19070
- if (element.roundness?.type === ROUNDNESS5.ADAPTIVE_RADIUS) {
19071
- const fixedRadiusSize = element.roundness?.value ?? DEFAULT_ADAPTIVE_RADIUS;
19072
- const CUTOFF_SIZE = fixedRadiusSize / DEFAULT_PROPORTIONAL_RADIUS;
19073
- if (x <= CUTOFF_SIZE) {
19074
- return x * DEFAULT_PROPORTIONAL_RADIUS;
19075
- }
19076
- return fixedRadiusSize;
19077
- }
19078
- return 0;
19079
- };
19068
+ import {
19069
+ DEFAULT_ADAPTIVE_RADIUS,
19070
+ DEFAULT_PROPORTIONAL_RADIUS,
19071
+ invariant as invariant11,
19072
+ LINE_CONFIRM_THRESHOLD,
19073
+ ROUNDNESS as ROUNDNESS5
19074
+ } from "@nous-excalidraw/common";
19075
+ import {
19076
+ bezierEquation,
19077
+ curve as curve2,
19078
+ curveCatmullRomCubicApproxPoints,
19079
+ curveOffsetPoints,
19080
+ lineSegment as lineSegment4,
19081
+ lineSegmentIntersectionPoints as lineSegmentIntersectionPoints2,
19082
+ pointDistance as pointDistance5,
19083
+ pointFrom as pointFrom12,
19084
+ pointFromArray as pointFromArray2,
19085
+ pointFromVector as pointFromVector5,
19086
+ pointRotateRads as pointRotateRads9,
19087
+ pointTranslate as pointTranslate2,
19088
+ rectangle,
19089
+ vectorFromPoint as vectorFromPoint7,
19090
+ vectorNormalize as vectorNormalize3,
19091
+ vectorScale as vectorScale6
19092
+ } from "@nous-excalidraw/math";
19093
+
19094
+ // ../element/src/strokeWidth.ts
19095
+ import {
19096
+ STROKE_WIDTH_CUSTOM_DATA_KEY as STROKE_WIDTH_CUSTOM_DATA_KEY3,
19097
+ STROKE_WIDTH_SCREEN,
19098
+ getDisplaySceneStrokeWidth,
19099
+ getEffectiveStrokeWidth as getEffectiveSceneStrokeWidth,
19100
+ getTierScreenStrokeWidth
19101
+ } from "@nous-excalidraw/common";
19102
+ var isElementStrokeWidthCustom = (element) => element.customData?.[STROKE_WIDTH_CUSTOM_DATA_KEY3] === true;
19103
+ var getEffectiveStrokeWidth = (element, zoom, renderScale = zoom) => getEffectiveSceneStrokeWidth(
19104
+ element.strokeWidth,
19105
+ zoom,
19106
+ renderScale,
19107
+ isElementStrokeWidthCustom(element)
19108
+ );
19109
+
19110
+ // ../element/src/collision.ts
19111
+ import { invariant as invariant10, isTransparent as isTransparent4 } from "@nous-excalidraw/common";
19112
+ import {
19113
+ curveIntersectLineSegment,
19114
+ isPointWithinBounds,
19115
+ lineSegment as lineSegment3,
19116
+ lineSegmentIntersectionPoints,
19117
+ pointFrom as pointFrom11,
19118
+ pointFromVector as pointFromVector4,
19119
+ pointRotateRads as pointRotateRads8,
19120
+ pointsEqual as pointsEqual7,
19121
+ vectorFromPoint as vectorFromPoint6,
19122
+ vectorNormalize as vectorNormalize2,
19123
+ vectorScale as vectorScale5
19124
+ } from "@nous-excalidraw/math";
19125
+ import {
19126
+ ellipse as ellipse2,
19127
+ ellipseSegmentInterceptPoints
19128
+ } from "@nous-excalidraw/math/ellipse";
19080
19129
 
19081
19130
  // ../element/src/textElement.ts
19082
19131
  import {
19083
19132
  ARROW_LABEL_FONT_SIZE_TO_MIN_WIDTH_RATIO,
19084
19133
  ARROW_LABEL_WIDTH_FRACTION,
19085
19134
  BOUND_TEXT_PADDING as BOUND_TEXT_PADDING3,
19086
- DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE4,
19135
+ DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE3,
19087
19136
  TEXT_ALIGN as TEXT_ALIGN2,
19088
19137
  VERTICAL_ALIGN as VERTICAL_ALIGN3,
19089
19138
  getFontString as getFontString4,
19090
19139
  isProdEnv as isProdEnv2,
19091
- invariant as invariant6
19140
+ invariant as invariant9
19092
19141
  } from "@nous-excalidraw/common";
19093
- import { pointFrom as pointFrom7, pointRotateRads as pointRotateRads4 } from "@nous-excalidraw/math";
19142
+ import { pointFrom as pointFrom10, pointRotateRads as pointRotateRads7 } from "@nous-excalidraw/math";
19094
19143
 
19095
- // ../element/src/textMeasurements.ts
19144
+ // ../element/src/linearElementEditor.ts
19096
19145
  import {
19097
- BOUND_TEXT_PADDING as BOUND_TEXT_PADDING2,
19098
- DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE3,
19099
- DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY3,
19100
- getFontString as getFontString3,
19101
- isTestEnv,
19102
- normalizeEOL
19146
+ pointCenter,
19147
+ pointFrom as pointFrom9,
19148
+ pointRotateRads as pointRotateRads6,
19149
+ pointsEqual as pointsEqual6,
19150
+ pointDistance as pointDistance4,
19151
+ vectorFromPoint as vectorFromPoint5,
19152
+ curveLength,
19153
+ curvePointAtLength
19154
+ } from "@nous-excalidraw/math";
19155
+ import {
19156
+ DRAGGING_THRESHOLD,
19157
+ KEYS as KEYS39,
19158
+ shouldRotateWithDiscreteAngle as shouldRotateWithDiscreteAngle2,
19159
+ getGridPoint,
19160
+ invariant as invariant8,
19161
+ isShallowEqual as isShallowEqual2,
19162
+ getFeatureFlag as getFeatureFlag2
19103
19163
  } from "@nous-excalidraw/common";
19104
- var DUMMY_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toLocaleUpperCase();
19164
+ import {
19165
+ deconstructLinearOrFreeDrawElement as deconstructLinearOrFreeDrawElement2,
19166
+ getSnapOutlineMidPoint,
19167
+ isPathALoop as isPathALoop2,
19168
+ moveArrowAboveBindable,
19169
+ projectFixedPointOntoDiagonal as projectFixedPointOntoDiagonal2
19170
+ } from "@nous-excalidraw/element";
19105
19171
 
19106
- // ../element/src/textWrapping.ts
19107
- import { isDevEnv as isDevEnv3, isTestEnv as isTestEnv2 } from "@nous-excalidraw/common";
19172
+ // ../element/src/binding.ts
19173
+ import {
19174
+ arrayToMap as arrayToMap16,
19175
+ getFeatureFlag,
19176
+ invariant as invariant7,
19177
+ isTransparent as isTransparent3
19178
+ } from "@nous-excalidraw/common";
19179
+ import {
19180
+ PRECISION as PRECISION2,
19181
+ clamp as clamp3,
19182
+ lineSegment as lineSegment2,
19183
+ pointDistance as pointDistance3,
19184
+ pointDistanceSq,
19185
+ pointFrom as pointFrom8,
19186
+ pointFromVector as pointFromVector3,
19187
+ pointRotateRads as pointRotateRads5,
19188
+ pointsEqual as pointsEqual4,
19189
+ vectorFromPoint as vectorFromPoint4,
19190
+ vectorNormalize,
19191
+ vectorScale as vectorScale4
19192
+ } from "@nous-excalidraw/math";
19108
19193
 
19109
19194
  // ../element/src/distance.ts
19110
19195
  import {
19111
19196
  curvePointDistance,
19112
19197
  distanceToLineSegment,
19113
- pointRotateRads as pointRotateRads5
19198
+ pointRotateRads as pointRotateRads3
19114
19199
  } from "@nous-excalidraw/math";
19115
19200
  import { ellipse, ellipseDistanceFromPoint } from "@nous-excalidraw/math/ellipse";
19116
19201
 
19117
19202
  // ../element/src/heading.ts
19118
19203
  import {
19119
- invariant as invariant8,
19120
- isDevEnv as isDevEnv4,
19121
- isTestEnv as isTestEnv3
19204
+ invariant as invariant5,
19205
+ isDevEnv as isDevEnv3,
19206
+ isTestEnv
19122
19207
  } from "@nous-excalidraw/common";
19123
19208
  import {
19124
- pointFrom as pointFrom9,
19125
- pointFromVector as pointFromVector4,
19126
- pointRotateRads as pointRotateRads7,
19209
+ pointFrom as pointFrom6,
19210
+ pointFromVector as pointFromVector2,
19211
+ pointRotateRads as pointRotateRads4,
19127
19212
  pointScaleFromOrigin,
19128
- pointsEqual as pointsEqual3,
19213
+ pointsEqual as pointsEqual2,
19129
19214
  triangleIncludesPoint,
19130
19215
  vectorCross,
19131
- vectorFromPoint as vectorFromPoint4,
19132
- vectorScale as vectorScale4
19216
+ vectorFromPoint as vectorFromPoint2,
19217
+ vectorScale as vectorScale2
19133
19218
  } from "@nous-excalidraw/math";
19134
19219
  var HEADING_RIGHT = [1, 0];
19135
19220
  var HEADING_DOWN = [0, 1];
@@ -19148,7 +19233,7 @@ var vectorToHeading = (vec) => {
19148
19233
  }
19149
19234
  return HEADING_UP;
19150
19235
  };
19151
- var headingForPoint = (p, o) => vectorToHeading(vectorFromPoint4(p, o));
19236
+ var headingForPoint = (p, o) => vectorToHeading(vectorFromPoint2(p, o));
19152
19237
  var headingForPointIsHorizontal = (p, o) => headingIsHorizontal(headingForPoint(p, o));
19153
19238
  var compareHeading = (a, b) => a[0] === b[0] && a[1] === b[1];
19154
19239
  var headingIsHorizontal = (a) => compareHeading(a, HEADING_RIGHT) || compareHeading(a, HEADING_LEFT);
@@ -19156,22 +19241,22 @@ var headingIsHorizontal = (a) => compareHeading(a, HEADING_RIGHT) || compareHead
19156
19241
  // ../element/src/elbowArrow.ts
19157
19242
  import {
19158
19243
  clamp as clamp2,
19159
- pointDistance as pointDistance3,
19160
- pointFrom as pointFrom10,
19244
+ pointDistance as pointDistance2,
19245
+ pointFrom as pointFrom7,
19161
19246
  pointScaleFromOrigin as pointScaleFromOrigin2,
19162
- pointsEqual as pointsEqual4,
19163
- pointTranslate as pointTranslate2,
19247
+ pointsEqual as pointsEqual3,
19248
+ pointTranslate,
19164
19249
  vector as vector2,
19165
19250
  vectorCross as vectorCross2,
19166
- vectorFromPoint as vectorFromPoint5,
19167
- vectorScale as vectorScale5
19251
+ vectorFromPoint as vectorFromPoint3,
19252
+ vectorScale as vectorScale3
19168
19253
  } from "@nous-excalidraw/math";
19169
19254
  import {
19170
19255
  BinaryHeap,
19171
- invariant as invariant9,
19256
+ invariant as invariant6,
19172
19257
  isAnyTrue,
19173
19258
  getSizeFromPoints,
19174
- isDevEnv as isDevEnv5,
19259
+ isDevEnv as isDevEnv4,
19175
19260
  arrayToMap as arrayToMap15
19176
19261
  } from "@nous-excalidraw/common";
19177
19262
 
@@ -19188,353 +19273,48 @@ import {
19188
19273
  radiansBetweenAngles,
19189
19274
  radiansDifference
19190
19275
  } from "@nous-excalidraw/math";
19191
- import { pointsEqual as pointsEqual6 } from "@nous-excalidraw/math";
19192
-
19193
- // ../element/src/bounds.ts
19194
- var getDiamondPoints = (element) => {
19195
- const topX = Math.floor(element.width / 2) + 1;
19196
- const topY = 0;
19197
- const rightX = element.width;
19198
- const rightY = Math.floor(element.height / 2) + 1;
19199
- const bottomX = topX;
19200
- const bottomY = element.height;
19201
- const leftX = 0;
19202
- const leftY = rightY;
19203
- return [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY];
19204
- };
19205
- var CARDINALITY_MARKER_SIZE = 20;
19206
- var CROWFOOT_ARROWHEAD_SIZE = 15;
19207
- var getArrowheadSize = (arrowhead) => {
19208
- switch (arrowhead) {
19209
- case "arrow":
19210
- return 25;
19211
- case "diamond":
19212
- case "diamond_outline":
19213
- return 12;
19214
- case "cardinality_many":
19215
- case "cardinality_one_or_many":
19216
- case "cardinality_zero_or_many":
19217
- return CROWFOOT_ARROWHEAD_SIZE;
19218
- case "cardinality_one":
19219
- case "cardinality_exactly_one":
19220
- case "cardinality_zero_or_one":
19221
- return CARDINALITY_MARKER_SIZE;
19222
- default:
19223
- return 15;
19224
- }
19225
- };
19226
- var getArrowheadAngle = (arrowhead) => {
19227
- switch (arrowhead) {
19228
- case "bar":
19229
- return 90;
19230
- case "arrow":
19231
- return 20;
19232
- default:
19233
- return 25;
19234
- }
19235
- };
19236
- var getArrowheadPoints = (element, shape, position, arrowhead, offsetMultiplier = 0) => {
19237
- if (arrowhead === null) {
19238
- return null;
19239
- }
19240
- if (shape.length < 1) {
19241
- return null;
19242
- }
19243
- const ops = getCurvePathOps(shape[0]);
19244
- if (ops.length < 1) {
19245
- return null;
19246
- }
19247
- const index = position === "start" ? 1 : ops.length - 1;
19248
- const data = ops[index].data;
19249
- invariant12(data.length === 6, "Op data length is not 6");
19250
- const p3 = pointFrom13(data[4], data[5]);
19251
- const p2 = pointFrom13(data[2], data[3]);
19252
- const p1 = pointFrom13(data[0], data[1]);
19253
- const prevOp = ops[index - 1];
19254
- let p0 = pointFrom13(0, 0);
19255
- if (prevOp.op === "move") {
19256
- const p = pointFromArray3(prevOp.data);
19257
- invariant12(p != null, "Op data is not a point");
19258
- p0 = p;
19259
- } else if (prevOp.op === "bcurveTo") {
19260
- p0 = pointFrom13(prevOp.data[4], prevOp.data[5]);
19261
- }
19262
- const equation = (t2, idx) => Math.pow(1 - t2, 3) * p3[idx] + 3 * t2 * Math.pow(1 - t2, 2) * p2[idx] + 3 * Math.pow(t2, 2) * (1 - t2) * p1[idx] + p0[idx] * Math.pow(t2, 3);
19263
- const [x2, y2] = position === "start" ? p0 : p3;
19264
- const [x1, y1] = [equation(0.3, 0), equation(0.3, 1)];
19265
- const distance3 = Math.hypot(x2 - x1, y2 - y1);
19266
- const nx = (x2 - x1) / distance3;
19267
- const ny = (y2 - y1) / distance3;
19268
- const size = getArrowheadSize(arrowhead);
19269
- let length = 0;
19270
- {
19271
- const [cx, cy] = position === "end" ? element.points[element.points.length - 1] : element.points[0];
19272
- const [px, py] = element.points.length > 1 ? position === "end" ? element.points[element.points.length - 2] : element.points[1] : [0, 0];
19273
- length = Math.hypot(cx - px, cy - py);
19274
- }
19275
- const lengthMultiplier = arrowhead === "diamond" || arrowhead === "diamond_outline" ? 0.25 : 0.5;
19276
- const minSize = Math.min(size, length * lengthMultiplier);
19277
- const tx = x2 - nx * minSize * offsetMultiplier;
19278
- const ty = y2 - ny * minSize * offsetMultiplier;
19279
- const xs = tx - nx * minSize;
19280
- const ys = ty - ny * minSize;
19281
- if (arrowhead === "circle" || arrowhead === "circle_outline") {
19282
- const diameter = Math.hypot(ys - ty, xs - tx) + element.strokeWidth - 2;
19283
- return [tx, ty, diameter];
19284
- }
19285
- const angle = getArrowheadAngle(arrowhead);
19286
- if (arrowhead === "cardinality_many" || arrowhead === "cardinality_one_or_many") {
19287
- const [x32, y32] = pointRotateRads10(
19288
- pointFrom13(tx, ty),
19289
- pointFrom13(xs, ys),
19290
- degreesToRadians(-angle)
19291
- );
19292
- const [x42, y42] = pointRotateRads10(
19293
- pointFrom13(tx, ty),
19294
- pointFrom13(xs, ys),
19295
- degreesToRadians(angle)
19296
- );
19297
- return [xs, ys, x32, y32, x42, y42];
19298
- }
19299
- const [x3, y3] = pointRotateRads10(
19300
- pointFrom13(xs, ys),
19301
- pointFrom13(tx, ty),
19302
- -angle * Math.PI / 180
19303
- );
19304
- const [x4, y4] = pointRotateRads10(
19305
- pointFrom13(xs, ys),
19306
- pointFrom13(tx, ty),
19307
- degreesToRadians(angle)
19308
- );
19309
- if (arrowhead === "diamond" || arrowhead === "diamond_outline") {
19310
- let ox;
19311
- let oy;
19312
- if (position === "start") {
19313
- const [px, py] = element.points.length > 1 ? element.points[1] : [0, 0];
19314
- [ox, oy] = pointRotateRads10(
19315
- pointFrom13(tx + minSize * 2, ty),
19316
- pointFrom13(tx, ty),
19317
- Math.atan2(py - ty, px - tx)
19318
- );
19319
- } else {
19320
- const [px, py] = element.points.length > 1 ? element.points[element.points.length - 2] : [0, 0];
19321
- [ox, oy] = pointRotateRads10(
19322
- pointFrom13(tx - minSize * 2, ty),
19323
- pointFrom13(tx, ty),
19324
- Math.atan2(ty - py, tx - px)
19325
- );
19326
- }
19327
- return [tx, ty, x3, y3, ox, oy, x4, y4];
19328
- }
19329
- return [tx, ty, x3, y3, x4, y4];
19330
- };
19331
-
19332
- // ../element/src/cropElement.ts
19333
- import {
19334
- pointFrom as pointFrom14,
19335
- pointCenter as pointCenter2,
19336
- pointRotateRads as pointRotateRads11,
19337
- vectorFromPoint as vectorFromPoint8,
19338
- vectorNormalize as vectorNormalize4,
19339
- vectorSubtract,
19340
- vectorAdd as vectorAdd2,
19341
- vectorScale as vectorScale7,
19342
- pointFromVector as pointFromVector6,
19343
- clamp as clamp4,
19344
- isCloseTo
19345
- } from "@nous-excalidraw/math";
19346
-
19347
- // ../element/src/frame.ts
19348
- import { arrayToMap as arrayToMap19, sizeOf as sizeOf2 } from "@nous-excalidraw/common";
19349
- import { isPointWithinBounds as isPointWithinBounds2, pointFrom as pointFrom16 } from "@nous-excalidraw/math";
19350
-
19351
- // ../utils/src/bbox.ts
19352
- import {
19353
- vectorCross as vectorCross3,
19354
- vectorFromPoint as vectorFromPoint9
19355
- } from "@nous-excalidraw/math";
19276
+ import { pointsEqual as pointsEqual5 } from "@nous-excalidraw/math";
19356
19277
 
19357
- // ../element/src/selection.ts
19358
- import { arrayToMap as arrayToMap18, isShallowEqual as isShallowEqual3 } from "@nous-excalidraw/common";
19278
+ // ../element/src/textMeasurements.ts
19359
19279
  import {
19360
- lineSegment as lineSegment6,
19361
- pointFrom as pointFrom15,
19362
- pointRotateRads as pointRotateRads12
19363
- } from "@nous-excalidraw/math";
19280
+ BOUND_TEXT_PADDING as BOUND_TEXT_PADDING2,
19281
+ DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE2,
19282
+ DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY3,
19283
+ getFontString as getFontString3,
19284
+ isTestEnv as isTestEnv2,
19285
+ normalizeEOL
19286
+ } from "@nous-excalidraw/common";
19287
+ var DUMMY_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toLocaleUpperCase();
19364
19288
 
19365
- // ../element/src/groups.ts
19366
- var selectGroupsForSelectedElements5 = function() {
19367
- let lastSelectedElements = null;
19368
- let lastElements = null;
19369
- let lastReturnValue = null;
19370
- const _selectGroups = (selectedElements, elements, appState, prevAppState) => {
19371
- if (lastReturnValue !== void 0 && elements === lastElements && selectedElements === lastSelectedElements && appState.editingGroupId === lastReturnValue?.editingGroupId) {
19372
- return lastReturnValue;
19373
- }
19374
- const selectedGroupIds = {};
19375
- for (const selectedElement of selectedElements) {
19376
- let groupIds = selectedElement.groupIds;
19377
- if (appState.editingGroupId) {
19378
- const indexOfEditingGroup = groupIds.indexOf(appState.editingGroupId);
19379
- if (indexOfEditingGroup > -1) {
19380
- groupIds = groupIds.slice(0, indexOfEditingGroup);
19381
- }
19382
- }
19383
- if (groupIds.length > 0) {
19384
- const lastSelectedGroup = groupIds[groupIds.length - 1];
19385
- selectedGroupIds[lastSelectedGroup] = true;
19386
- }
19387
- }
19388
- const groupElementsIndex = {};
19389
- const selectedElementIdsInGroups = elements.reduce(
19390
- (acc, element) => {
19391
- if (element.isDeleted) {
19392
- return acc;
19393
- }
19394
- const groupId = element.groupIds.find((id) => selectedGroupIds[id]);
19395
- if (groupId) {
19396
- acc[element.id] = true;
19397
- if (!Array.isArray(groupElementsIndex[groupId])) {
19398
- groupElementsIndex[groupId] = [element.id];
19399
- } else {
19400
- groupElementsIndex[groupId].push(element.id);
19401
- }
19402
- }
19403
- return acc;
19404
- },
19405
- {}
19406
- );
19407
- for (const groupId of Object.keys(groupElementsIndex)) {
19408
- if (groupElementsIndex[groupId].length < 2) {
19409
- if (selectedGroupIds[groupId]) {
19410
- selectedGroupIds[groupId] = false;
19411
- }
19412
- }
19413
- }
19414
- lastElements = elements;
19415
- lastSelectedElements = selectedElements;
19416
- lastReturnValue = {
19417
- editingGroupId: appState.editingGroupId,
19418
- selectedGroupIds,
19419
- selectedElementIds: makeNextSelectedElementIds2(
19420
- {
19421
- ...appState.selectedElementIds,
19422
- ...selectedElementIdsInGroups
19423
- },
19424
- prevAppState
19425
- )
19426
- };
19427
- return lastReturnValue;
19428
- };
19429
- const selectGroupsForSelectedElements8 = (appState, elements, prevAppState, app) => {
19430
- const selectedElements = app ? app.scene.getSelectedElements({
19431
- selectedElementIds: appState.selectedElementIds,
19432
- // supplying elements explicitly in case we're passed non-state elements
19433
- elements
19434
- }) : getSelectedElements3(elements, appState);
19435
- if (!selectedElements.length) {
19436
- return {
19437
- selectedGroupIds: {},
19438
- editingGroupId: null,
19439
- selectedElementIds: makeNextSelectedElementIds2(
19440
- appState.selectedElementIds,
19441
- prevAppState
19442
- )
19443
- };
19444
- }
19445
- return _selectGroups(selectedElements, elements, appState, prevAppState);
19446
- };
19447
- selectGroupsForSelectedElements8.clearCache = () => {
19448
- lastElements = null;
19449
- lastSelectedElements = null;
19450
- lastReturnValue = null;
19451
- };
19452
- return selectGroupsForSelectedElements8;
19453
- }();
19289
+ // ../element/src/textWrapping.ts
19290
+ import { isDevEnv as isDevEnv5, isTestEnv as isTestEnv3 } from "@nous-excalidraw/common";
19454
19291
 
19455
- // ../element/src/selection.ts
19456
- var isSomeElementSelected3 = function() {
19457
- let lastElements = null;
19458
- let lastSelectedElementIds = null;
19459
- let isSelected = null;
19460
- const ret = (elements, appState) => {
19461
- if (isSelected != null && elements === lastElements && appState.selectedElementIds === lastSelectedElementIds) {
19462
- return isSelected;
19463
- }
19464
- isSelected = elements.some(
19465
- (element) => appState.selectedElementIds[element.id]
19466
- );
19467
- lastElements = elements;
19468
- lastSelectedElementIds = appState.selectedElementIds;
19469
- return isSelected;
19470
- };
19471
- ret.clearCache = () => {
19472
- lastElements = null;
19473
- lastSelectedElementIds = null;
19474
- isSelected = null;
19475
- };
19476
- return ret;
19477
- }();
19478
- var getSelectedElements3 = (elements, appState, opts) => {
19479
- const addedElements = /* @__PURE__ */ new Set();
19480
- const selectedElements = [];
19481
- for (const element of elements.values()) {
19482
- if (appState.selectedElementIds[element.id]) {
19483
- selectedElements.push(element);
19484
- addedElements.add(element.id);
19485
- continue;
19486
- }
19487
- if (opts?.includeBoundTextElement && isBoundToContainer5(element) && appState.selectedElementIds[element?.containerId]) {
19488
- selectedElements.push(element);
19489
- addedElements.add(element.id);
19490
- continue;
19491
- }
19492
- }
19493
- if (opts?.includeElementsInFrames) {
19494
- const elementsToInclude = [];
19495
- selectedElements.forEach((element) => {
19496
- if (isFrameLikeElement7(element)) {
19497
- getFrameChildren2(elements, element.id).forEach(
19498
- (e) => !addedElements.has(e.id) && elementsToInclude.push(e)
19499
- );
19500
- }
19501
- elementsToInclude.push(element);
19502
- });
19503
- return elementsToInclude;
19292
+ // ../element/src/utils.ts
19293
+ var isPathALoop3 = (points, zoomValue = 1) => {
19294
+ if (points.length >= 3) {
19295
+ const [first, last] = [points[0], points[points.length - 1]];
19296
+ const distance3 = pointDistance5(first, last);
19297
+ return distance3 <= LINE_CONFIRM_THRESHOLD / zoomValue;
19504
19298
  }
19505
- return selectedElements;
19299
+ return false;
19506
19300
  };
19507
- var makeNextSelectedElementIds2 = (nextSelectedElementIds, prevState) => {
19508
- if (isShallowEqual3(prevState.selectedElementIds, nextSelectedElementIds)) {
19509
- return prevState.selectedElementIds;
19301
+ var getCornerRadius = (x, element) => {
19302
+ if (element.roundness?.type === ROUNDNESS5.PROPORTIONAL_RADIUS || element.roundness?.type === ROUNDNESS5.LEGACY) {
19303
+ return x * DEFAULT_PROPORTIONAL_RADIUS;
19510
19304
  }
19511
- return nextSelectedElementIds;
19512
- };
19513
-
19514
- // ../element/src/frame.ts
19515
- var getFrameChildren2 = (allElements, frameId) => {
19516
- const frameChildren = [];
19517
- for (const element of allElements.values()) {
19518
- if (element.frameId === frameId) {
19519
- frameChildren.push(element);
19305
+ if (element.roundness?.type === ROUNDNESS5.ADAPTIVE_RADIUS) {
19306
+ const fixedRadiusSize = element.roundness?.value ?? DEFAULT_ADAPTIVE_RADIUS;
19307
+ const CUTOFF_SIZE = fixedRadiusSize / DEFAULT_PROPORTIONAL_RADIUS;
19308
+ if (x <= CUTOFF_SIZE) {
19309
+ return x * DEFAULT_PROPORTIONAL_RADIUS;
19520
19310
  }
19311
+ return fixedRadiusSize;
19521
19312
  }
19522
- return frameChildren;
19313
+ return 0;
19523
19314
  };
19524
19315
 
19525
- // ../element/src/renderElement.ts
19526
- var IMAGE_PLACEHOLDER_IMG = typeof document !== "undefined" ? document.createElement("img") : { src: "" };
19527
- IMAGE_PLACEHOLDER_IMG.src = `data:${MIME_TYPES7.svg},${encodeURIComponent(
19528
- `<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="image" class="svg-inline--fa fa-image fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#888" d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>`
19529
- )}`;
19530
- var IMAGE_ERROR_PLACEHOLDER_IMG = typeof document !== "undefined" ? document.createElement("img") : { src: "" };
19531
- IMAGE_ERROR_PLACEHOLDER_IMG.src = `data:${MIME_TYPES7.svg},${encodeURIComponent(
19532
- `<svg viewBox="0 0 668 668" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48ZM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56ZM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.81709 0 0 .81709 124.825 145.825)"/><path d="M256 8C119.034 8 8 119.033 8 256c0 136.967 111.034 248 248 248s248-111.034 248-248S392.967 8 256 8Zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676ZM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.30366 0 0 .30366 506.822 60.065)"/></svg>`
19533
- )}`;
19534
- var elementWithCanvasCache = /* @__PURE__ */ new WeakMap();
19535
-
19536
19316
  // ../element/src/comparisons.ts
19537
- var canChangeRoundness2 = (type) => type === "rectangle" || type === "iframe" || type === "embeddable" || type === "line" || type === "diamond" || type === "image";
19317
+ var canChangeRoundness2 = (type) => type === "rectangle" || type === "iframe" || type === "embeddable" || type === "line" || type === "diamond" || type === "triangle" || type === "image";
19538
19318
 
19539
19319
  // ../element/src/shape.ts
19540
19320
  var _ShapeCache = class _ShapeCache {
@@ -19545,9 +19325,11 @@ __publicField(_ShapeCache, "cache", /* @__PURE__ */ new WeakMap());
19545
19325
  * Retrieves shape from cache if available. Use this only if shape
19546
19326
  * is optional and you have a fallback in case it's not cached.
19547
19327
  */
19548
- __publicField(_ShapeCache, "get", (element, theme) => {
19328
+ __publicField(_ShapeCache, "get", (element, theme, zoom, renderScale) => {
19549
19329
  const cached = _ShapeCache.cache.get(element);
19550
- if (cached && (theme === null || cached.theme === theme)) {
19330
+ const resolvedRenderScale = renderScale ?? zoom;
19331
+ const tierScreenStrokeWidth = zoom === void 0 ? void 0 : getTierScreenStrokeWidth2(zoom);
19332
+ if (cached && (theme === null || cached.theme === theme) && (zoom === void 0 || cached.zoom === zoom) && cached.strokeWidth === element.strokeWidth && cached.strokeWidthCustom === isElementStrokeWidthCustom(element) && (tierScreenStrokeWidth === void 0 || cached.tierScreenStrokeWidth === tierScreenStrokeWidth) && cached.strokeStyle === element.strokeStyle && cached.roughness === element.roughness && (resolvedRenderScale === void 0 || cached.renderScale === resolvedRenderScale)) {
19551
19333
  return cached.shape;
19552
19334
  }
19553
19335
  return void 0;
@@ -19564,7 +19346,14 @@ __publicField(_ShapeCache, "destroy", () => {
19564
19346
  * returns cached shape.
19565
19347
  */
19566
19348
  __publicField(_ShapeCache, "generateElementShape", (element, renderConfig) => {
19567
- const cachedShape = renderConfig?.isExporting ? void 0 : _ShapeCache.get(element, renderConfig ? renderConfig.theme : null);
19349
+ const zoom = renderConfig?.zoom ?? 1;
19350
+ const renderScale = renderConfig?.renderScale ?? zoom;
19351
+ const cachedShape = renderConfig?.isExporting ? void 0 : _ShapeCache.get(
19352
+ element,
19353
+ renderConfig ? renderConfig.theme : null,
19354
+ zoom,
19355
+ renderScale
19356
+ );
19568
19357
  if (cachedShape !== void 0) {
19569
19358
  return cachedShape;
19570
19359
  }
@@ -19572,17 +19361,26 @@ __publicField(_ShapeCache, "generateElementShape", (element, renderConfig) => {
19572
19361
  const shape = _generateElementShape(
19573
19362
  element,
19574
19363
  _ShapeCache.rg,
19575
- renderConfig || {
19576
- isExporting: false,
19577
- canvasBackgroundColor: COLOR_PALETTE4.white,
19578
- embedsValidationStatus: null,
19579
- theme: THEME10.LIGHT
19364
+ {
19365
+ isExporting: renderConfig?.isExporting ?? false,
19366
+ canvasBackgroundColor: renderConfig?.canvasBackgroundColor ?? COLOR_PALETTE4.white,
19367
+ embedsValidationStatus: renderConfig?.embedsValidationStatus ?? null,
19368
+ theme: renderConfig?.theme ?? THEME9.LIGHT,
19369
+ zoom,
19370
+ renderScale
19580
19371
  }
19581
19372
  );
19582
19373
  if (!renderConfig?.isExporting) {
19583
19374
  _ShapeCache.cache.set(element, {
19584
19375
  shape,
19585
- theme: renderConfig?.theme || THEME10.LIGHT
19376
+ theme: renderConfig?.theme || THEME9.LIGHT,
19377
+ zoom,
19378
+ strokeWidth: element.strokeWidth,
19379
+ strokeWidthCustom: isElementStrokeWidthCustom(element),
19380
+ tierScreenStrokeWidth: getTierScreenStrokeWidth2(zoom),
19381
+ strokeStyle: element.strokeStyle,
19382
+ roughness: element.roughness,
19383
+ renderScale
19586
19384
  });
19587
19385
  }
19588
19386
  return shape;
@@ -19604,33 +19402,36 @@ function adjustRoughness(element) {
19604
19402
  }
19605
19403
  return Math.min(roughness / (maxSize < 10 ? 3 : 2), 2.5);
19606
19404
  }
19607
- var generateRoughOptions = (element, continuousPath = false, isDarkMode = false) => {
19405
+ var generateRoughOptions = (element, continuousPath = false, isDarkMode = false, zoom = 1, renderScale = zoom) => {
19406
+ const strokeWidth = getEffectiveStrokeWidth(element, zoom, renderScale);
19407
+ const useCrispStroke = isCrispScreenStroke(zoom);
19608
19408
  const options = {
19609
19409
  seed: element.seed,
19610
- strokeLineDash: element.strokeStyle === "dashed" ? getDashArrayDashed(element.strokeWidth) : element.strokeStyle === "dotted" ? getDashArrayDotted(element.strokeWidth) : void 0,
19410
+ strokeLineDash: element.strokeStyle === "dashed" ? getDashArrayDashed(strokeWidth) : element.strokeStyle === "dotted" ? getDashArrayDotted(strokeWidth) : void 0,
19611
19411
  // for non-solid strokes, disable multiStroke because it tends to make
19612
19412
  // dashes/dots overlay each other
19613
- disableMultiStroke: element.strokeStyle !== "solid",
19413
+ disableMultiStroke: useCrispStroke || element.strokeStyle !== "solid",
19614
19414
  // for non-solid strokes, increase the width a bit to make it visually
19615
19415
  // similar to solid strokes, because we're also disabling multiStroke
19616
- strokeWidth: element.strokeStyle !== "solid" ? element.strokeWidth + 0.5 : element.strokeWidth,
19416
+ strokeWidth: element.strokeStyle !== "solid" ? strokeWidth + 0.5 : strokeWidth,
19617
19417
  // when increasing strokeWidth, we must explicitly set fillWeight and
19618
19418
  // hachureGap because if not specified, roughjs uses strokeWidth to
19619
19419
  // calculate them (and we don't want the fills to be modified)
19620
- fillWeight: element.strokeWidth / 2,
19621
- hachureGap: element.strokeWidth * 4,
19622
- roughness: adjustRoughness(element),
19623
- stroke: isDarkMode ? applyDarkModeFilter2(element.strokeColor) : element.strokeColor,
19624
- preserveVertices: continuousPath || element.roughness < ROUGHNESS.cartoonist
19420
+ fillWeight: strokeWidth / 2,
19421
+ hachureGap: strokeWidth * 4,
19422
+ roughness: useCrispStroke ? ROUGHNESS.architect : adjustRoughness(element),
19423
+ stroke: isDarkMode ? applyDarkModeFilter(element.strokeColor) : element.strokeColor,
19424
+ preserveVertices: useCrispStroke || continuousPath || element.roughness < ROUGHNESS.cartoonist
19625
19425
  };
19626
19426
  switch (element.type) {
19627
19427
  case "rectangle":
19628
19428
  case "iframe":
19629
19429
  case "embeddable":
19630
19430
  case "diamond":
19431
+ case "triangle":
19631
19432
  case "ellipse": {
19632
19433
  options.fillStyle = element.fillStyle;
19633
- options.fill = isTransparent5(element.backgroundColor) ? void 0 : isDarkMode ? applyDarkModeFilter2(element.backgroundColor) : element.backgroundColor;
19434
+ options.fill = isTransparent5(element.backgroundColor) ? void 0 : isDarkMode ? applyDarkModeFilter(element.backgroundColor) : element.backgroundColor;
19634
19435
  if (element.type === "ellipse") {
19635
19436
  options.curveFitting = 1;
19636
19437
  }
@@ -19638,9 +19439,9 @@ var generateRoughOptions = (element, continuousPath = false, isDarkMode = false)
19638
19439
  }
19639
19440
  case "line":
19640
19441
  case "freedraw": {
19641
- if (isPathALoop2(element.points)) {
19442
+ if (isPathALoop3(element.points)) {
19642
19443
  options.fillStyle = element.fillStyle;
19643
- options.fill = element.backgroundColor === "transparent" ? void 0 : isDarkMode ? applyDarkModeFilter2(element.backgroundColor) : element.backgroundColor;
19444
+ options.fill = element.backgroundColor === "transparent" ? void 0 : isDarkMode ? applyDarkModeFilter(element.backgroundColor) : element.backgroundColor;
19644
19445
  }
19645
19446
  return options;
19646
19447
  }
@@ -19687,8 +19488,9 @@ var generateArrowheadLinesToTip = (generator, arrowheadPoints, lineOptions) => {
19687
19488
  };
19688
19489
  var getArrowheadLineOptions = (element, options) => {
19689
19490
  const lineOptions = { ...options };
19491
+ const strokeWidth = options.strokeWidth ?? element.strokeWidth;
19690
19492
  if (element.strokeStyle === "dotted") {
19691
- const dash = getDashArrayDotted(element.strokeWidth - 1);
19493
+ const dash = getDashArrayDotted(strokeWidth - 1);
19692
19494
  lineOptions.strokeLineDash = [dash[0], dash[1] - 1];
19693
19495
  } else {
19694
19496
  delete lineOptions.strokeLineDash;
@@ -19715,8 +19517,17 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19715
19517
  if (arrowhead === null) {
19716
19518
  return [];
19717
19519
  }
19718
- const strokeColor = isDarkMode ? applyDarkModeFilter2(element.strokeColor) : element.strokeColor;
19719
- const backgroundFillColor = isDarkMode ? applyDarkModeFilter2(canvasBackgroundColor) : canvasBackgroundColor;
19520
+ const strokeWidth = options.strokeWidth ?? element.strokeWidth;
19521
+ const getPoints = (arrowhead2, offsetMultiplier = 0) => getArrowheadPoints(
19522
+ element,
19523
+ shape,
19524
+ position,
19525
+ arrowhead2,
19526
+ offsetMultiplier,
19527
+ strokeWidth
19528
+ );
19529
+ const strokeColor = isDarkMode ? applyDarkModeFilter(element.strokeColor) : element.strokeColor;
19530
+ const backgroundFillColor = isDarkMode ? applyDarkModeFilter(canvasBackgroundColor) : canvasBackgroundColor;
19720
19531
  const cardinalityOneOrManyOffset = -0.25;
19721
19532
  const cardinalityZeroCircleScale = 0.8;
19722
19533
  switch (arrowhead) {
@@ -19726,18 +19537,13 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19726
19537
  generator,
19727
19538
  options,
19728
19539
  strokeColor,
19729
- getArrowheadPoints(element, shape, position, arrowhead),
19540
+ getPoints(arrowhead),
19730
19541
  arrowhead === "circle_outline" ? backgroundFillColor : strokeColor
19731
19542
  );
19732
19543
  }
19733
19544
  case "triangle":
19734
19545
  case "triangle_outline": {
19735
- const arrowheadPoints = getArrowheadPoints(
19736
- element,
19737
- shape,
19738
- position,
19739
- arrowhead
19740
- );
19546
+ const arrowheadPoints = getPoints(arrowhead);
19741
19547
  if (arrowheadPoints === null) {
19742
19548
  return [];
19743
19549
  }
@@ -19763,12 +19569,7 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19763
19569
  }
19764
19570
  case "diamond":
19765
19571
  case "diamond_outline": {
19766
- const arrowheadPoints = getArrowheadPoints(
19767
- element,
19768
- shape,
19769
- position,
19770
- arrowhead
19771
- );
19572
+ const arrowheadPoints = getPoints(arrowhead);
19772
19573
  if (arrowheadPoints === null) {
19773
19574
  return [];
19774
19575
  }
@@ -19796,13 +19597,13 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19796
19597
  case "cardinality_one":
19797
19598
  return generateArrowheadCardinalityOne(
19798
19599
  generator,
19799
- getArrowheadPoints(element, shape, position, arrowhead),
19600
+ getPoints(arrowhead),
19800
19601
  getArrowheadLineOptions(element, options)
19801
19602
  );
19802
19603
  case "cardinality_many":
19803
19604
  return generateArrowheadLinesToTip(
19804
19605
  generator,
19805
- getArrowheadPoints(element, shape, position, arrowhead),
19606
+ getPoints(arrowhead),
19806
19607
  getArrowheadLineOptions(element, options)
19807
19608
  );
19808
19609
  case "cardinality_one_or_many": {
@@ -19810,18 +19611,12 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19810
19611
  return [
19811
19612
  ...generateArrowheadLinesToTip(
19812
19613
  generator,
19813
- getArrowheadPoints(element, shape, position, "cardinality_many"),
19614
+ getPoints("cardinality_many"),
19814
19615
  lineOptions
19815
19616
  ),
19816
19617
  ...generateArrowheadCardinalityOne(
19817
19618
  generator,
19818
- getArrowheadPoints(
19819
- element,
19820
- shape,
19821
- position,
19822
- "cardinality_one",
19823
- cardinalityOneOrManyOffset
19824
- ),
19619
+ getPoints("cardinality_one", cardinalityOneOrManyOffset),
19825
19620
  lineOptions
19826
19621
  )
19827
19622
  ];
@@ -19831,12 +19626,12 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19831
19626
  return [
19832
19627
  ...generateArrowheadCardinalityOne(
19833
19628
  generator,
19834
- getArrowheadPoints(element, shape, position, "cardinality_one", -0.5),
19629
+ getPoints("cardinality_one", -0.5),
19835
19630
  lineOptions
19836
19631
  ),
19837
19632
  ...generateArrowheadCardinalityOne(
19838
19633
  generator,
19839
- getArrowheadPoints(element, shape, position, "cardinality_one"),
19634
+ getPoints("cardinality_one"),
19840
19635
  lineOptions
19841
19636
  )
19842
19637
  ];
@@ -19848,13 +19643,13 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19848
19643
  generator,
19849
19644
  options,
19850
19645
  strokeColor,
19851
- getArrowheadPoints(element, shape, position, "circle_outline", 1.5),
19646
+ getPoints("circle_outline", 1.5),
19852
19647
  backgroundFillColor,
19853
19648
  cardinalityZeroCircleScale
19854
19649
  ),
19855
19650
  ...generateArrowheadCardinalityOne(
19856
19651
  generator,
19857
- getArrowheadPoints(element, shape, position, "cardinality_one", -0.5),
19652
+ getPoints("cardinality_one", -0.5),
19858
19653
  lineOptions
19859
19654
  )
19860
19655
  ];
@@ -19864,14 +19659,14 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19864
19659
  return [
19865
19660
  ...generateArrowheadLinesToTip(
19866
19661
  generator,
19867
- getArrowheadPoints(element, shape, position, "cardinality_many"),
19662
+ getPoints("cardinality_many"),
19868
19663
  lineOptions
19869
19664
  ),
19870
19665
  ...generateArrowheadOutlineCircle(
19871
19666
  generator,
19872
19667
  options,
19873
19668
  strokeColor,
19874
- getArrowheadPoints(element, shape, position, "circle_outline", 1.5),
19669
+ getPoints("circle_outline", 1.5),
19875
19670
  backgroundFillColor,
19876
19671
  cardinalityZeroCircleScale
19877
19672
  )
@@ -19882,7 +19677,7 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
19882
19677
  default: {
19883
19678
  return generateArrowheadLinesToTip(
19884
19679
  generator,
19885
- getArrowheadPoints(element, shape, position, arrowhead),
19680
+ getPoints(arrowhead),
19886
19681
  getArrowheadLineOptions(element, options)
19887
19682
  );
19888
19683
  }
@@ -19892,9 +19687,13 @@ var _generateElementShape = (element, generator, {
19892
19687
  isExporting,
19893
19688
  canvasBackgroundColor,
19894
19689
  embedsValidationStatus,
19895
- theme
19690
+ theme,
19691
+ zoom,
19692
+ renderScale
19896
19693
  }) => {
19897
- const isDarkMode = theme === THEME10.DARK;
19694
+ const renderZoom = zoom ?? 1;
19695
+ const resolvedRenderScale = renderScale ?? renderZoom;
19696
+ const isDarkMode = theme === THEME9.DARK;
19898
19697
  switch (element.type) {
19899
19698
  case "rectangle":
19900
19699
  case "iframe":
@@ -19913,7 +19712,9 @@ var _generateElementShape = (element, generator, {
19913
19712
  embedsValidationStatus
19914
19713
  ),
19915
19714
  true,
19916
- isDarkMode
19715
+ isDarkMode,
19716
+ renderZoom,
19717
+ resolvedRenderScale
19917
19718
  )
19918
19719
  );
19919
19720
  } else {
@@ -19929,7 +19730,9 @@ var _generateElementShape = (element, generator, {
19929
19730
  embedsValidationStatus
19930
19731
  ),
19931
19732
  false,
19932
- isDarkMode
19733
+ isDarkMode,
19734
+ renderZoom,
19735
+ resolvedRenderScale
19933
19736
  )
19934
19737
  );
19935
19738
  }
@@ -19953,7 +19756,13 @@ var _generateElementShape = (element, generator, {
19953
19756
  C ${leftX} ${leftY}, ${leftX} ${leftY}, ${leftX + verticalRadius} ${leftY - horizontalRadius}
19954
19757
  L ${topX - verticalRadius} ${topY + horizontalRadius}
19955
19758
  C ${topX} ${topY}, ${topX} ${topY}, ${topX + verticalRadius} ${topY + horizontalRadius}`,
19956
- generateRoughOptions(element, true, isDarkMode)
19759
+ generateRoughOptions(
19760
+ element,
19761
+ true,
19762
+ isDarkMode,
19763
+ renderZoom,
19764
+ resolvedRenderScale
19765
+ )
19957
19766
  );
19958
19767
  } else {
19959
19768
  shape = generator.polygon(
@@ -19963,7 +19772,112 @@ var _generateElementShape = (element, generator, {
19963
19772
  [bottomX, bottomY],
19964
19773
  [leftX, leftY]
19965
19774
  ],
19966
- generateRoughOptions(element, false, isDarkMode)
19775
+ generateRoughOptions(
19776
+ element,
19777
+ false,
19778
+ isDarkMode,
19779
+ renderZoom,
19780
+ resolvedRenderScale
19781
+ )
19782
+ );
19783
+ }
19784
+ return shape;
19785
+ }
19786
+ case "triangle": {
19787
+ let shape;
19788
+ const [topX, topY, leftX, leftY, rightX, rightY] = getTrianglePoints(element);
19789
+ if (element.roundness) {
19790
+ const leftEdgeLen = Math.hypot(topX - leftX, topY - leftY);
19791
+ const rightEdgeLen = Math.hypot(topX - rightX, topY - rightY);
19792
+ const bottomEdgeLen = Math.abs(rightX - leftX);
19793
+ const topLeftRadius = getCornerRadius(topX, element);
19794
+ const topRightRadius = getCornerRadius(element.width - topX, element);
19795
+ const bottomLeftRadius = getCornerRadius(topX, element);
19796
+ const bottomRightRadius = getCornerRadius(
19797
+ element.width - topX,
19798
+ element
19799
+ );
19800
+ const offsetAlongEdge = (vx, vy, nx, ny, r, edgeLen) => {
19801
+ const t2 = Math.min(r / edgeLen, 0.49);
19802
+ return [vx + t2 * (nx - vx), vy + t2 * (ny - vy)];
19803
+ };
19804
+ const [pTLx, pTLy] = offsetAlongEdge(
19805
+ topX,
19806
+ topY,
19807
+ leftX,
19808
+ leftY,
19809
+ topLeftRadius,
19810
+ leftEdgeLen
19811
+ );
19812
+ const [pTRx, pTRy] = offsetAlongEdge(
19813
+ topX,
19814
+ topY,
19815
+ rightX,
19816
+ rightY,
19817
+ topRightRadius,
19818
+ rightEdgeLen
19819
+ );
19820
+ const [pLTx, pLTy] = offsetAlongEdge(
19821
+ leftX,
19822
+ leftY,
19823
+ topX,
19824
+ topY,
19825
+ topLeftRadius,
19826
+ leftEdgeLen
19827
+ );
19828
+ const [pLBx, pLBy] = offsetAlongEdge(
19829
+ leftX,
19830
+ leftY,
19831
+ rightX,
19832
+ rightY,
19833
+ bottomLeftRadius,
19834
+ bottomEdgeLen
19835
+ );
19836
+ const [pRBx, pRBy] = offsetAlongEdge(
19837
+ rightX,
19838
+ rightY,
19839
+ leftX,
19840
+ leftY,
19841
+ bottomRightRadius,
19842
+ bottomEdgeLen
19843
+ );
19844
+ const [pRTx, pRTy] = offsetAlongEdge(
19845
+ rightX,
19846
+ rightY,
19847
+ topX,
19848
+ topY,
19849
+ topRightRadius,
19850
+ rightEdgeLen
19851
+ );
19852
+ shape = generator.path(
19853
+ `M ${pTLx} ${pTLy} L ${pLTx} ${pLTy}
19854
+ C ${leftX} ${leftY}, ${leftX} ${leftY}, ${pLBx} ${pLBy}
19855
+ L ${pRBx} ${pRBy}
19856
+ C ${rightX} ${rightY}, ${rightX} ${rightY}, ${pRTx} ${pRTy}
19857
+ L ${pTRx} ${pTRy}
19858
+ C ${topX} ${topY}, ${topX} ${topY}, ${pTLx} ${pTLy}`,
19859
+ generateRoughOptions(
19860
+ element,
19861
+ true,
19862
+ isDarkMode,
19863
+ renderZoom,
19864
+ resolvedRenderScale
19865
+ )
19866
+ );
19867
+ } else {
19868
+ shape = generator.polygon(
19869
+ [
19870
+ [topX, topY],
19871
+ [leftX, leftY],
19872
+ [rightX, rightY]
19873
+ ],
19874
+ generateRoughOptions(
19875
+ element,
19876
+ false,
19877
+ isDarkMode,
19878
+ renderZoom,
19879
+ resolvedRenderScale
19880
+ )
19967
19881
  );
19968
19882
  }
19969
19883
  return shape;
@@ -19974,199 +19888,585 @@ var _generateElementShape = (element, generator, {
19974
19888
  element.height / 2,
19975
19889
  element.width,
19976
19890
  element.height,
19977
- generateRoughOptions(element, false, isDarkMode)
19891
+ generateRoughOptions(
19892
+ element,
19893
+ false,
19894
+ isDarkMode,
19895
+ renderZoom,
19896
+ resolvedRenderScale
19897
+ )
19978
19898
  );
19979
19899
  return shape;
19980
19900
  }
19981
- case "line":
19982
- case "arrow": {
19983
- let shape;
19984
- const options = generateRoughOptions(element, false, isDarkMode);
19985
- const points = element.points.length ? element.points : [pointFrom18(0, 0)];
19986
- if (isElbowArrow6(element)) {
19987
- if (!points.every(
19988
- (point) => Math.abs(point[0]) <= 1e6 && Math.abs(point[1]) <= 1e6
19989
- )) {
19990
- console.error(
19991
- `Elbow arrow with extreme point positions detected. Arrow not rendered.`,
19992
- element.id,
19993
- JSON.stringify(points)
19994
- );
19995
- shape = [];
19996
- } else {
19997
- shape = [
19998
- generator.path(
19999
- generateElbowArrowShape(points, 16),
20000
- generateRoughOptions(element, true, isDarkMode)
20001
- )
20002
- ];
20003
- }
20004
- } else if (!element.roundness) {
20005
- if (options.fill) {
20006
- shape = [
20007
- generator.polygon(points, options)
20008
- ];
20009
- } else {
20010
- shape = [
20011
- generator.linearPath(points, options)
20012
- ];
19901
+ case "line":
19902
+ case "arrow": {
19903
+ let shape;
19904
+ const options = generateRoughOptions(
19905
+ element,
19906
+ false,
19907
+ isDarkMode,
19908
+ renderZoom,
19909
+ resolvedRenderScale
19910
+ );
19911
+ const points = element.points.length ? element.points : [pointFrom13(0, 0)];
19912
+ if (isElbowArrow6(element)) {
19913
+ if (!points.every(
19914
+ (point) => Math.abs(point[0]) <= 1e6 && Math.abs(point[1]) <= 1e6
19915
+ )) {
19916
+ console.error(
19917
+ `Elbow arrow with extreme point positions detected. Arrow not rendered.`,
19918
+ element.id,
19919
+ JSON.stringify(points)
19920
+ );
19921
+ shape = [];
19922
+ } else {
19923
+ shape = [
19924
+ generator.path(
19925
+ generateElbowArrowShape(points, 16),
19926
+ generateRoughOptions(
19927
+ element,
19928
+ true,
19929
+ isDarkMode,
19930
+ renderZoom,
19931
+ resolvedRenderScale
19932
+ )
19933
+ )
19934
+ ];
19935
+ }
19936
+ } else if (!element.roundness) {
19937
+ if (options.fill) {
19938
+ shape = [
19939
+ generator.polygon(points, options)
19940
+ ];
19941
+ } else {
19942
+ shape = [
19943
+ generator.linearPath(points, options)
19944
+ ];
19945
+ }
19946
+ } else {
19947
+ shape = [generator.curve(points, options)];
19948
+ }
19949
+ if (element.type === "arrow") {
19950
+ const { startArrowhead = null, endArrowhead = "arrow" } = element;
19951
+ if (startArrowhead !== null) {
19952
+ const shapes = getArrowheadShapes(
19953
+ element,
19954
+ shape,
19955
+ "start",
19956
+ startArrowhead,
19957
+ generator,
19958
+ options,
19959
+ canvasBackgroundColor,
19960
+ isDarkMode
19961
+ );
19962
+ shape.push(...shapes);
19963
+ }
19964
+ if (endArrowhead !== null) {
19965
+ if (endArrowhead === void 0) {
19966
+ }
19967
+ const shapes = getArrowheadShapes(
19968
+ element,
19969
+ shape,
19970
+ "end",
19971
+ endArrowhead,
19972
+ generator,
19973
+ options,
19974
+ canvasBackgroundColor,
19975
+ isDarkMode
19976
+ );
19977
+ shape.push(...shapes);
19978
+ }
19979
+ }
19980
+ return shape;
19981
+ }
19982
+ case "freedraw": {
19983
+ const shapes = [];
19984
+ if (isPathALoop3(element.points)) {
19985
+ const simplifiedPoints = simplify(
19986
+ element.points,
19987
+ 0.75
19988
+ );
19989
+ shapes.push(
19990
+ generator.curve(simplifiedPoints, {
19991
+ ...generateRoughOptions(
19992
+ element,
19993
+ false,
19994
+ isDarkMode,
19995
+ renderZoom,
19996
+ resolvedRenderScale
19997
+ ),
19998
+ stroke: "none"
19999
+ })
20000
+ );
20001
+ }
20002
+ shapes.push(
20003
+ getFreeDrawSvgPath(element, renderZoom, resolvedRenderScale)
20004
+ );
20005
+ return shapes;
20006
+ }
20007
+ case "frame":
20008
+ case "magicframe":
20009
+ case "text":
20010
+ case "image": {
20011
+ const shape = null;
20012
+ return shape;
20013
+ }
20014
+ default: {
20015
+ assertNever3(
20016
+ element,
20017
+ `generateElementShape(): Unimplemented type ${element?.type}`
20018
+ );
20019
+ return null;
20020
+ }
20021
+ }
20022
+ };
20023
+ var generateElbowArrowShape = (points, radius) => {
20024
+ const subpoints = [];
20025
+ for (let i = 1; i < points.length - 1; i += 1) {
20026
+ const prev = points[i - 1];
20027
+ const next = points[i + 1];
20028
+ const point = points[i];
20029
+ const prevIsHorizontal = headingForPointIsHorizontal(point, prev);
20030
+ const nextIsHorizontal = headingForPointIsHorizontal(next, point);
20031
+ const corner = Math.min(
20032
+ radius,
20033
+ pointDistance6(points[i], next) / 2,
20034
+ pointDistance6(points[i], prev) / 2
20035
+ );
20036
+ if (prevIsHorizontal) {
20037
+ if (prev[0] < point[0]) {
20038
+ subpoints.push([points[i][0] - corner, points[i][1]]);
20039
+ } else {
20040
+ subpoints.push([points[i][0] + corner, points[i][1]]);
20041
+ }
20042
+ } else if (prev[1] < point[1]) {
20043
+ subpoints.push([points[i][0], points[i][1] - corner]);
20044
+ } else {
20045
+ subpoints.push([points[i][0], points[i][1] + corner]);
20046
+ }
20047
+ subpoints.push(points[i]);
20048
+ if (nextIsHorizontal) {
20049
+ if (next[0] < point[0]) {
20050
+ subpoints.push([points[i][0] - corner, points[i][1]]);
20051
+ } else {
20052
+ subpoints.push([points[i][0] + corner, points[i][1]]);
20053
+ }
20054
+ } else if (next[1] < point[1]) {
20055
+ subpoints.push([points[i][0], points[i][1] - corner]);
20056
+ } else {
20057
+ subpoints.push([points[i][0], points[i][1] + corner]);
20058
+ }
20059
+ }
20060
+ const d = [`M ${points[0][0]} ${points[0][1]}`];
20061
+ for (let i = 0; i < subpoints.length; i += 3) {
20062
+ d.push(`L ${subpoints[i][0]} ${subpoints[i][1]}`);
20063
+ d.push(
20064
+ `Q ${subpoints[i + 1][0]} ${subpoints[i + 1][1]}, ${subpoints[i + 2][0]} ${subpoints[i + 2][1]}`
20065
+ );
20066
+ }
20067
+ d.push(`L ${points[points.length - 1][0]} ${points[points.length - 1][1]}`);
20068
+ return d.join(" ");
20069
+ };
20070
+ var getFreeDrawSvgPath = (element, zoom, renderScale = zoom) => {
20071
+ return getSvgPathFromStroke(
20072
+ getFreedrawOutlinePoints(element, zoom, renderScale)
20073
+ );
20074
+ };
20075
+ var getFreedrawOutlinePoints = (element, zoom = 1, renderScale = zoom) => {
20076
+ const inputPoints = element.simulatePressure ? element.points : element.points.length ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) : [[0, 0, 0.5]];
20077
+ return getStroke(inputPoints, {
20078
+ simulatePressure: element.simulatePressure,
20079
+ size: getEffectiveStrokeWidth(element, zoom, renderScale) * 4.25,
20080
+ thinning: 0.6,
20081
+ smoothing: 0.5,
20082
+ streamline: 0.5,
20083
+ easing: (t2) => Math.sin(t2 * Math.PI / 2),
20084
+ // https://easings.net/#easeOutSine
20085
+ last: true
20086
+ });
20087
+ };
20088
+ var med = (A, B) => {
20089
+ return [(A[0] + B[0]) / 2, (A[1] + B[1]) / 2];
20090
+ };
20091
+ var TO_FIXED_PRECISION = /(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g;
20092
+ var getSvgPathFromStroke = (points) => {
20093
+ if (!points.length) {
20094
+ return "";
20095
+ }
20096
+ const max = points.length - 1;
20097
+ return points.reduce(
20098
+ (acc, point, i, arr) => {
20099
+ if (i === max) {
20100
+ acc.push(point, med(point, arr[0]), "L", arr[0], "Z");
20101
+ } else {
20102
+ acc.push(point, med(point, arr[i + 1]));
20103
+ }
20104
+ return acc;
20105
+ },
20106
+ ["M", points[0], "Q"]
20107
+ ).join(" ").replace(TO_FIXED_PRECISION, "$1");
20108
+ };
20109
+
20110
+ // ../element/src/bounds.ts
20111
+ var getDiamondPoints = (element) => {
20112
+ const topX = Math.floor(element.width / 2) + 1;
20113
+ const topY = 0;
20114
+ const rightX = element.width;
20115
+ const rightY = Math.floor(element.height / 2) + 1;
20116
+ const bottomX = topX;
20117
+ const bottomY = element.height;
20118
+ const leftX = 0;
20119
+ const leftY = rightY;
20120
+ return [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY];
20121
+ };
20122
+ var getTrianglePoints = (element) => {
20123
+ const topX = Math.floor(element.width / 2) + 1;
20124
+ const topY = 0;
20125
+ const leftX = 0;
20126
+ const leftY = element.height;
20127
+ const rightX = element.width;
20128
+ const rightY = element.height;
20129
+ return [topX, topY, leftX, leftY, rightX, rightY];
20130
+ };
20131
+ var CARDINALITY_MARKER_SIZE = 20;
20132
+ var CROWFOOT_ARROWHEAD_SIZE = 15;
20133
+ var getArrowheadSize = (arrowhead) => {
20134
+ switch (arrowhead) {
20135
+ case "arrow":
20136
+ return 25;
20137
+ case "diamond":
20138
+ case "diamond_outline":
20139
+ return 12;
20140
+ case "cardinality_many":
20141
+ case "cardinality_one_or_many":
20142
+ case "cardinality_zero_or_many":
20143
+ return CROWFOOT_ARROWHEAD_SIZE;
20144
+ case "cardinality_one":
20145
+ case "cardinality_exactly_one":
20146
+ case "cardinality_zero_or_one":
20147
+ return CARDINALITY_MARKER_SIZE;
20148
+ default:
20149
+ return 15;
20150
+ }
20151
+ };
20152
+ var getArrowheadAngle = (arrowhead) => {
20153
+ switch (arrowhead) {
20154
+ case "bar":
20155
+ return 90;
20156
+ case "arrow":
20157
+ return 20;
20158
+ default:
20159
+ return 25;
20160
+ }
20161
+ };
20162
+ var getScaledArrowheadSize = (arrowhead, strokeWidth) => getArrowheadSize(arrowhead) * (strokeWidth / STROKE_WIDTH.bold);
20163
+ var getArrowheadPoints = (element, shape, position, arrowhead, offsetMultiplier = 0, renderStrokeWidth = element.strokeWidth) => {
20164
+ if (arrowhead === null) {
20165
+ return null;
20166
+ }
20167
+ if (shape.length < 1) {
20168
+ return null;
20169
+ }
20170
+ const ops = getCurvePathOps(shape[0]);
20171
+ if (ops.length < 1) {
20172
+ return null;
20173
+ }
20174
+ const index = position === "start" ? 1 : ops.length - 1;
20175
+ const data = ops[index].data;
20176
+ invariant12(data.length === 6, "Op data length is not 6");
20177
+ const p3 = pointFrom14(data[4], data[5]);
20178
+ const p2 = pointFrom14(data[2], data[3]);
20179
+ const p1 = pointFrom14(data[0], data[1]);
20180
+ const prevOp = ops[index - 1];
20181
+ let p0 = pointFrom14(0, 0);
20182
+ if (prevOp.op === "move") {
20183
+ const p = pointFromArray3(prevOp.data);
20184
+ invariant12(p != null, "Op data is not a point");
20185
+ p0 = p;
20186
+ } else if (prevOp.op === "bcurveTo") {
20187
+ p0 = pointFrom14(prevOp.data[4], prevOp.data[5]);
20188
+ }
20189
+ const equation = (t2, idx) => Math.pow(1 - t2, 3) * p3[idx] + 3 * t2 * Math.pow(1 - t2, 2) * p2[idx] + 3 * Math.pow(t2, 2) * (1 - t2) * p1[idx] + p0[idx] * Math.pow(t2, 3);
20190
+ const [x2, y2] = position === "start" ? p0 : p3;
20191
+ const [x1, y1] = [equation(0.3, 0), equation(0.3, 1)];
20192
+ const distance3 = Math.hypot(x2 - x1, y2 - y1);
20193
+ const nx = (x2 - x1) / distance3;
20194
+ const ny = (y2 - y1) / distance3;
20195
+ const size = getScaledArrowheadSize(arrowhead, renderStrokeWidth);
20196
+ let length = 0;
20197
+ {
20198
+ const [cx, cy] = position === "end" ? element.points[element.points.length - 1] : element.points[0];
20199
+ const [px, py] = element.points.length > 1 ? position === "end" ? element.points[element.points.length - 2] : element.points[1] : [0, 0];
20200
+ length = Math.hypot(cx - px, cy - py);
20201
+ }
20202
+ const lengthMultiplier = arrowhead === "diamond" || arrowhead === "diamond_outline" ? 0.25 : 0.5;
20203
+ const minSize = Math.min(size, length * lengthMultiplier);
20204
+ const tx = x2 - nx * minSize * offsetMultiplier;
20205
+ const ty = y2 - ny * minSize * offsetMultiplier;
20206
+ const xs = tx - nx * minSize;
20207
+ const ys = ty - ny * minSize;
20208
+ if (arrowhead === "circle" || arrowhead === "circle_outline") {
20209
+ const diameter = Math.hypot(ys - ty, xs - tx) + renderStrokeWidth - getDisplaySceneStrokeWidth2(1);
20210
+ return [tx, ty, diameter];
20211
+ }
20212
+ const angle = getArrowheadAngle(arrowhead);
20213
+ if (arrowhead === "cardinality_many" || arrowhead === "cardinality_one_or_many") {
20214
+ const [x32, y32] = pointRotateRads11(
20215
+ pointFrom14(tx, ty),
20216
+ pointFrom14(xs, ys),
20217
+ degreesToRadians(-angle)
20218
+ );
20219
+ const [x42, y42] = pointRotateRads11(
20220
+ pointFrom14(tx, ty),
20221
+ pointFrom14(xs, ys),
20222
+ degreesToRadians(angle)
20223
+ );
20224
+ return [xs, ys, x32, y32, x42, y42];
20225
+ }
20226
+ const [x3, y3] = pointRotateRads11(
20227
+ pointFrom14(xs, ys),
20228
+ pointFrom14(tx, ty),
20229
+ -angle * Math.PI / 180
20230
+ );
20231
+ const [x4, y4] = pointRotateRads11(
20232
+ pointFrom14(xs, ys),
20233
+ pointFrom14(tx, ty),
20234
+ degreesToRadians(angle)
20235
+ );
20236
+ if (arrowhead === "diamond" || arrowhead === "diamond_outline") {
20237
+ let ox;
20238
+ let oy;
20239
+ if (position === "start") {
20240
+ const [px, py] = element.points.length > 1 ? element.points[1] : [0, 0];
20241
+ [ox, oy] = pointRotateRads11(
20242
+ pointFrom14(tx + minSize * 2, ty),
20243
+ pointFrom14(tx, ty),
20244
+ Math.atan2(py - ty, px - tx)
20245
+ );
20246
+ } else {
20247
+ const [px, py] = element.points.length > 1 ? element.points[element.points.length - 2] : [0, 0];
20248
+ [ox, oy] = pointRotateRads11(
20249
+ pointFrom14(tx - minSize * 2, ty),
20250
+ pointFrom14(tx, ty),
20251
+ Math.atan2(ty - py, tx - px)
20252
+ );
20253
+ }
20254
+ return [tx, ty, x3, y3, ox, oy, x4, y4];
20255
+ }
20256
+ return [tx, ty, x3, y3, x4, y4];
20257
+ };
20258
+
20259
+ // ../element/src/renderElement.ts
20260
+ import {
20261
+ getSceneStrokeBorderForScreen,
20262
+ getSceneStrokeBorderForZoom,
20263
+ isCrispScreenStroke as isCrispScreenStroke2
20264
+ } from "@nous-excalidraw/common";
20265
+
20266
+ // ../element/src/cropElement.ts
20267
+ import {
20268
+ pointFrom as pointFrom15,
20269
+ pointCenter as pointCenter2,
20270
+ pointRotateRads as pointRotateRads12,
20271
+ vectorFromPoint as vectorFromPoint8,
20272
+ vectorNormalize as vectorNormalize4,
20273
+ vectorSubtract,
20274
+ vectorAdd as vectorAdd2,
20275
+ vectorScale as vectorScale7,
20276
+ pointFromVector as pointFromVector6,
20277
+ clamp as clamp4,
20278
+ isCloseTo
20279
+ } from "@nous-excalidraw/math";
20280
+
20281
+ // ../element/src/frame.ts
20282
+ import { arrayToMap as arrayToMap19 } from "@nous-excalidraw/common";
20283
+ import { isPointWithinBounds as isPointWithinBounds2, pointFrom as pointFrom17 } from "@nous-excalidraw/math";
20284
+
20285
+ // ../utils/src/bbox.ts
20286
+ import {
20287
+ vectorCross as vectorCross3,
20288
+ vectorFromPoint as vectorFromPoint9
20289
+ } from "@nous-excalidraw/math";
20290
+
20291
+ // ../element/src/selection.ts
20292
+ import { arrayToMap as arrayToMap18, isShallowEqual as isShallowEqual3 } from "@nous-excalidraw/common";
20293
+ import {
20294
+ lineSegment as lineSegment6,
20295
+ pointFrom as pointFrom16,
20296
+ pointRotateRads as pointRotateRads13
20297
+ } from "@nous-excalidraw/math";
20298
+
20299
+ // ../element/src/groups.ts
20300
+ var selectGroupsForSelectedElements5 = function() {
20301
+ let lastSelectedElements = null;
20302
+ let lastElements = null;
20303
+ let lastReturnValue = null;
20304
+ const _selectGroups = (selectedElements, elements, appState, prevAppState) => {
20305
+ if (lastReturnValue !== void 0 && elements === lastElements && selectedElements === lastSelectedElements && appState.editingGroupId === lastReturnValue?.editingGroupId) {
20306
+ return lastReturnValue;
20307
+ }
20308
+ const selectedGroupIds = {};
20309
+ for (const selectedElement of selectedElements) {
20310
+ let groupIds = selectedElement.groupIds;
20311
+ if (appState.editingGroupId) {
20312
+ const indexOfEditingGroup = groupIds.indexOf(appState.editingGroupId);
20313
+ if (indexOfEditingGroup > -1) {
20314
+ groupIds = groupIds.slice(0, indexOfEditingGroup);
20013
20315
  }
20014
- } else {
20015
- shape = [generator.curve(points, options)];
20016
20316
  }
20017
- if (element.type === "arrow") {
20018
- const { startArrowhead = null, endArrowhead = "arrow" } = element;
20019
- if (startArrowhead !== null) {
20020
- const shapes = getArrowheadShapes(
20021
- element,
20022
- shape,
20023
- "start",
20024
- startArrowhead,
20025
- generator,
20026
- options,
20027
- canvasBackgroundColor,
20028
- isDarkMode
20029
- );
20030
- shape.push(...shapes);
20317
+ if (groupIds.length > 0) {
20318
+ const lastSelectedGroup = groupIds[groupIds.length - 1];
20319
+ selectedGroupIds[lastSelectedGroup] = true;
20320
+ }
20321
+ }
20322
+ const groupElementsIndex = {};
20323
+ const selectedElementIdsInGroups = elements.reduce(
20324
+ (acc, element) => {
20325
+ if (element.isDeleted) {
20326
+ return acc;
20031
20327
  }
20032
- if (endArrowhead !== null) {
20033
- if (endArrowhead === void 0) {
20328
+ const groupId = element.groupIds.find((id) => selectedGroupIds[id]);
20329
+ if (groupId) {
20330
+ acc[element.id] = true;
20331
+ if (!Array.isArray(groupElementsIndex[groupId])) {
20332
+ groupElementsIndex[groupId] = [element.id];
20333
+ } else {
20334
+ groupElementsIndex[groupId].push(element.id);
20034
20335
  }
20035
- const shapes = getArrowheadShapes(
20036
- element,
20037
- shape,
20038
- "end",
20039
- endArrowhead,
20040
- generator,
20041
- options,
20042
- canvasBackgroundColor,
20043
- isDarkMode
20044
- );
20045
- shape.push(...shapes);
20336
+ }
20337
+ return acc;
20338
+ },
20339
+ {}
20340
+ );
20341
+ for (const groupId of Object.keys(groupElementsIndex)) {
20342
+ if (groupElementsIndex[groupId].length < 2) {
20343
+ if (selectedGroupIds[groupId]) {
20344
+ selectedGroupIds[groupId] = false;
20046
20345
  }
20047
20346
  }
20048
- return shape;
20049
- }
20050
- case "freedraw": {
20051
- const shapes = [];
20052
- if (isPathALoop2(element.points)) {
20053
- const simplifiedPoints = simplify(
20054
- element.points,
20055
- 0.75
20056
- );
20057
- shapes.push(
20058
- generator.curve(simplifiedPoints, {
20059
- ...generateRoughOptions(element, false, isDarkMode),
20060
- stroke: "none"
20061
- })
20062
- );
20063
- }
20064
- shapes.push(getFreeDrawSvgPath(element));
20065
- return shapes;
20066
20347
  }
20067
- case "frame":
20068
- case "magicframe":
20069
- case "text":
20070
- case "image": {
20071
- const shape = null;
20072
- return shape;
20348
+ lastElements = elements;
20349
+ lastSelectedElements = selectedElements;
20350
+ lastReturnValue = {
20351
+ editingGroupId: appState.editingGroupId,
20352
+ selectedGroupIds,
20353
+ selectedElementIds: makeNextSelectedElementIds2(
20354
+ {
20355
+ ...appState.selectedElementIds,
20356
+ ...selectedElementIdsInGroups
20357
+ },
20358
+ prevAppState
20359
+ )
20360
+ };
20361
+ return lastReturnValue;
20362
+ };
20363
+ const selectGroupsForSelectedElements8 = (appState, elements, prevAppState, app) => {
20364
+ const selectedElements = app ? app.scene.getSelectedElements({
20365
+ selectedElementIds: appState.selectedElementIds,
20366
+ // supplying elements explicitly in case we're passed non-state elements
20367
+ elements
20368
+ }) : getSelectedElements3(elements, appState);
20369
+ if (!selectedElements.length) {
20370
+ return {
20371
+ selectedGroupIds: {},
20372
+ editingGroupId: null,
20373
+ selectedElementIds: makeNextSelectedElementIds2(
20374
+ appState.selectedElementIds,
20375
+ prevAppState
20376
+ )
20377
+ };
20073
20378
  }
20074
- default: {
20075
- assertNever3(
20076
- element,
20077
- `generateElementShape(): Unimplemented type ${element?.type}`
20078
- );
20079
- return null;
20379
+ return _selectGroups(selectedElements, elements, appState, prevAppState);
20380
+ };
20381
+ selectGroupsForSelectedElements8.clearCache = () => {
20382
+ lastElements = null;
20383
+ lastSelectedElements = null;
20384
+ lastReturnValue = null;
20385
+ };
20386
+ return selectGroupsForSelectedElements8;
20387
+ }();
20388
+
20389
+ // ../element/src/selection.ts
20390
+ var isSomeElementSelected3 = function() {
20391
+ let lastElements = null;
20392
+ let lastSelectedElementIds = null;
20393
+ let isSelected = null;
20394
+ const ret = (elements, appState) => {
20395
+ if (isSelected != null && elements === lastElements && appState.selectedElementIds === lastSelectedElementIds) {
20396
+ return isSelected;
20080
20397
  }
20081
- }
20082
- };
20083
- var generateElbowArrowShape = (points, radius) => {
20084
- const subpoints = [];
20085
- for (let i = 1; i < points.length - 1; i += 1) {
20086
- const prev = points[i - 1];
20087
- const next = points[i + 1];
20088
- const point = points[i];
20089
- const prevIsHorizontal = headingForPointIsHorizontal(point, prev);
20090
- const nextIsHorizontal = headingForPointIsHorizontal(next, point);
20091
- const corner = Math.min(
20092
- radius,
20093
- pointDistance7(points[i], next) / 2,
20094
- pointDistance7(points[i], prev) / 2
20398
+ isSelected = elements.some(
20399
+ (element) => appState.selectedElementIds[element.id]
20095
20400
  );
20096
- if (prevIsHorizontal) {
20097
- if (prev[0] < point[0]) {
20098
- subpoints.push([points[i][0] - corner, points[i][1]]);
20099
- } else {
20100
- subpoints.push([points[i][0] + corner, points[i][1]]);
20101
- }
20102
- } else if (prev[1] < point[1]) {
20103
- subpoints.push([points[i][0], points[i][1] - corner]);
20104
- } else {
20105
- subpoints.push([points[i][0], points[i][1] + corner]);
20401
+ lastElements = elements;
20402
+ lastSelectedElementIds = appState.selectedElementIds;
20403
+ return isSelected;
20404
+ };
20405
+ ret.clearCache = () => {
20406
+ lastElements = null;
20407
+ lastSelectedElementIds = null;
20408
+ isSelected = null;
20409
+ };
20410
+ return ret;
20411
+ }();
20412
+ var getSelectedElements3 = (elements, appState, opts) => {
20413
+ const addedElements = /* @__PURE__ */ new Set();
20414
+ const selectedElements = [];
20415
+ for (const element of elements.values()) {
20416
+ if (appState.selectedElementIds[element.id]) {
20417
+ selectedElements.push(element);
20418
+ addedElements.add(element.id);
20419
+ continue;
20106
20420
  }
20107
- subpoints.push(points[i]);
20108
- if (nextIsHorizontal) {
20109
- if (next[0] < point[0]) {
20110
- subpoints.push([points[i][0] - corner, points[i][1]]);
20111
- } else {
20112
- subpoints.push([points[i][0] + corner, points[i][1]]);
20113
- }
20114
- } else if (next[1] < point[1]) {
20115
- subpoints.push([points[i][0], points[i][1] - corner]);
20116
- } else {
20117
- subpoints.push([points[i][0], points[i][1] + corner]);
20421
+ if (opts?.includeBoundTextElement && isBoundToContainer5(element) && appState.selectedElementIds[element?.containerId]) {
20422
+ selectedElements.push(element);
20423
+ addedElements.add(element.id);
20424
+ continue;
20118
20425
  }
20119
20426
  }
20120
- const d = [`M ${points[0][0]} ${points[0][1]}`];
20121
- for (let i = 0; i < subpoints.length; i += 3) {
20122
- d.push(`L ${subpoints[i][0]} ${subpoints[i][1]}`);
20123
- d.push(
20124
- `Q ${subpoints[i + 1][0]} ${subpoints[i + 1][1]}, ${subpoints[i + 2][0]} ${subpoints[i + 2][1]}`
20125
- );
20427
+ if (opts?.includeElementsInFrames) {
20428
+ const elementsToInclude = [];
20429
+ selectedElements.forEach((element) => {
20430
+ if (isFrameLikeElement7(element)) {
20431
+ getFrameChildren2(elements, element.id).forEach(
20432
+ (e) => !addedElements.has(e.id) && elementsToInclude.push(e)
20433
+ );
20434
+ }
20435
+ elementsToInclude.push(element);
20436
+ });
20437
+ return elementsToInclude;
20126
20438
  }
20127
- d.push(`L ${points[points.length - 1][0]} ${points[points.length - 1][1]}`);
20128
- return d.join(" ");
20129
- };
20130
- var getFreeDrawSvgPath = (element) => {
20131
- return getSvgPathFromStroke(
20132
- getFreedrawOutlinePoints(element)
20133
- );
20134
- };
20135
- var getFreedrawOutlinePoints = (element) => {
20136
- const inputPoints = element.simulatePressure ? element.points : element.points.length ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) : [[0, 0, 0.5]];
20137
- return getStroke(inputPoints, {
20138
- simulatePressure: element.simulatePressure,
20139
- size: element.strokeWidth * 4.25,
20140
- thinning: 0.6,
20141
- smoothing: 0.5,
20142
- streamline: 0.5,
20143
- easing: (t2) => Math.sin(t2 * Math.PI / 2),
20144
- // https://easings.net/#easeOutSine
20145
- last: true
20146
- });
20439
+ return selectedElements;
20147
20440
  };
20148
- var med = (A, B) => {
20149
- return [(A[0] + B[0]) / 2, (A[1] + B[1]) / 2];
20441
+ var makeNextSelectedElementIds2 = (nextSelectedElementIds, prevState) => {
20442
+ if (isShallowEqual3(prevState.selectedElementIds, nextSelectedElementIds)) {
20443
+ return prevState.selectedElementIds;
20444
+ }
20445
+ return nextSelectedElementIds;
20150
20446
  };
20151
- var TO_FIXED_PRECISION = /(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g;
20152
- var getSvgPathFromStroke = (points) => {
20153
- if (!points.length) {
20154
- return "";
20447
+
20448
+ // ../element/src/frame.ts
20449
+ var getFrameChildren2 = (allElements, frameId) => {
20450
+ const frameChildren = [];
20451
+ for (const element of allElements.values()) {
20452
+ if (element.frameId === frameId) {
20453
+ frameChildren.push(element);
20454
+ }
20155
20455
  }
20156
- const max = points.length - 1;
20157
- return points.reduce(
20158
- (acc, point, i, arr) => {
20159
- if (i === max) {
20160
- acc.push(point, med(point, arr[0]), "L", arr[0], "Z");
20161
- } else {
20162
- acc.push(point, med(point, arr[i + 1]));
20163
- }
20164
- return acc;
20165
- },
20166
- ["M", points[0], "Q"]
20167
- ).join(" ").replace(TO_FIXED_PRECISION, "$1");
20456
+ return frameChildren;
20168
20457
  };
20169
20458
 
20459
+ // ../element/src/renderElement.ts
20460
+ var IMAGE_PLACEHOLDER_IMG = typeof document !== "undefined" ? document.createElement("img") : { src: "" };
20461
+ IMAGE_PLACEHOLDER_IMG.src = `data:${MIME_TYPES7.svg},${encodeURIComponent(
20462
+ `<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="image" class="svg-inline--fa fa-image fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#888" d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>`
20463
+ )}`;
20464
+ var IMAGE_ERROR_PLACEHOLDER_IMG = typeof document !== "undefined" ? document.createElement("img") : { src: "" };
20465
+ IMAGE_ERROR_PLACEHOLDER_IMG.src = `data:${MIME_TYPES7.svg},${encodeURIComponent(
20466
+ `<svg viewBox="0 0 668 668" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48ZM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56ZM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.81709 0 0 .81709 124.825 145.825)"/><path d="M256 8C119.034 8 8 119.033 8 256c0 136.967 111.034 248 248 248s248-111.034 248-248S392.967 8 256 8Zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676ZM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.30366 0 0 .30366 506.822 60.065)"/></svg>`
20467
+ )}`;
20468
+ var elementWithCanvasCache = /* @__PURE__ */ new WeakMap();
20469
+
20170
20470
  // ../element/src/mutateElement.ts
20171
20471
  var newElementWith9 = (element, updates, force = false) => {
20172
20472
  let didChange = false;
@@ -21229,7 +21529,7 @@ var getElementsCorners = (elements, elementsMap, {
21229
21529
  }
21230
21530
  const halfWidth = (x2 - x1) / 2;
21231
21531
  const halfHeight = (y2 - y1) / 2;
21232
- if ((element.type === "diamond" || element.type === "ellipse") && !boundingBoxCorners) {
21532
+ if ((element.type === "diamond" || element.type === "triangle" || element.type === "ellipse") && !boundingBoxCorners) {
21233
21533
  const leftMid = pointRotateRads15(
21234
21534
  pointFrom19(x1, y1 + halfHeight),
21235
21535
  pointFrom19(cx, cy),
@@ -22113,7 +22413,7 @@ var getSnapLinesAtPointer = (elements, app, pointer, event, elementsMap) => {
22113
22413
  };
22114
22414
  };
22115
22415
  var isActiveToolNonLinearSnappable = (activeToolType) => {
22116
- return activeToolType === TOOL_TYPE.rectangle || activeToolType === TOOL_TYPE.ellipse || activeToolType === TOOL_TYPE.diamond || activeToolType === TOOL_TYPE.frame || activeToolType === TOOL_TYPE.magicframe || activeToolType === TOOL_TYPE.image || activeToolType === TOOL_TYPE.text;
22416
+ return activeToolType === TOOL_TYPE.rectangle || activeToolType === TOOL_TYPE.ellipse || activeToolType === TOOL_TYPE.diamond || activeToolType === TOOL_TYPE.triangle || activeToolType === TOOL_TYPE.frame || activeToolType === TOOL_TYPE.magicframe || activeToolType === TOOL_TYPE.image || activeToolType === TOOL_TYPE.text;
22117
22417
  };
22118
22418
 
22119
22419
  // scene/Renderer.ts
@@ -22590,7 +22890,8 @@ import {
22590
22890
  isTestEnv as isTestEnv4,
22591
22891
  MIME_TYPES as MIME_TYPES8,
22592
22892
  applyDarkModeFilter as applyDarkModeFilter3,
22593
- isRTL as isRTL2
22893
+ isRTL as isRTL2,
22894
+ sceneFontSizeToScreen
22594
22895
  } from "@nous-excalidraw/common";
22595
22896
  import { pointFrom as pointFrom21, pointRotateRads as pointRotateRads17 } from "@nous-excalidraw/math";
22596
22897
  import {
@@ -22623,18 +22924,12 @@ import {
22623
22924
  isBoundToContainer as isBoundToContainer7,
22624
22925
  isTextElement as isTextElement9
22625
22926
  } from "@nous-excalidraw/element";
22626
- var getTransform = (width, height, angle, appState, maxWidth, maxHeight) => {
22627
- const { zoom } = appState;
22628
- const degree = 180 * angle / Math.PI;
22629
- let translateX = width * (zoom.value - 1) / 2;
22630
- let translateY = height * (zoom.value - 1) / 2;
22631
- if (width > maxWidth && zoom.value !== 1) {
22632
- translateX = maxWidth * (zoom.value - 1) / 2;
22633
- }
22634
- if (height > maxHeight && zoom.value !== 1) {
22635
- translateY = maxHeight * (zoom.value - 1) / 2;
22927
+ var getTransform = (angle) => {
22928
+ if (!angle) {
22929
+ return "none";
22636
22930
  }
22637
- return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
22931
+ const degree = 180 * angle / Math.PI;
22932
+ return `rotate(${degree}deg)`;
22638
22933
  };
22639
22934
  var getLineDirection = (text, offset) => {
22640
22935
  const hardLineStart = text.lastIndexOf("\n", Math.max(0, offset - 1)) + 1;
@@ -22733,7 +23028,11 @@ var textWysiwyg = ({
22733
23028
  if (getFontFamilyString3({ fontFamily: updatedTextElement.fontFamily }) !== currentFont) {
22734
23029
  return true;
22735
23030
  }
22736
- if (`${updatedTextElement.fontSize}px` !== editable2.style.fontSize) {
23031
+ const screenFontSize = sceneFontSizeToScreen(
23032
+ updatedTextElement.fontSize,
23033
+ app.state.zoom.value
23034
+ );
23035
+ if (`${screenFontSize}px` !== editable2.style.fontSize) {
22737
23036
  return true;
22738
23037
  }
22739
23038
  return false;
@@ -22830,25 +23129,29 @@ var textWysiwyg = ({
22830
23129
  width += 0.5;
22831
23130
  }
22832
23131
  height *= 1.05;
22833
- const font = getFontString7(updatedTextElement);
23132
+ const zoom = appState.zoom.value;
23133
+ const screenFontSize = sceneFontSizeToScreen(
23134
+ updatedTextElement.fontSize,
23135
+ zoom
23136
+ );
23137
+ const font = getFontString7({
23138
+ fontSize: screenFontSize,
23139
+ fontFamily: updatedTextElement.fontFamily
23140
+ });
22834
23141
  const angle = getTextElementAngle(updatedTextElement, container);
22835
- const editorMaxHeight = (appState.height - viewportY) / appState.zoom.value;
23142
+ const screenWidth = width * zoom;
23143
+ const screenHeight = height * zoom;
23144
+ const editorMaxHeight = appState.height - viewportY;
22836
23145
  Object.assign(editable.style, {
22837
23146
  font,
22838
23147
  // must be defined *after* font ¯\_(ツ)_/¯
22839
23148
  lineHeight: updatedTextElement.lineHeight,
22840
- width: `${width}px`,
22841
- height: `${height}px`,
23149
+ width: `${screenWidth}px`,
23150
+ height: `${screenHeight}px`,
22842
23151
  left: `${viewportX}px`,
22843
23152
  top: `${viewportY}px`,
22844
- transform: getTransform(
22845
- width,
22846
- height,
22847
- angle,
22848
- appState,
22849
- maxWidth,
22850
- editorMaxHeight
22851
- ),
23153
+ transform: getTransform(angle),
23154
+ transformOrigin: "left top",
22852
23155
  textAlign,
22853
23156
  verticalAlign,
22854
23157
  color: appState.theme === THEME11.DARK ? applyDarkModeFilter3(updatedTextElement.strokeColor) : updatedTextElement.strokeColor,
@@ -23656,6 +23959,7 @@ import {
23656
23959
  getElementBounds as getElementBounds3,
23657
23960
  getElementLineSegments as getElementLineSegments3,
23658
23961
  getFreedrawOutlineAsSegments,
23962
+ getEffectiveStrokeWidth as getEffectiveStrokeWidth2,
23659
23963
  getFreedrawOutlinePoints as getFreedrawOutlinePoints2,
23660
23964
  intersectElementWithLineSegment as intersectElementWithLineSegment3,
23661
23965
  isArrowElement as isArrowElement9,
@@ -23792,7 +24096,8 @@ var EraserTrail = class extends AnimatedTrail {
23792
24096
  };
23793
24097
  var eraserTest = (pathSegment, element, elementsMap, zoom) => {
23794
24098
  const lastPoint = pathSegment[1];
23795
- const threshold = isFreeDrawElement3(element) ? 15 : element.strokeWidth / 2;
24099
+ const effectiveStrokeWidth = getEffectiveStrokeWidth2(element, zoom);
24100
+ const threshold = isFreeDrawElement3(element) ? 15 : effectiveStrokeWidth / 2;
23796
24101
  const segmentBounds = [
23797
24102
  Math.min(pathSegment[0][0], pathSegment[1][0]) - threshold,
23798
24103
  Math.min(pathSegment[0][1], pathSegment[1][1]) - threshold,
@@ -23813,7 +24118,7 @@ var eraserTest = (pathSegment, element, elementsMap, zoom) => {
23813
24118
  return true;
23814
24119
  }
23815
24120
  if (isFreeDrawElement3(element)) {
23816
- const outlinePoints = getFreedrawOutlinePoints2(element);
24121
+ const outlinePoints = getFreedrawOutlinePoints2(element, zoom);
23817
24122
  const strokeSegments = getFreedrawOutlineAsSegments(
23818
24123
  element,
23819
24124
  outlinePoints,
@@ -23838,8 +24143,8 @@ var eraserTest = (pathSegment, element, elementsMap, zoom) => {
23838
24143
  const boundTextElement = getBoundTextElement8(element, elementsMap);
23839
24144
  if (isArrowElement9(element) || isLineElement5(element) && !element.polygon) {
23840
24145
  const tolerance = Math.max(
23841
- element.strokeWidth,
23842
- element.strokeWidth * 2 / zoom
24146
+ effectiveStrokeWidth,
24147
+ effectiveStrokeWidth * 2 / zoom
23843
24148
  );
23844
24149
  const segments = getElementLineSegments3(element, elementsMap);
23845
24150
  for (const seg of segments) {
@@ -23869,7 +24174,7 @@ import { newElement as newElement4 } from "@nous-excalidraw/element";
23869
24174
  import {
23870
24175
  COLOR_PALETTE as COLOR_PALETTE5,
23871
24176
  DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY4,
23872
- DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE5,
24177
+ DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE4,
23873
24178
  VERTICAL_ALIGN as VERTICAL_ALIGN4
23874
24179
  } from "@nous-excalidraw/common";
23875
24180
  var CARTESIAN_BASE_SLOT_WIDTH = 44;
@@ -23902,7 +24207,7 @@ var RADAR_LEGEND_TEXT_GAP = BAR_GAP;
23902
24207
  var commonProps = {
23903
24208
  fillStyle: "hachure",
23904
24209
  fontFamily: DEFAULT_FONT_FAMILY4,
23905
- fontSize: DEFAULT_FONT_SIZE5,
24210
+ fontSize: DEFAULT_FONT_SIZE4,
23906
24211
  opacity: 100,
23907
24212
  roughness: 1,
23908
24213
  strokeColor: COLOR_PALETTE5.black,
@@ -23919,9 +24224,9 @@ import {
23919
24224
  COLOR_PALETTE as COLOR_PALETTE6,
23920
24225
  DEFAULT_CHART_COLOR_INDEX,
23921
24226
  FONT_FAMILY as FONT_FAMILY4,
23922
- FONT_SIZES as FONT_SIZES2,
24227
+ FONT_SIZES,
23923
24228
  ROUNDNESS as ROUNDNESS6,
23924
- DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE6,
24229
+ DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE5,
23925
24230
  getAllColorsSpecificShade,
23926
24231
  getFontString as getFontString8,
23927
24232
  getLineHeight as getLineHeight3,
@@ -24069,7 +24374,7 @@ var getRadarDisplayText = (text, fontString, maxWidth) => {
24069
24374
  };
24070
24375
  var createRadarAxisLabels = (labels, angles, centerX, centerY, radius, backgroundColor) => {
24071
24376
  const fontFamily = FONT_FAMILY4.Excalifont;
24072
- const fontSize = FONT_SIZES2.sm;
24377
+ const fontSize = FONT_SIZES.sm;
24073
24378
  const lineHeight = getLineHeight3(fontFamily);
24074
24379
  const fontString = getFontString8({ fontFamily, fontSize });
24075
24380
  const baseLabelWidth = Math.min(
@@ -24124,7 +24429,7 @@ var createSeriesLegend = (series, seriesColors, centerX, minLegendTopY, fallback
24124
24429
  return [];
24125
24430
  }
24126
24431
  const fontFamily = FONT_FAMILY4["Lilita One"];
24127
- const fontSize = FONT_SIZES2.lg;
24432
+ const fontSize = FONT_SIZES.lg;
24128
24433
  const lineHeight = getLineHeight3(fontFamily);
24129
24434
  const fontString = getFontString8({ fontFamily, fontSize });
24130
24435
  const legendItems = series.map((seriesItem, index) => {
@@ -24342,7 +24647,7 @@ var getRotatedTextElementBottom = (element) => {
24342
24647
  };
24343
24648
  var chartXLabels = (spreadsheet, x, y, backgroundColor, layout) => {
24344
24649
  const fontFamily = commonProps.fontFamily;
24345
- const fontSize = FONT_SIZES2.sm;
24650
+ const fontSize = FONT_SIZES.sm;
24346
24651
  const lineHeight = getLineHeight3(fontFamily);
24347
24652
  const fontString = getFontString8({ fontFamily, fontSize });
24348
24653
  const maxRotatedWidth = Math.max(
@@ -24435,10 +24740,10 @@ var chartBaseElements = (spreadsheet, x, y, backgroundColor, layout, maxValue =
24435
24740
  ...commonProps,
24436
24741
  text: spreadsheet.title,
24437
24742
  x: x + chartWidth / 2,
24438
- y: y - layout.chartHeight - layout.gap * 2 - DEFAULT_FONT_SIZE6,
24743
+ y: y - layout.chartHeight - layout.gap * 2 - DEFAULT_FONT_SIZE5,
24439
24744
  roundness: null,
24440
24745
  textAlign: "center",
24441
- fontSize: FONT_SIZES2.xl,
24746
+ fontSize: FONT_SIZES.xl,
24442
24747
  fontFamily: FONT_FAMILY4["Lilita One"]
24443
24748
  }) : null;
24444
24749
  const debugRect = debug ? newElement3({
@@ -24749,7 +25054,7 @@ var tryParseSpreadsheet = (text) => {
24749
25054
  import { pointFrom as pointFrom26 } from "@nous-excalidraw/math";
24750
25055
  import {
24751
25056
  FONT_FAMILY as FONT_FAMILY5,
24752
- FONT_SIZES as FONT_SIZES3,
25057
+ FONT_SIZES as FONT_SIZES2,
24753
25058
  getFontString as getFontString9,
24754
25059
  getLineHeight as getLineHeight4,
24755
25060
  ROUGHNESS as ROUGHNESS3
@@ -24785,7 +25090,7 @@ var renderRadarChart = (spreadsheet, x, y, colorSeed) => {
24785
25090
  backgroundColor
24786
25091
  );
24787
25092
  const titleFontFamily = FONT_FAMILY5["Lilita One"];
24788
- const titleFontSize = FONT_SIZES3.xl;
25093
+ const titleFontSize = FONT_SIZES2.xl;
24789
25094
  const titleLineHeight = getLineHeight4(titleFontFamily);
24790
25095
  const titleFontString = getFontString9({
24791
25096
  fontFamily: titleFontFamily,
@@ -25279,6 +25584,11 @@ var SHAPE_TOOLS = [
25279
25584
  icon: DiamondIcon,
25280
25585
  title: capitalizeString4(t("toolBar.diamond"))
25281
25586
  },
25587
+ {
25588
+ type: "triangle",
25589
+ icon: TriangleIcon,
25590
+ title: capitalizeString4(t("toolBar.triangle"))
25591
+ },
25282
25592
  {
25283
25593
  type: "ellipse",
25284
25594
  icon: EllipseIcon,
@@ -25315,7 +25625,7 @@ var MobileToolBar = ({
25315
25625
  const [lastActiveGenericShape, setLastActiveGenericShape] = useState27("rectangle");
25316
25626
  const [lastActiveLinearElement, setLastActiveLinearElement] = useState27("arrow");
25317
25627
  useEffect31(() => {
25318
- if (activeTool.type === "rectangle" || activeTool.type === "diamond" || activeTool.type === "ellipse") {
25628
+ if (activeTool.type === "rectangle" || activeTool.type === "diamond" || activeTool.type === "triangle" || activeTool.type === "ellipse") {
25319
25629
  setLastActiveGenericShape(activeTool.type);
25320
25630
  }
25321
25631
  }, [activeTool.type]);
@@ -25454,12 +25764,12 @@ var MobileToolBar = ({
25454
25764
  namePrefix: "shapeType",
25455
25765
  title: capitalizeString4(
25456
25766
  t(
25457
- lastActiveGenericShape === "rectangle" ? "toolBar.rectangle" : lastActiveGenericShape === "diamond" ? "toolBar.diamond" : lastActiveGenericShape === "ellipse" ? "toolBar.ellipse" : "toolBar.rectangle"
25767
+ lastActiveGenericShape === "rectangle" ? "toolBar.rectangle" : lastActiveGenericShape === "diamond" ? "toolBar.diamond" : lastActiveGenericShape === "triangle" ? "toolBar.triangle" : lastActiveGenericShape === "ellipse" ? "toolBar.ellipse" : "toolBar.rectangle"
25458
25768
  )
25459
25769
  ),
25460
25770
  "data-testid": "toolbar-rectangle",
25461
25771
  onToolChange: (type) => {
25462
- if (type === "rectangle" || type === "diamond" || type === "ellipse") {
25772
+ if (type === "rectangle" || type === "diamond" || type === "triangle" || type === "ellipse") {
25463
25773
  setLastActiveGenericShape(type);
25464
25774
  app.setActiveTool({ type });
25465
25775
  }
@@ -25855,6 +26165,13 @@ var getNonLinearElementRelativePoints = (element) => {
25855
26165
  pointFrom27(0, element.height / 2)
25856
26166
  ];
25857
26167
  }
26168
+ if (element.type === "triangle") {
26169
+ return [
26170
+ pointFrom27(element.width / 2, 0),
26171
+ pointFrom27(0, element.height),
26172
+ pointFrom27(element.width, element.height)
26173
+ ];
26174
+ }
25858
26175
  return [
25859
26176
  pointFrom27(0, 0),
25860
26177
  pointFrom27(0 + element.width, 0),
@@ -28464,7 +28781,7 @@ var TTDDialogInput = ({
28464
28781
  setShowSpinner(true);
28465
28782
  }
28466
28783
  }, SPINNER_DELAY_MS);
28467
- import("./components/TTDDialog/CodeMirrorEditor-T4CL43BJ.js").then((mod) => {
28784
+ import("./components/TTDDialog/CodeMirrorEditor-LUWBT76B.js").then((mod) => {
28468
28785
  if (!cancelled) {
28469
28786
  setEditorState({ type: "ready", component: mod.default });
28470
28787
  }
@@ -31381,15 +31698,15 @@ import {
31381
31698
  getUncroppedWidthAndHeight
31382
31699
  } from "@nous-excalidraw/element";
31383
31700
  import { resizeSingleElement } from "@nous-excalidraw/element";
31384
- import { isImageElement as isImageElement4 } from "@nous-excalidraw/element";
31701
+ import {
31702
+ isImageElement as isImageElement4,
31703
+ shouldForceMaintainAspectRatio
31704
+ } from "@nous-excalidraw/element";
31385
31705
  import { isFrameLikeElement as isFrameLikeElement12 } from "@nous-excalidraw/element";
31386
31706
  import { getElementsInResizingFrame as getElementsInResizingFrame2 } from "@nous-excalidraw/element";
31387
31707
  import { replaceAllElementsInFrame as replaceAllElementsInFrame2 } from "@nous-excalidraw/element";
31388
31708
  import { jsx as jsx137 } from "react/jsx-runtime";
31389
31709
  var STEP_SIZE4 = 10;
31390
- var _shouldKeepAspectRatio = (element) => {
31391
- return element.type === "image";
31392
- };
31393
31710
  var handleDimensionChange = ({
31394
31711
  accumulatedChange,
31395
31712
  originalElements,
@@ -31408,7 +31725,7 @@ var handleDimensionChange = ({
31408
31725
  const origElement = originalElements[0];
31409
31726
  const latestElement = elementsMap.get(origElement.id);
31410
31727
  if (origElement && latestElement) {
31411
- const keepAspectRatio = shouldKeepAspectRatio || _shouldKeepAspectRatio(origElement);
31728
+ const keepAspectRatio = shouldKeepAspectRatio || shouldForceMaintainAspectRatio(origElement);
31412
31729
  const aspectRatio = origElement.width / origElement.height;
31413
31730
  if (originalAppState.croppingElementId === origElement.id) {
31414
31731
  const element = elementsMap.get(origElement.id);
@@ -33242,6 +33559,13 @@ var HelpDialog = ({ onClose }) => {
33242
33559
  shortcuts: [KEYS54.D, KEYS54["3"]]
33243
33560
  }
33244
33561
  ),
33562
+ /* @__PURE__ */ jsx147(
33563
+ Shortcut,
33564
+ {
33565
+ label: t("toolBar.triangle"),
33566
+ shortcuts: [KEYS54.G]
33567
+ }
33568
+ ),
33245
33569
  /* @__PURE__ */ jsx147(
33246
33570
  Shortcut,
33247
33571
  {
@@ -35156,6 +35480,7 @@ import {
35156
35480
  import {
35157
35481
  arrayToMap as arrayToMap26,
35158
35482
  BIND_MODE_TIMEOUT,
35483
+ DEFAULT_TRANSFORM_HANDLE_SPACING as DEFAULT_TRANSFORM_HANDLE_SPACING2,
35159
35484
  FRAME_STYLE as FRAME_STYLE3,
35160
35485
  getFontString as getFontString11,
35161
35486
  getFeatureFlag as getFeatureFlag3,
@@ -35165,15 +35490,18 @@ import {
35165
35490
  } from "@nous-excalidraw/common";
35166
35491
  import {
35167
35492
  deconstructDiamondElement as deconstructDiamondElement2,
35493
+ deconstructTriangleElement as deconstructTriangleElement2,
35168
35494
  deconstructRectanguloidElement as deconstructRectanguloidElement2,
35169
35495
  elementCenterPoint as elementCenterPoint2,
35170
35496
  getDiamondBaseCorners,
35497
+ getTriangleBaseCorners,
35171
35498
  FOCUS_POINT_SIZE as FOCUS_POINT_SIZE2,
35172
35499
  getOmitSidesForEditorInterface,
35173
35500
  getTransformHandles,
35174
35501
  getTransformHandlesFromCoords,
35175
35502
  getCornerRadius as getCornerRadius2,
35176
35503
  getDiamondPoints as getDiamondPoints2,
35504
+ getTrianglePoints as getTrianglePoints2,
35177
35505
  getFreedrawOutlinePoints as getFreedrawOutlinePoints3,
35178
35506
  getLineHeightInPx as getLineHeightInPx3,
35179
35507
  hasBoundingBox,
@@ -35199,12 +35527,7 @@ import {
35199
35527
  isSelectedViaGroup,
35200
35528
  selectGroupsFromGivenElements as selectGroupsFromGivenElements3
35201
35529
  } from "@nous-excalidraw/element";
35202
- import {
35203
- getCommonBounds as getCommonBounds9,
35204
- getCommonSelectionBounds,
35205
- getElementAbsoluteCoords as getElementAbsoluteCoords7,
35206
- getElementSelectionCoords
35207
- } from "@nous-excalidraw/element";
35530
+ import { getCommonBounds as getCommonBounds9, getElementAbsoluteCoords as getElementAbsoluteCoords7 } from "@nous-excalidraw/element";
35208
35531
  import {
35209
35532
  getGlobalFixedPointForBindableElement as getGlobalFixedPointForBindableElement2,
35210
35533
  isFocusPointVisible
@@ -35482,10 +35805,9 @@ var renderBindingHighlightForBindableElement_simple = (context, suggestedBinding
35482
35805
  context.stroke();
35483
35806
  break;
35484
35807
  case "diamond":
35808
+ case "triangle":
35485
35809
  {
35486
- const [segments, curves] = deconstructDiamondElement2(
35487
- suggestedBinding.element
35488
- );
35810
+ const [segments, curves] = suggestedBinding.element.type === "diamond" ? deconstructDiamondElement2(suggestedBinding.element) : deconstructTriangleElement2(suggestedBinding.element);
35489
35811
  segments.forEach((segment) => {
35490
35812
  context.beginPath();
35491
35813
  context.moveTo(
@@ -35588,6 +35910,22 @@ var renderBindingHighlightForBindableElement_simple = (context, suggestedBinding
35588
35910
  return pointFrom33(rotatedPoint[0], rotatedPoint[1]);
35589
35911
  }
35590
35912
  );
35913
+ } else if (suggestedBinding.element.type === "triangle") {
35914
+ const center2 = elementCenterPoint2(
35915
+ suggestedBinding.element,
35916
+ elementsMap
35917
+ );
35918
+ midpoints = getTriangleBaseCorners(suggestedBinding.element).map(
35919
+ (curve3) => {
35920
+ const point = bezierEquation2(curve3, 0.5);
35921
+ const rotatedPoint = pointRotateRads22(
35922
+ point,
35923
+ center2,
35924
+ suggestedBinding.element.angle
35925
+ );
35926
+ return pointFrom33(rotatedPoint[0], rotatedPoint[1]);
35927
+ }
35928
+ );
35591
35929
  } else {
35592
35930
  const basePoints = [
35593
35931
  {
@@ -35728,11 +36066,9 @@ var renderBindingHighlightForBindableElement_complex = (app, context, element, a
35728
36066
  context.stroke();
35729
36067
  break;
35730
36068
  case "diamond":
36069
+ case "triangle":
35731
36070
  {
35732
- const [segments, curves] = deconstructDiamondElement2(
35733
- element,
35734
- offset
35735
- );
36071
+ const [segments, curves] = element.type === "diamond" ? deconstructDiamondElement2(element, offset) : deconstructTriangleElement2(element, offset);
35736
36072
  segments.forEach((segment) => {
35737
36073
  context.beginPath();
35738
36074
  context.moveTo(
@@ -35865,6 +36201,17 @@ var renderBindingHighlightForBindableElement_complex = (app, context, element, a
35865
36201
  y: rotatedPoint[1] - element.y
35866
36202
  };
35867
36203
  });
36204
+ } else if (element.type === "triangle") {
36205
+ const [, curves] = deconstructTriangleElement2(element);
36206
+ const center = elementCenterPoint2(element, allElementsMap);
36207
+ midpoints = curves.map((curve3) => {
36208
+ const point = bezierEquation2(curve3, 0.5);
36209
+ const rotatedPoint = pointRotateRads22(point, center, element.angle);
36210
+ return {
36211
+ x: rotatedPoint[0] - element.x,
36212
+ y: rotatedPoint[1] - element.y
36213
+ };
36214
+ });
35868
36215
  } else {
35869
36216
  const center = elementCenterPoint2(element, allElementsMap);
35870
36217
  const basePoints = [
@@ -35954,18 +36301,17 @@ var renderSelectionBorder = (context, appState, elementProperties) => {
35954
36301
  selectionColors,
35955
36302
  cx,
35956
36303
  cy,
35957
- dashed,
35958
- activeEmbeddable
36304
+ dashed
35959
36305
  } = elementProperties;
35960
36306
  const elementWidth = x2 - x1;
35961
36307
  const elementHeight = y2 - y1;
35962
- const padding = elementProperties.padding ?? 0;
36308
+ const padding = elementProperties.padding ?? DEFAULT_TRANSFORM_HANDLE_SPACING2 * 2;
35963
36309
  const linePadding = padding / appState.zoom.value;
35964
36310
  const lineWidth = 8 / appState.zoom.value;
35965
36311
  const spaceWidth = 4 / appState.zoom.value;
35966
36312
  context.save();
35967
36313
  context.translate(appState.scrollX, appState.scrollY);
35968
- context.lineWidth = (activeEmbeddable ? 4 : 1) / appState.zoom.value;
36314
+ context.lineWidth = SELECTION_BORDER_STROKE_PX / appState.zoom.value;
35969
36315
  const count = selectionColors.length;
35970
36316
  for (let index = 0; index < count; ++index) {
35971
36317
  context.strokeStyle = selectionColors[index];
@@ -35992,6 +36338,7 @@ var renderSelectionBorder = (context, appState, elementProperties) => {
35992
36338
  var HOVER_OUTLINE_STROKE_PX_FRAME = 3;
35993
36339
  var HOVER_OUTLINE_STROKE_PX_OTHER = 2;
35994
36340
  var HOVER_OUTLINE_COLOR = "#8F6AEF";
36341
+ var SELECTION_BORDER_STROKE_PX = 2;
35995
36342
  var DEFAULT_SELECTION_COLOR = "#8F6AEF";
35996
36343
  var elementEligibleForHoverOutline = (el) => isFrameLikeElement14(el) || isImageElement8(el) || isEmbeddableElement4(el) || isHoverNativeOutlineShapeElement(el) || isTextElement18(el);
35997
36344
  var TEXT_HOVER_UNDERLINE_GAP_BELOW_DESCENT_PX = 1;
@@ -36034,9 +36381,10 @@ var getTextHoverUnderlineLocalY = (element, zoom) => {
36034
36381
  var renderHoverOutlineElement = (context, appState, element, elementsMap) => {
36035
36382
  const hoverStrokePx = isFrameLikeElement14(element) ? HOVER_OUTLINE_STROKE_PX_FRAME : HOVER_OUTLINE_STROKE_PX_OTHER;
36036
36383
  const lineWidthScene = hoverStrokePx / appState.zoom.value;
36037
- const [x1, y1, x2, y2, cx, cy] = getElementSelectionCoords(
36384
+ const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords7(
36038
36385
  element,
36039
- elementsMap
36386
+ elementsMap,
36387
+ true
36040
36388
  );
36041
36389
  const width = x2 - x1;
36042
36390
  const height = y2 - y1;
@@ -36089,6 +36437,36 @@ var renderHoverOutlineElement = (context, appState, element, elementsMap) => {
36089
36437
  context.restore();
36090
36438
  return;
36091
36439
  }
36440
+ if (element.type === "triangle") {
36441
+ const [topX, topY, leftX, leftY, rightX, rightY] = getTrianglePoints2(element);
36442
+ const center = pointFrom33(cx, cy);
36443
+ const corners = [
36444
+ pointRotateRads22(
36445
+ pointFrom33(element.x + topX, element.y + topY),
36446
+ center,
36447
+ element.angle
36448
+ ),
36449
+ pointRotateRads22(
36450
+ pointFrom33(element.x + leftX, element.y + leftY),
36451
+ center,
36452
+ element.angle
36453
+ ),
36454
+ pointRotateRads22(
36455
+ pointFrom33(element.x + rightX, element.y + rightY),
36456
+ center,
36457
+ element.angle
36458
+ )
36459
+ ];
36460
+ context.beginPath();
36461
+ context.moveTo(corners[0][0], corners[0][1]);
36462
+ for (let i = 1; i < corners.length; i++) {
36463
+ context.lineTo(corners[i][0], corners[i][1]);
36464
+ }
36465
+ context.closePath();
36466
+ context.stroke();
36467
+ context.restore();
36468
+ return;
36469
+ }
36092
36470
  if (isLinearElement11(element)) {
36093
36471
  const pts = LinearElementEditor10.getPointsGlobalCoordinates(
36094
36472
  element,
@@ -36107,7 +36485,7 @@ var renderHoverOutlineElement = (context, appState, element, elementsMap) => {
36107
36485
  }
36108
36486
  if (element.type === "freedraw") {
36109
36487
  const fd = element;
36110
- const outline = getFreedrawOutlinePoints3(fd);
36488
+ const outline = getFreedrawOutlinePoints3(fd, appState.zoom.value);
36111
36489
  if (outline.length >= 2) {
36112
36490
  const center = pointFrom33(cx, cy);
36113
36491
  context.beginPath();
@@ -36208,9 +36586,10 @@ var buildElementSelectionBorders = ({
36208
36586
  }
36209
36587
  }
36210
36588
  if (selectionColors.length) {
36211
- const [x1, y1, x2, y2, cx, cy] = getElementSelectionCoords(
36589
+ const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords7(
36212
36590
  element,
36213
- elementsMap
36591
+ elementsMap,
36592
+ true
36214
36593
  );
36215
36594
  selections.push({
36216
36595
  angle: element.angle,
@@ -36223,16 +36602,13 @@ var buildElementSelectionBorders = ({
36223
36602
  cx,
36224
36603
  cy,
36225
36604
  activeEmbeddable: !isEmbeddableElement4(element) && appState.activeEmbeddable?.element === element && appState.activeEmbeddable.state === "active",
36226
- padding: 0
36605
+ padding: element.id === appState.croppingElementId || isImageElement8(element) || isEmbeddableElement4(element) || isFrameLikeElement14(element) ? 0 : void 0
36227
36606
  });
36228
36607
  }
36229
36608
  }
36230
36609
  const addSelectionForGroupId = (groupId) => {
36231
36610
  const groupElements = getElementsInGroup8(elementsMap, groupId);
36232
- const [x1, y1, x2, y2] = getCommonSelectionBounds(
36233
- groupElements,
36234
- elementsMap
36235
- );
36611
+ const [x1, y1, x2, y2] = getCommonBounds9(groupElements);
36236
36612
  selections.push({
36237
36613
  angle: 0,
36238
36614
  x1,
@@ -36243,8 +36619,7 @@ var buildElementSelectionBorders = ({
36243
36619
  dashed: true,
36244
36620
  cx: x1 + (x2 - x1) / 2,
36245
36621
  cy: y1 + (y2 - y1) / 2,
36246
- activeEmbeddable: false,
36247
- padding: 0
36622
+ activeEmbeddable: false
36248
36623
  });
36249
36624
  };
36250
36625
  for (const groupId of getSelectedGroupIds3(appState)) {
@@ -36255,7 +36630,7 @@ var buildElementSelectionBorders = ({
36255
36630
  }
36256
36631
  return selections;
36257
36632
  };
36258
- var shouldOmitSelectionChromeWhileDraggingSingleFrame = (appState, selectedElements) => !!(appState.selectedElementsAreBeingDragged && selectedElements.length === 1 && isFrameLikeElement14(selectedElements[0]));
36633
+ var shouldOmitSelectionChromeWhileDragging = (appState) => appState.selectedElementsAreBeingDragged;
36259
36634
  var shouldDrawHoverOutlineForElement = (appState, element) => !appState.selectedElementIds[element.id] && !isSelectedViaGroup(appState, element);
36260
36635
  var paintHoverAndSelectionOutlines = ({
36261
36636
  context,
@@ -36283,7 +36658,7 @@ var paintHoverAndSelectionOutlines = ({
36283
36658
  appState,
36284
36659
  editorInterface
36285
36660
  );
36286
- if (showBoundingBox && !shouldOmitSelectionChromeWhileDraggingSingleFrame(appState, selectedElements)) {
36661
+ if (showBoundingBox && !shouldOmitSelectionChromeWhileDragging(appState)) {
36287
36662
  const selections = buildElementSelectionBorders({
36288
36663
  elementsMap,
36289
36664
  selectedElements,
@@ -36570,7 +36945,8 @@ var renderTransformHandles = (context, renderConfig, appState, transformHandles,
36570
36945
  fillCircle(context, x + width / 2, y + height / 2, width / 2, true);
36571
36946
  } else if (CORNER_TRANSFORM_HANDLE_TYPES.has(handleType)) {
36572
36947
  const cornerStroke = renderConfig.selectionColor || DEFAULT_SELECTION_COLOR;
36573
- context.fillStyle = "#ffffff";
36948
+ const isHovered = renderConfig.hoveredCornerTransformHandleType === handleType;
36949
+ context.fillStyle = isHovered ? cornerStroke : "#ffffff";
36574
36950
  context.save();
36575
36951
  context.translate(x + width / 2, y + height / 2);
36576
36952
  context.rotate(angle);
@@ -36748,7 +37124,7 @@ var _renderInteractiveScene = ({
36748
37124
  if (canvas === null) {
36749
37125
  return { atLeastOneVisibleElement: false, elementsMap };
36750
37126
  }
36751
- const omitSelectionChromeDraggingSingleFrame = shouldOmitSelectionChromeWhileDraggingSingleFrame(appState, selectedElements);
37127
+ const omitSelectionChromeWhileDragging = shouldOmitSelectionChromeWhileDragging(appState);
36752
37128
  const [normalizedWidth, normalizedHeight] = getNormalizedCanvasDimensions(
36753
37129
  canvas,
36754
37130
  scale
@@ -36916,7 +37292,7 @@ var _renderInteractiveScene = ({
36916
37292
  );
36917
37293
  }
36918
37294
  const selectionColor = renderConfig.selectionColor || DEFAULT_SELECTION_COLOR;
36919
- if (showBoundingBox && !omitSelectionChromeDraggingSingleFrame) {
37295
+ if (showBoundingBox && !omitSelectionChromeWhileDragging) {
36920
37296
  const selections = buildElementSelectionBorders({
36921
37297
  elementsMap,
36922
37298
  selectedElements,
@@ -36933,7 +37309,7 @@ var _renderInteractiveScene = ({
36933
37309
  context.save();
36934
37310
  context.translate(appState.scrollX, appState.scrollY);
36935
37311
  if (selectedElements.length === 1) {
36936
- if (!outlineOverlayCanvas && !omitSelectionChromeDraggingSingleFrame) {
37312
+ if (!outlineOverlayCanvas && !omitSelectionChromeWhileDragging) {
36937
37313
  paintSingleSelectionTransformHandles(
36938
37314
  context,
36939
37315
  appState,
@@ -36956,23 +37332,21 @@ var _renderInteractiveScene = ({
36956
37332
  );
36957
37333
  }
36958
37334
  }
36959
- } else if (selectedElements.length > 1 && !appState.isRotating && !selectedElements.some((el) => el.locked)) {
37335
+ } else if (selectedElements.length > 1 && !appState.isRotating && !omitSelectionChromeWhileDragging && !selectedElements.some((el) => el.locked)) {
37336
+ const dashedLinePadding = DEFAULT_TRANSFORM_HANDLE_SPACING2 * 2 / appState.zoom.value;
36960
37337
  context.fillStyle = "#fff";
36961
- const [x1, y1, x2, y2] = getCommonSelectionBounds(
36962
- selectedElements,
36963
- elementsMap
36964
- );
37338
+ const [x1, y1, x2, y2] = getCommonBounds9(selectedElements, elementsMap);
36965
37339
  const initialLineDash = context.getLineDash();
36966
37340
  context.setLineDash([2 / appState.zoom.value]);
36967
37341
  const lineWidth = context.lineWidth;
36968
- context.lineWidth = 1 / appState.zoom.value;
37342
+ context.lineWidth = SELECTION_BORDER_STROKE_PX / appState.zoom.value;
36969
37343
  context.strokeStyle = selectionColor;
36970
37344
  strokeRectWithRotation_simple(
36971
37345
  context,
36972
- x1,
36973
- y1,
36974
- x2 - x1,
36975
- y2 - y1,
37346
+ x1 - dashedLinePadding,
37347
+ y1 - dashedLinePadding,
37348
+ x2 - x1 + dashedLinePadding * 2,
37349
+ y2 - y1 + dashedLinePadding * 2,
36976
37350
  (x1 + x2) / 2,
36977
37351
  (y1 + y2) / 2,
36978
37352
  0
@@ -37092,7 +37466,7 @@ var _renderInteractiveScene = ({
37092
37466
  renderConfig,
37093
37467
  editorInterface
37094
37468
  });
37095
- if (!appState.multiElement && !appState.newElement && !appState.selectedLinearElement?.isEditing && !omitSelectionChromeDraggingSingleFrame) {
37469
+ if (!appState.multiElement && !appState.newElement && !appState.selectedLinearElement?.isEditing && !omitSelectionChromeWhileDragging) {
37096
37470
  const showBoundingBox = hasBoundingBox(
37097
37471
  selectedElements,
37098
37472
  appState,
@@ -37250,6 +37624,7 @@ var InteractiveCanvas = (props) => {
37250
37624
  remotePointerUsernames,
37251
37625
  remotePointerUserStates,
37252
37626
  selectionColor,
37627
+ hoveredCornerTransformHandleType: props.app.hoveredCornerTransformHandleType,
37253
37628
  renderScrollbars: props.renderScrollbars,
37254
37629
  // NOTE not memoized on so we don't rerender on cursor move
37255
37630
  lastViewportPosition: props.app.lastViewportPosition
@@ -37331,6 +37706,7 @@ var getRelevantAppStateProps = (appState) => ({
37331
37706
  isMidpointSnappingEnabled: appState.isMidpointSnappingEnabled,
37332
37707
  suggestedBinding: appState.suggestedBinding,
37333
37708
  isRotating: appState.isRotating,
37709
+ isResizing: appState.isResizing,
37334
37710
  elementsToHighlight: appState.elementsToHighlight,
37335
37711
  collaborators: appState.collaborators,
37336
37712
  // Necessary for collab. sessions
@@ -37451,7 +37827,7 @@ var areEqual4 = (prevProps, nextProps) => {
37451
37827
  var StaticCanvas_default = React45.memo(StaticCanvas, areEqual4);
37452
37828
 
37453
37829
  // components/canvases/NewElementCanvas.tsx
37454
- import { useEffect as useEffect48, useRef as useRef44 } from "react";
37830
+ import { useLayoutEffect as useLayoutEffect10, useRef as useRef44 } from "react";
37455
37831
 
37456
37832
  // renderer/renderNewElementScene.ts
37457
37833
  import { throttleRAF as throttleRAF2 } from "@nous-excalidraw/common";
@@ -37486,6 +37862,7 @@ var _renderNewElementScene = ({
37486
37862
  context.scale(appState.zoom.value, appState.zoom.value);
37487
37863
  if (newElement7 && newElement7.type !== "selection") {
37488
37864
  if (isInvisiblySmallElement2(newElement7)) {
37865
+ context.restore();
37489
37866
  return;
37490
37867
  }
37491
37868
  const frameId = newElement7.frameId || appState.frameToHighlight?.id;
@@ -37527,7 +37904,7 @@ var renderNewElementScene = (renderConfig, throttle5) => {
37527
37904
  import { jsx as jsx159 } from "react/jsx-runtime";
37528
37905
  var NewElementCanvas = (props) => {
37529
37906
  const canvasRef = useRef44(null);
37530
- useEffect48(() => {
37907
+ useLayoutEffect10(() => {
37531
37908
  if (!canvasRef.current) {
37532
37909
  return;
37533
37910
  }
@@ -37542,7 +37919,7 @@ var NewElementCanvas = (props) => {
37542
37919
  renderConfig: props.renderConfig,
37543
37920
  appState: props.appState
37544
37921
  },
37545
- isRenderThrottlingEnabled()
37922
+ false
37546
37923
  );
37547
37924
  });
37548
37925
  return /* @__PURE__ */ jsx159(
@@ -37846,7 +38223,7 @@ var gesture = {
37846
38223
  initialDistance: null,
37847
38224
  initialScale: null
37848
38225
  };
37849
- var App = class _App extends React46.Component {
38226
+ var _App = class _App extends React46.Component {
37850
38227
  constructor(props) {
37851
38228
  super(props);
37852
38229
  __publicField(this, "canvas");
@@ -37907,6 +38284,7 @@ var App = class _App extends React46.Component {
37907
38284
  __publicField(this, "lastPointerMoveEvent", null);
37908
38285
  /** current frame pointer cords */
37909
38286
  __publicField(this, "lastPointerMoveCoords", null);
38287
+ __publicField(this, "hoveredCornerTransformHandleType", null);
37910
38288
  __publicField(this, "lastCompletedCanvasClicks", []);
37911
38289
  /** previous frame pointer coords */
37912
38290
  __publicField(this, "previousPointerMoveCoords", null);
@@ -38094,8 +38472,9 @@ var App = class _App extends React46.Component {
38094
38472
  const frameTitleMutedColor = isDarkTheme ? FRAME_STYLE4.nameColorDarkTheme : FRAME_STYLE4.nameColorLightTheme;
38095
38473
  const isFrameTitleHovered = this.state.hoveredFrameId === f.id && !this.state.selectedElementIds[f.id];
38096
38474
  const isFrameTitleSelected = !!this.state.selectedElementIds[f.id];
38097
- const frameTitleAccentColor = "#8F6AEF";
38098
- const frameTitleColor = isFrameTitleSelected || isFrameTitleHovered ? frameTitleAccentColor : frameTitleMutedColor;
38475
+ const frameTitleSelectedColor = "#8F6AEF";
38476
+ const frameTitleHoverColor = "#C6A6FF";
38477
+ const frameTitleColor = isFrameTitleSelected ? frameTitleSelectedColor : isFrameTitleHovered ? frameTitleHoverColor : frameTitleMutedColor;
38099
38478
  if (f.id === this.state.editingFrame) {
38100
38479
  const frameNameInEdit = frameName;
38101
38480
  frameNameJSX = /* @__PURE__ */ jsx161(
@@ -38524,6 +38903,8 @@ var App = class _App extends React46.Component {
38524
38903
  const nonDeletedRestoredElements = restoredElements.filter(
38525
38904
  (element) => !element.isDeleted
38526
38905
  );
38906
+ const sourceZoom = restoredAppState.zoom.value;
38907
+ let targetZoom = initialZoomValue;
38527
38908
  if (nonDeletedRestoredElements.length) {
38528
38909
  const { appState: fittedAppState } = zoomToFit({
38529
38910
  targetElements: nonDeletedRestoredElements,
@@ -38539,26 +38920,65 @@ var App = class _App extends React46.Component {
38539
38920
  maxZoom: initialZoomValue,
38540
38921
  canvasOffsets: this.getEditorUIOffsets()
38541
38922
  });
38923
+ targetZoom = fittedAppState.zoom.value;
38542
38924
  restoredAppState = {
38543
38925
  ...restoredAppState,
38544
38926
  scrollX: fittedAppState.scrollX,
38545
38927
  scrollY: fittedAppState.scrollY,
38546
- zoom: fittedAppState.zoom
38928
+ zoom: fittedAppState.zoom,
38929
+ currentItemFontSize: normalizeSceneFontSizeForZoom(
38930
+ restoredAppState.currentItemFontSize,
38931
+ sourceZoom,
38932
+ targetZoom
38933
+ )
38547
38934
  };
38548
38935
  } else {
38549
38936
  restoredAppState = {
38550
38937
  ...restoredAppState,
38551
- zoom: { value: initialZoomValue }
38938
+ zoom: { value: initialZoomValue },
38939
+ currentItemFontSize: normalizeSceneFontSizeForZoom(
38940
+ restoredAppState.currentItemFontSize,
38941
+ sourceZoom,
38942
+ initialZoomValue
38943
+ )
38552
38944
  };
38553
38945
  }
38946
+ restoredAppState = {
38947
+ ...restoredAppState,
38948
+ currentItemStrokeWidthCustom: false,
38949
+ currentItemStrokeWidth: getDisplaySceneStrokeWidth3(targetZoom)
38950
+ };
38951
+ const migratedElements = restoredElements.map((element) => {
38952
+ if (!isTextElement19(element)) {
38953
+ return element;
38954
+ }
38955
+ const fontSize = normalizeSceneFontSizeForZoom(
38956
+ element.fontSize,
38957
+ sourceZoom,
38958
+ targetZoom
38959
+ );
38960
+ if (fontSize === element.fontSize) {
38961
+ return element;
38962
+ }
38963
+ return newElementWith11(element, { fontSize });
38964
+ });
38554
38965
  this.resetStore();
38555
38966
  this.resetHistory();
38556
38967
  this.syncActionResult({
38557
- elements: restoredElements,
38968
+ elements: migratedElements,
38558
38969
  appState: restoredAppState,
38559
38970
  files: initialData?.files,
38560
38971
  captureUpdate: CaptureUpdateAction40.NEVER
38561
38972
  });
38973
+ for (const element of this.scene.getNonDeletedElements()) {
38974
+ if (isTextElement19(element)) {
38975
+ redrawTextBoundingBox8(
38976
+ element,
38977
+ this.scene.getContainerElement(element),
38978
+ this.scene
38979
+ );
38980
+ }
38981
+ }
38562
38982
  this.clearImageShapeCache();
38563
38983
  this.fonts.loadSceneFonts().then((fontFaces) => {
38564
38984
  this.fonts.onLoaded(fontFaces);
@@ -38944,16 +39364,28 @@ var App = class _App extends React46.Component {
38944
39364
  * Zooms on canvas viewport center
38945
39365
  */
38946
39366
  __publicField(this, "zoomCanvas", (value) => {
38947
- this.setState({
38948
- ...getStateForZoom(
38949
- {
38950
- viewportX: this.state.width / 2 + this.state.offsetLeft,
38951
- viewportY: this.state.height / 2 + this.state.offsetTop,
38952
- nextZoom: getNormalizedZoom(value)
38953
- },
38954
- this.state
39367
+ const zoomState = getStateForZoom(
39368
+ {
39369
+ viewportX: this.state.width / 2 + this.state.offsetLeft,
39370
+ viewportY: this.state.height / 2 + this.state.offsetTop,
39371
+ nextZoom: getNormalizedZoom(value)
39372
+ },
39373
+ this.state
39374
+ );
39375
+ this.syncSceneStrokeWidthsForZoom(zoomState.zoom.value);
39376
+ this.setState(zoomState);
39377
+ });
39378
+ __publicField(this, "syncSceneStrokeWidthsForZoom", (toZoom, fromZoom = this.state.zoom.value) => {
39379
+ if (toZoom === fromZoom) {
39380
+ return;
39381
+ }
39382
+ this.scene.replaceAllElements(
39383
+ syncElementsStrokeWidthForZoom2(
39384
+ this.scene.getElementsIncludingDeleted(),
39385
+ fromZoom,
39386
+ toZoom
38955
39387
  )
38956
- });
39388
+ );
38957
39389
  });
38958
39390
  __publicField(this, "cancelInProgressAnimation", null);
38959
39391
  __publicField(this, "scrollToContent", (target = this.scene.getNonDeletedElements(), opts) => {
@@ -38991,6 +39423,8 @@ var App = class _App extends React46.Component {
38991
39423
  if (opts?.fitToContent || opts?.fitToViewport) {
38992
39424
  const { appState } = zoomToFit({
38993
39425
  canvasOffsets: opts.canvasOffsets,
39426
+ fitCanvasOffsets: opts.fitCanvasOffsets,
39427
+ scrollCanvasOffsets: opts.scrollCanvasOffsets,
38994
39428
  targetElements,
38995
39429
  appState: this.state,
38996
39430
  fitToViewport: !!opts?.fitToViewport,
@@ -39001,6 +39435,15 @@ var App = class _App extends React46.Component {
39001
39435
  zoom = appState.zoom;
39002
39436
  scrollX = appState.scrollX;
39003
39437
  scrollY = appState.scrollY;
39438
+ if (opts?.clampHostStylebarAboveElement) {
39439
+ const fitOffsets = opts.fitCanvasOffsets ?? opts.canvasOffsets;
39440
+ const fitTop = fitOffsets?.top ?? 0;
39441
+ const [, y1] = getCommonBounds11(targetElements);
39442
+ const minScrollY = (fitTop + _App.HOST_STYLEBAR_GAP_ABOVE_ELEMENT) / zoom.value - y1;
39443
+ if (scrollY < minScrollY) {
39444
+ scrollY = minScrollY;
39445
+ }
39446
+ }
39004
39447
  } else {
39005
39448
  const scroll = calculateScrollCenter(targetElements, this.state);
39006
39449
  scrollX = scroll.scrollX;
@@ -39010,6 +39453,9 @@ var App = class _App extends React46.Component {
39010
39453
  const origScrollX = this.state.scrollX;
39011
39454
  const origScrollY = this.state.scrollY;
39012
39455
  const origZoom = this.state.zoom.value;
39456
+ const origStrokeWidth = this.state.currentItemStrokeWidth;
39457
+ const origStrokeWidthCustom = this.state.currentItemStrokeWidthCustom;
39458
+ const origFontSize = this.state.currentItemFontSize;
39013
39459
  const cancel = easeToValuesRAF({
39014
39460
  fromValues: {
39015
39461
  scrollX: origScrollX,
@@ -39023,11 +39469,23 @@ var App = class _App extends React46.Component {
39023
39469
  }
39024
39470
  return void 0;
39025
39471
  },
39026
- onStep: ({ scrollX: scrollX2, scrollY: scrollY2, zoom: zoom2 }) => {
39472
+ onStep: ({ scrollX: scrollX2, scrollY: scrollY2, zoom: stepZoom }) => {
39473
+ this.syncSceneStrokeWidthsForZoom(stepZoom);
39027
39474
  this.setState({
39028
39475
  scrollX: scrollX2,
39029
39476
  scrollY: scrollY2,
39030
- zoom: { value: zoom2 }
39477
+ zoom: { value: stepZoom },
39478
+ currentItemStrokeWidth: scaleStrokeWidthForZoomChange3(
39479
+ origStrokeWidth,
39480
+ origZoom,
39481
+ stepZoom,
39482
+ origStrokeWidthCustom
39483
+ ),
39484
+ currentItemFontSize: scaleFontSizeForZoomChange(
39485
+ origFontSize,
39486
+ origZoom,
39487
+ stepZoom
39488
+ )
39031
39489
  });
39032
39490
  },
39033
39491
  onStart: () => {
@@ -39046,7 +39504,23 @@ var App = class _App extends React46.Component {
39046
39504
  this.cancelInProgressAnimation = null;
39047
39505
  };
39048
39506
  } else {
39049
- this.setState({ scrollX, scrollY, zoom });
39507
+ this.syncSceneStrokeWidthsForZoom(zoom.value);
39508
+ this.setState({
39509
+ scrollX,
39510
+ scrollY,
39511
+ zoom,
39512
+ currentItemStrokeWidth: scaleStrokeWidthForZoomChange3(
39513
+ this.state.currentItemStrokeWidth,
39514
+ this.state.zoom.value,
39515
+ zoom.value,
39516
+ this.state.currentItemStrokeWidthCustom
39517
+ ),
39518
+ currentItemFontSize: scaleFontSizeForZoomChange(
39519
+ this.state.currentItemFontSize,
39520
+ this.state.zoom.value,
39521
+ zoom.value
39522
+ )
39523
+ });
39050
39524
  }
39051
39525
  });
39052
39526
  __publicField(this, "maybeUnfollowRemoteUser", () => {
@@ -39058,7 +39532,22 @@ var App = class _App extends React46.Component {
39058
39532
  __publicField(this, "translateCanvas", (state) => {
39059
39533
  this.cancelInProgressAnimation?.();
39060
39534
  this.maybeUnfollowRemoteUser();
39061
- this.setState(state);
39535
+ const maybeSyncZoom = (partial, prevZoom) => {
39536
+ const nextZoom = partial?.zoom?.value;
39537
+ if (nextZoom != null && nextZoom !== prevZoom) {
39538
+ this.syncSceneStrokeWidthsForZoom(nextZoom);
39539
+ }
39540
+ };
39541
+ if (typeof state === "function") {
39542
+ this.setState((prevState, props) => {
39543
+ const nextState = state(prevState, props);
39544
+ maybeSyncZoom(nextState, prevState.zoom.value);
39545
+ return nextState;
39546
+ });
39547
+ } else {
39548
+ maybeSyncZoom(state, this.state.zoom.value);
39549
+ this.setState(state);
39550
+ }
39062
39551
  });
39063
39552
  __publicField(this, "setToast", (toast) => {
39064
39553
  this.setState({ toast });
@@ -39197,13 +39686,31 @@ var App = class _App extends React46.Component {
39197
39686
  this.lastViewportPosition.y = event.clientY;
39198
39687
  }
39199
39688
  ));
39689
+ __publicField(this, "getHostUiBottomRelativeToContainer", (selector, containerTop) => {
39690
+ const rect = document.querySelector(selector)?.getBoundingClientRect();
39691
+ if (!rect || rect.width <= 0 || rect.height <= 0) {
39692
+ return 0;
39693
+ }
39694
+ return Math.max(rect.bottom - containerTop, 0);
39695
+ });
39200
39696
  __publicField(this, "getEditorUIOffsets", () => {
39201
- const toolbarBottom = this.excalidrawContainerRef?.current?.querySelector(".App-toolbar")?.getBoundingClientRect()?.bottom ?? 0;
39202
- const sidebarRect = this.excalidrawContainerRef?.current?.querySelector(".sidebar")?.getBoundingClientRect();
39203
- const propertiesPanelRect = this.excalidrawContainerRef?.current?.querySelector(".App-menu__left")?.getBoundingClientRect();
39697
+ const container = this.excalidrawContainerRef?.current;
39698
+ const containerTop = container?.getBoundingClientRect()?.top ?? 0;
39699
+ const nativeToolbarBottom = container?.querySelector(".App-toolbar")?.getBoundingClientRect()?.bottom ?? 0;
39700
+ const customToolbarBottom = this.getHostUiBottomRelativeToContainer(
39701
+ _App.HOST_TOOLBAR_SELECTOR,
39702
+ containerTop
39703
+ );
39704
+ const topUiOffset = Math.max(
39705
+ nativeToolbarBottom - containerTop,
39706
+ customToolbarBottom,
39707
+ 0
39708
+ );
39709
+ const sidebarRect = container?.querySelector(".sidebar")?.getBoundingClientRect();
39710
+ const propertiesPanelRect = container?.querySelector(".App-menu__left")?.getBoundingClientRect();
39204
39711
  const PADDING = 16;
39205
39712
  return getLanguage().rtl ? {
39206
- top: toolbarBottom + PADDING,
39713
+ top: topUiOffset + PADDING,
39207
39714
  right: Math.max(
39208
39715
  this.state.width - (propertiesPanelRect?.left ?? this.state.width),
39209
39716
  0
@@ -39211,7 +39718,7 @@ var App = class _App extends React46.Component {
39211
39718
  bottom: PADDING,
39212
39719
  left: Math.max(sidebarRect?.right ?? 0, 0) + PADDING
39213
39720
  } : {
39214
- top: toolbarBottom + PADDING,
39721
+ top: topUiOffset + PADDING,
39215
39722
  right: Math.max(
39216
39723
  this.state.width - (sidebarRect?.left ?? this.state.width) + PADDING,
39217
39724
  0
@@ -39875,16 +40382,20 @@ var App = class _App extends React46.Component {
39875
40382
  }
39876
40383
  const initialScale = gesture.initialScale;
39877
40384
  if (initialScale) {
39878
- this.setState((state) => ({
39879
- ...getStateForZoom(
40385
+ this.setState((state) => {
40386
+ const zoomState = getStateForZoom(
39880
40387
  {
39881
40388
  viewportX: this.lastViewportPosition.x,
39882
40389
  viewportY: this.lastViewportPosition.y,
39883
40390
  nextZoom: getNormalizedZoom(initialScale * event.scale)
39884
40391
  },
39885
40392
  state
39886
- )
39887
- }));
40393
+ );
40394
+ if (zoomState.zoom.value !== state.zoom.value) {
40395
+ this.syncSceneStrokeWidthsForZoom(zoomState.zoom.value);
40396
+ }
40397
+ return zoomState;
40398
+ });
39888
40399
  }
39889
40400
  }));
39890
40401
  // fires only on Safari
@@ -39961,7 +40472,7 @@ var App = class _App extends React46.Component {
39961
40472
  const existingTextElement = this.getSelectedTextElement(container) || this.getTextElementAtPosition(sceneX, sceneY);
39962
40473
  const fontFamily = existingTextElement?.fontFamily || this.state.currentItemFontFamily;
39963
40474
  const lineHeight = existingTextElement?.lineHeight || getLineHeight6(fontFamily);
39964
- const fontSize = this.state.currentItemFontSize;
40475
+ const fontSize = existingTextElement?.fontSize ?? getDefaultSceneFontSizeForZoom3(this.state.zoom.value);
39965
40476
  if (!existingTextElement && shouldBindToContainer && container && !isArrowElement14(container)) {
39966
40477
  const fontString = {
39967
40478
  fontSize,
@@ -40013,7 +40524,7 @@ var App = class _App extends React46.Component {
40013
40524
  strokeColor: this.state.currentItemStrokeColor,
40014
40525
  backgroundColor: this.state.currentItemBackgroundColor,
40015
40526
  fillStyle: this.state.currentItemFillStyle,
40016
- strokeWidth: this.state.currentItemStrokeWidth,
40527
+ ...this.getNewElementStrokeProps(),
40017
40528
  strokeStyle: this.state.currentItemStrokeStyle,
40018
40529
  roughness: this.state.currentItemRoughness,
40019
40530
  opacity: this.state.currentItemOpacity,
@@ -40108,11 +40619,10 @@ var App = class _App extends React46.Component {
40108
40619
  animate: true,
40109
40620
  duration: 500,
40110
40621
  fitToViewport: true,
40111
- viewportZoomFactor: 0.7,
40112
- // minZoom:
40113
- // this.state.zoom.value +
40114
- // getInteractiveZoomStep(this.state.zoom.value, "in"),
40115
- canvasOffsets: this.getEditorUIOffsets()
40622
+ viewportZoomFactor: 0.9,
40623
+ fitCanvasOffsets: this.getEditorUIOffsets(),
40624
+ scrollCanvasOffsets: this.getEditorUIOffsets(),
40625
+ clampHostStylebarAboveElement: true
40116
40626
  });
40117
40627
  return;
40118
40628
  }
@@ -40216,7 +40726,7 @@ var App = class _App extends React46.Component {
40216
40726
  sceneY
40217
40727
  );
40218
40728
  if (container) {
40219
- if (hasBoundTextElement9(container) || !isTransparent6(container.backgroundColor) || hitElementItself3({
40729
+ if (hasBoundTextElement9(container) || !isTransparent7(container.backgroundColor) || hitElementItself3({
40220
40730
  point: pointFrom34(sceneX, sceneY),
40221
40731
  element: container,
40222
40732
  elementsMap: this.scene.getNonDeletedElementsMap(),
@@ -40346,6 +40856,25 @@ var App = class _App extends React46.Component {
40346
40856
  );
40347
40857
  return frames.length ? frames[frames.length - 1] : null;
40348
40858
  });
40859
+ __publicField(this, "getHoveredCornerTransformHandleType", (handleType) => {
40860
+ if (handleType === "nw" || handleType === "ne" || handleType === "sw" || handleType === "se") {
40861
+ return handleType;
40862
+ }
40863
+ return null;
40864
+ });
40865
+ __publicField(this, "syncHoveredCornerTransformHandleType", (handleType) => {
40866
+ const cornerHandleType = this.getHoveredCornerTransformHandleType(handleType);
40867
+ if (cornerHandleType !== this.hoveredCornerTransformHandleType) {
40868
+ this.hoveredCornerTransformHandleType = cornerHandleType;
40869
+ this.triggerRender(true);
40870
+ }
40871
+ });
40872
+ __publicField(this, "clearHoveredCornerTransformHandleType", () => {
40873
+ if (this.hoveredCornerTransformHandleType !== null) {
40874
+ this.hoveredCornerTransformHandleType = null;
40875
+ this.triggerRender(true);
40876
+ }
40877
+ });
40349
40878
  __publicField(this, "clearHoverOutlineIfNeeded", () => {
40350
40879
  if (this.state.hoverOutlineElementId != null || this.state.hoveredFrameId != null) {
40351
40880
  this.setState({
@@ -40490,6 +41019,7 @@ var App = class _App extends React46.Component {
40490
41019
  }
40491
41020
  if (isHoldingSpace || isPanning || isDraggingScrollBar || isHandToolActive(this.state)) {
40492
41021
  this.clearHoverOutlineIfNeeded();
41022
+ this.clearHoveredCornerTransformHandleType();
40493
41023
  return;
40494
41024
  }
40495
41025
  const isPointerOverScrollBars = isOverScrollBars(
@@ -40724,6 +41254,7 @@ var App = class _App extends React46.Component {
40724
41254
  }
40725
41255
  }
40726
41256
  this.clearHoverOutlineIfNeeded();
41257
+ this.clearHoveredCornerTransformHandleType();
40727
41258
  return;
40728
41259
  }
40729
41260
  if (this.state.activeTool.type === "arrow") {
@@ -40755,6 +41286,7 @@ var App = class _App extends React46.Component {
40755
41286
  // over a link/embeddable, we change the cursor
40756
41287
  !isLaserTool && this.state.activeTool.type !== "selection" && this.state.activeTool.type !== "lasso" && this.state.activeTool.type !== "text" && this.state.activeTool.type !== "eraser") {
40757
41288
  this.clearHoverOutlineIfNeeded();
41289
+ this.clearHoveredCornerTransformHandleType();
40758
41290
  return;
40759
41291
  }
40760
41292
  const elements = this.scene.getNonDeletedElements();
@@ -40762,6 +41294,7 @@ var App = class _App extends React46.Component {
40762
41294
  if (this.isHittingTextAutoResizeHandle(selectedElements, scenePointer)) {
40763
41295
  setCursor(this.interactiveCanvas, CURSOR_TYPE4.POINTER);
40764
41296
  this.clearHoverOutlineIfNeeded();
41297
+ this.clearHoveredCornerTransformHandleType();
40765
41298
  return;
40766
41299
  }
40767
41300
  if (selectedElements.length === 1 && !isOverScrollBar && !this.state.selectedLinearElement?.isEditing) {
@@ -40791,6 +41324,9 @@ var App = class _App extends React46.Component {
40791
41324
  getCursorForResizingElement(elementWithTransformHandleType)
40792
41325
  );
40793
41326
  this.clearHoverOutlineIfNeeded();
41327
+ this.syncHoveredCornerTransformHandleType(
41328
+ elementWithTransformHandleType.transformHandleType
41329
+ );
40794
41330
  return;
40795
41331
  }
40796
41332
  }
@@ -40811,9 +41347,11 @@ var App = class _App extends React46.Component {
40811
41347
  })
40812
41348
  );
40813
41349
  this.clearHoverOutlineIfNeeded();
41350
+ this.syncHoveredCornerTransformHandleType(transformHandleType);
40814
41351
  return;
40815
41352
  }
40816
41353
  }
41354
+ this.clearHoveredCornerTransformHandleType();
40817
41355
  if (isEraserActive(this.state)) {
40818
41356
  this.clearHoverOutlineIfNeeded();
40819
41357
  return;
@@ -41737,7 +42275,7 @@ var App = class _App extends React46.Component {
41737
42275
  strokeColor: this.state.currentItemStrokeColor,
41738
42276
  backgroundColor: this.state.currentItemBackgroundColor,
41739
42277
  fillStyle: this.state.currentItemFillStyle,
41740
- strokeWidth: this.state.currentItemStrokeWidth,
42278
+ ...this.getNewElementStrokeProps(),
41741
42279
  strokeStyle: this.state.currentItemStrokeStyle,
41742
42280
  roughness: this.state.currentItemRoughness,
41743
42281
  opacity: this.state.currentItemOpacity,
@@ -41793,7 +42331,7 @@ var App = class _App extends React46.Component {
41793
42331
  strokeColor: "transparent",
41794
42332
  backgroundColor: "transparent",
41795
42333
  fillStyle: this.state.currentItemFillStyle,
41796
- strokeWidth: this.state.currentItemStrokeWidth,
42334
+ ...this.getNewElementStrokeProps(),
41797
42335
  strokeStyle: this.state.currentItemStrokeStyle,
41798
42336
  roughness: this.state.currentItemRoughness,
41799
42337
  roundness: this.getCurrentItemRoundness("iframe"),
@@ -41833,7 +42371,7 @@ var App = class _App extends React46.Component {
41833
42371
  strokeColor: "transparent",
41834
42372
  backgroundColor: "transparent",
41835
42373
  fillStyle: this.state.currentItemFillStyle,
41836
- strokeWidth: this.state.currentItemStrokeWidth,
42374
+ ...this.getNewElementStrokeProps(),
41837
42375
  strokeStyle: this.state.currentItemStrokeStyle,
41838
42376
  roughness: this.state.currentItemRoughness,
41839
42377
  roundness: this.getCurrentItemRoundness("embeddable"),
@@ -41866,7 +42404,7 @@ var App = class _App extends React46.Component {
41866
42404
  strokeColor: this.state.currentItemStrokeColor,
41867
42405
  backgroundColor: this.state.currentItemBackgroundColor,
41868
42406
  fillStyle: this.state.currentItemFillStyle,
41869
- strokeWidth: this.state.currentItemStrokeWidth,
42407
+ ...this.getNewElementStrokeProps(),
41870
42408
  strokeStyle: this.state.currentItemStrokeStyle,
41871
42409
  roughness: this.state.currentItemRoughness,
41872
42410
  roundness: null,
@@ -41975,7 +42513,7 @@ var App = class _App extends React46.Component {
41975
42513
  strokeColor: this.state.currentItemStrokeColor,
41976
42514
  backgroundColor: this.state.currentItemBackgroundColor,
41977
42515
  fillStyle: this.state.currentItemFillStyle,
41978
- strokeWidth: this.state.currentItemStrokeWidth,
42516
+ ...this.getNewElementStrokeProps(),
41979
42517
  strokeStyle: this.state.currentItemStrokeStyle,
41980
42518
  roughness: this.state.currentItemRoughness,
41981
42519
  opacity: this.state.currentItemOpacity,
@@ -41997,7 +42535,7 @@ var App = class _App extends React46.Component {
41997
42535
  strokeColor: this.state.currentItemStrokeColor,
41998
42536
  backgroundColor: this.state.currentItemBackgroundColor,
41999
42537
  fillStyle: this.state.currentItemFillStyle,
42000
- strokeWidth: this.state.currentItemStrokeWidth,
42538
+ ...this.getNewElementStrokeProps(),
42001
42539
  strokeStyle: this.state.currentItemStrokeStyle,
42002
42540
  roughness: this.state.currentItemRoughness,
42003
42541
  opacity: this.state.currentItemOpacity,
@@ -42092,6 +42630,17 @@ var App = class _App extends React46.Component {
42092
42630
  }
42093
42631
  }
42094
42632
  });
42633
+ __publicField(this, "getNewElementStrokeProps", () => {
42634
+ if (this.state.currentItemStrokeWidthCustom) {
42635
+ return {
42636
+ strokeWidth: this.state.currentItemStrokeWidth,
42637
+ customData: { [STROKE_WIDTH_CUSTOM_DATA_KEY4]: true }
42638
+ };
42639
+ }
42640
+ return {
42641
+ strokeWidth: getDisplaySceneStrokeWidth3(this.state.zoom.value)
42642
+ };
42643
+ });
42095
42644
  __publicField(this, "createGenericElementOnPointerDown", (elementType, pointerDownState) => {
42096
42645
  const [gridX, gridY] = getGridPoint2(
42097
42646
  pointerDownState.origin.x,
@@ -42108,7 +42657,7 @@ var App = class _App extends React46.Component {
42108
42657
  strokeColor: this.state.currentItemStrokeColor,
42109
42658
  backgroundColor: this.state.currentItemBackgroundColor,
42110
42659
  fillStyle: this.state.currentItemFillStyle,
42111
- strokeWidth: this.state.currentItemStrokeWidth,
42660
+ ...this.getNewElementStrokeProps(),
42112
42661
  strokeStyle: this.state.currentItemStrokeStyle,
42113
42662
  roughness: this.state.currentItemRoughness,
42114
42663
  opacity: this.state.currentItemOpacity,
@@ -42764,7 +43313,7 @@ var App = class _App extends React46.Component {
42764
43313
  y: gridY,
42765
43314
  width: distance2(pointerDownState.originInGrid.x, gridX),
42766
43315
  height: distance2(pointerDownState.originInGrid.y, gridY),
42767
- shouldMaintainAspectRatio: isImageElement9(newElement7) ? !shouldMaintainAspectRatio(event) : shouldMaintainAspectRatio(event),
43316
+ shouldMaintainAspectRatio: shouldForceMaintainAspectRatio2(newElement7) ? true : shouldMaintainAspectRatio(event),
42768
43317
  shouldResizeFromCenter: shouldResizeFromCenter(event),
42769
43318
  zoom: this.state.zoom.value,
42770
43319
  scene: this.scene,
@@ -42920,7 +43469,7 @@ var App = class _App extends React46.Component {
42920
43469
  this.scene,
42921
43470
  shouldRotateWithDiscreteAngle3(event),
42922
43471
  shouldResizeFromCenter(event),
42923
- selectedElements.some((element) => isImageElement9(element)) ? !shouldMaintainAspectRatio(event) : shouldMaintainAspectRatio(event),
43472
+ selectedElements.some(shouldForceMaintainAspectRatio2) ? true : shouldMaintainAspectRatio(event),
42924
43473
  resizeX,
42925
43474
  resizeY,
42926
43475
  pointerDownState.resize.center.x,
@@ -42935,7 +43484,6 @@ var App = class _App extends React46.Component {
42935
43484
  });
42936
43485
  __publicField(this, "getContextMenuItems", (type) => {
42937
43486
  const options = [];
42938
- options.push(actionCopyAsPng, actionCopyAsSvg);
42939
43487
  if (type === "canvas") {
42940
43488
  if (this.state.viewModeEnabled) {
42941
43489
  return [
@@ -42949,8 +43497,8 @@ var App = class _App extends React46.Component {
42949
43497
  return [
42950
43498
  actionPaste,
42951
43499
  CONTEXT_MENU_SEPARATOR,
42952
- actionCopyAsPng,
42953
- actionCopyAsSvg,
43500
+ // actionCopyAsPng,
43501
+ // actionCopyAsSvg,
42954
43502
  copyText,
42955
43503
  CONTEXT_MENU_SEPARATOR,
42956
43504
  actionSelectAll,
@@ -42969,7 +43517,7 @@ var App = class _App extends React46.Component {
42969
43517
  if (this.state.viewModeEnabled) {
42970
43518
  return [actionCopy, ...options];
42971
43519
  }
42972
- const zIndexActions = this.editorInterface.formFactor === "desktop" ? [
43520
+ const zIndexActions = this.editorInterface.formFactor !== "phone" ? [
42973
43521
  CONTEXT_MENU_SEPARATOR,
42974
43522
  actionSendBackward,
42975
43523
  actionBringForward,
@@ -43864,7 +44412,8 @@ var App = class _App extends React46.Component {
43864
44412
  this.state.cursorButton === "down"
43865
44413
  );
43866
44414
  const firstSelectedElement = selectedElements[0];
43867
- const frameDimensionLabelElement = this.state.newElement && isFrameLikeElement15(this.state.newElement) ? this.state.newElement : this.state.isResizing && !this.state.isRotating && selectedElements.length === 1 && isFrameLikeElement15(firstSelectedElement) ? firstSelectedElement : null;
44415
+ const isDraggingSelectedElements = this.state.selectedElementsAreBeingDragged;
44416
+ const frameDimensionLabelElement = this.state.newElement && isFrameLikeElement15(this.state.newElement) ? this.state.newElement : selectedElements.length === 1 && !this.state.isRotating && !isDraggingSelectedElements && isFrameLikeElement15(firstSelectedElement) ? firstSelectedElement : null;
43868
44417
  const showShapeSwitchPanel = editorJotaiStore.get(convertElementTypePopupAtom)?.type === "panel";
43869
44418
  return /* @__PURE__ */ jsx161(
43870
44419
  "div",
@@ -44067,7 +44616,8 @@ var App = class _App extends React46.Component {
44067
44616
  embedsValidationStatus: this.embedsValidationStatus,
44068
44617
  elementsPendingErasure: this.elementsPendingErasure,
44069
44618
  pendingFlowchartNodes: this.flowChartCreator.pendingNodes,
44070
- theme: this.state.theme
44619
+ theme: this.state.theme,
44620
+ zoom: this.state.zoom.value
44071
44621
  }
44072
44622
  }
44073
44623
  ),
@@ -44087,7 +44637,8 @@ var App = class _App extends React46.Component {
44087
44637
  embedsValidationStatus: this.embedsValidationStatus,
44088
44638
  elementsPendingErasure: this.elementsPendingErasure,
44089
44639
  pendingFlowchartNodes: null,
44090
- theme: this.state.theme
44640
+ theme: this.state.theme,
44641
+ zoom: this.state.zoom.value
44091
44642
  }
44092
44643
  }
44093
44644
  ),
@@ -44769,7 +45320,7 @@ var App = class _App extends React46.Component {
44769
45320
  strokeColor: this.state.currentItemStrokeColor,
44770
45321
  backgroundColor: this.state.currentItemBackgroundColor,
44771
45322
  fillStyle: this.state.currentItemFillStyle,
44772
- strokeWidth: this.state.currentItemStrokeWidth,
45323
+ ...this.getNewElementStrokeProps(),
44773
45324
  strokeStyle: this.state.currentItemStrokeStyle,
44774
45325
  roundness: null,
44775
45326
  roughness: this.state.currentItemRoughness,
@@ -45390,11 +45941,9 @@ var App = class _App extends React46.Component {
45390
45941
  DEFAULT_COLLISION_THRESHOLD / this.state.zoom.value,
45391
45942
  1
45392
45943
  );
45393
- const [x1, y1, x2, y2] = getCommonSelectionBounds2(
45394
- selectedElements,
45395
- this.scene.getNonDeletedElementsMap()
45396
- );
45397
- return point.x > x1 - threshold && point.x < x2 + threshold && point.y > y1 - threshold && point.y < y2 + threshold;
45944
+ const boundsPadding = DEFAULT_TRANSFORM_HANDLE_SPACING3 * 2 / this.state.zoom.value;
45945
+ const [x1, y1, x2, y2] = getCommonBounds11(selectedElements);
45946
+ return point.x > x1 - boundsPadding - threshold && point.x < x2 + boundsPadding + threshold && point.y > y1 - boundsPadding - threshold && point.y < y2 + boundsPadding + threshold;
45398
45947
  }
45399
45948
  getCurrentItemRoundness(elementType) {
45400
45949
  return this.state.currentItemRoundness === "round" ? {
@@ -46032,7 +46581,8 @@ var App = class _App extends React46.Component {
46032
46581
  this.state.selectionElement,
46033
46582
  this.scene.getNonDeletedElementsMap(),
46034
46583
  false,
46035
- this.state.boxSelectionMode
46584
+ "overlap",
46585
+ this.state.zoom.value
46036
46586
  ) : [];
46037
46587
  this.setState((prevState) => {
46038
46588
  const nextSelectedElementIds = {
@@ -46866,6 +47416,15 @@ var App = class _App extends React46.Component {
46866
47416
  this.setAppState({});
46867
47417
  }
46868
47418
  };
47419
+ /**
47420
+ * 宿主业务顶部 UI 占位(与 web-art-flow 布局对齐):
47421
+ * - tool-bar-wrapper: 顶部工具栏
47422
+ * - stylebar-wrapper: 选中元素上方的样式栏(moveStyleMenuBar 定位在元素上方)
47423
+ */
47424
+ __publicField(_App, "HOST_TOOLBAR_SELECTOR", ".tool-bar-wrapper");
47425
+ /** utils/index.ts: MEUE_LEFT_BAR_HEIGHT(47) + STYLE_BAR_TO_ELEMENT_TOP_GAP_PX(26) */
47426
+ __publicField(_App, "HOST_STYLEBAR_GAP_ABOVE_ELEMENT", 73);
47427
+ var App = _App;
46869
47428
  var createTestHook = () => {
46870
47429
  if (isTestEnv5() || isDevEnv10()) {
46871
47430
  window.h = window.h || {};
@@ -46894,9 +47453,9 @@ createTestHook();
46894
47453
  var App_default = App;
46895
47454
 
46896
47455
  // components/InitializeApp.tsx
46897
- import { useEffect as useEffect49 } from "react";
47456
+ import { useEffect as useEffect48 } from "react";
46898
47457
  var InitializeApp = (props) => {
46899
- useEffect49(() => {
47458
+ useEffect48(() => {
46900
47459
  const currentLang2 = languages.find((lang) => lang.code === props.langCode) || defaultLang;
46901
47460
  void setLanguage(currentLang2);
46902
47461
  }, [props.langCode]);
@@ -47191,7 +47750,7 @@ WelcomeScreen.Hints = { MenuHint, ToolbarHint, HelpHint };
47191
47750
  var WelcomeScreen_default = WelcomeScreen;
47192
47751
 
47193
47752
  // hooks/useAppStateValue.ts
47194
- import { useEffect as useEffect50, useRef as useRef45, useState as useState43 } from "react";
47753
+ import { useEffect as useEffect49, useRef as useRef45, useState as useState43 } from "react";
47195
47754
  var getSelectedValue = (appState, selector) => {
47196
47755
  if (typeof selector === "function") {
47197
47756
  return selector(appState);
@@ -47236,7 +47795,7 @@ function useAppStateValue(selector, _internal = true) {
47236
47795
  stateRef.current.isInitialized = true;
47237
47796
  stateRef.current.latestValue = getLatestValue(api, selector, _internal);
47238
47797
  }
47239
- useEffect50(() => {
47798
+ useEffect49(() => {
47240
47799
  const currentStateRef = stateRef.current;
47241
47800
  if (!api || api.isDestroyed || !currentStateRef) {
47242
47801
  return;
@@ -47256,7 +47815,7 @@ function useOnAppStateChange(selector, callback) {
47256
47815
  });
47257
47816
  stateRef.current.selector = selector;
47258
47817
  stateRef.current.callback = callback;
47259
- useEffect50(() => {
47818
+ useEffect49(() => {
47260
47819
  if (!api || api.isDestroyed) {
47261
47820
  return;
47262
47821
  }
@@ -47599,10 +48158,10 @@ import {
47599
48158
  } from "@nous-excalidraw/element";
47600
48159
 
47601
48160
  // components/DiagramToCodePlugin/DiagramToCodePlugin.tsx
47602
- import { useLayoutEffect as useLayoutEffect10 } from "react";
48161
+ import { useLayoutEffect as useLayoutEffect11 } from "react";
47603
48162
  var DiagramToCodePlugin = (props) => {
47604
48163
  const app = useApp();
47605
- useLayoutEffect10(() => {
48164
+ useLayoutEffect11(() => {
47606
48165
  app.setPlugins({
47607
48166
  diagramToCode: { generate: props.generate }
47608
48167
  });
@@ -47689,7 +48248,7 @@ var ExcalidrawBase = (props) => {
47689
48248
  },
47690
48249
  [setExcalidrawAPI]
47691
48250
  );
47692
- useEffect51(() => {
48251
+ useEffect50(() => {
47693
48252
  const importPolyfill = async () => {
47694
48253
  await import("canvas-roundrect-polyfill");
47695
48254
  };