@myoc/excalidraw 0.19.528 → 0.19.530

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.
package/dist/dev/index.js CHANGED
@@ -62,10 +62,10 @@ import {
62
62
  serializeAsJSON,
63
63
  strokeRectWithRotation_simple,
64
64
  zoomToFitBounds
65
- } from "./chunk-NY5S5VQK.js";
65
+ } from "./chunk-ROEGCKS3.js";
66
66
  import {
67
67
  define_import_meta_env_default
68
- } from "./chunk-6FFT5HLH.js";
68
+ } from "./chunk-XSA46KXZ.js";
69
69
  import {
70
70
  en_default
71
71
  } from "./chunk-SKCAT7JG.js";
@@ -10936,7 +10936,7 @@ var exportCanvas = async (type, elements, appState, files, {
10936
10936
  let blob = canvasToBlob(tempCanvas);
10937
10937
  if (appState.exportEmbedScene) {
10938
10938
  blob = blob.then(
10939
- (blob2) => import("./data/image-V7WKCORB.js").then(
10939
+ (blob2) => import("./data/image-AYT4E6ZF.js").then(
10940
10940
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
10941
10941
  blob: blob2,
10942
10942
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -13009,6 +13009,7 @@ var actionSmartZoom = register({
13009
13009
  type: "button",
13010
13010
  icon: arrowsToEyeIcon,
13011
13011
  "aria-label": t("labels.smartZoom"),
13012
+ title: `${t("labels.smartZoom")} - ${KEYS26.F.toLocaleUpperCase()}`,
13012
13013
  onClick: () => updateData(null),
13013
13014
  size: data?.size || "medium",
13014
13015
  "data-testid": "button-smart-zoom",
@@ -16832,12 +16833,13 @@ var actionToggleViewMode = register({
16832
16833
  if (appState.viewModeOnly || appProps.viewModeOnly) {
16833
16834
  return null;
16834
16835
  }
16836
+ const label = appState.viewModeEnabled ? "Edit mode" : t("labels.viewMode");
16835
16837
  return /* @__PURE__ */ jsx58(
16836
16838
  IconButton,
16837
16839
  {
16838
16840
  type: "button",
16839
- icon: eyeIcon,
16840
- "aria-label": t("labels.viewMode"),
16841
+ icon: appState.viewModeEnabled ? pencilIcon : eyeIcon,
16842
+ "aria-label": label,
16841
16843
  onClick: () => updateData(null),
16842
16844
  size: data?.size || "medium",
16843
16845
  "data-testid": "button-view-mode",
@@ -25567,6 +25569,7 @@ var getShapeActionPredicates = (appState, targetElements, elementsMap, app) => {
25567
25569
  ),
25568
25570
  align: !isSingleElementBoundContainer && alignActionsPredicate(appState, app),
25569
25571
  distribute: targetElements.length > 2,
25572
+ imageLayout: targetElements.length > 1 && targetElements.every(isImageElement4) && alignActionsPredicate(appState, app),
25570
25573
  // per-element actions
25571
25574
  // NOTE: the full panel treats a bound container as linkable; the compact /
25572
25575
  // mobile layouts only link a truly single selection. Both are preserved via
@@ -25597,7 +25600,8 @@ var LayersFieldset = ({
25597
25600
  ] });
25598
25601
  var AlignFieldset = ({
25599
25602
  renderAction,
25600
- showDistribute
25603
+ showDistribute,
25604
+ showImageLayout
25601
25605
  }) => {
25602
25606
  const isRTL3 = document.documentElement.getAttribute("dir") === "rtl";
25603
25607
  return /* @__PURE__ */ jsxs33("fieldset", { children: [
@@ -25630,7 +25634,12 @@ var AlignFieldset = ({
25630
25634
  showDistribute && renderAction("distributeVertically")
25631
25635
  ]
25632
25636
  }
25633
- )
25637
+ ),
25638
+ showImageLayout && /* @__PURE__ */ jsxs33(Fragment9, { children: [
25639
+ /* @__PURE__ */ jsx66("div", { style: { flexBasis: "100%", height: 0 } }),
25640
+ renderAction("arrangeElements"),
25641
+ renderAction("normaliseElements")
25642
+ ] })
25634
25643
  ] })
25635
25644
  ] });
25636
25645
  };
@@ -25677,7 +25686,8 @@ var SelectedShapeActions = ({
25677
25686
  AlignFieldset,
25678
25687
  {
25679
25688
  renderAction,
25680
- showDistribute: predicates.distribute
25689
+ showDistribute: predicates.distribute,
25690
+ showImageLayout: predicates.imageLayout
25681
25691
  }
25682
25692
  ),
25683
25693
  predicates.showExtraActions && /* @__PURE__ */ jsxs33("fieldset", { children: [
@@ -25689,7 +25699,8 @@ var SelectedShapeActions = ({
25689
25699
  renderAction("ungroup"),
25690
25700
  predicates.link && renderAction("hyperlink"),
25691
25701
  predicates.cropEditor && renderAction("cropEditor"),
25692
- predicates.lineEditor && renderAction("toggleLinearEditor")
25702
+ predicates.lineEditor && renderAction("toggleLinearEditor"),
25703
+ renderAction("smartZoom")
25693
25704
  ] })
25694
25705
  ] })
25695
25706
  ] });
@@ -25975,7 +25986,8 @@ var CombinedExtraActions = ({
25975
25986
  AlignFieldset,
25976
25987
  {
25977
25988
  renderAction,
25978
- showDistribute: predicates.distribute
25989
+ showDistribute: predicates.distribute,
25990
+ showImageLayout: predicates.imageLayout
25979
25991
  }
25980
25992
  ),
25981
25993
  /* @__PURE__ */ jsxs33("fieldset", { children: [
@@ -25985,6 +25997,7 @@ var CombinedExtraActions = ({
25985
25997
  renderAction("ungroup"),
25986
25998
  predicates.linkSingleOnly && renderAction("hyperlink"),
25987
25999
  predicates.cropEditor && renderAction("cropEditor"),
26000
+ renderAction("smartZoom"),
25988
26001
  showDuplicate && renderAction("duplicateSelection"),
25989
26002
  showDelete && renderAction("deleteSelectedElements")
25990
26003
  ] })
@@ -26238,17 +26251,6 @@ var ExitZenModeButton = ({
26238
26251
  children: t("buttons.exitZenMode")
26239
26252
  }
26240
26253
  );
26241
- var ExitViewModeButton = ({
26242
- actionManager
26243
- }) => /* @__PURE__ */ jsx66(
26244
- "button",
26245
- {
26246
- type: "button",
26247
- className: "disable-view-mode",
26248
- onClick: () => actionManager.executeAction(actionToggleViewMode),
26249
- children: pencilIcon
26250
- }
26251
- );
26252
26254
 
26253
26255
  // components/LoadingMessage.tsx
26254
26256
  import clsx29 from "clsx";
@@ -27038,22 +27040,19 @@ var MobileMenu = ({
27038
27040
  if (appState.openDialog?.name === "elementLinkSelector") {
27039
27041
  return null;
27040
27042
  }
27041
- const topRightUI = /* @__PURE__ */ jsxs39("div", { className: "excalidraw-ui-top-right", children: [
27042
- renderTopRightUI?.(true, appState) ?? (!appState.viewModeEnabled && /* @__PURE__ */ jsxs39(Fragment11, { children: [
27043
- defaultUIEnabled && /* @__PURE__ */ jsx80(
27044
- PenModeButton,
27045
- {
27046
- checked: appState.penMode,
27047
- onChange: () => onPenModeToggle(null),
27048
- title: t("toolBar.penMode"),
27049
- isMobile: true,
27050
- penDetected: appState.penDetected
27051
- }
27052
- ),
27053
- /* @__PURE__ */ jsx80(DefaultSidebarTriggerTunnel.Out, {})
27054
- ] })),
27055
- defaultUIEnabled && appState.viewModeEnabled && app.isInteractionEnabled() && /* @__PURE__ */ jsx80(ExitViewModeButton, { actionManager })
27056
- ] });
27043
+ const topRightUI = /* @__PURE__ */ jsx80("div", { className: "excalidraw-ui-top-right", children: renderTopRightUI?.(true, appState) ?? (!appState.viewModeEnabled && /* @__PURE__ */ jsxs39(Fragment11, { children: [
27044
+ defaultUIEnabled && /* @__PURE__ */ jsx80(
27045
+ PenModeButton,
27046
+ {
27047
+ checked: appState.penMode,
27048
+ onChange: () => onPenModeToggle(null),
27049
+ title: t("toolBar.penMode"),
27050
+ isMobile: true,
27051
+ penDetected: appState.penDetected
27052
+ }
27053
+ ),
27054
+ /* @__PURE__ */ jsx80(DefaultSidebarTriggerTunnel.Out, {})
27055
+ ] })) });
27057
27056
  const topLeftUI = /* @__PURE__ */ jsxs39("div", { className: "excalidraw-ui-top-left", children: [
27058
27057
  renderTopLeftUI?.(true, appState),
27059
27058
  /* @__PURE__ */ jsx80(MainMenuTunnel.Out, {})
@@ -27116,7 +27115,9 @@ var MobileMenu = ({
27116
27115
  {
27117
27116
  className: "App-bottom-bar",
27118
27117
  style: {
27119
- marginBottom: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN
27118
+ marginBottom: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN,
27119
+ left: 14,
27120
+ transform: "none"
27120
27121
  },
27121
27122
  "data-viewport-ui": "bottom",
27122
27123
  children: [
@@ -27137,7 +27138,14 @@ var MobileMenu = ({
27137
27138
  }
27138
27139
  )
27139
27140
  ] }),
27140
- !appState.viewModeEnabled && /* @__PURE__ */ jsx80(Island, { className: "App-toolbar", children: appState.openDialog?.name !== "elementLinkSelector" && renderToolbar() })
27141
+ !appState.viewModeEnabled && /* @__PURE__ */ jsx80(
27142
+ Island,
27143
+ {
27144
+ className: "App-toolbar",
27145
+ style: { justifyContent: "flex-start" },
27146
+ children: appState.openDialog?.name !== "elementLinkSelector" && renderToolbar()
27147
+ }
27148
+ )
27141
27149
  ]
27142
27150
  }
27143
27151
  ),
@@ -27816,7 +27824,13 @@ var Footer = ({
27816
27824
  }
27817
27825
  ),
27818
27826
  children: /* @__PURE__ */ jsx87(Stack_default.Col, { gap: 2, children: /* @__PURE__ */ jsxs45(Section, { heading: "canvasActions", children: [
27819
- !appState.viewModeOnly && /* @__PURE__ */ jsx87(Tooltip, { label: t("labels.viewMode"), children: /* @__PURE__ */ jsx87("div", { className: clsx39("view-mode-button"), children: actionManager.renderAction("viewMode") }) }),
27827
+ !appState.viewModeOnly && /* @__PURE__ */ jsx87(
27828
+ Tooltip,
27829
+ {
27830
+ label: appState.viewModeEnabled ? "Edit mode" : t("labels.viewMode"),
27831
+ children: /* @__PURE__ */ jsx87("div", { className: clsx39("view-mode-button"), children: actionManager.renderAction("viewMode") })
27832
+ }
27833
+ ),
27820
27834
  /* @__PURE__ */ jsx87(Tooltip, { label: t("buttons.smartZoom"), children: /* @__PURE__ */ jsx87("div", { className: clsx39("smart-zoom-button"), children: actionManager.renderAction("smartZoom") }) }),
27821
27835
  zoomUIEnabled && app.isNavigationEnabled() && /* @__PURE__ */ jsx87(ZoomActions, { renderAction: actionManager.renderAction }),
27822
27836
  defaultUIEnabled && !appState.viewModeEnabled && /* @__PURE__ */ jsx87(
@@ -33418,10 +33432,14 @@ var DefaultSidebar = Object.assign(
33418
33432
  children,
33419
33433
  className,
33420
33434
  docked,
33435
+ onDock,
33421
33436
  ...rest
33422
33437
  }) => {
33423
33438
  const appState = useUIAppState();
33439
+ const setAppState = useExcalidrawSetAppState();
33424
33440
  const isSearchSidebar = appState.openSidebar?.tab === CANVAS_SEARCH_TAB2;
33441
+ const isDocked = isSearchSidebar ? false : docked ?? appState.defaultSidebarDockedPreference;
33442
+ const canDock = !isSearchSidebar && docked == null && onDock !== false;
33425
33443
  return /* @__PURE__ */ createElement2(
33426
33444
  Sidebar,
33427
33445
  {
@@ -33433,8 +33451,13 @@ var DefaultSidebar = Object.assign(
33433
33451
  { "default-sidebar--search-only": isSearchSidebar },
33434
33452
  className
33435
33453
  ),
33436
- docked: isSearchSidebar ? false : docked ?? appState.defaultSidebarDockedPreference,
33437
- onDock: void 0
33454
+ docked: isDocked,
33455
+ onDock: canDock ? (nextDocked) => {
33456
+ setAppState({
33457
+ defaultSidebarDockedPreference: nextDocked
33458
+ });
33459
+ onDock?.(nextDocked);
33460
+ } : void 0
33438
33461
  },
33439
33462
  /* @__PURE__ */ jsxs64(Sidebar.Tabs, { children: [
33440
33463
  !isSearchSidebar && /* @__PURE__ */ jsx124(Sidebar.Header, {}),
@@ -34302,7 +34325,8 @@ var LayerUI = ({
34302
34325
  const renderCanvasActions = () => /* @__PURE__ */ jsxs67("div", { style: { position: "relative" }, children: [
34303
34326
  /* @__PURE__ */ jsxs67("div", { className: "excalidraw-ui-top-left", children: [
34304
34327
  renderTopLeftUI?.(false, appState),
34305
- /* @__PURE__ */ jsx131(tunnels.MainMenuTunnel.Out, {})
34328
+ /* @__PURE__ */ jsx131(tunnels.MainMenuTunnel.Out, {}),
34329
+ /* @__PURE__ */ jsx131(tunnels.DefaultSidebarTriggerTunnel.Out, {})
34306
34330
  ] }),
34307
34331
  renderWelcomeScreen && /* @__PURE__ */ jsx131(tunnels.WelcomeScreenMenuHintTunnel.Out, {})
34308
34332
  ] });
@@ -34642,9 +34666,9 @@ var LayerUI = ({
34642
34666
  ] })
34643
34667
  ]
34644
34668
  }
34645
- ),
34646
- renderSidebars()
34647
- ] })
34669
+ )
34670
+ ] }),
34671
+ renderSidebars()
34648
34672
  ] });
34649
34673
  return /* @__PURE__ */ jsx131(UIAppStateContext.Provider, { value: appState, children: /* @__PURE__ */ jsx131(TunnelsJotaiProvider, { children: /* @__PURE__ */ jsx131(TunnelsContext.Provider, { value: tunnels, children: layerUIJSX }) }) });
34650
34674
  };
@@ -36644,6 +36668,20 @@ var App = class _App extends React40.Component {
36644
36668
  const dataTransferList = await parseDataTransferEvent(event);
36645
36669
  const filesList = dataTransferList.getFiles();
36646
36670
  const data = await parseClipboard(dataTransferList, isPlainPaste);
36671
+ if (this.state.viewModeEnabled) {
36672
+ if (!this.containsImagePaste(data, filesList, isPlainPaste)) {
36673
+ return;
36674
+ }
36675
+ if (!this.shouldInsertImageInViewMode({
36676
+ source: "paste",
36677
+ files: filesList.map((file2) => file2.file),
36678
+ data,
36679
+ event
36680
+ })) {
36681
+ event?.preventDefault();
36682
+ return;
36683
+ }
36684
+ }
36647
36685
  if (this.props.onPaste) {
36648
36686
  try {
36649
36687
  if (await this.props.onPaste(data, event) === false) {
@@ -40373,9 +40411,8 @@ var App = class _App extends React40.Component {
40373
40411
  if (!isSupportedImageFile(imageFile)) {
40374
40412
  throw new Error(t("errors.unsupportedFileType"));
40375
40413
  }
40376
- const mimeType = imageFile.type;
40377
40414
  this.cursor.set("wait");
40378
- if (mimeType === MIME_TYPES9.svg) {
40415
+ if (imageFile.type === MIME_TYPES9.svg) {
40379
40416
  try {
40380
40417
  imageFile = SVGStringToFile(
40381
40418
  normalizeSVG(await imageFile.text()),
@@ -40385,7 +40422,18 @@ var App = class _App extends React40.Component {
40385
40422
  console.warn(error);
40386
40423
  throw new Error(t("errors.svgImageInsertError"));
40387
40424
  }
40425
+ } else {
40426
+ const { maxWidthOrHeight } = this.props.imageOptions;
40427
+ try {
40428
+ imageFile = await (this.props.compressImageFile ?? resizeImageFile)(
40429
+ imageFile,
40430
+ { maxWidthOrHeight }
40431
+ );
40432
+ } catch (error) {
40433
+ console.error("Error trying to resize image file on insertion", error);
40434
+ }
40388
40435
  }
40436
+ const mimeType = imageFile.type;
40389
40437
  const fileId = await (this.props.generateIdForFile?.(
40390
40438
  imageFile
40391
40439
  ) || generateIdFromFile(imageFile));
@@ -40397,15 +40445,7 @@ var App = class _App extends React40.Component {
40397
40445
  }
40398
40446
  const existingFileData = this.files[fileId];
40399
40447
  if (!existingFileData?.dataURL) {
40400
- const { maxWidthOrHeight, maxFileSizeBytes } = this.props.imageOptions;
40401
- try {
40402
- imageFile = await (this.props.compressImageFile ?? resizeImageFile)(
40403
- imageFile,
40404
- { maxWidthOrHeight }
40405
- );
40406
- } catch (error) {
40407
- console.error("Error trying to resize image file on insertion", error);
40408
- }
40448
+ const { maxFileSizeBytes } = this.props.imageOptions;
40409
40449
  if (imageFile.size > maxFileSizeBytes) {
40410
40450
  throw new Error(
40411
40451
  t("errors.fileTooBig", {
@@ -40709,6 +40749,29 @@ var App = class _App extends React40.Component {
40709
40749
  const dragDataSnapshot = captureDragEventData(event);
40710
40750
  const dataTransferList = await parseDataTransferEvent(event);
40711
40751
  const fileItems = dataTransferList.getFiles();
40752
+ const imageFiles = fileItems.map((data) => data.file).filter((file2) => isSupportedImageFile(file2));
40753
+ if (this.state.viewModeEnabled) {
40754
+ if (imageFiles.length === 0 || !this.isToolSupported("image")) {
40755
+ return;
40756
+ }
40757
+ if (!this.shouldInsertImageInViewMode({
40758
+ source: "drop",
40759
+ files: imageFiles,
40760
+ event
40761
+ })) {
40762
+ return;
40763
+ }
40764
+ return this.insertImages(
40765
+ imageFiles,
40766
+ sceneX,
40767
+ sceneY,
40768
+ parseDragImageMetadata(
40769
+ dataTransferList,
40770
+ imageFiles.length,
40771
+ dragDataSnapshot
40772
+ )
40773
+ );
40774
+ }
40712
40775
  if (fileItems.length === 1) {
40713
40776
  const { file: file2, fileHandle } = fileItems[0];
40714
40777
  if (file2 && (file2.type === MIME_TYPES9.png || file2.type === MIME_TYPES9.svg)) {
@@ -40736,7 +40799,6 @@ var App = class _App extends React40.Component {
40736
40799
  }
40737
40800
  }
40738
40801
  }
40739
- const imageFiles = fileItems.map((data) => data.file).filter((file2) => isSupportedImageFile(file2));
40740
40802
  if (imageFiles.length > 0 && this.isToolSupported("image")) {
40741
40803
  return this.insertImages(
40742
40804
  imageFiles,
@@ -41143,6 +41205,13 @@ var App = class _App extends React40.Component {
41143
41205
  }
41144
41206
  return [];
41145
41207
  });
41208
+ __publicField(this, "getImageActionContextMenuItems", (hitElement) => {
41209
+ const selectedElements = this.scene.getSelectedElements(this.state);
41210
+ if (selectedElements.length > 0 && selectedElements.every((element) => isImageElement9(element)) && (!hitElement || this.state.selectedElementIds[hitElement.id])) {
41211
+ return [actionArrangeElements, actionNormaliseElements];
41212
+ }
41213
+ return [];
41214
+ });
41146
41215
  __publicField(this, "getElementLinkContextMenuItems", (hitElement) => {
41147
41216
  if (!hitElement?.link) {
41148
41217
  return [];
@@ -41172,6 +41241,7 @@ var App = class _App extends React40.Component {
41172
41241
  });
41173
41242
  __publicField(this, "getContextMenuItems", (type, hitElement) => {
41174
41243
  const imageContextMenuItems = this.getImageContextMenuItems(hitElement);
41244
+ const imageActionContextMenuItems = this.getImageActionContextMenuItems(hitElement);
41175
41245
  const elementLinkContextMenuItems = this.getElementLinkContextMenuItems(hitElement);
41176
41246
  if (type === "canvas") {
41177
41247
  if (this.state.viewModeEnabled) {
@@ -41222,6 +41292,8 @@ var App = class _App extends React40.Component {
41222
41292
  actionPaste,
41223
41293
  imageContextMenuItems.length > 0 && CONTEXT_MENU_SEPARATOR,
41224
41294
  ...imageContextMenuItems,
41295
+ imageActionContextMenuItems.length > 0 && CONTEXT_MENU_SEPARATOR,
41296
+ ...imageActionContextMenuItems,
41225
41297
  CONTEXT_MENU_SEPARATOR,
41226
41298
  actionSelectAllElementsInFrame,
41227
41299
  actionRemoveAllElementsFromFrame,
@@ -42644,6 +42716,21 @@ var App = class _App extends React40.Component {
42644
42716
  EVENT11.GESTURE_END,
42645
42717
  this.onGestureEnd,
42646
42718
  false
42719
+ ),
42720
+ addEventListener2(document, EVENT11.PASTE, this.pasteFromClipboard, {
42721
+ passive: false
42722
+ }),
42723
+ addEventListener2(
42724
+ this.excalidrawContainerRef.current,
42725
+ EVENT11.DRAG_OVER,
42726
+ this.disableEvent,
42727
+ false
42728
+ ),
42729
+ addEventListener2(
42730
+ this.excalidrawContainerRef.current,
42731
+ EVENT11.DROP,
42732
+ this.disableEvent,
42733
+ false
42647
42734
  )
42648
42735
  );
42649
42736
  if (this.state.viewModeEnabled) {
@@ -42656,9 +42743,6 @@ var App = class _App extends React40.Component {
42656
42743
  this.onFullscreenChange,
42657
42744
  { passive: false }
42658
42745
  ),
42659
- addEventListener2(document, EVENT11.PASTE, this.pasteFromClipboard, {
42660
- passive: false
42661
- }),
42662
42746
  addEventListener2(document, EVENT11.CUT, this.onCut, { passive: false }),
42663
42747
  addEventListener2(window, EVENT11.RESIZE, this.onResize, false),
42664
42748
  addEventListener2(window, EVENT11.UNLOAD, this.onUnload, false),
@@ -42668,18 +42752,6 @@ var App = class _App extends React40.Component {
42668
42752
  EVENT11.WHEEL,
42669
42753
  this.handleWheel,
42670
42754
  { passive: false }
42671
- ),
42672
- addEventListener2(
42673
- this.excalidrawContainerRef.current,
42674
- EVENT11.DRAG_OVER,
42675
- this.disableEvent,
42676
- false
42677
- ),
42678
- addEventListener2(
42679
- this.excalidrawContainerRef.current,
42680
- EVENT11.DROP,
42681
- this.disableEvent,
42682
- false
42683
42755
  )
42684
42756
  );
42685
42757
  if (this.props.detectScroll) {
@@ -42902,6 +42974,42 @@ var App = class _App extends React40.Component {
42902
42974
  }
42903
42975
  this.addTextFromPaste(data.text, isPlainPaste);
42904
42976
  }
42977
+ containsImagePaste(data, dataTransferFiles, isPlainPaste) {
42978
+ if (dataTransferFiles.some((data2) => isSupportedImageFile(data2.file))) {
42979
+ return true;
42980
+ }
42981
+ if (!isPlainPaste && data.mixedContent?.some((node) => node.type === "imageUrl")) {
42982
+ return true;
42983
+ }
42984
+ if (isPlainPaste || !data.text) {
42985
+ return false;
42986
+ }
42987
+ const trimmedText = data.text.trim();
42988
+ return trimmedText.startsWith("<svg") && trimmedText.endsWith("</svg>");
42989
+ }
42990
+ shouldInsertImageInViewMode({
42991
+ source,
42992
+ files,
42993
+ data,
42994
+ event
42995
+ }) {
42996
+ if (!this.state.viewModeEnabled) {
42997
+ return true;
42998
+ }
42999
+ if (this.state.viewModeOnly || this.props.viewModeImageInsertBehavior === "reject") {
43000
+ this.props.onViewModeImageInsertRejected?.({
43001
+ source,
43002
+ files,
43003
+ data,
43004
+ event
43005
+ });
43006
+ return false;
43007
+ }
43008
+ flushSync2(() => {
43009
+ this.setState({ viewModeEnabled: false });
43010
+ });
43011
+ return true;
43012
+ }
42905
43013
  // TODO rewrite this to paste both text & images at the same time if
42906
43014
  // pasted data contains both
42907
43015
  async addElementsFromMixedContentPaste(mixedContent, {
@@ -45619,6 +45727,8 @@ var ExcalidrawBase = (props) => {
45619
45727
  editorPreferences,
45620
45728
  onEditorPreferencesChange,
45621
45729
  onPaste,
45730
+ viewModeImageInsertBehavior,
45731
+ onViewModeImageInsertRejected,
45622
45732
  detectScroll = true,
45623
45733
  handleKeyboardGlobally = false,
45624
45734
  autoFocus = false,
@@ -45732,6 +45842,8 @@ var ExcalidrawBase = (props) => {
45732
45842
  onEditorPreferencesChange,
45733
45843
  UIOptions,
45734
45844
  onPaste,
45845
+ viewModeImageInsertBehavior,
45846
+ onViewModeImageInsertRejected,
45735
45847
  detectScroll,
45736
45848
  handleKeyboardGlobally,
45737
45849
  autoFocus,