@excalidraw/excalidraw 0.17.1-c0b80a0 → 0.17.1-c329470

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 (178) hide show
  1. package/dist/browser/dev/excalidraw-assets-dev/{chunk-JGDL4H2X.js → chunk-3DLVY5XU.js} +8272 -6864
  2. package/dist/browser/dev/excalidraw-assets-dev/chunk-3DLVY5XU.js.map +7 -0
  3. package/dist/browser/dev/excalidraw-assets-dev/{chunk-V7NFEZA6.js → chunk-NOAEU4NM.js} +9 -2
  4. package/dist/browser/dev/excalidraw-assets-dev/chunk-NOAEU4NM.js.map +7 -0
  5. package/dist/browser/dev/excalidraw-assets-dev/{en-ZSVWGT55.js → en-7IBTMWBG.js} +2 -2
  6. package/dist/browser/dev/excalidraw-assets-dev/{image-RJG3J34Y.js → image-N5AC7SEK.js} +2 -6
  7. package/dist/browser/dev/index.css +85 -50
  8. package/dist/browser/dev/index.css.map +3 -3
  9. package/dist/browser/dev/index.js +4375 -3766
  10. package/dist/browser/dev/index.js.map +4 -4
  11. package/dist/browser/prod/excalidraw-assets/{chunk-LDVEIXGO.js → chunk-7CSIPVOW.js} +2 -2
  12. package/dist/browser/prod/excalidraw-assets/chunk-TX3BU7T2.js +47 -0
  13. package/dist/browser/prod/excalidraw-assets/{en-UPNEHLDS.js → en-LOGQBETY.js} +1 -1
  14. package/dist/browser/prod/excalidraw-assets/image-3V4U7GZE.js +1 -0
  15. package/dist/browser/prod/index.css +1 -1
  16. package/dist/browser/prod/index.js +40 -40
  17. package/dist/dev/index.css +85 -50
  18. package/dist/dev/index.css.map +3 -3
  19. package/dist/dev/index.js +8688 -6706
  20. package/dist/dev/index.js.map +4 -4
  21. package/dist/{prod/locales/en-ZXYG7GCR.json → dev/locales/en-V6KXFSCK.json} +8 -1
  22. package/dist/excalidraw/actions/actionAlign.d.ts +7 -6
  23. package/dist/excalidraw/actions/actionAlign.js +14 -14
  24. package/dist/excalidraw/actions/actionClipboard.d.ts +7 -3
  25. package/dist/excalidraw/actions/actionDeleteSelected.d.ts +7 -3
  26. package/dist/excalidraw/actions/actionDeleteSelected.js +103 -34
  27. package/dist/excalidraw/actions/actionDuplicateSelection.js +105 -95
  28. package/dist/excalidraw/actions/actionFlip.js +16 -7
  29. package/dist/excalidraw/actions/actionFrame.d.ts +493 -0
  30. package/dist/excalidraw/actions/actionFrame.js +45 -2
  31. package/dist/excalidraw/actions/actionGroup.js +6 -4
  32. package/dist/excalidraw/actions/actionProperties.js +145 -116
  33. package/dist/excalidraw/actions/actionSelectAll.js +4 -3
  34. package/dist/excalidraw/actions/shortcuts.d.ts +1 -1
  35. package/dist/excalidraw/actions/shortcuts.js +1 -0
  36. package/dist/excalidraw/actions/types.d.ts +1 -1
  37. package/dist/excalidraw/align.d.ts +2 -1
  38. package/dist/excalidraw/align.js +15 -6
  39. package/dist/excalidraw/clipboard.d.ts +27 -5
  40. package/dist/excalidraw/clipboard.js +55 -28
  41. package/dist/excalidraw/components/Actions.d.ts +2 -1
  42. package/dist/excalidraw/components/Actions.js +4 -2
  43. package/dist/excalidraw/components/ActiveConfirmDialog.d.ts +1 -1
  44. package/dist/excalidraw/components/ActiveConfirmDialog.js +2 -3
  45. package/dist/excalidraw/components/App.d.ts +1 -0
  46. package/dist/excalidraw/components/App.js +216 -111
  47. package/dist/excalidraw/components/ColorPicker/ColorInput.js +2 -3
  48. package/dist/excalidraw/components/ColorPicker/ColorPicker.js +2 -3
  49. package/dist/excalidraw/components/ColorPicker/CustomColorList.js +1 -1
  50. package/dist/excalidraw/components/ColorPicker/Picker.js +1 -1
  51. package/dist/excalidraw/components/ColorPicker/PickerColorList.js +1 -1
  52. package/dist/excalidraw/components/ColorPicker/ShadeList.js +1 -1
  53. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +1 -1
  54. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.js +1 -1
  55. package/dist/excalidraw/components/CommandPalette/CommandPalette.js +3 -3
  56. package/dist/excalidraw/components/ConfirmDialog.js +17 -5
  57. package/dist/excalidraw/components/Dialog.js +2 -3
  58. package/dist/excalidraw/components/EyeDropper.d.ts +1 -1
  59. package/dist/excalidraw/components/EyeDropper.js +1 -1
  60. package/dist/excalidraw/components/IconPicker.d.ts +2 -2
  61. package/dist/excalidraw/components/IconPicker.js +56 -53
  62. package/dist/excalidraw/components/LayerUI.js +6 -6
  63. package/dist/excalidraw/components/LibraryMenu.d.ts +2 -16
  64. package/dist/excalidraw/components/LibraryMenu.js +70 -28
  65. package/dist/excalidraw/components/LibraryMenuHeaderContent.js +4 -5
  66. package/dist/excalidraw/components/MobileMenu.js +1 -1
  67. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirm.js +2 -3
  68. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.d.ts +1 -1
  69. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.js +2 -3
  70. package/dist/excalidraw/components/Range.d.ts +9 -0
  71. package/dist/excalidraw/components/Range.js +24 -0
  72. package/dist/excalidraw/components/SearchMenu.d.ts +1 -1
  73. package/dist/excalidraw/components/SearchMenu.js +3 -4
  74. package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +1 -1
  75. package/dist/excalidraw/components/Sidebar/Sidebar.js +2 -3
  76. package/dist/excalidraw/components/Stats/Collapsible.d.ts +2 -1
  77. package/dist/excalidraw/components/Stats/Collapsible.js +2 -2
  78. package/dist/excalidraw/components/Stats/Dimension.js +94 -8
  79. package/dist/excalidraw/components/Stats/MultiDimension.js +8 -5
  80. package/dist/excalidraw/components/Stats/Position.js +63 -3
  81. package/dist/excalidraw/components/Stats/index.js +21 -4
  82. package/dist/excalidraw/components/Stats/utils.d.ts +1 -1
  83. package/dist/excalidraw/components/Stats/utils.js +2 -55
  84. package/dist/excalidraw/components/TTDDialog/TTDDialog.js +1 -1
  85. package/dist/excalidraw/components/ToolButton.js +4 -9
  86. package/dist/excalidraw/components/hoc/withInternalFallback.js +3 -3
  87. package/dist/excalidraw/components/hyperlink/Hyperlink.js +6 -12
  88. package/dist/excalidraw/components/icons.d.ts +9 -0
  89. package/dist/excalidraw/components/icons.js +4 -4
  90. package/dist/excalidraw/components/main-menu/DefaultItems.js +2 -3
  91. package/dist/excalidraw/constants.d.ts +5 -1
  92. package/dist/excalidraw/constants.js +9 -1
  93. package/dist/excalidraw/context/tunnels.d.ts +2 -1
  94. package/dist/excalidraw/context/tunnels.js +3 -1
  95. package/dist/excalidraw/data/blob.d.ts +1 -0
  96. package/dist/excalidraw/data/blob.js +7 -3
  97. package/dist/excalidraw/data/filesystem.d.ts +2 -1
  98. package/dist/excalidraw/data/filesystem.js +1 -0
  99. package/dist/excalidraw/data/image.d.ts +0 -6
  100. package/dist/excalidraw/data/image.js +1 -43
  101. package/dist/excalidraw/data/index.js +6 -6
  102. package/dist/excalidraw/data/library.d.ts +9 -3
  103. package/dist/excalidraw/data/library.js +43 -6
  104. package/dist/excalidraw/data/restore.js +26 -8
  105. package/dist/excalidraw/data/url.d.ts +0 -1
  106. package/dist/excalidraw/data/url.js +2 -4
  107. package/dist/excalidraw/editor-jotai.d.ts +56 -0
  108. package/dist/excalidraw/editor-jotai.js +8 -0
  109. package/dist/excalidraw/element/binding.d.ts +9 -6
  110. package/dist/excalidraw/element/binding.js +124 -44
  111. package/dist/excalidraw/element/bounds.js +10 -0
  112. package/dist/excalidraw/element/cropElement.d.ts +5 -0
  113. package/dist/excalidraw/element/cropElement.js +28 -1
  114. package/dist/excalidraw/element/dragElements.js +13 -7
  115. package/dist/excalidraw/element/elbowArrow.d.ts +16 -0
  116. package/dist/excalidraw/element/elbowArrow.js +1268 -0
  117. package/dist/excalidraw/element/embeddable.js +4 -5
  118. package/dist/excalidraw/element/flowchart.d.ts +1 -1
  119. package/dist/excalidraw/element/flowchart.js +25 -9
  120. package/dist/excalidraw/element/heading.d.ts +5 -1
  121. package/dist/excalidraw/element/heading.js +5 -1
  122. package/dist/excalidraw/element/image.js +19 -5
  123. package/dist/excalidraw/element/linearElementEditor.d.ts +9 -10
  124. package/dist/excalidraw/element/linearElementEditor.js +97 -38
  125. package/dist/excalidraw/element/mutateElement.d.ts +3 -1
  126. package/dist/excalidraw/element/mutateElement.js +31 -4
  127. package/dist/excalidraw/element/newElement.d.ts +8 -12
  128. package/dist/excalidraw/element/newElement.js +36 -21
  129. package/dist/excalidraw/element/resizeElements.d.ts +20 -5
  130. package/dist/excalidraw/element/resizeElements.js +593 -361
  131. package/dist/excalidraw/element/sortElements.js +1 -4
  132. package/dist/excalidraw/element/types.d.ts +23 -1
  133. package/dist/excalidraw/fonts/Fonts.d.ts +0 -16
  134. package/dist/excalidraw/fonts/Fonts.js +6 -31
  135. package/dist/excalidraw/frame.d.ts +11 -5
  136. package/dist/excalidraw/frame.js +146 -35
  137. package/dist/excalidraw/groups.js +3 -0
  138. package/dist/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
  139. package/dist/excalidraw/hooks/useLibraryItemSvg.js +2 -3
  140. package/dist/excalidraw/hooks/useScrollPosition.js +1 -1
  141. package/dist/excalidraw/i18n.js +3 -4
  142. package/dist/excalidraw/index.js +3 -4
  143. package/dist/excalidraw/locales/en.json +8 -1
  144. package/dist/excalidraw/renderer/interactiveScene.js +43 -32
  145. package/dist/excalidraw/renderer/staticScene.js +6 -4
  146. package/dist/excalidraw/renderer/staticSvgScene.js +1 -1
  147. package/dist/excalidraw/scene/Shape.js +40 -17
  148. package/dist/excalidraw/scene/comparisons.d.ts +0 -477
  149. package/dist/excalidraw/scene/comparisons.js +0 -37
  150. package/dist/excalidraw/scene/export.d.ts +7 -0
  151. package/dist/excalidraw/scene/export.js +107 -43
  152. package/dist/excalidraw/scene/index.d.ts +1 -1
  153. package/dist/excalidraw/scene/index.js +1 -1
  154. package/dist/excalidraw/scene/selection.js +4 -1
  155. package/dist/excalidraw/types.d.ts +15 -0
  156. package/dist/excalidraw/utility-types.d.ts +1 -0
  157. package/dist/excalidraw/utils.d.ts +8 -1
  158. package/dist/excalidraw/utils.js +9 -0
  159. package/dist/excalidraw/visualdebug.d.ts +8 -1
  160. package/dist/excalidraw/visualdebug.js +3 -0
  161. package/dist/math/line.d.ts +19 -0
  162. package/dist/math/line.js +32 -3
  163. package/dist/math/point.d.ts +10 -0
  164. package/dist/math/point.js +12 -1
  165. package/dist/prod/index.css +1 -1
  166. package/dist/prod/index.js +29 -44
  167. package/dist/{dev/locales/en-ZXYG7GCR.json → prod/locales/en-V6KXFSCK.json} +8 -1
  168. package/package.json +5 -2
  169. package/dist/browser/dev/excalidraw-assets-dev/chunk-JGDL4H2X.js.map +0 -7
  170. package/dist/browser/dev/excalidraw-assets-dev/chunk-V7NFEZA6.js.map +0 -7
  171. package/dist/browser/prod/excalidraw-assets/chunk-S2XKB3DE.js +0 -62
  172. package/dist/browser/prod/excalidraw-assets/image-OFI2YYMP.js +0 -1
  173. package/dist/excalidraw/element/routing.d.ts +0 -12
  174. package/dist/excalidraw/element/routing.js +0 -642
  175. package/dist/excalidraw/jotai.d.ts +0 -34
  176. package/dist/excalidraw/jotai.js +0 -18
  177. /package/dist/browser/dev/excalidraw-assets-dev/{en-ZSVWGT55.js.map → en-7IBTMWBG.js.map} +0 -0
  178. /package/dist/browser/dev/excalidraw-assets-dev/{image-RJG3J34Y.js.map → image-N5AC7SEK.js.map} +0 -0
@@ -1,11 +1,9 @@
1
1
  import { pointFrom, pointRotateRads } from "../../../math";
2
2
  import { bindOrUnbindLinearElements, updateBoundElements, } from "../../element/binding";
3
3
  import { mutateElement } from "../../element/mutateElement";
4
- import { measureFontSizeFromWidth, rescalePointsInElement, } from "../../element/resizeElements";
5
- import { getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getBoundTextMaxWidth, handleBindTextResize, } from "../../element/textElement";
4
+ import { getBoundTextElement } from "../../element/textElement";
6
5
  import { isFrameLikeElement, isLinearElement, isTextElement, } from "../../element/typeChecks";
7
6
  import { getSelectedGroupIds, getElementsInGroup, isInGroup, } from "../../groups";
8
- import { getFontString } from "../../utils";
9
7
  export const SMALLEST_DELTA = 0.01;
10
8
  export const isPropertyEditable = (element, property) => {
11
9
  if (property === "height" && isTextElement(element)) {
@@ -55,57 +53,6 @@ export const newOrigin = (x1, y1, w1, h1, w2, h2, angle) => {
55
53
  ((h2 - h1) / 2) * Math.cos(angle),
56
54
  };
57
55
  };
58
- export const resizeElement = (nextWidth, nextHeight, keepAspectRatio, origElement, elementsMap, elements, scene, shouldInformMutation = true) => {
59
- const latestElement = elementsMap.get(origElement.id);
60
- if (!latestElement) {
61
- return;
62
- }
63
- let boundTextFont = {};
64
- const boundTextElement = getBoundTextElement(latestElement, elementsMap);
65
- if (boundTextElement) {
66
- const minWidth = getApproxMinLineWidth(getFontString(boundTextElement), boundTextElement.lineHeight);
67
- const minHeight = getApproxMinLineHeight(boundTextElement.fontSize, boundTextElement.lineHeight);
68
- nextWidth = Math.max(nextWidth, minWidth);
69
- nextHeight = Math.max(nextHeight, minHeight);
70
- }
71
- mutateElement(latestElement, {
72
- ...newOrigin(latestElement.x, latestElement.y, latestElement.width, latestElement.height, nextWidth, nextHeight, latestElement.angle),
73
- width: nextWidth,
74
- height: nextHeight,
75
- ...rescalePointsInElement(origElement, nextWidth, nextHeight, true),
76
- }, shouldInformMutation);
77
- updateBindings(latestElement, elementsMap, elements, scene, {
78
- newSize: {
79
- width: nextWidth,
80
- height: nextHeight,
81
- },
82
- });
83
- if (boundTextElement) {
84
- boundTextFont = {
85
- fontSize: boundTextElement.fontSize,
86
- };
87
- if (keepAspectRatio) {
88
- const updatedElement = {
89
- ...latestElement,
90
- width: nextWidth,
91
- height: nextHeight,
92
- };
93
- const nextFont = measureFontSizeFromWidth(boundTextElement, elementsMap, getBoundTextMaxWidth(updatedElement, boundTextElement));
94
- boundTextFont = {
95
- fontSize: nextFont?.size ?? boundTextElement.fontSize,
96
- };
97
- }
98
- }
99
- updateBoundElements(latestElement, elementsMap, {
100
- newSize: { width: nextWidth, height: nextHeight },
101
- });
102
- if (boundTextElement && boundTextFont) {
103
- mutateElement(boundTextElement, {
104
- fontSize: boundTextFont.fontSize,
105
- });
106
- }
107
- handleBindTextResize(latestElement, elementsMap, "e", keepAspectRatio);
108
- };
109
56
  export const moveElement = (newTopLeftX, newTopLeftY, originalElement, elementsMap, elements, scene, originalElementsMap, shouldInformMutation = true) => {
110
57
  const latestElement = elementsMap.get(originalElement.id);
111
58
  if (!latestElement) {
@@ -153,7 +100,7 @@ export const getAtomicUnits = (targetElements, appState) => {
153
100
  };
154
101
  export const updateBindings = (latestElement, elementsMap, elements, scene, options) => {
155
102
  if (isLinearElement(latestElement)) {
156
- bindOrUnbindLinearElements([latestElement], elementsMap, elements, scene, true, []);
103
+ bindOrUnbindLinearElements([latestElement], elementsMap, elements, scene, true, [], options?.zoom);
157
104
  }
158
105
  else {
159
106
  updateBoundElements(latestElement, elementsMap, options);
@@ -17,7 +17,7 @@ import { TTDDialogPanels } from "./TTDDialogPanels";
17
17
  import { convertMermaidToExcalidraw, insertToEditor, saveMermaidDataToStorage, } from "./common";
18
18
  import { ArrowRightIcon } from "../icons";
19
19
  import "./TTDDialog.scss";
20
- import { atom, useAtom } from "jotai";
20
+ import { atom, useAtom } from "../../editor-jotai";
21
21
  import { trackEvent } from "../../analytics";
22
22
  import { InlineIcon } from "../InlineIcon";
23
23
  import { TTDDialogSubmitShortcut } from "./TTDDialogSubmitShortcut";
@@ -6,11 +6,11 @@ import { useExcalidrawContainer } from "./App";
6
6
  import { AbortError } from "../errors";
7
7
  import Spinner from "./Spinner";
8
8
  import { isPromiseLike } from "../utils";
9
- export const ToolButton = React.forwardRef((props, ref) => {
9
+ export const ToolButton = React.forwardRef(({ size = "medium", visible = true, className = "", ...props }, ref) => {
10
10
  const { id: excalId } = useExcalidrawContainer();
11
11
  const innerRef = React.useRef(null);
12
12
  React.useImperativeHandle(ref, () => innerRef.current);
13
- const sizeCn = `ToolIcon_size_${props.size}`;
13
+ const sizeCn = `ToolIcon_size_${size}`;
14
14
  const [isLoading, setIsLoading] = useState(false);
15
15
  const isMountedRef = useRef(true);
16
16
  const onClick = async (event) => {
@@ -46,7 +46,7 @@ export const ToolButton = React.forwardRef((props, ref) => {
46
46
  props.type === "icon" ||
47
47
  props.type === "submit") {
48
48
  const type = (props.type === "icon" ? "button" : props.type);
49
- return (_jsxs("button", { className: clsx("ToolIcon_type_button", sizeCn, props.className, props.visible && !props.hidden
49
+ return (_jsxs("button", { className: clsx("ToolIcon_type_button", sizeCn, className, visible && !props.hidden
50
50
  ? "ToolIcon_type_button--show"
51
51
  : "ToolIcon_type_button--hide", {
52
52
  ToolIcon: !props.hidden,
@@ -54,7 +54,7 @@ export const ToolButton = React.forwardRef((props, ref) => {
54
54
  "ToolIcon--plain": props.type === "icon",
55
55
  }), style: props.style, "data-testid": props["data-testid"], hidden: props.hidden, title: props.title, "aria-label": props["aria-label"], type: type, onClick: onClick, ref: innerRef, disabled: isLoading || props.isLoading || !!props.disabled, children: [(props.icon || props.label) && (_jsxs("div", { className: "ToolIcon__icon", "aria-hidden": "true", "aria-disabled": !!props.disabled, children: [props.icon || props.label, props.keyBindingLabel && (_jsx("span", { className: "ToolIcon__keybinding", children: props.keyBindingLabel })), props.isLoading && _jsx(Spinner, {})] })), props.showAriaLabel && (_jsxs("div", { className: "ToolIcon__label", children: [props["aria-label"], " ", isLoading && _jsx(Spinner, {})] })), props.children] }));
56
56
  }
57
- return (_jsxs("label", { className: clsx("ToolIcon", props.className), title: props.title, onPointerDown: (event) => {
57
+ return (_jsxs("label", { className: clsx("ToolIcon", className), title: props.title, onPointerDown: (event) => {
58
58
  lastPointerTypeRef.current = event.pointerType || null;
59
59
  props.onPointerDown?.({ pointerType: event.pointerType || null });
60
60
  }, onPointerUp: () => {
@@ -65,9 +65,4 @@ export const ToolButton = React.forwardRef((props, ref) => {
65
65
  props.onChange?.({ pointerType: lastPointerTypeRef.current });
66
66
  }, checked: props.checked, ref: innerRef }), _jsxs("div", { className: "ToolIcon__icon", children: [props.icon, props.keyBindingLabel && (_jsx("span", { className: "ToolIcon__keybinding", children: props.keyBindingLabel }))] })] }));
67
67
  });
68
- ToolButton.defaultProps = {
69
- visible: true,
70
- className: "",
71
- size: "medium",
72
- };
73
68
  ToolButton.displayName = "ToolButton";
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { atom, useAtom } from "jotai";
3
2
  import { useLayoutEffect, useRef } from "react";
4
3
  import { useTunnels } from "../../context/tunnels";
4
+ import { atom } from "../../editor-jotai";
5
5
  export const withInternalFallback = (componentName, Component) => {
6
6
  const renderAtom = atom(0);
7
7
  const WrapperComponent = (props) => {
8
- const { jotaiScope } = useTunnels();
8
+ const { tunnelsJotai: { useAtom }, } = useTunnels();
9
9
  // for rerenders
10
- const [, setCounter] = useAtom(renderAtom, jotaiScope);
10
+ const [, setCounter] = useAtom(renderAtom);
11
11
  // for initial & subsequent renders. Tracked as component state
12
12
  // due to excalidraw multi-instance scanerios.
13
13
  const metaRef = useRef({
@@ -118,12 +118,14 @@ export const Hyperlink = ({ element, elementsMap, setAppState, onLinkOpen, setTo
118
118
  };
119
119
  }, [handleSubmit]);
120
120
  useEffect(() => {
121
- let timeoutId = null;
122
- if (inputRef &&
123
- inputRef.current &&
121
+ if (isEditing &&
122
+ inputRef?.current &&
124
123
  !(device.viewport.isMobile || device.isTouchScreen)) {
125
124
  inputRef.current.select();
126
125
  }
126
+ }, [isEditing, device.viewport.isMobile, device.isTouchScreen]);
127
+ useEffect(() => {
128
+ let timeoutId = null;
127
129
  const handlePointerMove = (event) => {
128
130
  if (isEditing) {
129
131
  return;
@@ -145,15 +147,7 @@ export const Hyperlink = ({ element, elementsMap, setAppState, onLinkOpen, setTo
145
147
  clearTimeout(timeoutId);
146
148
  }
147
149
  };
148
- }, [
149
- appState,
150
- element,
151
- isEditing,
152
- setAppState,
153
- elementsMap,
154
- device.viewport.isMobile,
155
- device.isTouchScreen,
156
- ]);
150
+ }, [appState, element, isEditing, setAppState, elementsMap]);
157
151
  const handleRemove = useCallback(() => {
158
152
  trackEvent("hyperlink", "delete");
159
153
  mutateElement(element, { link: null });
@@ -135,6 +135,15 @@ export declare const ArrowheadDiamondIcon: React.MemoExoticComponent<({ flip }:
135
135
  export declare const ArrowheadDiamondOutlineIcon: React.MemoExoticComponent<({ flip }: {
136
136
  flip?: boolean | undefined;
137
137
  }) => JSX.Element>;
138
+ export declare const ArrowheadCrowfootIcon: React.MemoExoticComponent<({ flip }: {
139
+ flip?: boolean | undefined;
140
+ }) => JSX.Element>;
141
+ export declare const ArrowheadCrowfootOneIcon: React.MemoExoticComponent<({ flip }: {
142
+ flip?: boolean | undefined;
143
+ }) => JSX.Element>;
144
+ export declare const ArrowheadCrowfootOneOrManyIcon: React.MemoExoticComponent<({ flip }: {
145
+ flip?: boolean | undefined;
146
+ }) => JSX.Element>;
138
147
  export declare const FontSizeSmallIcon: JSX.Element;
139
148
  export declare const FontSizeMediumIcon: JSX.Element;
140
149
  export declare const FontSizeLargeIcon: JSX.Element;
@@ -184,10 +184,7 @@ export const SloppinessCartoonistIcon = createIcon(_jsx("path", { d: "M2.5 11.93
184
184
  export const EdgeSharpIcon = createIcon(_jsxs("svg", { strokeWidth: "1.5", children: [_jsx("path", { d: "M3.33334 9.99998V6.66665C3.33334 6.04326 3.33403 4.9332 3.33539 3.33646C4.95233 3.33436 6.06276 3.33331 6.66668 3.33331H10" }), _jsx("path", { d: "M13.3333 3.33331V3.34331" }), _jsx("path", { d: "M16.6667 3.33331V3.34331" }), _jsx("path", { d: "M16.6667 6.66669V6.67669" }), _jsx("path", { d: "M16.6667 10V10.01" }), _jsx("path", { d: "M3.33334 13.3333V13.3433" }), _jsx("path", { d: "M16.6667 13.3333V13.3433" }), _jsx("path", { d: "M3.33334 16.6667V16.6767" }), _jsx("path", { d: "M6.66666 16.6667V16.6767" }), _jsx("path", { d: "M10 16.6667V16.6767" }), _jsx("path", { d: "M13.3333 16.6667V16.6767" }), _jsx("path", { d: "M16.6667 16.6667V16.6767" })] }), modifiedTablerIconProps);
185
185
  // tabler-icons: border-radius
186
186
  export const EdgeRoundIcon = createIcon(_jsxs("g", { strokeWidth: "1.5", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("path", { d: "M4 12v-4a4 4 0 0 1 4 -4h4" }), _jsx("line", { x1: "16", y1: "4", x2: "16", y2: "4.01" }), _jsx("line", { x1: "20", y1: "4", x2: "20", y2: "4.01" }), _jsx("line", { x1: "20", y1: "8", x2: "20", y2: "8.01" }), _jsx("line", { x1: "20", y1: "12", x2: "20", y2: "12.01" }), _jsx("line", { x1: "4", y1: "16", x2: "4", y2: "16.01" }), _jsx("line", { x1: "20", y1: "16", x2: "20", y2: "16.01" }), _jsx("line", { x1: "4", y1: "20", x2: "4", y2: "20.01" }), _jsx("line", { x1: "8", y1: "20", x2: "8", y2: "20.01" }), _jsx("line", { x1: "12", y1: "20", x2: "12", y2: "20.01" }), _jsx("line", { x1: "16", y1: "20", x2: "16", y2: "20.01" }), _jsx("line", { x1: "20", y1: "20", x2: "20", y2: "20.01" })] }), tablerIconProps);
187
- export const ArrowheadNoneIcon = createIcon(_jsx("path", { d: "M6 10H34", stroke: "currentColor", strokeWidth: 2, fill: "none" }), {
188
- width: 40,
189
- height: 20,
190
- });
187
+ export const ArrowheadNoneIcon = createIcon(_jsxs("g", { stroke: "currentColor", opacity: 0.3, strokeWidth: 2, children: [_jsx("path", { d: "M12 12l9 0" }), _jsx("path", { d: "M3 9l6 6" }), _jsx("path", { d: "M3 15l6 -6" })] }), tablerIconProps);
191
188
  export const ArrowheadArrowIcon = React.memo(({ flip = false }) => createIcon(_jsxs("g", { transform: flip ? "translate(40, 0) scale(-1, 1)" : "", stroke: "currentColor", strokeWidth: 2, fill: "none", children: [_jsx("path", { d: "M34 10H6M34 10L27 5M34 10L27 15" }), _jsx("path", { d: "M27.5 5L34.5 10L27.5 15" })] }), { width: 40, height: 20 }));
192
189
  export const ArrowheadCircleIcon = React.memo(({ flip = false }) => createIcon(_jsxs("g", { stroke: "currentColor", fill: "currentColor", transform: flip ? "translate(40, 0) scale(-1, 1)" : "", children: [_jsx("path", { d: "M32 10L6 10", strokeWidth: 2 }), _jsx("circle", { r: "4", transform: "matrix(-1 0 0 1 30 10)" })] }), { width: 40, height: 20 }));
193
190
  export const ArrowheadCircleOutlineIcon = React.memo(({ flip = false }) => createIcon(_jsxs("g", { stroke: "currentColor", fill: "none", transform: flip ? "translate(40, 0) scale(-1, 1)" : "", strokeWidth: 2, children: [_jsx("path", { d: "M26 10L6 10" }), _jsx("circle", { r: "4", transform: "matrix(-1 0 0 1 30 10)" })] }), { width: 40, height: 20 }));
@@ -196,6 +193,9 @@ export const ArrowheadTriangleIcon = React.memo(({ flip = false }) => createIcon
196
193
  export const ArrowheadTriangleOutlineIcon = React.memo(({ flip = false }) => createIcon(_jsxs("g", { stroke: "currentColor", fill: "none", transform: flip ? "translate(40, 0) scale(-1, 1)" : "", strokeWidth: 2, strokeLinejoin: "round", children: [_jsx("path", { d: "M6,9.5H27" }), _jsx("path", { d: "M27,5L34,10L27,14Z", fill: "none" })] }), { width: 40, height: 20 }));
197
194
  export const ArrowheadDiamondIcon = React.memo(({ flip = false }) => createIcon(_jsxs("g", { stroke: "currentColor", fill: "currentColor", transform: flip ? "translate(40, 0) scale(-1, 1)" : "", strokeLinejoin: "round", strokeWidth: 2, children: [_jsx("path", { d: "M6,9.5H20" }), _jsx("path", { d: "M27,5L34,10L27,14L20,9.5Z" })] }), { width: 40, height: 20 }));
198
195
  export const ArrowheadDiamondOutlineIcon = React.memo(({ flip = false }) => createIcon(_jsxs("g", { stroke: "currentColor", fill: "none", transform: flip ? "translate(40, 0) scale(-1, 1)" : "", strokeLinejoin: "round", strokeWidth: 2, children: [_jsx("path", { d: "M6,9.5H20" }), _jsx("path", { d: "M27,5L34,10L27,14L20,9.5Z" })] }), { width: 40, height: 20 }));
196
+ export const ArrowheadCrowfootIcon = React.memo(({ flip = false }) => createIcon(_jsx("g", { stroke: "currentColor", fill: "none", transform: flip ? "" : "translate(40, 0) scale(-1, 1)", strokeLinejoin: "round", strokeWidth: 2, children: _jsx("path", { d: "M34,10 H6 M15,10 L7,5 M15,10 L7,15" }) }), { width: 40, height: 20 }));
197
+ export const ArrowheadCrowfootOneIcon = React.memo(({ flip = false }) => createIcon(_jsx("g", { stroke: "currentColor", fill: "none", transform: flip ? "" : "translate(40, 0) scale(-1, 1)", strokeLinejoin: "round", strokeWidth: 2, children: _jsx("path", { d: "M34,10 H6 M15,10 L15,15 L15,5" }) }), { width: 40, height: 20 }));
198
+ export const ArrowheadCrowfootOneOrManyIcon = React.memo(({ flip = false }) => createIcon(_jsx("g", { stroke: "currentColor", fill: "none", transform: flip ? "" : "translate(40, 0) scale(-1, 1)", strokeLinejoin: "round", strokeWidth: 2, children: _jsx("path", { d: "M34,10 H6 M15,10 L15,16 L15,4 M15,10 L7,5 M15,10 L7,15" }) }), { width: 40, height: 20 }));
199
199
  export const FontSizeSmallIcon = createIcon(_jsxs(_Fragment, { children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { d: "M14.167 6.667a3.333 3.333 0 0 0-3.334-3.334H9.167a3.333 3.333 0 0 0 0 6.667h1.666a3.333 3.333 0 0 1 0 6.667H9.167a3.333 3.333 0 0 1-3.334-3.334", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h20v20H0z" }) }) })] }), modifiedTablerIconProps);
200
200
  export const FontSizeMediumIcon = createIcon(_jsxs(_Fragment, { children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { d: "M5 16.667V3.333L10 15l5-11.667v13.334", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h20v20H0z" }) }) })] }), modifiedTablerIconProps);
201
201
  export const FontSizeLargeIcon = createIcon(_jsxs(_Fragment, { children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { d: "M5.833 3.333v13.334h8.334", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h20v20H0z" }) }) })] }), modifiedTablerIconProps);
@@ -8,9 +8,8 @@ import DropdownMenuItem from "../dropdownMenu/DropdownMenuItem";
8
8
  import DropdownMenuItemLink from "../dropdownMenu/DropdownMenuItemLink";
9
9
  import { actionClearCanvas, actionLoadScene, actionSaveToActiveFile, actionShortcuts, actionToggleSearchMenu, actionToggleTheme, } from "../../actions";
10
10
  import clsx from "clsx";
11
- import { useSetAtom } from "jotai";
12
11
  import { activeConfirmDialogAtom } from "../ActiveConfirmDialog";
13
- import { jotaiScope } from "../../jotai";
12
+ import { useSetAtom } from "../../editor-jotai";
14
13
  import { useUIAppState } from "../../context/ui-appState";
15
14
  import { openConfirmModal } from "../OverwriteConfirm/OverwriteConfirmState";
16
15
  import Trans from "../Trans";
@@ -79,7 +78,7 @@ export const Help = () => {
79
78
  Help.displayName = "Help";
80
79
  export const ClearCanvas = () => {
81
80
  const { t } = useI18n();
82
- const setActiveConfirmDialog = useSetAtom(activeConfirmDialogAtom, jotaiScope);
81
+ const setActiveConfirmDialog = useSetAtom(activeConfirmDialogAtom);
83
82
  const actionManager = useExcalidrawActionManager();
84
83
  if (!actionManager.isActionEnabled(actionClearCanvas)) {
85
84
  return null;
@@ -161,7 +161,6 @@ export declare const IMAGE_MIME_TYPES: {
161
161
  readonly avif: "image/avif";
162
162
  readonly jfif: "image/jfif";
163
163
  };
164
- export declare const ALLOWED_PASTE_MIME_TYPES: readonly ["text/plain", "text/html"];
165
164
  export declare const MIME_TYPES: {
166
165
  readonly svg: "image/svg+xml";
167
166
  readonly png: "image/png";
@@ -172,6 +171,8 @@ export declare const MIME_TYPES: {
172
171
  readonly ico: "image/x-icon";
173
172
  readonly avif: "image/avif";
174
173
  readonly jfif: "image/jfif";
174
+ readonly text: "text/plain";
175
+ readonly html: "text/html";
175
176
  readonly json: "application/json";
176
177
  readonly excalidraw: "application/vnd.excalidraw+json";
177
178
  readonly excalidrawlib: "application/vnd.excalidrawlib+json";
@@ -179,6 +180,7 @@ export declare const MIME_TYPES: {
179
180
  readonly "excalidraw.png": "image/png";
180
181
  readonly binary: "application/octet-stream";
181
182
  };
183
+ export declare const ALLOWED_PASTE_MIME_TYPES: readonly ["text/plain", "text/html", ...("image/svg+xml" | "image/png" | "image/jpeg" | "image/gif" | "image/webp" | "image/bmp" | "image/x-icon" | "image/avif" | "image/jfif")[]];
182
184
  export declare const EXPORT_IMAGE_TYPES: {
183
185
  readonly png: "png";
184
186
  readonly svg: "svg";
@@ -312,3 +314,5 @@ export declare const ARROW_TYPE: {
312
314
  };
313
315
  export declare const DEFAULT_REDUCED_GLOBAL_ALPHA = 0.3;
314
316
  export declare const ELEMENT_LINK_KEY = "element";
317
+ /** used in tests */
318
+ export declare const ORIG_ID: unique symbol;
@@ -183,8 +183,9 @@ export const IMAGE_MIME_TYPES = {
183
183
  avif: "image/avif",
184
184
  jfif: "image/jfif",
185
185
  };
186
- export const ALLOWED_PASTE_MIME_TYPES = ["text/plain", "text/html"];
187
186
  export const MIME_TYPES = {
187
+ text: "text/plain",
188
+ html: "text/html",
188
189
  json: "application/json",
189
190
  // excalidraw data
190
191
  excalidraw: "application/vnd.excalidraw+json",
@@ -197,6 +198,11 @@ export const MIME_TYPES = {
197
198
  // image
198
199
  ...IMAGE_MIME_TYPES,
199
200
  };
201
+ export const ALLOWED_PASTE_MIME_TYPES = [
202
+ MIME_TYPES.text,
203
+ MIME_TYPES.html,
204
+ ...Object.values(IMAGE_MIME_TYPES),
205
+ ];
200
206
  export const EXPORT_IMAGE_TYPES = {
201
207
  png: "png",
202
208
  svg: "svg",
@@ -372,3 +378,5 @@ export const ARROW_TYPE = {
372
378
  };
373
379
  export const DEFAULT_REDUCED_GLOBAL_ALPHA = 0.3;
374
380
  export const ELEMENT_LINK_KEY = "element";
381
+ /** used in tests */
382
+ export const ORIG_ID = Symbol.for("__test__originalId__");
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import tunnel from "tunnel-rat";
3
+ import { createIsolation } from "jotai-scope";
3
4
  export type Tunnel = ReturnType<typeof tunnel>;
4
5
  type TunnelsContextValue = {
5
6
  MainMenuTunnel: Tunnel;
@@ -12,7 +13,7 @@ type TunnelsContextValue = {
12
13
  DefaultSidebarTabTriggersTunnel: Tunnel;
13
14
  OverwriteConfirmDialogTunnel: Tunnel;
14
15
  TTDDialogTriggerTunnel: Tunnel;
15
- jotaiScope: symbol;
16
+ tunnelsJotai: ReturnType<typeof createIsolation>;
16
17
  };
17
18
  export declare const TunnelsContext: React.Context<TunnelsContextValue>;
18
19
  export declare const useTunnels: () => TunnelsContextValue;
@@ -1,7 +1,9 @@
1
1
  import React from "react";
2
2
  import tunnel from "tunnel-rat";
3
+ import { createIsolation } from "jotai-scope";
3
4
  export const TunnelsContext = React.createContext(null);
4
5
  export const useTunnels = () => React.useContext(TunnelsContext);
6
+ const tunnelsJotai = createIsolation();
5
7
  export const useInitializeTunnels = () => {
6
8
  return React.useMemo(() => {
7
9
  return {
@@ -15,7 +17,7 @@ export const useInitializeTunnels = () => {
15
17
  DefaultSidebarTabTriggersTunnel: tunnel(),
16
18
  OverwriteConfirmDialogTunnel: tunnel(),
17
19
  TTDDialogTriggerTunnel: tunnel(),
18
- jotaiScope: Symbol(),
20
+ tunnelsJotai,
19
21
  };
20
22
  }, []);
21
23
  };
@@ -8,6 +8,7 @@ export declare const getMimeType: (blob: Blob | string) => string;
8
8
  export declare const getFileHandleType: (handle: FileSystemHandle | null) => string | null;
9
9
  export declare const isImageFileHandleType: (type: string | null) => type is "png" | "svg";
10
10
  export declare const isImageFileHandle: (handle: FileSystemHandle | null) => boolean;
11
+ export declare const isSupportedImageFileType: (type: string | null | undefined) => boolean;
11
12
  export declare const isSupportedImageFile: (blob: Blob | null | undefined) => blob is Blob & {
12
13
  type: ValueOf<typeof IMAGE_MIME_TYPES>;
13
14
  };
@@ -4,6 +4,7 @@ import { IMAGE_MIME_TYPES, MIME_TYPES } from "../constants";
4
4
  import { clearElementsForExport } from "../element";
5
5
  import { CanvasError, ImageSceneDataError } from "../errors";
6
6
  import { calculateScrollCenter } from "../scene";
7
+ import { decodeSvgBase64Payload } from "../scene/export";
7
8
  import { bytesToHexString, isPromiseLike } from "../utils";
8
9
  import { base64ToString, stringToBase64, toByteString } from "./encode";
9
10
  import { nativeFileSystemSupported } from "./filesystem";
@@ -41,7 +42,7 @@ const parseFileContents = async (blob) => {
41
42
  }
42
43
  if (blob.type === MIME_TYPES.svg) {
43
44
  try {
44
- return (await import("./image")).decodeSvgMetadata({
45
+ return decodeSvgBase64Payload({
45
46
  svg: contents,
46
47
  });
47
48
  }
@@ -95,9 +96,12 @@ export const isImageFileHandle = (handle) => {
95
96
  const type = getFileHandleType(handle);
96
97
  return type === "png" || type === "svg";
97
98
  };
99
+ export const isSupportedImageFileType = (type) => {
100
+ return !!type && Object.values(IMAGE_MIME_TYPES).includes(type);
101
+ };
98
102
  export const isSupportedImageFile = (blob) => {
99
103
  const { type } = blob || {};
100
- return !!type && Object.values(IMAGE_MIME_TYPES).includes(type);
104
+ return isSupportedImageFileType(type);
101
105
  };
102
106
  export const loadSceneOrLibraryFromBlob = async (blob,
103
107
  /** @see restore.localAppState */
@@ -258,7 +262,7 @@ export const resizeImageFile = async (file, opts) => {
258
262
  if (!isSupportedImageFile(file)) {
259
263
  throw new Error("Error: unsupported file type", { cause: "UNSUPPORTED" });
260
264
  }
261
- return new File([await reduce.toBlob(file, { max: opts.maxWidthOrHeight })], file.name, {
265
+ return new File([await reduce.toBlob(file, { max: opts.maxWidthOrHeight, alpha: true })], file.name, {
262
266
  type: opts.outputType || file.type,
263
267
  });
264
268
  };
@@ -12,9 +12,10 @@ export declare const fileSave: (blob: Blob | Promise<Blob>, opts: {
12
12
  name: string;
13
13
  /** file extension */
14
14
  extension: FILE_EXTENSION;
15
+ mimeTypes?: string[];
15
16
  description: string;
16
17
  /** existing FileSystemHandle */
17
18
  fileHandle?: FileSystemHandle | null;
18
19
  }) => Promise<FileSystemHandle | null>;
19
- export type { FileSystemHandle };
20
20
  export { nativeFileSystemSupported };
21
+ export type { FileSystemHandle };
@@ -60,6 +60,7 @@ export const fileSave = (blob, opts) => {
60
60
  fileName: `${opts.name}.${opts.extension}`,
61
61
  description: opts.description,
62
62
  extensions: [`.${opts.extension}`],
63
+ mimeTypes: opts.mimeTypes,
63
64
  }, opts.fileHandle);
64
65
  };
65
66
  export { nativeFileSystemSupported };
@@ -7,9 +7,3 @@ export declare const encodePngMetadata: ({ blob, metadata, }: {
7
7
  metadata: string;
8
8
  }) => Promise<Blob>;
9
9
  export declare const decodePngMetadata: (blob: Blob) => Promise<string>;
10
- export declare const encodeSvgMetadata: ({ text }: {
11
- text: string;
12
- }) => string;
13
- export declare const decodeSvgMetadata: ({ svg }: {
14
- svg: string;
15
- }) => string;
@@ -1,7 +1,7 @@
1
1
  import decodePng from "png-chunks-extract";
2
2
  import tEXt from "png-chunk-text";
3
3
  import encodePng from "png-chunks-encode";
4
- import { stringToBase64, encode, decode, base64ToString } from "./encode";
4
+ import { encode, decode } from "./encode";
5
5
  import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants";
6
6
  import { blobToArrayBuffer } from "./blob";
7
7
  // -----------------------------------------------------------------------------
@@ -47,45 +47,3 @@ export const decodePngMetadata = async (blob) => {
47
47
  }
48
48
  throw new Error("INVALID");
49
49
  };
50
- // -----------------------------------------------------------------------------
51
- // SVG
52
- // -----------------------------------------------------------------------------
53
- export const encodeSvgMetadata = ({ text }) => {
54
- const base64 = stringToBase64(JSON.stringify(encode({ text })), true /* is already byte string */);
55
- let metadata = "";
56
- metadata += `<!-- payload-type:${MIME_TYPES.excalidraw} -->`;
57
- metadata += `<!-- payload-version:2 -->`;
58
- metadata += "<!-- payload-start -->";
59
- metadata += base64;
60
- metadata += "<!-- payload-end -->";
61
- return metadata;
62
- };
63
- export const decodeSvgMetadata = ({ svg }) => {
64
- if (svg.includes(`payload-type:${MIME_TYPES.excalidraw}`)) {
65
- const match = svg.match(/<!-- payload-start -->\s*(.+?)\s*<!-- payload-end -->/);
66
- if (!match) {
67
- throw new Error("INVALID");
68
- }
69
- const versionMatch = svg.match(/<!-- payload-version:(\d+) -->/);
70
- const version = versionMatch?.[1] || "1";
71
- const isByteString = version !== "1";
72
- try {
73
- const json = base64ToString(match[1], isByteString);
74
- const encodedData = JSON.parse(json);
75
- if (!("encoded" in encodedData)) {
76
- // legacy, un-encoded scene JSON
77
- if ("type" in encodedData &&
78
- encodedData.type === EXPORT_DATA_TYPES.excalidraw) {
79
- return json;
80
- }
81
- throw new Error("FAILED");
82
- }
83
- return decode(encodedData);
84
- }
85
- catch (error) {
86
- console.error(error);
87
- throw new Error("FAILED");
88
- }
89
- }
90
- throw new Error("INVALID");
91
- };
@@ -1,15 +1,15 @@
1
1
  import { copyBlobToClipboardAsPng, copyTextToSystemClipboard, } from "../clipboard";
2
- import { DEFAULT_EXPORT_PADDING, DEFAULT_FILENAME, isFirefox, MIME_TYPES, } from "../constants";
2
+ import { DEFAULT_EXPORT_PADDING, DEFAULT_FILENAME, IMAGE_MIME_TYPES, isFirefox, MIME_TYPES, } from "../constants";
3
3
  import { getNonDeletedElements } from "../element";
4
4
  import { isFrameLikeElement } from "../element/typeChecks";
5
+ import { getElementsOverlappingFrame } from "../frame";
5
6
  import { t } from "../i18n";
6
- import { isSomeElementSelected, getSelectedElements } from "../scene";
7
+ import { getSelectedElements, isSomeElementSelected } from "../scene";
7
8
  import { exportToCanvas, exportToSvg } from "../scene/export";
8
9
  import { cloneJSON } from "../utils";
9
10
  import { canvasToBlob } from "./blob";
10
11
  import { fileSave } from "./filesystem";
11
12
  import { serializeAsJSON } from "./json";
12
- import { getElementsOverlappingFrame } from "../frame";
13
13
  export { loadFromBlob } from "./blob";
14
14
  export { loadFromJSON, saveAsJSON } from "./json";
15
15
  export const prepareElementsForExport = (elements, { selectedElementIds }, exportSelectionOnly) => {
@@ -60,6 +60,7 @@ export const exportCanvas = async (type, elements, appState, files, { exportBack
60
60
  description: "Export to SVG",
61
61
  name,
62
62
  extension: appState.exportEmbedScene ? "excalidraw.svg" : "svg",
63
+ mimeTypes: [IMAGE_MIME_TYPES.svg],
63
64
  fileHandle,
64
65
  });
65
66
  }
@@ -91,9 +92,8 @@ export const exportCanvas = async (type, elements, appState, files, { exportBack
91
92
  return fileSave(blob, {
92
93
  description: "Export to PNG",
93
94
  name,
94
- // FIXME reintroduce `excalidraw.png` when most people upgrade away
95
- // from 111.0.5563.64 (arm64), see #6349
96
- extension: /* appState.exportEmbedScene ? "excalidraw.png" : */ "png",
95
+ extension: appState.exportEmbedScene ? "excalidraw.png" : "png",
96
+ mimeTypes: [IMAGE_MIME_TYPES.png],
97
97
  fileHandle,
98
98
  });
99
99
  }
@@ -37,7 +37,7 @@ export interface LibraryMigrationAdapter {
37
37
  /** clears entire storage afterwards */
38
38
  clear(): MaybePromise<void>;
39
39
  }
40
- export declare const libraryItemsAtom: import("jotai").PrimitiveAtom<{
40
+ export declare const libraryItemsAtom: import("jotai/vanilla/atom").PrimitiveAtom<{
41
41
  status: "loading" | "loaded";
42
42
  /** indicates whether library is initialized with library items (has gone
43
43
  * through at least one update). Used in UI. Specific to this atom only. */
@@ -83,6 +83,7 @@ declare class Library {
83
83
  }
84
84
  export default Library;
85
85
  export declare const distributeLibraryItemsOnSquareGrid: (libraryItems: LibraryItems) => ExcalidrawElement[];
86
+ export declare const validateLibraryUrl: (libraryUrl: string, validator?: string[] | ((libraryUrl: string) => boolean)) => true;
86
87
  export declare const parseLibraryTokensFromUrl: () => {
87
88
  libraryUrl: string;
88
89
  idToken: string | null;
@@ -90,9 +91,14 @@ export declare const parseLibraryTokensFromUrl: () => {
90
91
  export declare const getLibraryItemsHash: (items: LibraryItems) => number;
91
92
  export declare const useHandleLibrary: (opts: {
92
93
  excalidrawAPI: ExcalidrawImperativeAPI | null;
94
+ /**
95
+ * Return `true` if the library install url should be allowed.
96
+ * If not supplied, only the excalidraw.com base domain is allowed.
97
+ */
98
+ validateLibraryUrl?: ((libraryUrl: string) => boolean) | undefined;
93
99
  } & ({
94
100
  /** @deprecated we recommend using `opts.adapter` instead */
95
- getInitialLibraryItems?: () => MaybePromise<LibraryItemsSource>;
101
+ getInitialLibraryItems?: (() => MaybePromise<LibraryItemsSource>) | undefined;
96
102
  } | {
97
103
  adapter: LibraryPersistenceAdapter;
98
104
  /**
@@ -102,5 +108,5 @@ export declare const useHandleLibrary: (opts: {
102
108
  *
103
109
  * Can be a different LibraryPersistenceAdapter.
104
110
  */
105
- migrationAdapter?: LibraryMigrationAdapter;
111
+ migrationAdapter?: LibraryMigrationAdapter | undefined;
106
112
  })) => void;