@zsviczian/excalidraw 0.18.101-beta.1 β 0.18.102
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.
|
@@ -341,7 +341,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
341
341
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
342
342
|
|
|
343
343
|
"use strict";
|
|
344
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addEventListener: () => (/* binding */ addEventListener),\n/* harmony export */ allowFullScreen: () => (/* binding */ allowFullScreen),\n/* harmony export */ arrayToList: () => (/* binding */ arrayToList),\n/* harmony export */ arrayToMap: () => (/* binding */ arrayToMap),\n/* harmony export */ arrayToMapWithIndex: () => (/* binding */ arrayToMapWithIndex),\n/* harmony export */ arrayToObject: () => (/* binding */ arrayToObject),\n/* harmony export */ assertNever: () => (/* binding */ assertNever),\n/* harmony export */ bytesToHexString: () => (/* binding */ bytesToHexString),\n/* harmony export */ capitalizeString: () => (/* binding */ capitalizeString),\n/* harmony export */ castArray: () => (/* binding */ castArray),\n/* harmony export */ chunk: () => (/* binding */ chunk),\n/* harmony export */ cloneJSON: () => (/* binding */ cloneJSON),\n/* harmony export */ composeEventHandlers: () => (/* binding */ composeEventHandlers),\n/* harmony export */ debounce: () => (/* binding */ debounce),\n/* harmony export */ distance: () => (/* binding */ distance),\n/* harmony export */ easeOut: () => (/* binding */ easeOut),\n/* harmony export */ easeToValuesRAF: () => (/* binding */ easeToValuesRAF),\n/* harmony export */ escapeDoubleQuotes: () => (/* binding */ escapeDoubleQuotes),\n/* harmony export */ exitFullScreen: () => (/* binding */ exitFullScreen),\n/* harmony export */ findIndex: () => (/* binding */ findIndex),\n/* harmony export */ findLastIndex: () => (/* binding */ findLastIndex),\n/* harmony export */ focusNearestParent: () => (/* binding */ focusNearestParent),\n/* harmony export */ getDateTime: () => (/* binding */ getDateTime),\n/* harmony export */ getFeatureFlag: () => (/* binding */ getFeatureFlag),\n/* harmony export */ getFontFamilyString: () => (/* binding */ getFontFamilyString),\n/* harmony export */ getFontString: () => (/* binding */ getFontString),\n/* harmony export */ getFrame: () => (/* binding */ getFrame),\n/* harmony export */ getGlobalCSSVariable: () => (/* binding */ getGlobalCSSVariable),\n/* harmony export */ getNearestScrollableContainer: () => (/* binding */ getNearestScrollableContainer),\n/* harmony export */ getSvgPathFromStroke: () => (/* binding */ getSvgPathFromStroke),\n/* harmony export */ getUpdatedTimestamp: () => (/* binding */ getUpdatedTimestamp),\n/* harmony export */ getVersion: () => (/* binding */ getVersion),\n/* harmony export */ invariant: () => (/* binding */ invariant),\n/* harmony export */ isAnyTrue: () => (/* binding */ isAnyTrue),\n/* harmony export */ isDevEnv: () => (/* binding */ isDevEnv),\n/* harmony export */ isFullScreen: () => (/* binding */ isFullScreen),\n/* harmony export */ isInputLike: () => (/* binding */ isInputLike),\n/* harmony export */ isInteractive: () => (/* binding */ isInteractive),\n/* harmony export */ isMemberOf: () => (/* binding */ isMemberOf),\n/* harmony export */ isPrimitive: () => (/* binding */ isPrimitive),\n/* harmony export */ isProdEnv: () => (/* binding */ isProdEnv),\n/* harmony export */ isPromiseLike: () => (/* binding */ isPromiseLike),\n/* harmony export */ isRTL: () => (/* binding */ isRTL),\n/* harmony export */ isReadonlyArray: () => (/* binding */ isReadonlyArray),\n/* harmony export */ isRunningInIframe: () => (/* binding */ isRunningInIframe),\n/* harmony export */ isSelectionLikeTool: () => (/* binding */ isSelectionLikeTool),\n/* harmony export */ isServerEnv: () => (/* binding */ isServerEnv),\n/* harmony export */ isShallowEqual: () => (/* binding */ isShallowEqual),\n/* harmony export */ isTestEnv: () => (/* binding */ isTestEnv),\n/* harmony export */ isToolIcon: () => (/* binding */ isToolIcon),\n/* harmony export */ isWritableElement: () => (/* binding */ isWritableElement),\n/* harmony export */ mapFind: () => (/* binding */ mapFind),\n/* harmony export */ memoize: () => (/* binding */ memoize),\n/* harmony export */ muteFSAbortError: () => (/* binding */ muteFSAbortError),\n/* harmony export */ nFormatter: () => (/* binding */ nFormatter),\n/* harmony export */ nextAnimationFrame: () => (/* binding */ nextAnimationFrame),\n/* harmony export */ normalizeEOL: () => (/* binding */ normalizeEOL),\n/* harmony export */ oneOf: () => (/* binding */ oneOf),\n/* harmony export */ preventUnload: () => (/* binding */ preventUnload),\n/* harmony export */ promiseTry: () => (/* binding */ promiseTry),\n/* harmony export */ queryFocusableElements: () => (/* binding */ queryFocusableElements),\n/* harmony export */ reduceToCommonValue: () => (/* binding */ reduceToCommonValue),\n/* harmony export */ removeSelection: () => (/* binding */ removeSelection),\n/* harmony export */ resolvablePromise: () => (/* binding */ resolvablePromise),\n/* harmony export */ safelyParseJSON: () => (/* binding */ safelyParseJSON),\n/* harmony export */ sceneCoordsToViewportCoords: () => (/* binding */ sceneCoordsToViewportCoords),\n/* harmony export */ selectNode: () => (/* binding */ selectNode),\n/* harmony export */ setDateTimeForTests: () => (/* binding */ setDateTimeForTests),\n/* harmony export */ setFeatureFlag: () => (/* binding */ setFeatureFlag),\n/* harmony export */ sizeOf: () => (/* binding */ sizeOf),\n/* harmony export */ supportsEmoji: () => (/* binding */ supportsEmoji),\n/* harmony export */ throttleRAF: () => (/* binding */ throttleRAF),\n/* harmony export */ toArray: () => (/* binding */ toArray),\n/* harmony export */ toBrandedType: () => (/* binding */ toBrandedType),\n/* harmony export */ toIterable: () => (/* binding */ toIterable),\n/* harmony export */ tupleToCoors: () => (/* binding */ tupleToCoors),\n/* harmony export */ updateActiveTool: () => (/* binding */ updateActiveTool),\n/* harmony export */ updateObject: () => (/* binding */ updateObject),\n/* harmony export */ updateStable: () => (/* binding */ updateStable),\n/* harmony export */ viewportCoordsToSceneCoords: () => (/* binding */ viewportCoordsToSceneCoords),\n/* harmony export */ wrapEvent: () => (/* binding */ wrapEvent)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/math */ \"../math/src/index.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ \"../common/src/constants.ts\");\n\n\nlet mockDateTime = null;\nconst setDateTimeForTests = dateTime => {\n mockDateTime = dateTime;\n};\nconst getDateTime = () => {\n if (mockDateTime) {\n return mockDateTime;\n }\n\n const date = new Date();\n const year = date.getFullYear();\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n const day = `${date.getDate()}`.padStart(2, \"0\");\n const hr = `${date.getHours()}`.padStart(2, \"0\");\n const min = `${date.getMinutes()}`.padStart(2, \"0\");\n return `${year}-${month}-${day}-${hr}${min}`;\n};\nconst capitalizeString = str => str.charAt(0).toUpperCase() + str.slice(1);\nconst isToolIcon = target => target instanceof HTMLElement && target.className.includes(\"ToolIcon\");\nconst isInputLike = target => target instanceof HTMLElement && target.dataset.type === \"wysiwyg\" || target instanceof HTMLBRElement || // newline in wysiwyg\ntarget instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement;\nconst isInteractive = target => {\n return isInputLike(target) || target instanceof Element && !!target.closest(\"label, button\");\n};\nconst isWritableElement = target => target instanceof HTMLElement && target.dataset.type === \"wysiwyg\" || target instanceof HTMLBRElement || // newline in wysiwyg\ntarget instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && (target.type === \"text\" || target.type === \"number\" || target.type === \"password\" || target.type === \"search\") || target instanceof HTMLElement && target.closest(\".cm-editor\") !== null;\nconst getFontFamilyString = ({\n fontFamily\n}) => {\n for (const [fontFamilyString, id] of Object.entries(_constants__WEBPACK_IMPORTED_MODULE_1__.FONT_FAMILY)) {\n if (id === fontFamily) {\n return `${fontFamilyString}${(0,_constants__WEBPACK_IMPORTED_MODULE_1__.getFontFamilyFallbacks)(id).map(x => `, ${x}`).join(\"\")}`;\n }\n }\n\n return _constants__WEBPACK_IMPORTED_MODULE_1__.WINDOWS_EMOJI_FALLBACK_FONT;\n};\n/** returns fontSize+fontFamily string for assignment to DOM elements */\n\nconst getFontString = ({\n fontSize,\n fontFamily\n}) => {\n return `${fontSize}px ${getFontFamilyString({\n fontFamily\n })}`;\n};\n/** executes callback in the frame that's after the current one */\n\nconst nextAnimationFrame = async cb => {\n requestAnimationFrame(() => requestAnimationFrame(cb));\n};\nconst debounce = (fn, timeout) => {\n let handle = 0;\n let lastArgs = null;\n\n const ret = (...args) => {\n lastArgs = args;\n clearTimeout(handle);\n handle = window.setTimeout(() => {\n lastArgs = null;\n fn(...args);\n }, timeout);\n };\n\n ret.flush = () => {\n clearTimeout(handle);\n\n if (lastArgs) {\n const _lastArgs = lastArgs;\n lastArgs = null;\n fn(..._lastArgs);\n }\n };\n\n ret.cancel = () => {\n lastArgs = null;\n clearTimeout(handle);\n };\n\n return ret;\n}; // throttle callback to execute once per animation frame using the latest args\n\nconst throttleRAF = fn => {\n let timerId = null;\n let lastArgs = null;\n\n const scheduleFunc = () => {\n timerId = window.requestAnimationFrame(() => {\n timerId = null;\n const args = lastArgs;\n lastArgs = null;\n\n if (args) {\n fn(...args);\n }\n });\n };\n\n const ret = (...args) => {\n lastArgs = args;\n\n if (timerId === null) {\n scheduleFunc();\n }\n };\n\n ret.flush = () => {\n if (timerId !== null) {\n cancelAnimationFrame(timerId);\n timerId = null;\n }\n\n if (lastArgs) {\n fn(...lastArgs);\n lastArgs = null;\n }\n };\n\n ret.cancel = () => {\n lastArgs = null;\n\n if (timerId !== null) {\n cancelAnimationFrame(timerId);\n timerId = null;\n }\n };\n\n return ret;\n};\n/**\n * Exponential ease-out method\n *\n * @param {number} k - The value to be tweened.\n * @returns {number} The tweened value.\n */\n\nconst easeOut = k => {\n return 1 - Math.pow(1 - k, 4);\n};\n\nconst easeOutInterpolate = (from, to, progress) => {\n return (to - from) * easeOut(progress) + from;\n};\n/**\n * Animates values from `fromValues` to `toValues` using the requestAnimationFrame API.\n * Executes the `onStep` callback on each step with the interpolated values.\n * Returns a function that can be called to cancel the animation.\n *\n * @example\n * // Example usage:\n * const fromValues = { x: 0, y: 0 };\n * const toValues = { x: 100, y: 200 };\n * const onStep = ({x, y}) => {\n * setState(x, y)\n * };\n * const onCancel = () => {\n * console.log(\"Animation canceled\");\n * };\n *\n * const cancelAnimation = easeToValuesRAF({\n * fromValues,\n * toValues,\n * onStep,\n * onCancel,\n * });\n *\n * // To cancel the animation:\n * cancelAnimation();\n */\n\n\nconst easeToValuesRAF = ({\n fromValues,\n toValues,\n onStep,\n duration = 250,\n interpolateValue,\n onStart,\n onEnd,\n onCancel\n}) => {\n let canceled = false;\n let frameId = 0;\n let startTime;\n\n function step(timestamp) {\n if (canceled) {\n return;\n }\n\n if (startTime === undefined) {\n startTime = timestamp;\n onStart === null || onStart === void 0 ? void 0 : onStart();\n }\n\n const elapsed = Math.min(timestamp - startTime, duration);\n const factor = easeOut(elapsed / duration);\n const newValues = {};\n Object.keys(fromValues).forEach(key => {\n const _key = key;\n const result = (toValues[_key] - fromValues[_key]) * factor + fromValues[_key];\n newValues[_key] = result;\n });\n onStep(newValues);\n\n if (elapsed < duration) {\n const progress = elapsed / duration;\n const newValues = {};\n Object.keys(fromValues).forEach(key => {\n const _key = key;\n const startValue = fromValues[_key];\n const endValue = toValues[_key];\n let result;\n result = interpolateValue ? interpolateValue(startValue, endValue, progress, _key) : easeOutInterpolate(startValue, endValue, progress);\n\n if (result == null) {\n result = easeOutInterpolate(startValue, endValue, progress);\n }\n\n newValues[_key] = result;\n });\n onStep(newValues);\n frameId = window.requestAnimationFrame(step);\n } else {\n onStep(toValues);\n onEnd === null || onEnd === void 0 ? void 0 : onEnd();\n }\n }\n\n frameId = window.requestAnimationFrame(step);\n return () => {\n onCancel === null || onCancel === void 0 ? void 0 : onCancel();\n canceled = true;\n window.cancelAnimationFrame(frameId);\n };\n}; // https://github.com/lodash/lodash/blob/es/chunk.js\n\nconst chunk = (array, size) => {\n if (!array.length || size < 1) {\n return [];\n }\n\n let index = 0;\n let resIndex = 0;\n const result = Array(Math.ceil(array.length / size));\n\n while (index < array.length) {\n result[resIndex++] = array.slice(index, index += size);\n }\n\n return result;\n};\nconst selectNode = node => {\n const selection = window.getSelection();\n\n if (selection) {\n const range = document.createRange();\n range.selectNodeContents(node);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n};\nconst removeSelection = () => {\n const selection = window.getSelection();\n\n if (selection) {\n selection.removeAllRanges();\n }\n};\nconst distance = (x, y) => Math.abs(x - y);\nconst isSelectionLikeTool = type => {\n return type === \"selection\" || type === \"lasso\";\n};\nconst updateActiveTool = (appState, data) => {\n var _a, _b, _c;\n\n if (data.type === \"custom\") {\n return Object.assign(Object.assign({}, appState.activeTool), {\n type: \"custom\",\n customType: data.customType,\n locked: (_a = data.locked) !== null && _a !== void 0 ? _a : appState.activeTool.locked\n });\n }\n\n return Object.assign(Object.assign({}, appState.activeTool), {\n lastActiveTool: data.lastActiveToolBeforeEraser === undefined ? appState.activeTool.lastActiveTool : data.lastActiveToolBeforeEraser,\n type: data.type,\n customType: null,\n locked: (_b = data.locked) !== null && _b !== void 0 ? _b : appState.activeTool.locked,\n fromSelection: (_c = data.fromSelection) !== null && _c !== void 0 ? _c : false\n });\n};\nconst isFullScreen = () => {\n var _a;\n\n return ((_a = document.fullscreenElement) === null || _a === void 0 ? void 0 : _a.nodeName) === \"HTML\";\n};\nconst allowFullScreen = () => document.documentElement.requestFullscreen();\nconst exitFullScreen = () => document.exitFullscreen();\nconst viewportCoordsToSceneCoords = ({\n clientX,\n clientY\n}, {\n zoom,\n offsetLeft,\n offsetTop,\n scrollX,\n scrollY\n}) => {\n const x = (clientX - offsetLeft) / zoom.value - scrollX;\n const y = (clientY - offsetTop) / zoom.value - scrollY;\n return {\n x,\n y\n };\n};\nconst sceneCoordsToViewportCoords = ({\n sceneX,\n sceneY\n}, {\n zoom,\n offsetLeft,\n offsetTop,\n scrollX,\n scrollY\n}) => {\n const x = (sceneX + scrollX) * zoom.value + offsetLeft;\n const y = (sceneY + scrollY) * zoom.value + offsetTop;\n return {\n x,\n y\n };\n};\nconst getGlobalCSSVariable = name => getComputedStyle(document.documentElement).getPropertyValue(`--${name}`);\nconst RS_LTR_CHARS = \"A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02B8\\u0300-\\u0590\\u0800-\\u1FFF\" + \"\\u2C00-\\uFB1C\\uFDFE-\\uFE6F\\uFEFD-\\uFFFF\";\nconst RS_RTL_CHARS = \"\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC\";\nconst RE_RTL_CHECK = new RegExp(`^[^${RS_LTR_CHARS}]*[${RS_RTL_CHARS}]`);\n/**\n * Checks whether first directional character is RTL. Meaning whether it starts\n * with RTL characters, or indeterminate (numbers etc.) characters followed by\n * RTL.\n * See https://github.com/excalidraw/excalidraw/pull/1722#discussion_r436340171\n */\n\nconst isRTL = text => RE_RTL_CHECK.test(text);\nconst tupleToCoors = xyTuple => {\n const [x, y] = xyTuple;\n return {\n x,\n y\n };\n};\n/** use as a rejectionHandler to mute filesystem Abort errors */\n\nconst muteFSAbortError = error => {\n if ((error === null || error === void 0 ? void 0 : error.name) === \"AbortError\") {\n console.warn(error);\n return;\n }\n\n throw error;\n};\nconst findIndex = (array, cb, fromIndex = 0) => {\n if (fromIndex < 0) {\n fromIndex = array.length + fromIndex;\n }\n\n fromIndex = Math.min(array.length, Math.max(fromIndex, 0));\n let index = fromIndex - 1;\n\n while (++index < array.length) {\n if (cb(array[index], index, array)) {\n return index;\n }\n }\n\n return -1;\n};\nconst findLastIndex = (array, cb, fromIndex = array.length - 1) => {\n if (fromIndex < 0) {\n fromIndex = array.length + fromIndex;\n }\n\n fromIndex = Math.min(array.length - 1, Math.max(fromIndex, 0));\n let index = fromIndex + 1;\n\n while (--index > -1) {\n if (cb(array[index], index, array)) {\n return index;\n }\n }\n\n return -1;\n};\n/** returns the first non-null mapped value */\n\nconst mapFind = (collection, iteratee) => {\n for (let idx = 0; idx < collection.length; idx++) {\n const result = iteratee(collection[idx], idx);\n\n if (result != null) {\n return result;\n }\n }\n\n return undefined;\n};\nconst resolvablePromise = () => {\n let resolve;\n let reject;\n const promise = new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n });\n promise.resolve = resolve;\n promise.reject = reject;\n return promise;\n}; //https://stackoverflow.com/a/9462382/8418\n\nconst nFormatter = (num, digits) => {\n const si = [{\n value: 1,\n symbol: \"b\"\n }, {\n value: 1e3,\n symbol: \"k\"\n }, {\n value: 1e6,\n symbol: \"M\"\n }, {\n value: 1e9,\n symbol: \"G\"\n }];\n const rx = /\\.0+$|(\\.[0-9]*[1-9])0+$/;\n let index;\n\n for (index = si.length - 1; index > 0; index--) {\n if (num >= si[index].value) {\n break;\n }\n }\n\n return (num / si[index].value).toFixed(digits).replace(rx, \"$1\") + si[index].symbol;\n};\nconst getVersion = () => {\n var _a;\n\n return ((_a = document.querySelector('meta[name=\"version\"]')) === null || _a === void 0 ? void 0 : _a.content) || _constants__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_VERSION;\n}; // Adapted from https://github.com/Modernizr/Modernizr/blob/master/feature-detects/emoji.js\n\nconst supportsEmoji = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n\n if (!ctx) {\n return false;\n }\n\n const offset = 12;\n ctx.fillStyle = \"#f00\";\n ctx.textBaseline = \"top\";\n ctx.font = \"32px Arial\"; // Modernizr used π¨, but it is sort of supported on Windows 7.\n // Luckily π isn't supported.\n\n ctx.fillText(\"π\", 0, 0);\n return ctx.getImageData(offset, offset, 1, 1).data[0] !== 0;\n};\nconst getNearestScrollableContainer = element => {\n let parent = element.parentElement;\n\n while (parent) {\n if (parent === document.body) {\n return document;\n }\n\n const {\n overflowY\n } = window.getComputedStyle(parent);\n const hasScrollableContent = parent.scrollHeight > parent.clientHeight;\n\n if (hasScrollableContent && (overflowY === \"auto\" || overflowY === \"scroll\" || overflowY === \"overlay\")) {\n return parent;\n }\n\n parent = parent.parentElement;\n }\n\n return document;\n};\nconst focusNearestParent = element => {\n let parent = element.parentElement;\n\n while (parent) {\n if (parent.tabIndex > -1) {\n parent.focus();\n return;\n }\n\n parent = parent.parentElement;\n }\n};\nconst preventUnload = event => {\n event.preventDefault(); // NOTE: modern browsers no longer allow showing a custom message here\n\n event.returnValue = \"\";\n};\nconst bytesToHexString = bytes => {\n return Array.from(bytes).map(byte => `0${byte.toString(16)}`.slice(-2)).join(\"\");\n};\nconst getUpdatedTimestamp = () => isTestEnv() ? 1 : Date.now();\n/**\n * Transforms array of objects containing `id` attribute,\n * or array of ids (strings), into a Map, keyd by `id`.\n */\n\nconst arrayToMap = items => {\n if (items instanceof Map) {\n return items;\n }\n\n return items.reduce((acc, element) => {\n acc.set(typeof element === \"string\" ? element : element.id, element);\n return acc;\n }, new Map());\n};\nconst arrayToMapWithIndex = elements => elements.reduce((acc, element, idx) => {\n acc.set(element.id, [element, idx]);\n return acc;\n}, new Map());\n/**\n * Transform array into an object, use only when array order is irrelevant.\n */\n\nconst arrayToObject = (array, groupBy) => array.reduce((acc, value, idx) => {\n acc[groupBy ? groupBy(value) : idx] = value;\n return acc;\n}, {});\n/**\n * Creates a circular doubly linked list by adding `prev` and `next` props to the existing array nodes.\n */\n\nconst arrayToList = array => array.reduce((acc, curr, index) => {\n const node = Object.assign(Object.assign({}, curr), {\n prev: null,\n next: null\n }); // no-op for first item, we don't want circular references on a single item\n\n if (index !== 0) {\n const prevNode = acc[index - 1];\n node.prev = prevNode;\n prevNode.next = node;\n\n if (index === array.length - 1) {\n // make the references circular and connect head & tail\n const firstNode = acc[0];\n node.next = firstNode;\n firstNode.prev = node;\n }\n }\n\n acc.push(node);\n return acc;\n}, []);\n/**\n * Converts a readonly array or map into an iterable.\n * Useful for avoiding entry allocations when iterating object / map on each iteration.\n */\n\nconst toIterable = values => {\n return Array.isArray(values) ? values : values.values();\n};\n/**\n * Converts a readonly array or map into an array.\n */\n\nconst toArray = values => {\n return Array.isArray(values) ? values : Array.from(toIterable(values));\n};\nconst isTestEnv = () => \"development\" === _constants__WEBPACK_IMPORTED_MODULE_1__.ENV.TEST;\nconst isDevEnv = () => \"development\" === _constants__WEBPACK_IMPORTED_MODULE_1__.ENV.DEVELOPMENT;\nconst isProdEnv = () => \"development\" === _constants__WEBPACK_IMPORTED_MODULE_1__.ENV.PRODUCTION;\nconst isServerEnv = () => {\n var _a;\n\n return typeof process !== \"undefined\" && !!((_a = process === null || process === void 0 ? void 0 : ({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.0\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true})) === null || _a === void 0 ? void 0 : _a.NODE_ENV);\n};\nconst wrapEvent = (name, nativeEvent) => {\n return new CustomEvent(name, {\n detail: {\n nativeEvent\n },\n cancelable: true\n });\n};\nconst updateObject = (obj, updates) => {\n let didChange = false;\n\n for (const key in updates) {\n const value = updates[key];\n\n if (typeof value !== \"undefined\") {\n if (obj[key] === value && ( // if object, always update because its attrs could have changed\n typeof value !== \"object\" || value === null)) {\n continue;\n }\n\n didChange = true;\n }\n }\n\n if (!didChange) {\n return obj;\n }\n\n return Object.assign(Object.assign({}, obj), updates);\n};\nconst isPrimitive = val => {\n const type = typeof val;\n return val == null || type !== \"object\" && type !== \"function\";\n};\nconst getFrame = () => {\n try {\n return window.self === window.top ? \"top\" : \"iframe\";\n } catch (error) {\n return \"iframe\";\n }\n};\nconst isRunningInIframe = () => getFrame() === \"iframe\";\nconst isPromiseLike = value => {\n return !!value && typeof value === \"object\" && \"then\" in value && \"catch\" in value && \"finally\" in value;\n};\nconst queryFocusableElements = container => {\n const focusableElements = container === null || container === void 0 ? void 0 : container.querySelectorAll(\"button, a, input, select, textarea, div[tabindex], label[tabindex]\");\n return focusableElements ? Array.from(focusableElements).filter(element => element.tabIndex > -1 && !element.disabled) : [];\n};\n/** use as a fallback after identity check (for perf reasons) */\n\nconst _defaultIsShallowComparatorFallback = (a, b) => {\n // consider two empty arrays equal\n if (Array.isArray(a) && Array.isArray(b) && a.length === 0 && b.length === 0) {\n return true;\n }\n\n return a === b;\n};\n/**\n * Returns whether object/array is shallow equal.\n * Considers empty object/arrays as equal (whether top-level or second-level).\n */\n\n\nconst isShallowEqual = (objA, objB, comparators, debug = false) => {\n const aKeys = Object.keys(objA);\n const bKeys = Object.keys(objB);\n\n if (aKeys.length !== bKeys.length) {\n if (debug) {\n console.warn(`%cisShallowEqual: objects don't have same properties ->`, \"color: #8B4000\", objA, objB);\n }\n\n return false;\n }\n\n if (comparators && Array.isArray(comparators)) {\n for (const key of comparators) {\n const ret = objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]);\n\n if (!ret) {\n if (debug) {\n console.warn(`%cisShallowEqual: ${key} not equal ->`, \"color: #8B4000\", objA[key], objB[key]);\n }\n\n return false;\n }\n }\n\n return true;\n }\n\n return aKeys.every(key => {\n const comparator = comparators === null || comparators === void 0 ? void 0 : comparators[key];\n const ret = comparator ? comparator(objA[key], objB[key]) : objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]);\n\n if (!ret && debug) {\n console.warn(`%cisShallowEqual: ${key} not equal ->`, \"color: #8B4000\", objA[key], objB[key]);\n }\n\n return ret;\n });\n}; // taken from Radix UI\n// https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx\n\nconst composeEventHandlers = (originalEventHandler, ourEventHandler, {\n checkForDefaultPrevented = true\n} = {}) => {\n return function handleEvent(event) {\n originalEventHandler === null || originalEventHandler === void 0 ? void 0 : originalEventHandler(event);\n\n if (!checkForDefaultPrevented || !(event === null || event === void 0 ? void 0 : event.defaultPrevented)) {\n return ourEventHandler === null || ourEventHandler === void 0 ? void 0 : ourEventHandler(event);\n }\n };\n};\n/**\n * supply `null` as message if non-never value is valid, you just need to\n * typecheck against it\n */\n\nconst assertNever = (value, message, softAssert) => {\n if (!message) {\n return value;\n }\n\n if (softAssert) {\n console.error(message);\n return value;\n }\n\n throw new Error(message);\n};\nfunction invariant(condition, message) {\n if (!condition) {\n throw new Error(message);\n }\n}\n/**\n * Memoizes on values of `opts` object (strict equality).\n */\n\nconst memoize = func => {\n let lastArgs;\n let lastResult;\n\n const ret = function (opts) {\n const currentArgs = Object.entries(opts);\n\n if (lastArgs) {\n let argsAreEqual = true;\n\n for (const [key, value] of currentArgs) {\n if (lastArgs.get(key) !== value) {\n argsAreEqual = false;\n break;\n }\n }\n\n if (argsAreEqual) {\n return lastResult;\n }\n }\n\n const result = func(opts);\n lastArgs = new Map(currentArgs);\n lastResult = result;\n return result;\n };\n\n ret.clear = () => {\n lastArgs = undefined;\n lastResult = undefined;\n };\n\n return ret;\n};\n/** Checks if value is inside given collection. Useful for type-safety. */\n\nconst isMemberOf = (\n/** Set/Map/Array/Object */\ncollection,\n/** value to look for */\nvalue) => {\n return collection instanceof Set || collection instanceof Map ? collection.has(value) : \"includes\" in collection ? collection.includes(value) : collection.hasOwnProperty(value);\n};\nconst cloneJSON = obj => JSON.parse(JSON.stringify(obj));\nconst updateStable = (prevValue, nextValue) => {\n if (isShallowEqual(prevValue, nextValue)) {\n return prevValue;\n }\n\n return nextValue;\n}; // implem\n\nfunction addEventListener(\n/**\n * allows for falsy values so you don't have to type check when adding\n * event listeners to optional elements\n */\ntarget, type, listener, options) {\n var _a;\n\n if (!target) {\n return () => {};\n }\n\n (_a = target === null || target === void 0 ? void 0 : target.addEventListener) === null || _a === void 0 ? void 0 : _a.call(target, type, listener, options);\n return () => {\n var _a;\n\n (_a = target === null || target === void 0 ? void 0 : target.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(target, type, listener, options);\n };\n}\nfunction getSvgPathFromStroke(points, closed = true) {\n const len = points.length;\n\n if (len < 4) {\n return ``;\n }\n\n let a = points[0];\n let b = points[1];\n const c = points[2];\n let result = `M${a[0].toFixed(2)},${a[1].toFixed(2)} Q${b[0].toFixed(2)},${b[1].toFixed(2)} ${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(b[0], c[0]).toFixed(2)},${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(b[1], c[1]).toFixed(2)} T`;\n\n for (let i = 2, max = len - 1; i < max; i++) {\n a = points[i];\n b = points[i + 1];\n result += `${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(a[0], b[0]).toFixed(2)},${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(a[1], b[1]).toFixed(2)} `;\n }\n\n if (closed) {\n result += \"Z\";\n }\n\n return result;\n}\nconst normalizeEOL = str => {\n return str.replace(/\\r?\\n|\\r/g, \"\\n\");\n};\nfunction toBrandedType(value) {\n return value;\n} // -----------------------------------------------------------------------------\n// Promise.try, adapted from https://github.com/sindresorhus/p-try\n\nconst promiseTry = async (fn, ...args) => {\n return new Promise(resolve => {\n resolve(fn(...args));\n });\n};\nconst isAnyTrue = (...args) => Math.max(...args.map(arg => arg ? 1 : 0)) > 0;\nconst safelyParseJSON = json => {\n try {\n return JSON.parse(json);\n } catch (_a) {\n return null;\n }\n};\n/**\n * use when you need to render unsafe string as HTML attribute, but MAKE SURE\n * the attribute is double-quoted when constructing the HTML string\n */\n\nconst escapeDoubleQuotes = str => {\n return str.replace(/\"/g, \""\");\n};\nconst castArray = value => Array.isArray(value) ? value : [value];\n/** hack for Array.isArray type guard not working with readonly value[] */\n\nconst isReadonlyArray = value => {\n return Array.isArray(value);\n};\nconst sizeOf = value => {\n return isReadonlyArray(value) ? value.length : value instanceof Map || value instanceof Set ? value.size : Object.keys(value).length;\n};\nconst reduceToCommonValue = (collection, getValue) => {\n if (sizeOf(collection) === 0) {\n return null;\n }\n\n const valueExtractor = getValue || (item => item);\n\n let commonValue = null;\n\n for (const item of collection) {\n const value = valueExtractor(item);\n\n if ((commonValue === null || commonValue === value) && value != null) {\n commonValue = value;\n } else {\n return null;\n }\n }\n\n return commonValue;\n};\nconst FEATURE_FLAGS_STORAGE_KEY = \"excalidraw-feature-flags\";\nconst DEFAULT_FEATURE_FLAGS = {\n COMPLEX_BINDINGS: false\n};\nlet featureFlags = null;\nconst getFeatureFlag = flag => {\n if (!featureFlags) {\n try {\n const serializedFlags = localStorage.getItem(FEATURE_FLAGS_STORAGE_KEY);\n\n if (serializedFlags) {\n const flags = JSON.parse(serializedFlags);\n featureFlags = flags !== null && flags !== void 0 ? flags : DEFAULT_FEATURE_FLAGS;\n }\n } catch (_a) {}\n }\n\n return (featureFlags || DEFAULT_FEATURE_FLAGS)[flag];\n};\nconst setFeatureFlag = (flag, value) => {\n try {\n featureFlags = Object.assign(Object.assign({}, featureFlags || DEFAULT_FEATURE_FLAGS), {\n [flag]: value\n });\n localStorage.setItem(FEATURE_FLAGS_STORAGE_KEY, JSON.stringify(featureFlags));\n } catch (e) {\n console.error(\"unable to set feature flag\", e);\n }\n};\nconst oneOf = (needle, haystack) => {\n return haystack.includes(needle);\n};\n\n//# sourceURL=webpack://ExcalidrawLib/../common/src/utils.ts?\n}");
|
|
344
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addEventListener: () => (/* binding */ addEventListener),\n/* harmony export */ allowFullScreen: () => (/* binding */ allowFullScreen),\n/* harmony export */ arrayToList: () => (/* binding */ arrayToList),\n/* harmony export */ arrayToMap: () => (/* binding */ arrayToMap),\n/* harmony export */ arrayToMapWithIndex: () => (/* binding */ arrayToMapWithIndex),\n/* harmony export */ arrayToObject: () => (/* binding */ arrayToObject),\n/* harmony export */ assertNever: () => (/* binding */ assertNever),\n/* harmony export */ bytesToHexString: () => (/* binding */ bytesToHexString),\n/* harmony export */ capitalizeString: () => (/* binding */ capitalizeString),\n/* harmony export */ castArray: () => (/* binding */ castArray),\n/* harmony export */ chunk: () => (/* binding */ chunk),\n/* harmony export */ cloneJSON: () => (/* binding */ cloneJSON),\n/* harmony export */ composeEventHandlers: () => (/* binding */ composeEventHandlers),\n/* harmony export */ debounce: () => (/* binding */ debounce),\n/* harmony export */ distance: () => (/* binding */ distance),\n/* harmony export */ easeOut: () => (/* binding */ easeOut),\n/* harmony export */ easeToValuesRAF: () => (/* binding */ easeToValuesRAF),\n/* harmony export */ escapeDoubleQuotes: () => (/* binding */ escapeDoubleQuotes),\n/* harmony export */ exitFullScreen: () => (/* binding */ exitFullScreen),\n/* harmony export */ findIndex: () => (/* binding */ findIndex),\n/* harmony export */ findLastIndex: () => (/* binding */ findLastIndex),\n/* harmony export */ focusNearestParent: () => (/* binding */ focusNearestParent),\n/* harmony export */ getDateTime: () => (/* binding */ getDateTime),\n/* harmony export */ getFeatureFlag: () => (/* binding */ getFeatureFlag),\n/* harmony export */ getFontFamilyString: () => (/* binding */ getFontFamilyString),\n/* harmony export */ getFontString: () => (/* binding */ getFontString),\n/* harmony export */ getFrame: () => (/* binding */ getFrame),\n/* harmony export */ getGlobalCSSVariable: () => (/* binding */ getGlobalCSSVariable),\n/* harmony export */ getNearestScrollableContainer: () => (/* binding */ getNearestScrollableContainer),\n/* harmony export */ getSvgPathFromStroke: () => (/* binding */ getSvgPathFromStroke),\n/* harmony export */ getUpdatedTimestamp: () => (/* binding */ getUpdatedTimestamp),\n/* harmony export */ getVersion: () => (/* binding */ getVersion),\n/* harmony export */ invariant: () => (/* binding */ invariant),\n/* harmony export */ isAnyTrue: () => (/* binding */ isAnyTrue),\n/* harmony export */ isDevEnv: () => (/* binding */ isDevEnv),\n/* harmony export */ isFullScreen: () => (/* binding */ isFullScreen),\n/* harmony export */ isInputLike: () => (/* binding */ isInputLike),\n/* harmony export */ isInteractive: () => (/* binding */ isInteractive),\n/* harmony export */ isMemberOf: () => (/* binding */ isMemberOf),\n/* harmony export */ isPrimitive: () => (/* binding */ isPrimitive),\n/* harmony export */ isProdEnv: () => (/* binding */ isProdEnv),\n/* harmony export */ isPromiseLike: () => (/* binding */ isPromiseLike),\n/* harmony export */ isRTL: () => (/* binding */ isRTL),\n/* harmony export */ isReadonlyArray: () => (/* binding */ isReadonlyArray),\n/* harmony export */ isRunningInIframe: () => (/* binding */ isRunningInIframe),\n/* harmony export */ isSelectionLikeTool: () => (/* binding */ isSelectionLikeTool),\n/* harmony export */ isServerEnv: () => (/* binding */ isServerEnv),\n/* harmony export */ isShallowEqual: () => (/* binding */ isShallowEqual),\n/* harmony export */ isTestEnv: () => (/* binding */ isTestEnv),\n/* harmony export */ isToolIcon: () => (/* binding */ isToolIcon),\n/* harmony export */ isWritableElement: () => (/* binding */ isWritableElement),\n/* harmony export */ mapFind: () => (/* binding */ mapFind),\n/* harmony export */ memoize: () => (/* binding */ memoize),\n/* harmony export */ muteFSAbortError: () => (/* binding */ muteFSAbortError),\n/* harmony export */ nFormatter: () => (/* binding */ nFormatter),\n/* harmony export */ nextAnimationFrame: () => (/* binding */ nextAnimationFrame),\n/* harmony export */ normalizeEOL: () => (/* binding */ normalizeEOL),\n/* harmony export */ oneOf: () => (/* binding */ oneOf),\n/* harmony export */ preventUnload: () => (/* binding */ preventUnload),\n/* harmony export */ promiseTry: () => (/* binding */ promiseTry),\n/* harmony export */ queryFocusableElements: () => (/* binding */ queryFocusableElements),\n/* harmony export */ reduceToCommonValue: () => (/* binding */ reduceToCommonValue),\n/* harmony export */ removeSelection: () => (/* binding */ removeSelection),\n/* harmony export */ resolvablePromise: () => (/* binding */ resolvablePromise),\n/* harmony export */ safelyParseJSON: () => (/* binding */ safelyParseJSON),\n/* harmony export */ sceneCoordsToViewportCoords: () => (/* binding */ sceneCoordsToViewportCoords),\n/* harmony export */ selectNode: () => (/* binding */ selectNode),\n/* harmony export */ setDateTimeForTests: () => (/* binding */ setDateTimeForTests),\n/* harmony export */ setFeatureFlag: () => (/* binding */ setFeatureFlag),\n/* harmony export */ sizeOf: () => (/* binding */ sizeOf),\n/* harmony export */ supportsEmoji: () => (/* binding */ supportsEmoji),\n/* harmony export */ throttleRAF: () => (/* binding */ throttleRAF),\n/* harmony export */ toArray: () => (/* binding */ toArray),\n/* harmony export */ toBrandedType: () => (/* binding */ toBrandedType),\n/* harmony export */ toIterable: () => (/* binding */ toIterable),\n/* harmony export */ tupleToCoors: () => (/* binding */ tupleToCoors),\n/* harmony export */ updateActiveTool: () => (/* binding */ updateActiveTool),\n/* harmony export */ updateObject: () => (/* binding */ updateObject),\n/* harmony export */ updateStable: () => (/* binding */ updateStable),\n/* harmony export */ viewportCoordsToSceneCoords: () => (/* binding */ viewportCoordsToSceneCoords),\n/* harmony export */ wrapEvent: () => (/* binding */ wrapEvent)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/math */ \"../math/src/index.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ \"../common/src/constants.ts\");\n\n\nlet mockDateTime = null;\nconst setDateTimeForTests = dateTime => {\n mockDateTime = dateTime;\n};\nconst getDateTime = () => {\n if (mockDateTime) {\n return mockDateTime;\n }\n\n const date = new Date();\n const year = date.getFullYear();\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n const day = `${date.getDate()}`.padStart(2, \"0\");\n const hr = `${date.getHours()}`.padStart(2, \"0\");\n const min = `${date.getMinutes()}`.padStart(2, \"0\");\n return `${year}-${month}-${day}-${hr}${min}`;\n};\nconst capitalizeString = str => str.charAt(0).toUpperCase() + str.slice(1);\nconst isToolIcon = target => target instanceof HTMLElement && target.className.includes(\"ToolIcon\");\nconst isInputLike = target => target instanceof HTMLElement && target.dataset.type === \"wysiwyg\" || target instanceof HTMLBRElement || // newline in wysiwyg\ntarget instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement;\nconst isInteractive = target => {\n return isInputLike(target) || target instanceof Element && !!target.closest(\"label, button\");\n};\nconst isWritableElement = target => target instanceof HTMLElement && target.dataset.type === \"wysiwyg\" || target instanceof HTMLBRElement || // newline in wysiwyg\ntarget instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && (target.type === \"text\" || target.type === \"number\" || target.type === \"password\" || target.type === \"search\") || target instanceof HTMLElement && target.closest(\".cm-editor\") !== null;\nconst getFontFamilyString = ({\n fontFamily\n}) => {\n for (const [fontFamilyString, id] of Object.entries(_constants__WEBPACK_IMPORTED_MODULE_1__.FONT_FAMILY)) {\n if (id === fontFamily) {\n return `${fontFamilyString}${(0,_constants__WEBPACK_IMPORTED_MODULE_1__.getFontFamilyFallbacks)(id).map(x => `, ${x}`).join(\"\")}`;\n }\n }\n\n return _constants__WEBPACK_IMPORTED_MODULE_1__.WINDOWS_EMOJI_FALLBACK_FONT;\n};\n/** returns fontSize+fontFamily string for assignment to DOM elements */\n\nconst getFontString = ({\n fontSize,\n fontFamily\n}) => {\n return `${fontSize}px ${getFontFamilyString({\n fontFamily\n })}`;\n};\n/** executes callback in the frame that's after the current one */\n\nconst nextAnimationFrame = async cb => {\n requestAnimationFrame(() => requestAnimationFrame(cb));\n};\nconst debounce = (fn, timeout) => {\n let handle = 0;\n let lastArgs = null;\n\n const ret = (...args) => {\n lastArgs = args;\n clearTimeout(handle);\n handle = window.setTimeout(() => {\n lastArgs = null;\n fn(...args);\n }, timeout);\n };\n\n ret.flush = () => {\n clearTimeout(handle);\n\n if (lastArgs) {\n const _lastArgs = lastArgs;\n lastArgs = null;\n fn(..._lastArgs);\n }\n };\n\n ret.cancel = () => {\n lastArgs = null;\n clearTimeout(handle);\n };\n\n return ret;\n}; // throttle callback to execute once per animation frame using the latest args\n\nconst throttleRAF = fn => {\n let timerId = null;\n let lastArgs = null;\n\n const scheduleFunc = () => {\n timerId = window.requestAnimationFrame(() => {\n timerId = null;\n const args = lastArgs;\n lastArgs = null;\n\n if (args) {\n fn(...args);\n }\n });\n };\n\n const ret = (...args) => {\n lastArgs = args;\n\n if (timerId === null) {\n scheduleFunc();\n }\n };\n\n ret.flush = () => {\n if (timerId !== null) {\n cancelAnimationFrame(timerId);\n timerId = null;\n }\n\n if (lastArgs) {\n fn(...lastArgs);\n lastArgs = null;\n }\n };\n\n ret.cancel = () => {\n lastArgs = null;\n\n if (timerId !== null) {\n cancelAnimationFrame(timerId);\n timerId = null;\n }\n };\n\n return ret;\n};\n/**\n * Exponential ease-out method\n *\n * @param {number} k - The value to be tweened.\n * @returns {number} The tweened value.\n */\n\nconst easeOut = k => {\n return 1 - Math.pow(1 - k, 4);\n};\n\nconst easeOutInterpolate = (from, to, progress) => {\n return (to - from) * easeOut(progress) + from;\n};\n/**\n * Animates values from `fromValues` to `toValues` using the requestAnimationFrame API.\n * Executes the `onStep` callback on each step with the interpolated values.\n * Returns a function that can be called to cancel the animation.\n *\n * @example\n * // Example usage:\n * const fromValues = { x: 0, y: 0 };\n * const toValues = { x: 100, y: 200 };\n * const onStep = ({x, y}) => {\n * setState(x, y)\n * };\n * const onCancel = () => {\n * console.log(\"Animation canceled\");\n * };\n *\n * const cancelAnimation = easeToValuesRAF({\n * fromValues,\n * toValues,\n * onStep,\n * onCancel,\n * });\n *\n * // To cancel the animation:\n * cancelAnimation();\n */\n\n\nconst easeToValuesRAF = ({\n fromValues,\n toValues,\n onStep,\n duration = 250,\n interpolateValue,\n onStart,\n onEnd,\n onCancel\n}) => {\n let canceled = false;\n let frameId = 0;\n let startTime;\n\n function step(timestamp) {\n if (canceled) {\n return;\n }\n\n if (startTime === undefined) {\n startTime = timestamp;\n onStart === null || onStart === void 0 ? void 0 : onStart();\n }\n\n const elapsed = Math.min(timestamp - startTime, duration);\n const factor = easeOut(elapsed / duration);\n const newValues = {};\n Object.keys(fromValues).forEach(key => {\n const _key = key;\n const result = (toValues[_key] - fromValues[_key]) * factor + fromValues[_key];\n newValues[_key] = result;\n });\n onStep(newValues);\n\n if (elapsed < duration) {\n const progress = elapsed / duration;\n const newValues = {};\n Object.keys(fromValues).forEach(key => {\n const _key = key;\n const startValue = fromValues[_key];\n const endValue = toValues[_key];\n let result;\n result = interpolateValue ? interpolateValue(startValue, endValue, progress, _key) : easeOutInterpolate(startValue, endValue, progress);\n\n if (result == null) {\n result = easeOutInterpolate(startValue, endValue, progress);\n }\n\n newValues[_key] = result;\n });\n onStep(newValues);\n frameId = window.requestAnimationFrame(step);\n } else {\n onStep(toValues);\n onEnd === null || onEnd === void 0 ? void 0 : onEnd();\n }\n }\n\n frameId = window.requestAnimationFrame(step);\n return () => {\n onCancel === null || onCancel === void 0 ? void 0 : onCancel();\n canceled = true;\n window.cancelAnimationFrame(frameId);\n };\n}; // https://github.com/lodash/lodash/blob/es/chunk.js\n\nconst chunk = (array, size) => {\n if (!array.length || size < 1) {\n return [];\n }\n\n let index = 0;\n let resIndex = 0;\n const result = Array(Math.ceil(array.length / size));\n\n while (index < array.length) {\n result[resIndex++] = array.slice(index, index += size);\n }\n\n return result;\n};\nconst selectNode = node => {\n const selection = window.getSelection();\n\n if (selection) {\n const range = document.createRange();\n range.selectNodeContents(node);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n};\nconst removeSelection = () => {\n const selection = window.getSelection();\n\n if (selection) {\n selection.removeAllRanges();\n }\n};\nconst distance = (x, y) => Math.abs(x - y);\nconst isSelectionLikeTool = type => {\n return type === \"selection\" || type === \"lasso\";\n};\nconst updateActiveTool = (appState, data) => {\n var _a, _b, _c;\n\n if (data.type === \"custom\") {\n return Object.assign(Object.assign({}, appState.activeTool), {\n type: \"custom\",\n customType: data.customType,\n locked: (_a = data.locked) !== null && _a !== void 0 ? _a : appState.activeTool.locked\n });\n }\n\n return Object.assign(Object.assign({}, appState.activeTool), {\n lastActiveTool: data.lastActiveToolBeforeEraser === undefined ? appState.activeTool.lastActiveTool : data.lastActiveToolBeforeEraser,\n type: data.type,\n customType: null,\n locked: (_b = data.locked) !== null && _b !== void 0 ? _b : appState.activeTool.locked,\n fromSelection: (_c = data.fromSelection) !== null && _c !== void 0 ? _c : false\n });\n};\nconst isFullScreen = () => {\n var _a;\n\n return ((_a = document.fullscreenElement) === null || _a === void 0 ? void 0 : _a.nodeName) === \"HTML\";\n};\nconst allowFullScreen = () => document.documentElement.requestFullscreen();\nconst exitFullScreen = () => document.exitFullscreen();\nconst viewportCoordsToSceneCoords = ({\n clientX,\n clientY\n}, {\n zoom,\n offsetLeft,\n offsetTop,\n scrollX,\n scrollY\n}) => {\n const x = (clientX - offsetLeft) / zoom.value - scrollX;\n const y = (clientY - offsetTop) / zoom.value - scrollY;\n return {\n x,\n y\n };\n};\nconst sceneCoordsToViewportCoords = ({\n sceneX,\n sceneY\n}, {\n zoom,\n offsetLeft,\n offsetTop,\n scrollX,\n scrollY\n}) => {\n const x = (sceneX + scrollX) * zoom.value + offsetLeft;\n const y = (sceneY + scrollY) * zoom.value + offsetTop;\n return {\n x,\n y\n };\n};\nconst getGlobalCSSVariable = name => getComputedStyle(document.documentElement).getPropertyValue(`--${name}`);\nconst RS_LTR_CHARS = \"A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02B8\\u0300-\\u0590\\u0800-\\u1FFF\" + \"\\u2C00-\\uFB1C\\uFDFE-\\uFE6F\\uFEFD-\\uFFFF\";\nconst RS_RTL_CHARS = \"\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC\";\nconst RE_RTL_CHECK = new RegExp(`^[^${RS_LTR_CHARS}]*[${RS_RTL_CHARS}]`);\n/**\n * Checks whether first directional character is RTL. Meaning whether it starts\n * with RTL characters, or indeterminate (numbers etc.) characters followed by\n * RTL.\n * See https://github.com/excalidraw/excalidraw/pull/1722#discussion_r436340171\n */\n\nconst isRTL = text => RE_RTL_CHECK.test(text);\nconst tupleToCoors = xyTuple => {\n const [x, y] = xyTuple;\n return {\n x,\n y\n };\n};\n/** use as a rejectionHandler to mute filesystem Abort errors */\n\nconst muteFSAbortError = error => {\n if ((error === null || error === void 0 ? void 0 : error.name) === \"AbortError\") {\n console.warn(error);\n return;\n }\n\n throw error;\n};\nconst findIndex = (array, cb, fromIndex = 0) => {\n if (fromIndex < 0) {\n fromIndex = array.length + fromIndex;\n }\n\n fromIndex = Math.min(array.length, Math.max(fromIndex, 0));\n let index = fromIndex - 1;\n\n while (++index < array.length) {\n if (cb(array[index], index, array)) {\n return index;\n }\n }\n\n return -1;\n};\nconst findLastIndex = (array, cb, fromIndex = array.length - 1) => {\n if (fromIndex < 0) {\n fromIndex = array.length + fromIndex;\n }\n\n fromIndex = Math.min(array.length - 1, Math.max(fromIndex, 0));\n let index = fromIndex + 1;\n\n while (--index > -1) {\n if (cb(array[index], index, array)) {\n return index;\n }\n }\n\n return -1;\n};\n/** returns the first non-null mapped value */\n\nconst mapFind = (collection, iteratee) => {\n for (let idx = 0; idx < collection.length; idx++) {\n const result = iteratee(collection[idx], idx);\n\n if (result != null) {\n return result;\n }\n }\n\n return undefined;\n};\nconst resolvablePromise = () => {\n let resolve;\n let reject;\n const promise = new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n });\n promise.resolve = resolve;\n promise.reject = reject;\n return promise;\n}; //https://stackoverflow.com/a/9462382/8418\n\nconst nFormatter = (num, digits) => {\n const si = [{\n value: 1,\n symbol: \"b\"\n }, {\n value: 1e3,\n symbol: \"k\"\n }, {\n value: 1e6,\n symbol: \"M\"\n }, {\n value: 1e9,\n symbol: \"G\"\n }];\n const rx = /\\.0+$|(\\.[0-9]*[1-9])0+$/;\n let index;\n\n for (index = si.length - 1; index > 0; index--) {\n if (num >= si[index].value) {\n break;\n }\n }\n\n return (num / si[index].value).toFixed(digits).replace(rx, \"$1\") + si[index].symbol;\n};\nconst getVersion = () => {\n var _a;\n\n return ((_a = document.querySelector('meta[name=\"version\"]')) === null || _a === void 0 ? void 0 : _a.content) || _constants__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_VERSION;\n}; // Adapted from https://github.com/Modernizr/Modernizr/blob/master/feature-detects/emoji.js\n\nconst supportsEmoji = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n\n if (!ctx) {\n return false;\n }\n\n const offset = 12;\n ctx.fillStyle = \"#f00\";\n ctx.textBaseline = \"top\";\n ctx.font = \"32px Arial\"; // Modernizr used π¨, but it is sort of supported on Windows 7.\n // Luckily π isn't supported.\n\n ctx.fillText(\"π\", 0, 0);\n return ctx.getImageData(offset, offset, 1, 1).data[0] !== 0;\n};\nconst getNearestScrollableContainer = element => {\n let parent = element.parentElement;\n\n while (parent) {\n if (parent === document.body) {\n return document;\n }\n\n const {\n overflowY\n } = window.getComputedStyle(parent);\n const hasScrollableContent = parent.scrollHeight > parent.clientHeight;\n\n if (hasScrollableContent && (overflowY === \"auto\" || overflowY === \"scroll\" || overflowY === \"overlay\")) {\n return parent;\n }\n\n parent = parent.parentElement;\n }\n\n return document;\n};\nconst focusNearestParent = element => {\n let parent = element.parentElement;\n\n while (parent) {\n if (parent.tabIndex > -1) {\n parent.focus();\n return;\n }\n\n parent = parent.parentElement;\n }\n};\nconst preventUnload = event => {\n event.preventDefault(); // NOTE: modern browsers no longer allow showing a custom message here\n\n event.returnValue = \"\";\n};\nconst bytesToHexString = bytes => {\n return Array.from(bytes).map(byte => `0${byte.toString(16)}`.slice(-2)).join(\"\");\n};\nconst getUpdatedTimestamp = () => isTestEnv() ? 1 : Date.now();\n/**\n * Transforms array of objects containing `id` attribute,\n * or array of ids (strings), into a Map, keyd by `id`.\n */\n\nconst arrayToMap = items => {\n if (items instanceof Map) {\n return items;\n }\n\n return items.reduce((acc, element) => {\n acc.set(typeof element === \"string\" ? element : element.id, element);\n return acc;\n }, new Map());\n};\nconst arrayToMapWithIndex = elements => elements.reduce((acc, element, idx) => {\n acc.set(element.id, [element, idx]);\n return acc;\n}, new Map());\n/**\n * Transform array into an object, use only when array order is irrelevant.\n */\n\nconst arrayToObject = (array, groupBy) => array.reduce((acc, value, idx) => {\n acc[groupBy ? groupBy(value) : idx] = value;\n return acc;\n}, {});\n/**\n * Creates a circular doubly linked list by adding `prev` and `next` props to the existing array nodes.\n */\n\nconst arrayToList = array => array.reduce((acc, curr, index) => {\n const node = Object.assign(Object.assign({}, curr), {\n prev: null,\n next: null\n }); // no-op for first item, we don't want circular references on a single item\n\n if (index !== 0) {\n const prevNode = acc[index - 1];\n node.prev = prevNode;\n prevNode.next = node;\n\n if (index === array.length - 1) {\n // make the references circular and connect head & tail\n const firstNode = acc[0];\n node.next = firstNode;\n firstNode.prev = node;\n }\n }\n\n acc.push(node);\n return acc;\n}, []);\n/**\n * Converts a readonly array or map into an iterable.\n * Useful for avoiding entry allocations when iterating object / map on each iteration.\n */\n\nconst toIterable = values => {\n return Array.isArray(values) ? values : values.values();\n};\n/**\n * Converts a readonly array or map into an array.\n */\n\nconst toArray = values => {\n return Array.isArray(values) ? values : Array.from(toIterable(values));\n};\nconst isTestEnv = () => \"development\" === _constants__WEBPACK_IMPORTED_MODULE_1__.ENV.TEST;\nconst isDevEnv = () => \"development\" === _constants__WEBPACK_IMPORTED_MODULE_1__.ENV.DEVELOPMENT;\nconst isProdEnv = () => \"development\" === _constants__WEBPACK_IMPORTED_MODULE_1__.ENV.PRODUCTION;\nconst isServerEnv = () => {\n var _a;\n\n return typeof process !== \"undefined\" && !!((_a = process === null || process === void 0 ? void 0 : ({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.1\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true})) === null || _a === void 0 ? void 0 : _a.NODE_ENV);\n};\nconst wrapEvent = (name, nativeEvent) => {\n return new CustomEvent(name, {\n detail: {\n nativeEvent\n },\n cancelable: true\n });\n};\nconst updateObject = (obj, updates) => {\n let didChange = false;\n\n for (const key in updates) {\n const value = updates[key];\n\n if (typeof value !== \"undefined\") {\n if (obj[key] === value && ( // if object, always update because its attrs could have changed\n typeof value !== \"object\" || value === null)) {\n continue;\n }\n\n didChange = true;\n }\n }\n\n if (!didChange) {\n return obj;\n }\n\n return Object.assign(Object.assign({}, obj), updates);\n};\nconst isPrimitive = val => {\n const type = typeof val;\n return val == null || type !== \"object\" && type !== \"function\";\n};\nconst getFrame = () => {\n try {\n return window.self === window.top ? \"top\" : \"iframe\";\n } catch (error) {\n return \"iframe\";\n }\n};\nconst isRunningInIframe = () => getFrame() === \"iframe\";\nconst isPromiseLike = value => {\n return !!value && typeof value === \"object\" && \"then\" in value && \"catch\" in value && \"finally\" in value;\n};\nconst queryFocusableElements = container => {\n const focusableElements = container === null || container === void 0 ? void 0 : container.querySelectorAll(\"button, a, input, select, textarea, div[tabindex], label[tabindex]\");\n return focusableElements ? Array.from(focusableElements).filter(element => element.tabIndex > -1 && !element.disabled) : [];\n};\n/** use as a fallback after identity check (for perf reasons) */\n\nconst _defaultIsShallowComparatorFallback = (a, b) => {\n // consider two empty arrays equal\n if (Array.isArray(a) && Array.isArray(b) && a.length === 0 && b.length === 0) {\n return true;\n }\n\n return a === b;\n};\n/**\n * Returns whether object/array is shallow equal.\n * Considers empty object/arrays as equal (whether top-level or second-level).\n */\n\n\nconst isShallowEqual = (objA, objB, comparators, debug = false) => {\n const aKeys = Object.keys(objA);\n const bKeys = Object.keys(objB);\n\n if (aKeys.length !== bKeys.length) {\n if (debug) {\n console.warn(`%cisShallowEqual: objects don't have same properties ->`, \"color: #8B4000\", objA, objB);\n }\n\n return false;\n }\n\n if (comparators && Array.isArray(comparators)) {\n for (const key of comparators) {\n const ret = objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]);\n\n if (!ret) {\n if (debug) {\n console.warn(`%cisShallowEqual: ${key} not equal ->`, \"color: #8B4000\", objA[key], objB[key]);\n }\n\n return false;\n }\n }\n\n return true;\n }\n\n return aKeys.every(key => {\n const comparator = comparators === null || comparators === void 0 ? void 0 : comparators[key];\n const ret = comparator ? comparator(objA[key], objB[key]) : objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]);\n\n if (!ret && debug) {\n console.warn(`%cisShallowEqual: ${key} not equal ->`, \"color: #8B4000\", objA[key], objB[key]);\n }\n\n return ret;\n });\n}; // taken from Radix UI\n// https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx\n\nconst composeEventHandlers = (originalEventHandler, ourEventHandler, {\n checkForDefaultPrevented = true\n} = {}) => {\n return function handleEvent(event) {\n originalEventHandler === null || originalEventHandler === void 0 ? void 0 : originalEventHandler(event);\n\n if (!checkForDefaultPrevented || !(event === null || event === void 0 ? void 0 : event.defaultPrevented)) {\n return ourEventHandler === null || ourEventHandler === void 0 ? void 0 : ourEventHandler(event);\n }\n };\n};\n/**\n * supply `null` as message if non-never value is valid, you just need to\n * typecheck against it\n */\n\nconst assertNever = (value, message, softAssert) => {\n if (!message) {\n return value;\n }\n\n if (softAssert) {\n console.error(message);\n return value;\n }\n\n throw new Error(message);\n};\nfunction invariant(condition, message) {\n if (!condition) {\n throw new Error(message);\n }\n}\n/**\n * Memoizes on values of `opts` object (strict equality).\n */\n\nconst memoize = func => {\n let lastArgs;\n let lastResult;\n\n const ret = function (opts) {\n const currentArgs = Object.entries(opts);\n\n if (lastArgs) {\n let argsAreEqual = true;\n\n for (const [key, value] of currentArgs) {\n if (lastArgs.get(key) !== value) {\n argsAreEqual = false;\n break;\n }\n }\n\n if (argsAreEqual) {\n return lastResult;\n }\n }\n\n const result = func(opts);\n lastArgs = new Map(currentArgs);\n lastResult = result;\n return result;\n };\n\n ret.clear = () => {\n lastArgs = undefined;\n lastResult = undefined;\n };\n\n return ret;\n};\n/** Checks if value is inside given collection. Useful for type-safety. */\n\nconst isMemberOf = (\n/** Set/Map/Array/Object */\ncollection,\n/** value to look for */\nvalue) => {\n return collection instanceof Set || collection instanceof Map ? collection.has(value) : \"includes\" in collection ? collection.includes(value) : collection.hasOwnProperty(value);\n};\nconst cloneJSON = obj => JSON.parse(JSON.stringify(obj));\nconst updateStable = (prevValue, nextValue) => {\n if (isShallowEqual(prevValue, nextValue)) {\n return prevValue;\n }\n\n return nextValue;\n}; // implem\n\nfunction addEventListener(\n/**\n * allows for falsy values so you don't have to type check when adding\n * event listeners to optional elements\n */\ntarget, type, listener, options) {\n var _a;\n\n if (!target) {\n return () => {};\n }\n\n (_a = target === null || target === void 0 ? void 0 : target.addEventListener) === null || _a === void 0 ? void 0 : _a.call(target, type, listener, options);\n return () => {\n var _a;\n\n (_a = target === null || target === void 0 ? void 0 : target.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(target, type, listener, options);\n };\n}\nfunction getSvgPathFromStroke(points, closed = true) {\n const len = points.length;\n\n if (len < 4) {\n return ``;\n }\n\n let a = points[0];\n let b = points[1];\n const c = points[2];\n let result = `M${a[0].toFixed(2)},${a[1].toFixed(2)} Q${b[0].toFixed(2)},${b[1].toFixed(2)} ${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(b[0], c[0]).toFixed(2)},${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(b[1], c[1]).toFixed(2)} T`;\n\n for (let i = 2, max = len - 1; i < max; i++) {\n a = points[i];\n b = points[i + 1];\n result += `${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(a[0], b[0]).toFixed(2)},${(0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_0__.average)(a[1], b[1]).toFixed(2)} `;\n }\n\n if (closed) {\n result += \"Z\";\n }\n\n return result;\n}\nconst normalizeEOL = str => {\n return str.replace(/\\r?\\n|\\r/g, \"\\n\");\n};\nfunction toBrandedType(value) {\n return value;\n} // -----------------------------------------------------------------------------\n// Promise.try, adapted from https://github.com/sindresorhus/p-try\n\nconst promiseTry = async (fn, ...args) => {\n return new Promise(resolve => {\n resolve(fn(...args));\n });\n};\nconst isAnyTrue = (...args) => Math.max(...args.map(arg => arg ? 1 : 0)) > 0;\nconst safelyParseJSON = json => {\n try {\n return JSON.parse(json);\n } catch (_a) {\n return null;\n }\n};\n/**\n * use when you need to render unsafe string as HTML attribute, but MAKE SURE\n * the attribute is double-quoted when constructing the HTML string\n */\n\nconst escapeDoubleQuotes = str => {\n return str.replace(/\"/g, \""\");\n};\nconst castArray = value => Array.isArray(value) ? value : [value];\n/** hack for Array.isArray type guard not working with readonly value[] */\n\nconst isReadonlyArray = value => {\n return Array.isArray(value);\n};\nconst sizeOf = value => {\n return isReadonlyArray(value) ? value.length : value instanceof Map || value instanceof Set ? value.size : Object.keys(value).length;\n};\nconst reduceToCommonValue = (collection, getValue) => {\n if (sizeOf(collection) === 0) {\n return null;\n }\n\n const valueExtractor = getValue || (item => item);\n\n let commonValue = null;\n\n for (const item of collection) {\n const value = valueExtractor(item);\n\n if ((commonValue === null || commonValue === value) && value != null) {\n commonValue = value;\n } else {\n return null;\n }\n }\n\n return commonValue;\n};\nconst FEATURE_FLAGS_STORAGE_KEY = \"excalidraw-feature-flags\";\nconst DEFAULT_FEATURE_FLAGS = {\n COMPLEX_BINDINGS: false\n};\nlet featureFlags = null;\nconst getFeatureFlag = flag => {\n if (!featureFlags) {\n try {\n const serializedFlags = localStorage.getItem(FEATURE_FLAGS_STORAGE_KEY);\n\n if (serializedFlags) {\n const flags = JSON.parse(serializedFlags);\n featureFlags = flags !== null && flags !== void 0 ? flags : DEFAULT_FEATURE_FLAGS;\n }\n } catch (_a) {}\n }\n\n return (featureFlags || DEFAULT_FEATURE_FLAGS)[flag];\n};\nconst setFeatureFlag = (flag, value) => {\n try {\n featureFlags = Object.assign(Object.assign({}, featureFlags || DEFAULT_FEATURE_FLAGS), {\n [flag]: value\n });\n localStorage.setItem(FEATURE_FLAGS_STORAGE_KEY, JSON.stringify(featureFlags));\n } catch (e) {\n console.error(\"unable to set feature flag\", e);\n }\n};\nconst oneOf = (needle, haystack) => {\n return haystack.includes(needle);\n};\n\n//# sourceURL=webpack://ExcalidrawLib/../common/src/utils.ts?\n}");
|
|
345
345
|
|
|
346
346
|
/***/ },
|
|
347
347
|
|
|
@@ -605,7 +605,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
605
605
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
606
606
|
|
|
607
607
|
"use strict";
|
|
608
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addElementsToFrame: () => (/* binding */ addElementsToFrame),\n/* harmony export */ bindElementsToFramesAfterDuplication: () => (/* binding */ bindElementsToFramesAfterDuplication),\n/* harmony export */ elementOverlapsWithFrame: () => (/* binding */ elementOverlapsWithFrame),\n/* harmony export */ elementsAreInFrameBounds: () => (/* binding */ elementsAreInFrameBounds),\n/* harmony export */ filterElementsEligibleAsFrameChildren: () => (/* binding */ filterElementsEligibleAsFrameChildren),\n/* harmony export */ frameAndChildrenSelectedTogether: () => (/* binding */ frameAndChildrenSelectedTogether),\n/* harmony export */ getCommonFrameId: () => (/* binding */ getCommonFrameId),\n/* harmony export */ getContainingFrame: () => (/* binding */ getContainingFrame),\n/* harmony export */ getDefaultFrameName: () => (/* binding */ getDefaultFrameName),\n/* harmony export */ getElementsCompletelyInFrame: () => (/* binding */ getElementsCompletelyInFrame),\n/* harmony export */ getElementsInNewFrame: () => (/* binding */ getElementsInNewFrame),\n/* harmony export */ getElementsInResizingFrame: () => (/* binding */ getElementsInResizingFrame),\n/* harmony export */ getElementsIntersectingFrame: () => (/* binding */ getElementsIntersectingFrame),\n/* harmony export */ getElementsOverlappingFrame: () => (/* binding */ getElementsOverlappingFrame),\n/* harmony export */ getFrameChildren: () => (/* binding */ getFrameChildren),\n/* harmony export */ getFrameChildrenInsertionIndex: () => (/* binding */ getFrameChildrenInsertionIndex),\n/* harmony export */ getFrameLikeElements: () => (/* binding */ getFrameLikeElements),\n/* harmony export */ getFrameLikeTitle: () => (/* binding */ getFrameLikeTitle),\n/* harmony export */ getRootElements: () => (/* binding */ getRootElements),\n/* harmony export */ getTargetFrame: () => (/* binding */ getTargetFrame),\n/* harmony export */ groupByFrameLikes: () => (/* binding */ groupByFrameLikes),\n/* harmony export */ groupsAreAtLeastIntersectingTheFrame: () => (/* binding */ groupsAreAtLeastIntersectingTheFrame),\n/* harmony export */ groupsAreCompletelyOutOfFrame: () => (/* binding */ groupsAreCompletelyOutOfFrame),\n/* harmony export */ isCursorInFrame: () => (/* binding */ isCursorInFrame),\n/* harmony export */ isElementContainingFrame: () => (/* binding */ isElementContainingFrame),\n/* harmony export */ isElementInFrame: () => (/* binding */ isElementInFrame),\n/* harmony export */ isElementIntersectingFrame: () => (/* binding */ isElementIntersectingFrame),\n/* harmony export */ omitGroupsContainingFrameLikes: () => (/* binding */ omitGroupsContainingFrameLikes),\n/* harmony export */ omitPartialGroups: () => (/* binding */ omitPartialGroups),\n/* harmony export */ removeAllElementsFromFrame: () => (/* binding */ removeAllElementsFromFrame),\n/* harmony export */ removeElementsFromFrame: () => (/* binding */ removeElementsFromFrame),\n/* harmony export */ replaceAllElementsInFrame: () => (/* binding */ replaceAllElementsInFrame),\n/* harmony export */ shouldApplyFrameClip: () => (/* binding */ shouldApplyFrameClip),\n/* harmony export */ updateFrameMembershipOfSelectedElements: () => (/* binding */ updateFrameMembershipOfSelectedElements)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _excalidraw_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @excalidraw/math */ \"../math/src/index.ts\");\n/* harmony import */ var _selection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./selection */ \"../element/src/selection.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./groups */ \"../element/src/groups.ts\");\n/* harmony import */ var _bounds__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./bounds */ \"../element/src/bounds.ts\");\n/* harmony import */ var _mutateElement__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./mutateElement */ \"../element/src/mutateElement.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./textElement */ \"../element/src/textElement.ts\");\n/* harmony import */ var _fractionalIndex__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./fractionalIndex */ \"../element/src/fractionalIndex.ts\");\n/* harmony import */ var _typeChecks__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./typeChecks */ \"../element/src/typeChecks.ts\");\n\n\n\n\n\n\n\n\n // --------------------------- Frame State ------------------------------------\n\nconst bindElementsToFramesAfterDuplication = (nextElements, origElements, origIdToDuplicateId) => {\n const nextElementMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(nextElements);\n\n for (const element of origElements) {\n if (element.frameId) {\n // use its frameId to get the new frameId\n const nextElementId = origIdToDuplicateId.get(element.id);\n const nextFrameId = origIdToDuplicateId.get(element.frameId);\n const nextElement = nextElementId && nextElementMap.get(nextElementId);\n\n if (nextElement) {\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_5__.mutateElement)(nextElement, nextElementMap, {\n frameId: nextFrameId !== null && nextFrameId !== void 0 ? nextFrameId : null\n });\n }\n }\n }\n};\nfunction isElementIntersectingFrame(element, frame, elementsMap) {\n const frameLineSegments = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementLineSegments)(frame, elementsMap);\n const elementLineSegments = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementLineSegments)(element, elementsMap);\n const intersecting = frameLineSegments.some(frameLineSegment => elementLineSegments.some(elementLineSegment => (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.segmentsIntersectAt)(frameLineSegment, elementLineSegment)));\n return intersecting;\n}\nconst getElementsCompletelyInFrame = (elements, frame, elementsMap) => omitGroupsContainingFrameLikes((0,_selection__WEBPACK_IMPORTED_MODULE_2__.getElementsWithinSelection)(elements, frame, elementsMap, false)).filter(element => !(0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && !element.frameId || element.frameId === frame.id);\nconst isElementContainingFrame = (element, frame, elementsMap) => {\n return (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.boundsContainBounds)((0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(element, elementsMap), (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(frame, elementsMap));\n};\nconst getElementsIntersectingFrame = (elements, frame) => {\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n return elements.filter(element => isElementIntersectingFrame(element, frame, elementsMap));\n};\nconst elementsAreInFrameBounds = (elements, frame, elementsMap) => {\n const [frameX1, frameY1, frameX2, frameY2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementAbsoluteCoords)(frame, elementsMap);\n const [elementX1, elementY1, elementX2, elementY2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getCommonBounds)(elements);\n return frameX1 <= elementX1 && frameY1 <= elementY1 && frameX2 >= elementX2 && frameY2 >= elementY2;\n};\nconst elementOverlapsWithFrame = (element, frame, elementsMap) => {\n return elementsAreInFrameBounds([element], frame, elementsMap) || isElementIntersectingFrame(element, frame, elementsMap) || isElementContainingFrame(element, frame, elementsMap);\n};\nconst isCursorInFrame = (cursorCoords, frame, elementsMap) => {\n const [fx1, fy1, fx2, fy2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementAbsoluteCoords)(frame, elementsMap);\n return (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.isPointWithinBounds)((0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.pointFrom)(fx1, fy1), (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.pointFrom)(cursorCoords.x, cursorCoords.y), (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.pointFrom)(fx2, fy2));\n};\nconst groupsAreAtLeastIntersectingTheFrame = (elements, groupIds, frame) => {\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n const elementsInGroup = groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, groupId));\n\n if (elementsInGroup.length === 0) {\n return true;\n }\n\n return !!elementsInGroup.find(element => elementsAreInFrameBounds([element], frame, elementsMap) || isElementIntersectingFrame(element, frame, elementsMap));\n};\nconst groupsAreCompletelyOutOfFrame = (elements, groupIds, frame) => {\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n const elementsInGroup = groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, groupId));\n\n if (elementsInGroup.length === 0) {\n return true;\n }\n\n return elementsInGroup.find(element => elementsAreInFrameBounds([element], frame, elementsMap) || isElementIntersectingFrame(element, frame, elementsMap)) === undefined;\n}; // --------------------------- Frame Utils ------------------------------------\n\n/**\n * Returns a map of frameId to frame elements. Includes empty frames.\n */\n\nconst groupByFrameLikes = elements => {\n const frameElementsMap = new Map();\n\n for (const element of elements) {\n const frameId = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) ? element.id : element.frameId;\n\n if (frameId && !frameElementsMap.has(frameId)) {\n frameElementsMap.set(frameId, getFrameChildren(elements, frameId));\n }\n }\n\n return frameElementsMap;\n};\nconst getFrameChildren = (allElements, frameId) => {\n const frameChildren = [];\n\n for (const element of allElements.values()) {\n if (element.frameId === frameId) {\n frameChildren.push(element);\n }\n }\n\n return frameChildren;\n};\nconst getFrameLikeElements = allElements => {\n return allElements.filter(element => (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element));\n};\n/**\n * Returns ExcalidrawFrameElements and non-frame-children elements.\n *\n * Considers children as root elements if they point to a frame parent\n * non-existing in the elements set.\n *\n * Considers non-frame bound elements (container or arrow labels) as root.\n */\n\nconst getRootElements = allElements => {\n const frameElements = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(getFrameLikeElements(allElements));\n return allElements.filter(element => frameElements.has(element.id) || !element.frameId || !frameElements.has(element.frameId));\n};\nconst getElementsInResizingFrame = (allElements, frame, appState, elementsMap) => {\n const prevElementsInFrame = getFrameChildren(allElements, frame.id); //zsviczian: do not suggest adding new elements to marker frames while resizing\n\n if (frame.frameRole === \"marker\") {\n return prevElementsInFrame.filter(element => !((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) && element.containerId));\n }\n\n const nextElementsInFrame = new Set(prevElementsInFrame);\n const elementsCompletelyInFrame = new Set([...getElementsCompletelyInFrame(allElements, frame, elementsMap), ...prevElementsInFrame.filter(element => isElementContainingFrame(element, frame, elementsMap))]);\n const elementsNotCompletelyInFrame = prevElementsInFrame.filter(element => !elementsCompletelyInFrame.has(element)); // for elements that are completely in the frame\n // if they are part of some groups, then those groups are still\n // considered to belong to the frame\n\n const groupsToKeep = new Set(Array.from(elementsCompletelyInFrame).flatMap(element => element.groupIds));\n\n for (const element of elementsNotCompletelyInFrame) {\n if (!isElementIntersectingFrame(element, frame, elementsMap)) {\n if (element.groupIds.length === 0) {\n nextElementsInFrame.delete(element);\n }\n } else if (element.groupIds.length > 0) {\n // group element intersects with the frame, we should keep the groups\n // that this element is part of\n for (const id of element.groupIds) {\n groupsToKeep.add(id);\n }\n }\n }\n\n for (const element of elementsNotCompletelyInFrame) {\n if (element.groupIds.length > 0) {\n let shouldRemoveElement = true;\n\n for (const id of element.groupIds) {\n if (groupsToKeep.has(id)) {\n shouldRemoveElement = false;\n }\n }\n\n if (shouldRemoveElement) {\n nextElementsInFrame.delete(element);\n }\n }\n }\n\n const individualElementsCompletelyInFrame = Array.from(elementsCompletelyInFrame).filter(element => element.groupIds.length === 0);\n\n for (const element of individualElementsCompletelyInFrame) {\n nextElementsInFrame.add(element);\n }\n\n const newGroupElementsCompletelyInFrame = Array.from(elementsCompletelyInFrame).filter(element => element.groupIds.length > 0);\n const groupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.selectGroupsFromGivenElements)(newGroupElementsCompletelyInFrame, appState); // new group elements\n\n for (const [id, isSelected] of Object.entries(groupIds)) {\n if (isSelected) {\n const elementsInGroup = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElements, id);\n\n if (elementsAreInFrameBounds(elementsInGroup, frame, elementsMap)) {\n for (const element of elementsInGroup) {\n nextElementsInFrame.add(element);\n }\n }\n }\n }\n\n return [...nextElementsInFrame].filter(element => {\n return !((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) && element.containerId);\n });\n};\nconst getElementsInNewFrame = (elements, frame, elementsMap) => {\n return omitPartialGroups(omitGroupsContainingFrameLikes(elements, getElementsCompletelyInFrame(elements, frame, elementsMap)), frame, elementsMap);\n};\nconst omitPartialGroups = (elements, frame, allElementsMap) => {\n const elementsToReturn = [];\n const checkedGroups = new Map();\n\n for (const element of elements) {\n let shouldOmit = false;\n\n if (element.groupIds.length > 0) {\n // if some partial group should be omitted, then all elements in that group should be omitted\n if (element.groupIds.some(gid => checkedGroups.get(gid))) {\n shouldOmit = true;\n } else {\n const allElementsInGroup = new Set(element.groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElementsMap, gid)));\n shouldOmit = !elementsAreInFrameBounds(Array.from(allElementsInGroup), frame, allElementsMap);\n }\n\n element.groupIds.forEach(gid => {\n checkedGroups.set(gid, shouldOmit);\n });\n }\n\n if (!shouldOmit) {\n elementsToReturn.push(element);\n }\n }\n\n return elementsToReturn;\n};\nconst getContainingFrame = (element, elementsMap) => {\n if (!element.frameId) {\n return null;\n }\n\n return elementsMap.get(element.frameId) || null;\n}; // --------------------------- Frame Operations -------------------------------\n\n/** */\n\nconst filterElementsEligibleAsFrameChildren = (elements, frame) => {\n //zsviczian: nothing is eligible for marker frames\n if (frame.frameRole === \"marker\") {\n return [];\n }\n\n const otherFrames = new Set();\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n elements = omitGroupsContainingFrameLikes(elements);\n\n for (const element of elements) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && element.id !== frame.id) {\n otherFrames.add(element.id);\n }\n }\n\n const processedGroups = new Set();\n const eligibleElements = [];\n\n for (const element of elements) {\n // don't add frames or their children\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) || element.frameId && otherFrames.has(element.frameId)) {\n continue;\n }\n\n if (element.groupIds.length) {\n const shallowestGroupId = element.groupIds.at(-1);\n\n if (!processedGroups.has(shallowestGroupId)) {\n processedGroups.add(shallowestGroupId);\n const groupElements = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, shallowestGroupId);\n\n if (groupElements.some(el => elementOverlapsWithFrame(el, frame, elementsMap))) {\n for (const child of groupElements) {\n eligibleElements.push(child);\n }\n }\n }\n } else {\n const overlaps = elementOverlapsWithFrame(element, frame, elementsMap);\n\n if (overlaps) {\n eligibleElements.push(element);\n }\n }\n }\n\n return eligibleElements;\n};\nconst getCommonFrameId = elements => {\n let commonFrameId;\n\n for (const element of elements) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) || !element.frameId) {\n return null;\n }\n\n if (commonFrameId === undefined) {\n commonFrameId = element.frameId;\n } else if (commonFrameId !== element.frameId) {\n return null;\n }\n }\n\n return commonFrameId !== null && commonFrameId !== void 0 ? commonFrameId : null;\n};\nconst getFrameChildrenInsertionIndex = (elements, frameId) => {\n for (let index = elements.length - 1; index >= 0; index--) {\n const element = elements[index];\n\n if (element.id === frameId) {\n return index;\n } else if (element.frameId === frameId) {\n return index + 1;\n }\n }\n\n return null;\n};\n/**\n * Adds elements and their bound elements to frame. Reorders added elements to\n * be just below frame, or just above its highest child (whichever is higher).\n *\n * @returns mutated allElements (same data structure)\n */\n\nconst addElementsToFrame = (allElements, elementsToAdd, frame) => {\n if (frame.frameRole === \"marker\") {\n return allElements;\n } //zsviczian\n\n\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(allElements);\n const commonFrameId = getCommonFrameId(elementsToAdd);\n const finalElementsToAdd = new Set();\n const otherFrames = new Set();\n\n for (const element of elementsToAdd) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && element.id !== frame.id) {\n otherFrames.add(element.id);\n }\n } // - add bound text elements if not already in the array\n // - keep elements already in the frame so mixed selections can be reordered\n // together\n\n\n for (const element of omitGroupsContainingFrameLikes(allElements, elementsToAdd)) {\n // don't add frames or their children\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) || element.frameId && otherFrames.has(element.frameId)) {\n continue;\n }\n\n if (element.frameId && element.frameId !== frame.id) {\n continue;\n }\n\n finalElementsToAdd.add(element);\n const boundTextElement = (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getBoundTextElement)(element, elementsMap);\n\n if (boundTextElement && !finalElementsToAdd.has(boundTextElement)) {\n finalElementsToAdd.add(boundTextElement);\n }\n }\n\n for (const element of finalElementsToAdd) {\n // we don't always need to update the element if it's already in the frame,\n // but we still need to accumulate in finalElementsToAdd so we potentially\n // reorder them if added together\n if (element.frameId !== frame.id) {\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_5__.mutateElement)(element, elementsMap, {\n frameId: frame.id\n });\n }\n } // (re)order elements to be just below the frame,\n // or just above the highest child if that is higher\n // (latter case is denormalized order until we migrate)\n // ---------------------------------------------------------------------------\n\n\n if (!finalElementsToAdd.size || // if all elements to add already belong to the frame, then we don't want to\n // reorder (case: we're dragging element children within the frame)\n commonFrameId === frame.id) {\n return allElements;\n }\n\n const otherElements = Array.from(allElements.values()).filter(element => !finalElementsToAdd.has(element));\n const insertionIndex = getFrameChildrenInsertionIndex(otherElements, frame.id);\n\n if (insertionIndex === null) {\n return allElements;\n }\n\n const reorderedElements = [...otherElements.slice(0, insertionIndex), ...finalElementsToAdd, ...otherElements.slice(insertionIndex)];\n (0,_fractionalIndex__WEBPACK_IMPORTED_MODULE_7__.syncMovedIndices)(reorderedElements, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)([...finalElementsToAdd]));\n return Array.isArray(allElements) ? reorderedElements : new Map(reorderedElements.map(element => [element.id, element]));\n};\nconst removeElementsFromFrame = (elementsToRemove, elementsMap) => {\n const _elementsToRemove = new Map();\n\n const toRemoveElementsByFrame = new Map();\n\n for (const element of elementsToRemove) {\n if (element.frameId) {\n _elementsToRemove.set(element.id, element);\n\n const arr = toRemoveElementsByFrame.get(element.frameId) || [];\n arr.push(element);\n const boundTextElement = (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getBoundTextElement)(element, elementsMap);\n\n if (boundTextElement) {\n _elementsToRemove.set(boundTextElement.id, boundTextElement);\n\n arr.push(boundTextElement);\n }\n\n toRemoveElementsByFrame.set(element.frameId, arr);\n }\n }\n\n for (const [, element] of _elementsToRemove) {\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_5__.mutateElement)(element, elementsMap, {\n frameId: null\n });\n }\n};\nconst removeAllElementsFromFrame = (allElements, frame) => {\n const elementsInFrame = getFrameChildren(allElements, frame.id);\n removeElementsFromFrame(elementsInFrame, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(allElements));\n return allElements;\n};\nconst replaceAllElementsInFrame = (allElements, nextElementsInFrame, frame) => {\n return addElementsToFrame(removeAllElementsFromFrame(allElements, frame), nextElementsInFrame, frame).slice();\n};\n/** does not mutate elements, but returns new ones */\n\nconst updateFrameMembershipOfSelectedElements = (allElements, appState, app) => {\n const selectedElements = app.scene.getSelectedElements({\n selectedElementIds: appState.selectedElementIds,\n // supplying elements explicitly in case we're passed non-state elements\n elements: allElements\n });\n const elementsToFilter = new Set(selectedElements);\n\n if (appState.editingGroupId) {\n for (const element of selectedElements) {\n if (element.groupIds.length === 0) {\n elementsToFilter.add(element);\n } else {\n element.groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElements, gid)).forEach(element => elementsToFilter.add(element));\n }\n }\n }\n\n const elementsToRemove = new Set();\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(allElements);\n elementsToFilter.forEach(element => {\n if (element.frameId && !(0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && !isElementInFrame(element, elementsMap, appState)) {\n elementsToRemove.add(element);\n }\n });\n\n if (elementsToRemove.size > 0) {\n removeElementsFromFrame(elementsToRemove, elementsMap);\n }\n\n return allElements;\n};\n/**\n * filters out elements that are inside groups that contain a frame element\n * anywhere in the group tree\n */\n\nconst omitGroupsContainingFrameLikes = (allElements,\n/** subset of elements you want to filter. Optional perf optimization so we\n * don't have to filter all elements unnecessarily\n */\nselectedElements) => {\n const uniqueGroupIds = new Set();\n const elements = selectedElements || allElements;\n\n for (const el of elements.values()) {\n const topMostGroupId = el.groupIds[el.groupIds.length - 1];\n\n if (topMostGroupId) {\n uniqueGroupIds.add(topMostGroupId);\n }\n }\n\n const rejectedGroupIds = new Set();\n\n for (const groupId of uniqueGroupIds) {\n if ((0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElements, groupId).some(el => (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(el))) {\n rejectedGroupIds.add(groupId);\n }\n }\n\n const ret = [];\n\n for (const element of elements.values()) {\n if (!rejectedGroupIds.has(element.groupIds[element.groupIds.length - 1])) {\n ret.push(element);\n }\n }\n\n return ret;\n};\n/**\n * depending on the appState, return target frame, which is the frame the given element\n * is going to be added to or remove from\n */\n\nconst getTargetFrame = (element, elementsMap, appState) => {\n const _element = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) ? (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getContainerElement)(element, elementsMap) || element : element; // if the element and its containing frame are both selected, then\n // the containing frame is the target frame\n\n\n if (_element.frameId && appState.selectedElementIds[_element.id] && appState.selectedElementIds[_element.frameId]) {\n return getContainingFrame(_element, elementsMap);\n }\n\n return appState.selectedElementIds[_element.id] && appState.selectedElementsAreBeingDragged ? appState.frameToHighlight : getContainingFrame(_element, elementsMap);\n}; // TODO: this a huge bottleneck for large scenes, optimise\n// given an element, return if the element is in some frame\n\nconst isElementInFrame = (element, allElementsMap, appState, opts) => {\n var _a, _b;\n\n const frame = (_a = opts === null || opts === void 0 ? void 0 : opts.targetFrame) !== null && _a !== void 0 ? _a : getTargetFrame(element, allElementsMap, appState);\n\n if (!frame) {\n return false;\n }\n\n const _element = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) ? (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getContainerElement)(element, allElementsMap) || element : element;\n\n const setGroupsInFrame = isInFrame => {\n if (opts === null || opts === void 0 ? void 0 : opts.checkedGroups) {\n _element.groupIds.forEach(groupId => {\n var _a;\n\n (_a = opts.checkedGroups) === null || _a === void 0 ? void 0 : _a.set(groupId, isInFrame);\n });\n }\n };\n\n if ( // if the element is not selected, or it is selected but not being dragged,\n // frame membership won't update, so return true\n !appState.selectedElementIds[_element.id] || !appState.selectedElementsAreBeingDragged || // if both frame and element are selected, won't update membership, so return true\n appState.selectedElementIds[_element.id] && appState.selectedElementIds[frame.id]) {\n return true;\n }\n\n if (_element.groupIds.length === 0) {\n return elementOverlapsWithFrame(_element, frame, allElementsMap);\n }\n\n for (const gid of _element.groupIds) {\n if ((_b = opts === null || opts === void 0 ? void 0 : opts.checkedGroups) === null || _b === void 0 ? void 0 : _b.has(gid)) {\n return opts.checkedGroups.get(gid);\n }\n }\n\n const allElementsInGroup = new Set(_element.groupIds.filter(gid => {\n if (opts === null || opts === void 0 ? void 0 : opts.checkedGroups) {\n return !opts.checkedGroups.has(gid);\n }\n\n return true;\n }).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElementsMap, gid)));\n\n if (appState.editingGroupId && appState.selectedElementsAreBeingDragged) {\n const selectedElements = new Set((0,_selection__WEBPACK_IMPORTED_MODULE_2__.getSelectedElements)(allElementsMap, appState));\n const editingGroupOverlapsFrame = appState.frameToHighlight !== null;\n\n if (editingGroupOverlapsFrame) {\n return true;\n }\n\n selectedElements.forEach(selectedElement => {\n allElementsInGroup.delete(selectedElement);\n });\n }\n\n for (const elementInGroup of allElementsInGroup) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(elementInGroup)) {\n setGroupsInFrame(false);\n return false;\n }\n }\n\n for (const elementInGroup of allElementsInGroup) {\n if (elementOverlapsWithFrame(elementInGroup, frame, allElementsMap)) {\n setGroupsInFrame(true);\n return true;\n }\n }\n\n return false;\n};\nconst shouldApplyFrameClip = (element, frame, appState, elementsMap, checkedGroups) => {\n if (!appState.frameRendering || !appState.frameRendering.clip) {\n return false;\n } // for individual elements, only clip when the element is\n // a. overlapping with the frame, or\n // b. containing the frame, for example when an element is used as a background\n // and is therefore bigger than the frame and completely contains the frame\n\n\n const shouldClipElementItself = isElementIntersectingFrame(element, frame, elementsMap) || isElementContainingFrame(element, frame, elementsMap);\n\n if (shouldClipElementItself) {\n for (const groupId of element.groupIds) {\n checkedGroups === null || checkedGroups === void 0 ? void 0 : checkedGroups.set(groupId, true);\n }\n\n return true;\n } // if an element is outside the frame, but is part of a group that has some elements\n // \"in\" the frame, we should clip the element\n\n\n if (!shouldClipElementItself && element.groupIds.length > 0 && !elementsAreInFrameBounds([element], frame, elementsMap)) {\n let shouldClip = false; // if no elements are being dragged, we can skip the geometry check\n // because we know if the element is in the given frame or not\n\n if (!appState.selectedElementsAreBeingDragged) {\n shouldClip = element.frameId === frame.id;\n\n for (const groupId of element.groupIds) {\n checkedGroups === null || checkedGroups === void 0 ? void 0 : checkedGroups.set(groupId, shouldClip);\n }\n } else {\n shouldClip = isElementInFrame(element, elementsMap, appState, {\n targetFrame: frame,\n checkedGroups\n });\n }\n\n for (const groupId of element.groupIds) {\n checkedGroups === null || checkedGroups === void 0 ? void 0 : checkedGroups.set(groupId, shouldClip);\n }\n\n return shouldClip;\n }\n\n return false;\n};\nconst DEFAULT_FRAME_NAME = \"Frame\";\nconst DEFAULT_AI_FRAME_NAME = \"AI Frame\";\nconst getDefaultFrameName = element => {\n // TODO name frames \"AI\" only if specific to AI frames\n return (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameElement)(element) ? DEFAULT_FRAME_NAME : DEFAULT_AI_FRAME_NAME;\n};\nconst getFrameLikeTitle = element => {\n return element.name === null ? getDefaultFrameName(element) : element.name;\n};\nconst getElementsOverlappingFrame = (elements, frame, elementsMap) => {\n return elements.filter(el => // exclude elements which are overlapping, but are in a different frame,\n // and thus invisible in target frame\n (!el.frameId || el.frameId === frame.id) && (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.doBoundsIntersect)((0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(el, elementsMap), (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(frame, elementsMap)));\n};\nconst frameAndChildrenSelectedTogether = selectedElements => {\n const selectedElementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(selectedElements);\n return selectedElements.length > 1 && selectedElements.some(element => element.frameId && selectedElementsMap.has(element.frameId));\n};\n\n//# sourceURL=webpack://ExcalidrawLib/../element/src/frame.ts?\n}");
|
|
608
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addElementsToFrame: () => (/* binding */ addElementsToFrame),\n/* harmony export */ bindElementsToFramesAfterDuplication: () => (/* binding */ bindElementsToFramesAfterDuplication),\n/* harmony export */ elementOverlapsWithFrame: () => (/* binding */ elementOverlapsWithFrame),\n/* harmony export */ elementsAreInFrameBounds: () => (/* binding */ elementsAreInFrameBounds),\n/* harmony export */ filterElementsEligibleAsFrameChildren: () => (/* binding */ filterElementsEligibleAsFrameChildren),\n/* harmony export */ frameAndChildrenSelectedTogether: () => (/* binding */ frameAndChildrenSelectedTogether),\n/* harmony export */ getCommonFrameId: () => (/* binding */ getCommonFrameId),\n/* harmony export */ getContainingFrame: () => (/* binding */ getContainingFrame),\n/* harmony export */ getDefaultFrameName: () => (/* binding */ getDefaultFrameName),\n/* harmony export */ getElementsCompletelyInFrame: () => (/* binding */ getElementsCompletelyInFrame),\n/* harmony export */ getElementsInNewFrame: () => (/* binding */ getElementsInNewFrame),\n/* harmony export */ getElementsInResizingFrame: () => (/* binding */ getElementsInResizingFrame),\n/* harmony export */ getElementsIntersectingFrame: () => (/* binding */ getElementsIntersectingFrame),\n/* harmony export */ getElementsOverlappingFrame: () => (/* binding */ getElementsOverlappingFrame),\n/* harmony export */ getFrameChildren: () => (/* binding */ getFrameChildren),\n/* harmony export */ getFrameChildrenInsertionIndex: () => (/* binding */ getFrameChildrenInsertionIndex),\n/* harmony export */ getFrameLikeElements: () => (/* binding */ getFrameLikeElements),\n/* harmony export */ getFrameLikeTitle: () => (/* binding */ getFrameLikeTitle),\n/* harmony export */ getRootElements: () => (/* binding */ getRootElements),\n/* harmony export */ getTargetFrame: () => (/* binding */ getTargetFrame),\n/* harmony export */ groupByFrameLikes: () => (/* binding */ groupByFrameLikes),\n/* harmony export */ groupsAreAtLeastIntersectingTheFrame: () => (/* binding */ groupsAreAtLeastIntersectingTheFrame),\n/* harmony export */ groupsAreCompletelyOutOfFrame: () => (/* binding */ groupsAreCompletelyOutOfFrame),\n/* harmony export */ isCursorInFrame: () => (/* binding */ isCursorInFrame),\n/* harmony export */ isElementContainingFrame: () => (/* binding */ isElementContainingFrame),\n/* harmony export */ isElementInFrame: () => (/* binding */ isElementInFrame),\n/* harmony export */ isElementIntersectingFrame: () => (/* binding */ isElementIntersectingFrame),\n/* harmony export */ omitGroupsContainingFrameLikes: () => (/* binding */ omitGroupsContainingFrameLikes),\n/* harmony export */ omitPartialGroups: () => (/* binding */ omitPartialGroups),\n/* harmony export */ removeAllElementsFromFrame: () => (/* binding */ removeAllElementsFromFrame),\n/* harmony export */ removeElementsFromFrame: () => (/* binding */ removeElementsFromFrame),\n/* harmony export */ replaceAllElementsInFrame: () => (/* binding */ replaceAllElementsInFrame),\n/* harmony export */ shouldApplyFrameClip: () => (/* binding */ shouldApplyFrameClip),\n/* harmony export */ updateFrameMembershipOfSelectedElements: () => (/* binding */ updateFrameMembershipOfSelectedElements)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _excalidraw_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @excalidraw/math */ \"../math/src/index.ts\");\n/* harmony import */ var _selection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./selection */ \"../element/src/selection.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./groups */ \"../element/src/groups.ts\");\n/* harmony import */ var _bounds__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./bounds */ \"../element/src/bounds.ts\");\n/* harmony import */ var _mutateElement__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./mutateElement */ \"../element/src/mutateElement.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./textElement */ \"../element/src/textElement.ts\");\n/* harmony import */ var _fractionalIndex__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./fractionalIndex */ \"../element/src/fractionalIndex.ts\");\n/* harmony import */ var _typeChecks__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./typeChecks */ \"../element/src/typeChecks.ts\");\n\n\n\n\n\n\n\n\n // --------------------------- Frame State ------------------------------------\n\nconst bindElementsToFramesAfterDuplication = (nextElements, origElements, origIdToDuplicateId) => {\n const nextElementMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(nextElements);\n\n for (const element of origElements) {\n if (element.frameId) {\n // use its frameId to get the new frameId\n const nextElementId = origIdToDuplicateId.get(element.id);\n const nextFrameId = origIdToDuplicateId.get(element.frameId);\n const nextElement = nextElementId && nextElementMap.get(nextElementId);\n\n if (nextElement) {\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_5__.mutateElement)(nextElement, nextElementMap, {\n frameId: nextFrameId !== null && nextFrameId !== void 0 ? nextFrameId : null\n });\n }\n }\n }\n};\nfunction isElementIntersectingFrame(element, frame, elementsMap) {\n const frameLineSegments = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementLineSegments)(frame, elementsMap);\n const elementLineSegments = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementLineSegments)(element, elementsMap);\n const intersecting = frameLineSegments.some(frameLineSegment => elementLineSegments.some(elementLineSegment => (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.segmentsIntersectAt)(frameLineSegment, elementLineSegment)));\n return intersecting;\n}\nconst getElementsCompletelyInFrame = (elements, frame, elementsMap) => omitGroupsContainingFrameLikes((0,_selection__WEBPACK_IMPORTED_MODULE_2__.getElementsWithinSelection)(elements, frame, elementsMap, false)).filter(element => !(0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && !element.frameId || element.frameId === frame.id);\nconst isElementContainingFrame = (element, frame, elementsMap) => {\n return (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.boundsContainBounds)((0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(element, elementsMap), (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(frame, elementsMap));\n};\nconst getElementsIntersectingFrame = (elements, frame) => {\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n return elements.filter(element => isElementIntersectingFrame(element, frame, elementsMap));\n};\nconst elementsAreInFrameBounds = (elements, frame, elementsMap) => {\n const [frameX1, frameY1, frameX2, frameY2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementAbsoluteCoords)(frame, elementsMap);\n const [elementX1, elementY1, elementX2, elementY2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getCommonBounds)(elements);\n return frameX1 <= elementX1 && frameY1 <= elementY1 && frameX2 >= elementX2 && frameY2 >= elementY2;\n};\nconst elementOverlapsWithFrame = (element, frame, elementsMap) => {\n return elementsAreInFrameBounds([element], frame, elementsMap) || isElementIntersectingFrame(element, frame, elementsMap) || isElementContainingFrame(element, frame, elementsMap);\n};\nconst isCursorInFrame = (cursorCoords, frame, elementsMap) => {\n const [fx1, fy1, fx2, fy2] = (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementAbsoluteCoords)(frame, elementsMap);\n return (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.isPointWithinBounds)((0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.pointFrom)(fx1, fy1), (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.pointFrom)(cursorCoords.x, cursorCoords.y), (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.pointFrom)(fx2, fy2));\n};\nconst groupsAreAtLeastIntersectingTheFrame = (elements, groupIds, frame) => {\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n const elementsInGroup = groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, groupId));\n\n if (elementsInGroup.length === 0) {\n return true;\n }\n\n return !!elementsInGroup.find(element => elementsAreInFrameBounds([element], frame, elementsMap) || isElementIntersectingFrame(element, frame, elementsMap));\n};\nconst groupsAreCompletelyOutOfFrame = (elements, groupIds, frame) => {\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n const elementsInGroup = groupIds.flatMap(groupId => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, groupId));\n\n if (elementsInGroup.length === 0) {\n return true;\n }\n\n return elementsInGroup.find(element => elementsAreInFrameBounds([element], frame, elementsMap) || isElementIntersectingFrame(element, frame, elementsMap)) === undefined;\n}; // --------------------------- Frame Utils ------------------------------------\n\n/**\n * Returns a map of frameId to frame elements. Includes empty frames.\n */\n\nconst groupByFrameLikes = elements => {\n const frameElementsMap = new Map();\n\n for (const element of elements) {\n const frameId = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) ? element.id : element.frameId;\n\n if (frameId && !frameElementsMap.has(frameId)) {\n frameElementsMap.set(frameId, getFrameChildren(elements, frameId));\n }\n }\n\n return frameElementsMap;\n};\nconst getFrameChildren = (allElements, frameId) => {\n const frameChildren = [];\n\n for (const element of allElements.values()) {\n if (element.frameId === frameId) {\n frameChildren.push(element);\n }\n }\n\n return frameChildren;\n};\nconst getFrameLikeElements = allElements => {\n return allElements.filter(element => (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element));\n};\n/**\n * Returns ExcalidrawFrameElements and non-frame-children elements.\n *\n * Considers children as root elements if they point to a frame parent\n * non-existing in the elements set.\n *\n * Considers non-frame bound elements (container or arrow labels) as root.\n */\n\nconst getRootElements = allElements => {\n const frameElements = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(getFrameLikeElements(allElements));\n return allElements.filter(element => frameElements.has(element.id) || !element.frameId || !frameElements.has(element.frameId));\n};\nconst getElementsInResizingFrame = (allElements, frame, appState, elementsMap) => {\n const prevElementsInFrame = getFrameChildren(allElements, frame.id); //zsviczian: do not suggest adding new elements to marker frames while resizing\n\n if (frame.frameRole === \"marker\") {\n return prevElementsInFrame.filter(element => !((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) && element.containerId));\n }\n\n const nextElementsInFrame = new Set(prevElementsInFrame);\n const elementsCompletelyInFrame = new Set([...getElementsCompletelyInFrame(allElements, frame, elementsMap), ...prevElementsInFrame.filter(element => isElementContainingFrame(element, frame, elementsMap))]);\n const elementsNotCompletelyInFrame = prevElementsInFrame.filter(element => !elementsCompletelyInFrame.has(element)); // for elements that are completely in the frame\n // if they are part of some groups, then those groups are still\n // considered to belong to the frame\n\n const groupsToKeep = new Set(Array.from(elementsCompletelyInFrame).flatMap(element => element.groupIds));\n\n for (const element of elementsNotCompletelyInFrame) {\n if (!isElementIntersectingFrame(element, frame, elementsMap)) {\n if (element.groupIds.length === 0) {\n nextElementsInFrame.delete(element);\n }\n } else if (element.groupIds.length > 0) {\n // group element intersects with the frame, we should keep the groups\n // that this element is part of\n for (const id of element.groupIds) {\n groupsToKeep.add(id);\n }\n }\n }\n\n for (const element of elementsNotCompletelyInFrame) {\n if (element.groupIds.length > 0) {\n let shouldRemoveElement = true;\n\n for (const id of element.groupIds) {\n if (groupsToKeep.has(id)) {\n shouldRemoveElement = false;\n }\n }\n\n if (shouldRemoveElement) {\n nextElementsInFrame.delete(element);\n }\n }\n }\n\n const individualElementsCompletelyInFrame = Array.from(elementsCompletelyInFrame).filter(element => element.groupIds.length === 0);\n\n for (const element of individualElementsCompletelyInFrame) {\n nextElementsInFrame.add(element);\n }\n\n const newGroupElementsCompletelyInFrame = Array.from(elementsCompletelyInFrame).filter(element => element.groupIds.length > 0);\n const groupIds = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.selectGroupsFromGivenElements)(newGroupElementsCompletelyInFrame, appState); // new group elements\n\n for (const [id, isSelected] of Object.entries(groupIds)) {\n if (isSelected) {\n const elementsInGroup = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElements, id);\n\n if (elementsAreInFrameBounds(elementsInGroup, frame, elementsMap)) {\n for (const element of elementsInGroup) {\n nextElementsInFrame.add(element);\n }\n }\n }\n }\n\n return [...nextElementsInFrame].filter(element => {\n return !((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) && element.containerId);\n });\n};\nconst getElementsInNewFrame = (elements, frame, elementsMap) => {\n return omitPartialGroups(omitGroupsContainingFrameLikes(elements, getElementsCompletelyInFrame(elements, frame, elementsMap)), frame, elementsMap);\n};\nconst omitPartialGroups = (elements, frame, allElementsMap) => {\n const elementsToReturn = [];\n const checkedGroups = new Map();\n\n for (const element of elements) {\n let shouldOmit = false;\n\n if (element.groupIds.length > 0) {\n // if some partial group should be omitted, then all elements in that group should be omitted\n if (element.groupIds.some(gid => checkedGroups.get(gid))) {\n shouldOmit = true;\n } else {\n const allElementsInGroup = new Set(element.groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElementsMap, gid)));\n shouldOmit = !elementsAreInFrameBounds(Array.from(allElementsInGroup), frame, allElementsMap);\n }\n\n element.groupIds.forEach(gid => {\n checkedGroups.set(gid, shouldOmit);\n });\n }\n\n if (!shouldOmit) {\n elementsToReturn.push(element);\n }\n }\n\n return elementsToReturn;\n};\nconst getContainingFrame = (element, elementsMap) => {\n if (!element.frameId) {\n return null;\n }\n\n return elementsMap.get(element.frameId) || null;\n}; // --------------------------- Frame Operations -------------------------------\n\n/** */\n\nconst filterElementsEligibleAsFrameChildren = (elements, frame) => {\n //zsviczian: nothing is eligible for marker frames\n if (frame.frameRole === \"marker\") {\n return [];\n }\n\n const otherFrames = new Set();\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elements);\n elements = omitGroupsContainingFrameLikes(elements);\n\n for (const element of elements) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && element.id !== frame.id) {\n otherFrames.add(element.id);\n }\n }\n\n const processedGroups = new Set();\n const eligibleElements = [];\n\n for (const element of elements) {\n // don't add frames or their children\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) || element.frameId && otherFrames.has(element.frameId)) {\n continue;\n }\n\n if (element.groupIds.length) {\n const shallowestGroupId = element.groupIds.at(-1);\n\n if (!processedGroups.has(shallowestGroupId)) {\n processedGroups.add(shallowestGroupId);\n const groupElements = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, shallowestGroupId);\n\n if (groupElements.some(el => elementOverlapsWithFrame(el, frame, elementsMap))) {\n for (const child of groupElements) {\n eligibleElements.push(child);\n }\n }\n }\n } else {\n const overlaps = elementOverlapsWithFrame(element, frame, elementsMap);\n\n if (overlaps) {\n eligibleElements.push(element);\n }\n }\n }\n\n return eligibleElements;\n};\nconst getCommonFrameId = elements => {\n let commonFrameId;\n\n for (const element of elements) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) || !element.frameId) {\n return null;\n }\n\n if (commonFrameId === undefined) {\n commonFrameId = element.frameId;\n } else if (commonFrameId !== element.frameId) {\n return null;\n }\n }\n\n return commonFrameId !== null && commonFrameId !== void 0 ? commonFrameId : null;\n};\nconst getFrameChildrenInsertionIndex = (elements, frameId) => {\n for (let index = elements.length - 1; index >= 0; index--) {\n const element = elements[index];\n\n if (element.id === frameId) {\n return index;\n } else if (element.frameId === frameId) {\n return index + 1;\n }\n }\n\n return null;\n};\n/**\n * Adds elements and their bound elements to frame. Reorders added elements to\n * be just below frame, or just above its highest child (whichever is higher).\n *\n * @returns mutated allElements (same data structure)\n */\n\nconst addElementsToFrame = (allElements, elementsToAdd, frame) => {\n if (frame.frameRole === \"marker\") {\n return allElements;\n } //zsviczian\n\n\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(allElements);\n const commonFrameId = getCommonFrameId(elementsToAdd);\n const finalElementsToAdd = new Set();\n const otherFrames = new Set();\n\n for (const element of elementsToAdd) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && element.id !== frame.id) {\n otherFrames.add(element.id);\n }\n } // - add bound text elements if not already in the array\n // - keep elements already in the frame so mixed selections can be reordered\n // together\n\n\n for (const element of omitGroupsContainingFrameLikes(allElements, elementsToAdd)) {\n // don't add frames or their children\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) || element.frameId && otherFrames.has(element.frameId)) {\n continue;\n }\n\n finalElementsToAdd.add(element);\n const boundTextElement = (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getBoundTextElement)(element, elementsMap);\n\n if (boundTextElement && !finalElementsToAdd.has(boundTextElement)) {\n finalElementsToAdd.add(boundTextElement);\n }\n }\n\n for (const element of finalElementsToAdd) {\n // we don't always need to update the element if it's already in the frame,\n // but we still need to accumulate in finalElementsToAdd so we potentially\n // reorder them if added together\n if (element.frameId !== frame.id) {\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_5__.mutateElement)(element, elementsMap, {\n frameId: frame.id\n });\n }\n } // (re)order elements to be just below the frame,\n // or just above the highest child if that is higher\n // (latter case is denormalized order until we migrate)\n // ---------------------------------------------------------------------------\n\n\n if (!finalElementsToAdd.size || // if all elements to add already belong to the frame, then we don't want to\n // reorder (case: we're dragging element children within the frame)\n commonFrameId === frame.id) {\n return allElements;\n }\n\n const otherElements = Array.from(allElements.values()).filter(element => !finalElementsToAdd.has(element));\n const insertionIndex = getFrameChildrenInsertionIndex(otherElements, frame.id);\n\n if (insertionIndex === null) {\n return allElements;\n }\n\n const reorderedElements = [...otherElements.slice(0, insertionIndex), ...finalElementsToAdd, ...otherElements.slice(insertionIndex)];\n (0,_fractionalIndex__WEBPACK_IMPORTED_MODULE_7__.syncMovedIndices)(reorderedElements, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)([...finalElementsToAdd]));\n return Array.isArray(allElements) ? reorderedElements : new Map(reorderedElements.map(element => [element.id, element]));\n};\nconst removeElementsFromFrame = (elementsToRemove, elementsMap) => {\n const _elementsToRemove = new Map();\n\n const toRemoveElementsByFrame = new Map();\n\n for (const element of elementsToRemove) {\n if (element.frameId) {\n _elementsToRemove.set(element.id, element);\n\n const arr = toRemoveElementsByFrame.get(element.frameId) || [];\n arr.push(element);\n const boundTextElement = (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getBoundTextElement)(element, elementsMap);\n\n if (boundTextElement) {\n _elementsToRemove.set(boundTextElement.id, boundTextElement);\n\n arr.push(boundTextElement);\n }\n\n toRemoveElementsByFrame.set(element.frameId, arr);\n }\n }\n\n for (const [, element] of _elementsToRemove) {\n (0,_mutateElement__WEBPACK_IMPORTED_MODULE_5__.mutateElement)(element, elementsMap, {\n frameId: null\n });\n }\n};\nconst removeAllElementsFromFrame = (allElements, frame) => {\n const elementsInFrame = getFrameChildren(allElements, frame.id);\n removeElementsFromFrame(elementsInFrame, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(allElements));\n return allElements;\n};\nconst replaceAllElementsInFrame = (allElements, nextElementsInFrame, frame) => {\n return addElementsToFrame(removeAllElementsFromFrame(allElements, frame), nextElementsInFrame, frame).slice();\n};\n/** does not mutate elements, but returns new ones */\n\nconst updateFrameMembershipOfSelectedElements = (allElements, appState, app) => {\n const selectedElements = app.scene.getSelectedElements({\n selectedElementIds: appState.selectedElementIds,\n // supplying elements explicitly in case we're passed non-state elements\n elements: allElements\n });\n const elementsToFilter = new Set(selectedElements);\n\n if (appState.editingGroupId) {\n for (const element of selectedElements) {\n if (element.groupIds.length === 0) {\n elementsToFilter.add(element);\n } else {\n element.groupIds.flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElements, gid)).forEach(element => elementsToFilter.add(element));\n }\n }\n }\n\n const elementsToRemove = new Set();\n const elementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(allElements);\n elementsToFilter.forEach(element => {\n if (element.frameId && !(0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(element) && !isElementInFrame(element, elementsMap, appState)) {\n elementsToRemove.add(element);\n }\n });\n\n if (elementsToRemove.size > 0) {\n removeElementsFromFrame(elementsToRemove, elementsMap);\n }\n\n return allElements;\n};\n/**\n * filters out elements that are inside groups that contain a frame element\n * anywhere in the group tree\n */\n\nconst omitGroupsContainingFrameLikes = (allElements,\n/** subset of elements you want to filter. Optional perf optimization so we\n * don't have to filter all elements unnecessarily\n */\nselectedElements) => {\n const uniqueGroupIds = new Set();\n const elements = selectedElements || allElements;\n\n for (const el of elements.values()) {\n const topMostGroupId = el.groupIds[el.groupIds.length - 1];\n\n if (topMostGroupId) {\n uniqueGroupIds.add(topMostGroupId);\n }\n }\n\n const rejectedGroupIds = new Set();\n\n for (const groupId of uniqueGroupIds) {\n if ((0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElements, groupId).some(el => (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(el))) {\n rejectedGroupIds.add(groupId);\n }\n }\n\n const ret = [];\n\n for (const element of elements.values()) {\n if (!rejectedGroupIds.has(element.groupIds[element.groupIds.length - 1])) {\n ret.push(element);\n }\n }\n\n return ret;\n};\n/**\n * depending on the appState, return target frame, which is the frame the given element\n * is going to be added to or remove from\n */\n\nconst getTargetFrame = (element, elementsMap, appState) => {\n const _element = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) ? (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getContainerElement)(element, elementsMap) || element : element; // if the element and its containing frame are both selected, then\n // the containing frame is the target frame\n\n\n if (_element.frameId && appState.selectedElementIds[_element.id] && appState.selectedElementIds[_element.frameId]) {\n return getContainingFrame(_element, elementsMap);\n }\n\n return appState.selectedElementIds[_element.id] && appState.selectedElementsAreBeingDragged ? appState.frameToHighlight : getContainingFrame(_element, elementsMap);\n}; // TODO: this a huge bottleneck for large scenes, optimise\n// given an element, return if the element is in some frame\n\nconst isElementInFrame = (element, allElementsMap, appState, opts) => {\n var _a, _b;\n\n const frame = (_a = opts === null || opts === void 0 ? void 0 : opts.targetFrame) !== null && _a !== void 0 ? _a : getTargetFrame(element, allElementsMap, appState);\n\n if (!frame) {\n return false;\n }\n\n const _element = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isTextElement)(element) ? (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getContainerElement)(element, allElementsMap) || element : element;\n\n const setGroupsInFrame = isInFrame => {\n if (opts === null || opts === void 0 ? void 0 : opts.checkedGroups) {\n _element.groupIds.forEach(groupId => {\n var _a;\n\n (_a = opts.checkedGroups) === null || _a === void 0 ? void 0 : _a.set(groupId, isInFrame);\n });\n }\n };\n\n if ( // if the element is not selected, or it is selected but not being dragged,\n // frame membership won't update, so return true\n !appState.selectedElementIds[_element.id] || !appState.selectedElementsAreBeingDragged || // if both frame and element are selected, won't update membership, so return true\n appState.selectedElementIds[_element.id] && appState.selectedElementIds[frame.id]) {\n return true;\n }\n\n if (_element.groupIds.length === 0) {\n return elementOverlapsWithFrame(_element, frame, allElementsMap);\n }\n\n for (const gid of _element.groupIds) {\n if ((_b = opts === null || opts === void 0 ? void 0 : opts.checkedGroups) === null || _b === void 0 ? void 0 : _b.has(gid)) {\n return opts.checkedGroups.get(gid);\n }\n }\n\n const allElementsInGroup = new Set(_element.groupIds.filter(gid => {\n if (opts === null || opts === void 0 ? void 0 : opts.checkedGroups) {\n return !opts.checkedGroups.has(gid);\n }\n\n return true;\n }).flatMap(gid => (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(allElementsMap, gid)));\n\n if (appState.editingGroupId && appState.selectedElementsAreBeingDragged) {\n const selectedElements = new Set((0,_selection__WEBPACK_IMPORTED_MODULE_2__.getSelectedElements)(allElementsMap, appState));\n const editingGroupOverlapsFrame = appState.frameToHighlight !== null;\n\n if (editingGroupOverlapsFrame) {\n return true;\n }\n\n selectedElements.forEach(selectedElement => {\n allElementsInGroup.delete(selectedElement);\n });\n }\n\n for (const elementInGroup of allElementsInGroup) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameLikeElement)(elementInGroup)) {\n setGroupsInFrame(false);\n return false;\n }\n }\n\n for (const elementInGroup of allElementsInGroup) {\n if (elementOverlapsWithFrame(elementInGroup, frame, allElementsMap)) {\n setGroupsInFrame(true);\n return true;\n }\n }\n\n return false;\n};\nconst shouldApplyFrameClip = (element, frame, appState, elementsMap, checkedGroups) => {\n if (!appState.frameRendering || !appState.frameRendering.clip) {\n return false;\n } // for individual elements, only clip when the element is\n // a. overlapping with the frame, or\n // b. containing the frame, for example when an element is used as a background\n // and is therefore bigger than the frame and completely contains the frame\n\n\n const shouldClipElementItself = isElementIntersectingFrame(element, frame, elementsMap) || isElementContainingFrame(element, frame, elementsMap);\n\n if (shouldClipElementItself) {\n for (const groupId of element.groupIds) {\n checkedGroups === null || checkedGroups === void 0 ? void 0 : checkedGroups.set(groupId, true);\n }\n\n return true;\n } // if an element is outside the frame, but is part of a group that has some elements\n // \"in\" the frame, we should clip the element\n\n\n if (!shouldClipElementItself && element.groupIds.length > 0 && !elementsAreInFrameBounds([element], frame, elementsMap)) {\n let shouldClip = false; // if no elements are being dragged, we can skip the geometry check\n // because we know if the element is in the given frame or not\n\n if (!appState.selectedElementsAreBeingDragged) {\n shouldClip = element.frameId === frame.id;\n\n for (const groupId of element.groupIds) {\n checkedGroups === null || checkedGroups === void 0 ? void 0 : checkedGroups.set(groupId, shouldClip);\n }\n } else {\n shouldClip = isElementInFrame(element, elementsMap, appState, {\n targetFrame: frame,\n checkedGroups\n });\n }\n\n for (const groupId of element.groupIds) {\n checkedGroups === null || checkedGroups === void 0 ? void 0 : checkedGroups.set(groupId, shouldClip);\n }\n\n return shouldClip;\n }\n\n return false;\n};\nconst DEFAULT_FRAME_NAME = \"Frame\";\nconst DEFAULT_AI_FRAME_NAME = \"AI Frame\";\nconst getDefaultFrameName = element => {\n // TODO name frames \"AI\" only if specific to AI frames\n return (0,_typeChecks__WEBPACK_IMPORTED_MODULE_8__.isFrameElement)(element) ? DEFAULT_FRAME_NAME : DEFAULT_AI_FRAME_NAME;\n};\nconst getFrameLikeTitle = element => {\n return element.name === null ? getDefaultFrameName(element) : element.name;\n};\nconst getElementsOverlappingFrame = (elements, frame, elementsMap) => {\n return elements.filter(el => // exclude elements which are overlapping, but are in a different frame,\n // and thus invisible in target frame\n (!el.frameId || el.frameId === frame.id) && (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.doBoundsIntersect)((0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(el, elementsMap), (0,_bounds__WEBPACK_IMPORTED_MODULE_4__.getElementBounds)(frame, elementsMap)));\n};\nconst frameAndChildrenSelectedTogether = selectedElements => {\n const selectedElementsMap = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(selectedElements);\n return selectedElements.length > 1 && selectedElements.some(element => element.frameId && selectedElementsMap.has(element.frameId));\n};\n\n//# sourceURL=webpack://ExcalidrawLib/../element/src/frame.ts?\n}");
|
|
609
609
|
|
|
610
610
|
/***/ },
|
|
611
611
|
|
|
@@ -891,7 +891,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
891
891
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
892
892
|
|
|
893
893
|
"use strict";
|
|
894
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ moveAllLeft: () => (/* binding */ moveAllLeft),\n/* harmony export */ moveAllRight: () => (/* binding */ moveAllRight),\n/* harmony export */ moveArrowAboveBindable: () => (/* binding */ moveArrowAboveBindable),\n/* harmony export */ moveOneLeft: () => (/* binding */ moveOneLeft),\n/* harmony export */ moveOneRight: () => (/* binding */ moveOneRight)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _typeChecks__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./typeChecks */ \"../element/src/typeChecks.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./groups */ \"../element/src/groups.ts\");\n/* harmony import */ var _fractionalIndex__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./fractionalIndex */ \"../element/src/fractionalIndex.ts\");\n/* harmony import */ var _selection__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./selection */ \"../element/src/selection.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./textElement */ \"../element/src/textElement.ts\");\n/* harmony import */ var _collision__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./collision */ \"../element/src/collision.ts\");\n\n\n\n\n\n\n\n\nconst isOfTargetFrame = (element, frameId) => {\n return element.frameId === frameId || element.id === frameId;\n};\n/**\n * Returns indices of elements to move based on selected elements.\n * Includes contiguous deleted elements that are between two selected elements,\n * e.g.: [0 (selected), 1 (deleted), 2 (deleted), 3 (selected)]\n *\n * Specified elements (elementsToBeMoved) take precedence over\n * appState.selectedElementsIds\n */\n\n\nconst getIndicesToMove = (elements, appState, elementsToBeMoved) => {\n let selectedIndices = [];\n let deletedIndices = [];\n let includeDeletedIndex = null;\n let index = -1;\n const selectedElementIds = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elementsToBeMoved ? elementsToBeMoved : (0,_selection__WEBPACK_IMPORTED_MODULE_4__.getSelectedElements)(elements, appState, {\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }));\n\n while (++index < elements.length) {\n const element = elements[index];\n\n if (selectedElementIds.get(element.id)) {\n if (deletedIndices.length) {\n selectedIndices = selectedIndices.concat(deletedIndices);\n deletedIndices = [];\n }\n\n selectedIndices.push(index);\n includeDeletedIndex = index + 1;\n } else if (element.isDeleted && includeDeletedIndex === index) {\n includeDeletedIndex = index + 1;\n deletedIndices.push(index);\n } else {\n deletedIndices = [];\n }\n }\n\n return selectedIndices;\n};\n\nconst toContiguousGroups = array => {\n let cursor = 0;\n return array.reduce((acc, value, index) => {\n if (index > 0 && array[index - 1] !== value - 1) {\n cursor = ++cursor;\n }\n\n (acc[cursor] || (acc[cursor] = [])).push(value);\n return acc;\n }, []);\n};\n/**\n * @returns index of target element, consindering tightly-bound elements\n * (currently non-linear elements bound to a container) as a one unit.\n * If no binding present, returns `undefined`.\n */\n\n\nconst getTargetIndexAccountingForBinding = (nextElement, elements, direction, scene) => {\n var _a, _b;\n\n if (\"containerId\" in nextElement && nextElement.containerId) {\n // TODO: why not to get the container from the nextElements?\n const containerElement = scene.getElement(nextElement.containerId);\n\n if (containerElement) {\n return direction === \"left\" ? Math.min(elements.indexOf(containerElement), elements.indexOf(nextElement)) : Math.max(elements.indexOf(containerElement), elements.indexOf(nextElement));\n }\n } else {\n const boundElementId = (_b = (_a = nextElement.boundElements) === null || _a === void 0 ? void 0 : _a.find(binding => binding.type !== \"arrow\")) === null || _b === void 0 ? void 0 : _b.id;\n\n if (boundElementId) {\n const boundTextElement = scene.getElement(boundElementId);\n\n if (boundTextElement) {\n return direction === \"left\" ? Math.min(elements.indexOf(boundTextElement), elements.indexOf(nextElement)) : Math.max(elements.indexOf(boundTextElement), elements.indexOf(nextElement));\n }\n }\n }\n};\n\nconst getContiguousFrameRangeElements = (allElements, frameId) => {\n let rangeStart = -1;\n let rangeEnd = -1;\n allElements.forEach((element, index) => {\n if (isOfTargetFrame(element, frameId)) {\n if (rangeStart === -1) {\n rangeStart = index;\n }\n\n rangeEnd = index;\n }\n });\n\n if (rangeStart === -1) {\n return [];\n }\n\n return allElements.slice(rangeStart, rangeEnd + 1);\n};\n/**\n * Moves the arrow element above any bindable elements it intersects with or\n * hovers over.\n */\n\n\nconst moveArrowAboveBindable = (point, arrow, elements, elementsMap, scene, hit) => {\n const hoveredElement = hit ? hit : (0,_collision__WEBPACK_IMPORTED_MODULE_6__.getHoveredElementForBinding)(point, elements, elementsMap);\n\n if (!hoveredElement) {\n return elements;\n }\n\n const boundTextElement = (0,_textElement__WEBPACK_IMPORTED_MODULE_5__.getBoundTextElement)(hoveredElement, elementsMap);\n const containerElement = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_1__.isTextElement)(hoveredElement) ? (0,_textElement__WEBPACK_IMPORTED_MODULE_5__.getContainerElement)(hoveredElement, elementsMap) : null;\n const bindableIds = [hoveredElement.id, boundTextElement === null || boundTextElement === void 0 ? void 0 : boundTextElement.id, containerElement === null || containerElement === void 0 ? void 0 : containerElement.id].filter(id => !!id);\n const bindableIdx = elements.findIndex(el => bindableIds.includes(el.id));\n const arrowIdx = elements.findIndex(el => el.id === arrow.id);\n\n if (arrowIdx !== -1 && bindableIdx !== -1 && arrowIdx < bindableIdx) {\n const updatedElements = Array.from(elements);\n const arrow = updatedElements.splice(arrowIdx, 1)[0];\n updatedElements.splice(bindableIdx, 0, arrow);\n scene.replaceAllElements(updatedElements);\n }\n\n return elements;\n};\n/**\n * Returns next candidate index that's available to be moved to. Currently that\n * is a non-deleted element, and not inside a group (unless we're editing it).\n */\n\nconst getTargetIndex = (appState, elements, boundaryIndex, direction,\n/**\n * Frame id if moving frame children.\n * If whole frame (including all children) is being moved, supply `null`.\n */\ncontainingFrame, scene) => {\n var _a, _b;\n\n const sourceElement = elements[boundaryIndex];\n\n const indexFilter = element => {\n if (element.isDeleted) {\n return false;\n }\n\n if (containingFrame) {\n return element.frameId === containingFrame;\n } // if we're editing group, find closest sibling irrespective of whether\n // there's a different-group element between them (for legacy reasons)\n\n\n if (appState.editingGroupId) {\n return element.groupIds.includes(appState.editingGroupId);\n }\n\n return true;\n };\n\n const candidateIndex = direction === \"left\" ? (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findLastIndex)(elements, el => indexFilter(el), Math.max(0, boundaryIndex - 1)) : (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findIndex)(elements, el => indexFilter(el), boundaryIndex + 1);\n const nextElement = elements[candidateIndex];\n\n if (!nextElement) {\n return -1;\n }\n\n if (appState.editingGroupId) {\n if ( // candidate element is a sibling in current editing group β return\n (sourceElement === null || sourceElement === void 0 ? void 0 : sourceElement.groupIds.join(\"\")) === (nextElement === null || nextElement === void 0 ? void 0 : nextElement.groupIds.join(\"\"))) {\n return (_a = getTargetIndexAccountingForBinding(nextElement, elements, direction, scene)) !== null && _a !== void 0 ? _a : candidateIndex;\n } else if (!(nextElement === null || nextElement === void 0 ? void 0 : nextElement.groupIds.includes(appState.editingGroupId))) {\n // candidate element is outside current editing group β prevent\n return -1;\n }\n }\n\n if (!containingFrame && (nextElement.frameId || (0,_typeChecks__WEBPACK_IMPORTED_MODULE_1__.isFrameLikeElement)(nextElement))) {\n const frameElements = getContiguousFrameRangeElements(elements, nextElement.frameId || nextElement.id);\n return direction === \"left\" ? elements.indexOf(frameElements[0]) : elements.indexOf(frameElements[frameElements.length - 1]);\n }\n\n if (!nextElement.groupIds.length) {\n return (_b = getTargetIndexAccountingForBinding(nextElement, elements, direction, scene)) !== null && _b !== void 0 ? _b : candidateIndex;\n }\n\n const siblingGroupId = appState.editingGroupId ? nextElement.groupIds[nextElement.groupIds.indexOf(appState.editingGroupId) - 1] : nextElement.groupIds[nextElement.groupIds.length - 1];\n const elementsInSiblingGroup = (0,_groups__WEBPACK_IMPORTED_MODULE_2__.getElementsInGroup)(elements, siblingGroupId);\n\n if (elementsInSiblingGroup.length) {\n // assumes getElementsInGroup() returned elements are sorted\n // by zIndex (ascending)\n return direction === \"left\" ? elements.indexOf(elementsInSiblingGroup[0]) : elements.indexOf(elementsInSiblingGroup[elementsInSiblingGroup.length - 1]);\n }\n\n return candidateIndex;\n};\n\nconst getTargetElementsMap = (elements, indices) => {\n return indices.reduce((acc, index) => {\n const element = elements[index];\n acc.set(element.id, element);\n return acc;\n }, new Map());\n};\n\nconst shiftElementsByOne = (elements, appState, direction, scene) => {\n const indicesToMove = getIndicesToMove(elements, appState);\n const targetElementsMap = getTargetElementsMap(elements, indicesToMove);\n let groupedIndices = toContiguousGroups(indicesToMove);\n\n if (direction === \"right\") {\n groupedIndices = groupedIndices.reverse();\n }\n\n const selectedFrames = new Set(indicesToMove.filter(idx => (0,_typeChecks__WEBPACK_IMPORTED_MODULE_1__.isFrameLikeElement)(elements[idx])).map(idx => elements[idx].id));\n groupedIndices.forEach((indices, i) => {\n var _a;\n\n const leadingIndex = indices[0];\n const trailingIndex = indices[indices.length - 1];\n const boundaryIndex = direction === \"left\" ? leadingIndex : trailingIndex;\n const containingFrame = indices.some(idx => {\n const el = elements[idx];\n return el.frameId && selectedFrames.has(el.frameId);\n }) ? null : (_a = elements[boundaryIndex]) === null || _a === void 0 ? void 0 : _a.frameId;\n const targetIndex = getTargetIndex(appState, elements, boundaryIndex, direction, containingFrame, scene);\n\n if (targetIndex === -1 || boundaryIndex === targetIndex) {\n return;\n }\n\n const leadingElements = direction === \"left\" ? elements.slice(0, targetIndex) : elements.slice(0, leadingIndex);\n const targetElements = elements.slice(leadingIndex, trailingIndex + 1);\n const displacedElements = direction === \"left\" ? elements.slice(targetIndex, leadingIndex) : elements.slice(trailingIndex + 1, targetIndex + 1);\n const trailingElements = direction === \"left\" ? elements.slice(trailingIndex + 1) : elements.slice(targetIndex + 1);\n elements = direction === \"left\" ? [...leadingElements, ...targetElements, ...displacedElements, ...trailingElements] : [...leadingElements, ...displacedElements, ...targetElements, ...trailingElements];\n });\n (0,_fractionalIndex__WEBPACK_IMPORTED_MODULE_3__.syncMovedIndices)(elements, targetElementsMap);\n return elements;\n};\n\nconst shiftElementsToEnd = (elements, appState, direction, containingFrame, elementsToBeMoved) => {\n const indicesToMove = getIndicesToMove(elements, appState, elementsToBeMoved);\n const targetElementsMap = getTargetElementsMap(elements, indicesToMove);\n const displacedElements = [];\n let leadingIndex;\n let trailingIndex;\n\n if (direction === \"left\") {\n if (containingFrame) {\n leadingIndex = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findIndex)(elements, el => isOfTargetFrame(el, containingFrame));\n } else if (appState.editingGroupId) {\n const groupElements = (0,_groups__WEBPACK_IMPORTED_MODULE_2__.getElementsInGroup)(elements, appState.editingGroupId);\n\n if (!groupElements.length) {\n return elements;\n }\n\n leadingIndex = elements.indexOf(groupElements[0]);\n } else {\n leadingIndex = 0;\n }\n\n trailingIndex = indicesToMove[indicesToMove.length - 1];\n } else {\n if (containingFrame) {\n trailingIndex = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findLastIndex)(elements, el => isOfTargetFrame(el, containingFrame));\n } else if (appState.editingGroupId) {\n const groupElements = (0,_groups__WEBPACK_IMPORTED_MODULE_2__.getElementsInGroup)(elements, appState.editingGroupId);\n\n if (!groupElements.length) {\n return elements;\n }\n\n trailingIndex = elements.indexOf(groupElements[groupElements.length - 1]);\n } else {\n trailingIndex = elements.length - 1;\n }\n\n leadingIndex = indicesToMove[0];\n }\n\n if (leadingIndex === -1) {\n leadingIndex = 0;\n }\n\n for (let index = leadingIndex; index < trailingIndex + 1; index++) {\n if (!indicesToMove.includes(index)) {\n displacedElements.push(elements[index]);\n }\n }\n\n const targetElements = Array.from(targetElementsMap.values());\n const leadingElements = elements.slice(0, leadingIndex);\n const trailingElements = elements.slice(trailingIndex + 1);\n const nextElements = direction === \"left\" ? [...leadingElements, ...targetElements, ...displacedElements, ...trailingElements] : [...leadingElements, ...displacedElements, ...targetElements, ...trailingElements];\n (0,_fractionalIndex__WEBPACK_IMPORTED_MODULE_3__.syncMovedIndices)(nextElements, targetElementsMap);\n return nextElements;\n};\n\nfunction shiftElementsAccountingForFrames(allElements, appState, direction, shiftFunction) {\n const elementsToMove = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)((0,_selection__WEBPACK_IMPORTED_MODULE_4__.getSelectedElements)(allElements, appState, {\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }));\n const frameAwareContiguousElementsToMove = {\n regularElements: [],\n frameChildren: new Map()\n };\n const fullySelectedFrames = new Set();\n\n for (const element of allElements) {\n if (elementsToMove.has(element.id) && (0,_typeChecks__WEBPACK_IMPORTED_MODULE_1__.isFrameLikeElement)(element)) {\n fullySelectedFrames.add(element.id);\n }\n }\n\n for (const element of allElements) {\n if (elementsToMove.has(element.id)) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_1__.isFrameLikeElement)(element) || element.frameId && fullySelectedFrames.has(element.frameId)) {\n frameAwareContiguousElementsToMove.regularElements.push(element);\n } else if (!element.frameId) {\n frameAwareContiguousElementsToMove.regularElements.push(element);\n } else {\n const frameChildren = frameAwareContiguousElementsToMove.frameChildren.get(element.frameId) || [];\n frameChildren.push(element);\n frameAwareContiguousElementsToMove.frameChildren.set(element.frameId, frameChildren);\n }\n }\n }\n\n let nextElements = allElements;\n const frameChildrenSets = Array.from(frameAwareContiguousElementsToMove.frameChildren.entries());\n\n for (const [frameId, children] of frameChildrenSets) {\n nextElements = shiftFunction(allElements, appState, direction, frameId, children);\n }\n\n return shiftFunction(nextElements, appState, direction, null, frameAwareContiguousElementsToMove.regularElements);\n} // public API\n// -----------------------------------------------------------------------------\n\n\nconst moveOneLeft = (allElements, appState, scene) => {\n return shiftElementsByOne(allElements, appState, \"left\", scene);\n};\nconst moveOneRight = (allElements, appState, scene) => {\n return shiftElementsByOne(allElements, appState, \"right\", scene);\n};\nconst moveAllLeft = (allElements, appState) => {\n return shiftElementsAccountingForFrames(allElements, appState, \"left\", shiftElementsToEnd);\n};\nconst moveAllRight = (allElements, appState) => {\n return shiftElementsAccountingForFrames(allElements, appState, \"right\", shiftElementsToEnd);\n};\n\n//# sourceURL=webpack://ExcalidrawLib/../element/src/zindex.ts?\n}");
|
|
894
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ moveAllLeft: () => (/* binding */ moveAllLeft),\n/* harmony export */ moveAllRight: () => (/* binding */ moveAllRight),\n/* harmony export */ moveArrowAboveBindable: () => (/* binding */ moveArrowAboveBindable),\n/* harmony export */ moveOneLeft: () => (/* binding */ moveOneLeft),\n/* harmony export */ moveOneRight: () => (/* binding */ moveOneRight)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _excalidraw_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @excalidraw/math */ \"../math/src/index.ts\");\n/* harmony import */ var _typeChecks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./typeChecks */ \"../element/src/typeChecks.ts\");\n/* harmony import */ var _groups__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./groups */ \"../element/src/groups.ts\");\n/* harmony import */ var _fractionalIndex__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./fractionalIndex */ \"../element/src/fractionalIndex.ts\");\n/* harmony import */ var _selection__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./selection */ \"../element/src/selection.ts\");\n/* harmony import */ var _textElement__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./textElement */ \"../element/src/textElement.ts\");\n/* harmony import */ var _collision__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./collision */ \"../element/src/collision.ts\");\n\n\n\n\n\n\n\n\n\nconst isOfTargetFrame = (element, frameId) => {\n return element.frameId === frameId || element.id === frameId;\n};\n/**\n * Returns indices of elements to move based on selected elements.\n * Includes contiguous deleted elements that are between two selected elements,\n * e.g.: [0 (selected), 1 (deleted), 2 (deleted), 3 (selected)]\n *\n * Specified elements (elementsToBeMoved) take precedence over\n * appState.selectedElementsIds\n */\n\n\nconst getIndicesToMove = (elements, appState, elementsToBeMoved) => {\n let selectedIndices = [];\n let deletedIndices = [];\n let includeDeletedIndex = null;\n let index = -1;\n const selectedElementIds = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)(elementsToBeMoved ? elementsToBeMoved : (0,_selection__WEBPACK_IMPORTED_MODULE_5__.getSelectedElements)(elements, appState, {\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }));\n\n while (++index < elements.length) {\n const element = elements[index];\n\n if (selectedElementIds.get(element.id)) {\n if (deletedIndices.length) {\n selectedIndices = selectedIndices.concat(deletedIndices);\n deletedIndices = [];\n }\n\n selectedIndices.push(index);\n includeDeletedIndex = index + 1;\n } else if (element.isDeleted && includeDeletedIndex === index) {\n includeDeletedIndex = index + 1;\n deletedIndices.push(index);\n } else {\n deletedIndices = [];\n }\n }\n\n return selectedIndices;\n};\n\nconst toContiguousGroups = array => {\n let cursor = 0;\n return array.reduce((acc, value, index) => {\n if (index > 0 && array[index - 1] !== value - 1) {\n cursor = ++cursor;\n }\n\n (acc[cursor] || (acc[cursor] = [])).push(value);\n return acc;\n }, []);\n};\n/**\n * @returns index of target element, consindering tightly-bound elements\n * (currently non-linear elements bound to a container) as a one unit.\n * If no binding present, returns `undefined`.\n */\n\n\nconst getTargetIndexAccountingForBinding = (nextElement, elements, direction, scene) => {\n var _a, _b;\n\n if (\"containerId\" in nextElement && nextElement.containerId) {\n // TODO: why not to get the container from the nextElements?\n const containerElement = scene.getElement(nextElement.containerId);\n\n if (containerElement) {\n return direction === \"left\" ? Math.min(elements.indexOf(containerElement), elements.indexOf(nextElement)) : Math.max(elements.indexOf(containerElement), elements.indexOf(nextElement));\n }\n } else {\n const boundElementId = (_b = (_a = nextElement.boundElements) === null || _a === void 0 ? void 0 : _a.find(binding => binding.type !== \"arrow\")) === null || _b === void 0 ? void 0 : _b.id;\n\n if (boundElementId) {\n const boundTextElement = scene.getElement(boundElementId);\n\n if (boundTextElement) {\n return direction === \"left\" ? Math.min(elements.indexOf(boundTextElement), elements.indexOf(nextElement)) : Math.max(elements.indexOf(boundTextElement), elements.indexOf(nextElement));\n }\n }\n }\n};\n\nconst getContiguousFrameRangeElements = (allElements, frameId) => {\n let rangeStart = -1;\n let rangeEnd = -1;\n allElements.forEach((element, index) => {\n if (isOfTargetFrame(element, frameId)) {\n if (rangeStart === -1) {\n rangeStart = index;\n }\n\n rangeEnd = index;\n }\n });\n\n if (rangeStart === -1) {\n return [];\n }\n\n return allElements.slice(rangeStart, rangeEnd + 1);\n};\n/**\n * Moves the arrow element above any bindable elements it intersects with or\n * hovers over.\n */\n\n\nconst moveArrowAboveBindable = (point, arrow, elements, elementsMap, scene, hit) => {\n const hoveredElement = hit ? hit : (0,_collision__WEBPACK_IMPORTED_MODULE_7__.getHoveredElementForBinding)(point, elements, elementsMap);\n\n if (!hoveredElement) {\n return elements;\n }\n\n const boundTextElement = (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getBoundTextElement)(hoveredElement, elementsMap);\n const containerElement = (0,_typeChecks__WEBPACK_IMPORTED_MODULE_2__.isTextElement)(hoveredElement) ? (0,_textElement__WEBPACK_IMPORTED_MODULE_6__.getContainerElement)(hoveredElement, elementsMap) : null;\n const bindableIds = [hoveredElement.id, boundTextElement === null || boundTextElement === void 0 ? void 0 : boundTextElement.id, containerElement === null || containerElement === void 0 ? void 0 : containerElement.id].filter(id => !!id);\n const bindableIdx = elements.findIndex(el => bindableIds.includes(el.id));\n const arrowIdx = elements.findIndex(el => el.id === arrow.id);\n\n if (arrowIdx !== -1 && bindableIdx !== -1 && arrowIdx < bindableIdx) {\n const updatedElements = Array.from(elements);\n const arrow = updatedElements.splice(arrowIdx, 1)[0];\n updatedElements.splice(bindableIdx, 0, arrow);\n scene.replaceAllElements(updatedElements);\n }\n\n return elements;\n};\n/**\n * Returns next candidate index that's available to be moved to. Currently that\n * is a non-deleted element, and not inside a group (unless we're editing it).\n */\n\nconst getTargetIndex = (appState, elements, boundaryIndex, direction,\n/**\n * Frame id if moving frame children.\n * If whole frame (including all children) is being moved, supply `null`.\n */\ncontainingFrame, scene) => {\n var _a, _b;\n\n const sourceElement = elements[boundaryIndex];\n\n const indexFilter = element => {\n if (element.isDeleted) {\n return false;\n }\n\n if (containingFrame) {\n return element.frameId === containingFrame;\n } // if we're editing group, find closest sibling irrespective of whether\n // there's a different-group element between them (for legacy reasons)\n\n\n if (appState.editingGroupId) {\n return element.groupIds.includes(appState.editingGroupId);\n }\n\n return true;\n };\n\n const candidateIndex = direction === \"left\" ? (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findLastIndex)(elements, el => indexFilter(el), Math.max(0, boundaryIndex - 1)) : (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findIndex)(elements, el => indexFilter(el), boundaryIndex + 1);\n const nextElement = elements[candidateIndex];\n\n if (!nextElement) {\n return -1;\n }\n\n if (appState.editingGroupId) {\n if ( // candidate element is a sibling in current editing group β return\n (sourceElement === null || sourceElement === void 0 ? void 0 : sourceElement.groupIds.join(\"\")) === (nextElement === null || nextElement === void 0 ? void 0 : nextElement.groupIds.join(\"\"))) {\n return (_a = getTargetIndexAccountingForBinding(nextElement, elements, direction, scene)) !== null && _a !== void 0 ? _a : candidateIndex;\n } else if (!(nextElement === null || nextElement === void 0 ? void 0 : nextElement.groupIds.includes(appState.editingGroupId))) {\n // candidate element is outside current editing group β prevent\n return -1;\n }\n }\n\n if (!containingFrame && (nextElement.frameId || (0,_typeChecks__WEBPACK_IMPORTED_MODULE_2__.isFrameLikeElement)(nextElement))) {\n const frameElements = getContiguousFrameRangeElements(elements, nextElement.frameId || nextElement.id);\n return direction === \"left\" ? elements.indexOf(frameElements[0]) : elements.indexOf(frameElements[frameElements.length - 1]);\n }\n\n if (!nextElement.groupIds.length) {\n return (_b = getTargetIndexAccountingForBinding(nextElement, elements, direction, scene)) !== null && _b !== void 0 ? _b : candidateIndex;\n }\n\n const siblingGroupId = appState.editingGroupId ? nextElement.groupIds[nextElement.groupIds.indexOf(appState.editingGroupId) - 1] : nextElement.groupIds[nextElement.groupIds.length - 1];\n const elementsInSiblingGroup = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, siblingGroupId);\n\n if (elementsInSiblingGroup.length) {\n // assumes getElementsInGroup() returned elements are sorted\n // by zIndex (ascending)\n return direction === \"left\" ? elements.indexOf(elementsInSiblingGroup[0]) : elements.indexOf(elementsInSiblingGroup[elementsInSiblingGroup.length - 1]);\n }\n\n return candidateIndex;\n};\n\nconst getTargetElementsMap = (elements, indices) => {\n return indices.reduce((acc, index) => {\n const element = elements[index];\n acc.set(element.id, element);\n return acc;\n }, new Map());\n};\n\nconst hasSameElementIds = (prevElements, nextElements) => {\n if (prevElements.length !== nextElements.length) {\n console.error(\"z-index reordering failed: resulting array have different lengths\");\n return false;\n }\n\n const prevElementIdCounts = new Map();\n\n for (const element of prevElements) {\n prevElementIdCounts.set(element.id, (prevElementIdCounts.get(element.id) || 0) + 1);\n }\n\n for (const element of nextElements) {\n const count = prevElementIdCounts.get(element.id);\n\n if (!count) {\n console.error(\"z-index reordering failed: element id mismatch / duplicate ids\");\n return false;\n }\n\n prevElementIdCounts.set(element.id, count - 1);\n }\n\n return true;\n};\n\nconst shiftElementsByOne = (elements, appState, direction, scene) => {\n const originalElements = elements;\n const indicesToMove = getIndicesToMove(elements, appState);\n const targetElementsMap = getTargetElementsMap(elements, indicesToMove);\n let groupedIndices = toContiguousGroups(indicesToMove);\n\n if (direction === \"right\") {\n groupedIndices = groupedIndices.reverse();\n }\n\n const selectedFrames = new Set(indicesToMove.filter(idx => (0,_typeChecks__WEBPACK_IMPORTED_MODULE_2__.isFrameLikeElement)(elements[idx])).map(idx => elements[idx].id));\n groupedIndices.forEach((indices, i) => {\n var _a;\n\n const leadingIndex = indices[0];\n const trailingIndex = indices[indices.length - 1];\n const boundaryIndex = direction === \"left\" ? leadingIndex : trailingIndex;\n const containingFrame = indices.some(idx => {\n const el = elements[idx];\n return el.frameId && selectedFrames.has(el.frameId);\n }) ? null : (_a = elements[boundaryIndex]) === null || _a === void 0 ? void 0 : _a.frameId;\n const targetIndex = getTargetIndex(appState, elements, boundaryIndex, direction, containingFrame, scene);\n\n if (targetIndex === -1 || boundaryIndex === targetIndex) {\n return;\n }\n\n const leadingElements = direction === \"left\" ? elements.slice(0, targetIndex) : elements.slice(0, leadingIndex);\n const targetElements = elements.slice(leadingIndex, trailingIndex + 1);\n const displacedElements = direction === \"left\" ? elements.slice(targetIndex, leadingIndex) : elements.slice(trailingIndex + 1, targetIndex + 1);\n const trailingElements = direction === \"left\" ? elements.slice(trailingIndex + 1) : elements.slice(targetIndex + 1);\n elements = direction === \"left\" ? [...leadingElements, ...targetElements, ...displacedElements, ...trailingElements] : [...leadingElements, ...displacedElements, ...targetElements, ...trailingElements];\n });\n\n if (!hasSameElementIds(originalElements, elements)) {\n return originalElements;\n }\n\n (0,_fractionalIndex__WEBPACK_IMPORTED_MODULE_4__.syncMovedIndices)(elements, targetElementsMap);\n return elements;\n};\n\nconst shiftElementsToEnd = (elements, appState, direction, containingFrame, elementsToBeMoved) => {\n const indicesToMove = getIndicesToMove(elements, appState, elementsToBeMoved); // Nothing to move (e.g. `elementsToBeMoved` is empty because all selected\n // elements were frame children handled in a prior pass). Bail out early β\n // otherwise `leadingIndex`/`trailingIndex` below resolve to `undefined` and\n // the resulting `slice()` calls overlap, duplicating elements.\n\n if (indicesToMove.length === 0) {\n return elements;\n }\n\n const targetElementsMap = getTargetElementsMap(elements, indicesToMove);\n const displacedElements = [];\n let leadingIndex;\n let trailingIndex;\n\n if (direction === \"left\") {\n if (containingFrame) {\n leadingIndex = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findIndex)(elements, el => isOfTargetFrame(el, containingFrame));\n } else if (appState.editingGroupId) {\n const groupElements = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, appState.editingGroupId);\n\n if (!groupElements.length) {\n return elements;\n }\n\n leadingIndex = elements.indexOf(groupElements[0]);\n } else {\n leadingIndex = 0;\n }\n\n trailingIndex = indicesToMove[indicesToMove.length - 1];\n } else {\n if (containingFrame) {\n trailingIndex = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.findLastIndex)(elements, el => isOfTargetFrame(el, containingFrame));\n } else if (appState.editingGroupId) {\n const groupElements = (0,_groups__WEBPACK_IMPORTED_MODULE_3__.getElementsInGroup)(elements, appState.editingGroupId);\n\n if (!groupElements.length) {\n return elements;\n }\n\n trailingIndex = elements.indexOf(groupElements[groupElements.length - 1]);\n } else {\n trailingIndex = elements.length - 1;\n }\n\n leadingIndex = indicesToMove[0];\n }\n\n if (leadingIndex === -1) {\n leadingIndex = 0;\n }\n\n const isValidIndex = index => {\n return (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_1__.isFiniteNumber)(index) && index >= 0;\n };\n\n if (!isValidIndex(leadingIndex) || !isValidIndex(trailingIndex) || leadingIndex > trailingIndex || indicesToMove.some(index => index < leadingIndex || index > trailingIndex)) {\n return elements;\n }\n\n for (let index = leadingIndex; index < trailingIndex + 1; index++) {\n if (!indicesToMove.includes(index)) {\n displacedElements.push(elements[index]);\n }\n }\n\n const targetElements = Array.from(targetElementsMap.values());\n const leadingElements = elements.slice(0, leadingIndex);\n const trailingElements = elements.slice(trailingIndex + 1);\n const nextElements = direction === \"left\" ? [...leadingElements, ...targetElements, ...displacedElements, ...trailingElements] : [...leadingElements, ...displacedElements, ...targetElements, ...trailingElements];\n\n if (!hasSameElementIds(elements, nextElements)) {\n return elements;\n }\n\n (0,_fractionalIndex__WEBPACK_IMPORTED_MODULE_4__.syncMovedIndices)(nextElements, targetElementsMap);\n return nextElements;\n};\n\nfunction shiftElementsAccountingForFrames(allElements, appState, direction, shiftFunction) {\n const elementsToMove = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.arrayToMap)((0,_selection__WEBPACK_IMPORTED_MODULE_5__.getSelectedElements)(allElements, appState, {\n includeBoundTextElement: true,\n includeElementsInFrames: true\n }));\n const frameAwareContiguousElementsToMove = {\n regularElements: [],\n frameChildren: new Map()\n };\n const fullySelectedFrames = new Set();\n\n for (const element of allElements) {\n if (elementsToMove.has(element.id) && (0,_typeChecks__WEBPACK_IMPORTED_MODULE_2__.isFrameLikeElement)(element)) {\n fullySelectedFrames.add(element.id);\n }\n }\n\n for (const element of allElements) {\n if (elementsToMove.has(element.id)) {\n if ((0,_typeChecks__WEBPACK_IMPORTED_MODULE_2__.isFrameLikeElement)(element) || element.frameId && fullySelectedFrames.has(element.frameId)) {\n frameAwareContiguousElementsToMove.regularElements.push(element);\n } else if (!element.frameId) {\n frameAwareContiguousElementsToMove.regularElements.push(element);\n } else {\n const frameChildren = frameAwareContiguousElementsToMove.frameChildren.get(element.frameId) || [];\n frameChildren.push(element);\n frameAwareContiguousElementsToMove.frameChildren.set(element.frameId, frameChildren);\n }\n }\n }\n\n let nextElements = allElements;\n const frameChildrenSets = Array.from(frameAwareContiguousElementsToMove.frameChildren.entries());\n\n for (const [frameId, children] of frameChildrenSets) {\n nextElements = shiftFunction(nextElements, appState, direction, frameId, children);\n }\n\n return shiftFunction(nextElements, appState, direction, null, frameAwareContiguousElementsToMove.regularElements);\n} // public API\n// -----------------------------------------------------------------------------\n\n\nconst moveOneLeft = (allElements, appState, scene) => {\n return shiftElementsByOne(allElements, appState, \"left\", scene);\n};\nconst moveOneRight = (allElements, appState, scene) => {\n return shiftElementsByOne(allElements, appState, \"right\", scene);\n};\nconst moveAllLeft = (allElements, appState) => {\n return shiftElementsAccountingForFrames(allElements, appState, \"left\", shiftElementsToEnd);\n};\nconst moveAllRight = (allElements, appState) => {\n return shiftElementsAccountingForFrames(allElements, appState, \"right\", shiftElementsToEnd);\n};\n\n//# sourceURL=webpack://ExcalidrawLib/../element/src/zindex.ts?\n}");
|
|
895
895
|
|
|
896
896
|
/***/ },
|
|
897
897
|
|
|
@@ -1573,7 +1573,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
1573
1573
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
1574
1574
|
|
|
1575
1575
|
"use strict";
|
|
1576
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ trackEvent: () => (/* binding */ trackEvent)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n// place here categories that you want to track. We want to track just a\n // small subset of categories at a given time.\n\nconst ALLOWED_CATEGORIES_TO_TRACK = new Set([\"command_palette\", \"export\"]);\nconst trackEvent = (category, action, label, value) => {\n try {\n if (typeof window === \"undefined\" || ({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.
|
|
1576
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ trackEvent: () => (/* binding */ trackEvent)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n// place here categories that you want to track. We want to track just a\n // small subset of categories at a given time.\n\nconst ALLOWED_CATEGORIES_TO_TRACK = new Set([\"command_palette\", \"export\"]);\nconst trackEvent = (category, action, label, value) => {\n try {\n if (typeof window === \"undefined\" || ({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.1\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).VITE_WORKER_ID || \"true\" !== \"true\") {\n return;\n }\n\n if (!ALLOWED_CATEGORIES_TO_TRACK.has(category)) {\n return;\n }\n\n if ((0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.isDevEnv)()) {\n // comment out to debug in dev\n return;\n }\n\n if (true) {\n console.info(\"trackEvent\", {\n category,\n action,\n label,\n value\n });\n }\n\n if (window.sa_event) {\n window.sa_event(action, {\n category,\n label,\n value\n });\n }\n } catch (error) {\n console.error(\"error during analytics\", error);\n }\n};\n\n//# sourceURL=webpack://ExcalidrawLib/./analytics.ts?\n}");
|
|
1577
1577
|
|
|
1578
1578
|
/***/ },
|
|
1579
1579
|
|
|
@@ -1991,7 +1991,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
1991
1991
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
1992
1992
|
|
|
1993
1993
|
"use strict";
|
|
1994
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ adjustBoundTextSize: () => (/* binding */ adjustBoundTextSize),\n/* harmony export */ convertElementTypePopupAtom: () => (/* binding */ convertElementTypePopupAtom),\n/* harmony export */ convertElementTypes: () => (/* binding */ convertElementTypes),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ getConversionTypeFromElements: () => (/* binding */ getConversionTypeFromElements)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @excalidraw/element */ \"../element/src/index.ts\");\n/* harmony import */ var _excalidraw_math__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @excalidraw/math */ \"../math/src/index.ts\");\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _analytics__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../analytics */ \"./analytics.ts\");\n/* harmony import */ var _editor_jotai__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../editor-jotai */ \"./editor-jotai.ts\");\n/* harmony import */ var _ConvertElementTypePopup_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./ConvertElementTypePopup.scss */ \"./components/ConvertElementTypePopup.scss\");\n/* harmony import */ var _ToolButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./ToolButton */ \"./components/ToolButton.tsx\");\n/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./icons */ \"./components/icons.tsx\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst GAP_HORIZONTAL = 8;\nconst GAP_VERTICAL = 10; // indicates order of switching\n\nconst GENERIC_TYPES = [\"rectangle\", \"diamond\", \"ellipse\"]; // indicates order of switching\n\nconst LINEAR_TYPES = [\"line\", \"sharpArrow\", \"curvedArrow\", \"elbowArrow\"];\nconst CONVERTIBLE_GENERIC_TYPES = new Set(GENERIC_TYPES);\nconst CONVERTIBLE_LINEAR_TYPES = new Set(LINEAR_TYPES);\n\nconst isConvertibleGenericType = elementType => CONVERTIBLE_GENERIC_TYPES.has(elementType);\n\nconst isConvertibleLinearType = elementType => elementType === \"arrow\" || CONVERTIBLE_LINEAR_TYPES.has(elementType);\n\nconst convertElementTypePopupAtom = (0,_editor_jotai__WEBPACK_IMPORTED_MODULE_5__.atom)(null);\nconst FONT_SIZE_CONVERSION_CACHE = new Map();\nconst LINEAR_ELEMENT_CONVERSION_CACHE = new Map();\n\nconst ConvertElementTypePopup = ({\n app\n}) => {\n const selectedElements = app.scene.getSelectedElements(app.state);\n const elementsCategoryRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); // close shape switch panel if selecting different \"types\" of elements\n\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n if (selectedElements.length === 0) {\n app.updateEditorAtom(convertElementTypePopupAtom, null);\n return;\n }\n\n const conversionType = getConversionTypeFromElements(selectedElements);\n\n if (conversionType && !elementsCategoryRef.current) {\n elementsCategoryRef.current = conversionType;\n } else if (elementsCategoryRef.current && !conversionType || elementsCategoryRef.current && conversionType !== elementsCategoryRef.current) {\n app.updateEditorAtom(convertElementTypePopupAtom, null);\n elementsCategoryRef.current = null;\n }\n }, [selectedElements, app]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n return () => {\n FONT_SIZE_CONVERSION_CACHE.clear();\n LINEAR_ELEMENT_CONVERSION_CACHE.clear();\n };\n }, []);\n return React.createElement(Panel, {\n app: app,\n elements: selectedElements\n });\n};\n\nconst Panel = ({\n app,\n elements\n}) => {\n const conversionType = getConversionTypeFromElements(elements);\n const genericElements = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => {\n return conversionType === \"generic\" ? filterGenericConvetibleElements(elements) : [];\n }, [conversionType, elements]);\n const linearElements = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => {\n return conversionType === \"linear\" ? filterLinearConvertibleElements(elements) : [];\n }, [conversionType, elements]);\n const sameType = conversionType === \"generic\" ? genericElements.every(element => element.type === genericElements[0].type) : conversionType === \"linear\" ? linearElements.every(element => (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(element) === (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(linearElements[0])) : false;\n const [panelPosition, setPanelPosition] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({\n x: 0,\n y: 0\n });\n const positionRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(\"\");\n const panelRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n const elements = [...genericElements, ...linearElements].sort((a, b) => a.id.localeCompare(b.id));\n const newPositionRef = `\n ${app.state.scrollX}${app.state.scrollY}${app.state.offsetTop}${app.state.offsetLeft}${app.state.zoom.value}${elements.map(el => el.id).join(\",\")}`;\n\n if (newPositionRef === positionRef.current) {\n return;\n }\n\n positionRef.current = newPositionRef;\n let bottomLeft;\n\n if (elements.length === 1) {\n const [x1,,, y2, cx, cy] = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getElementAbsoluteCoords)(elements[0], app.scene.getNonDeletedElementsMap());\n bottomLeft = (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointRotateRads)((0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(x1, y2), (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(cx, cy), elements[0].angle);\n } else {\n const {\n minX,\n maxY\n } = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getCommonBoundingBox)(elements);\n bottomLeft = (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(minX, maxY);\n }\n\n const {\n x,\n y\n } = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.sceneCoordsToViewportCoords)({\n sceneX: bottomLeft[0],\n sceneY: bottomLeft[1]\n }, app.state);\n setPanelPosition({\n x,\n y\n });\n }, [genericElements, linearElements, app.scene, app.state]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n for (const linearElement of linearElements) {\n const cacheKey = toCacheKey(linearElement.id, getConvertibleType(linearElement));\n\n if (!LINEAR_ELEMENT_CONVERSION_CACHE.has(cacheKey)) {\n LINEAR_ELEMENT_CONVERSION_CACHE.set(cacheKey, linearElement);\n }\n }\n }, [linearElements]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n for (const element of genericElements) {\n if (!FONT_SIZE_CONVERSION_CACHE.has(element.id)) {\n const boundText = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextElement)(element, app.scene.getNonDeletedElementsMap());\n\n if (boundText) {\n FONT_SIZE_CONVERSION_CACHE.set(element.id, {\n fontSize: boundText.fontSize\n });\n }\n }\n }\n }, [genericElements, app.scene]);\n const SHAPES = conversionType === \"linear\" ? [[\"line\", _icons__WEBPACK_IMPORTED_MODULE_8__.LineIcon], [\"sharpArrow\", _icons__WEBPACK_IMPORTED_MODULE_8__.sharpArrowIcon], [\"curvedArrow\", _icons__WEBPACK_IMPORTED_MODULE_8__.roundArrowIcon], [\"elbowArrow\", _icons__WEBPACK_IMPORTED_MODULE_8__.elbowArrowIcon]] : conversionType === \"generic\" ? [[\"rectangle\", _icons__WEBPACK_IMPORTED_MODULE_8__.RectangleIcon], [\"diamond\", _icons__WEBPACK_IMPORTED_MODULE_8__.DiamondIcon], [\"ellipse\", _icons__WEBPACK_IMPORTED_MODULE_8__.EllipseIcon]] : [];\n return React.createElement(\"div\", {\n ref: panelRef,\n tabIndex: -1,\n style: {\n position: \"absolute\",\n top: `${panelPosition.y + (GAP_VERTICAL + 8) * app.state.zoom.value - app.state.offsetTop}px`,\n left: `${panelPosition.x - app.state.offsetLeft - GAP_HORIZONTAL}px`,\n zIndex: 2\n },\n className: _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.CLASSES.CONVERT_ELEMENT_TYPE_POPUP\n }, SHAPES.map(([type, icon]) => {\n const isSelected = sameType && (conversionType === \"generic\" && genericElements[0].type === type || conversionType === \"linear\" && (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(linearElements[0]) === type);\n return React.createElement(_ToolButton__WEBPACK_IMPORTED_MODULE_7__.ToolButton, {\n className: \"Shape\",\n key: `${elements[0].id}${elements[0].version}_${type}`,\n type: \"radio\",\n icon: icon,\n checked: isSelected,\n name: \"convertElementType-option\",\n title: type,\n keyBindingLabel: \"\",\n \"aria-label\": type,\n \"data-testid\": `toolbar-${type}`,\n onChange: () => {\n var _a;\n\n if (app.state.activeTool.type !== type) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_4__.trackEvent)(\"convertElementType\", type, \"ui\");\n }\n\n convertElementTypes(app, {\n conversionType,\n nextType: type\n });\n (_a = panelRef.current) === null || _a === void 0 ? void 0 : _a.focus();\n }\n });\n }));\n};\n\nconst adjustBoundTextSize = (container, boundText, scene) => {\n const maxWidth = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextMaxWidth)(container, boundText);\n const maxHeight = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextMaxHeight)(container, boundText);\n const wrappedText = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.wrapText)(boundText.text, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.getFontString)(boundText), maxWidth);\n let metrics = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.measureText)(wrappedText, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.getFontString)(boundText), boundText.lineHeight);\n let nextFontSize = boundText.fontSize;\n\n while ((metrics.width > maxWidth || metrics.height > maxHeight) && nextFontSize > 0) {\n nextFontSize -= 1;\n\n const _updatedTextElement = Object.assign(Object.assign({}, boundText), {\n fontSize: nextFontSize\n });\n\n metrics = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.measureText)(boundText.text, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.getFontString)(_updatedTextElement), boundText.lineHeight);\n }\n\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.mutateElement)(boundText, scene.getNonDeletedElementsMap(), {\n fontSize: nextFontSize,\n width: metrics.width,\n height: metrics.height\n });\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.redrawTextBoundingBox)(boundText, container, scene);\n};\nconst convertElementTypes = (app, {\n conversionType,\n nextType,\n direction = \"right\"\n}) => {\n var _a, _b;\n\n if (!conversionType) {\n return false;\n }\n\n const selectedElements = app.scene.getSelectedElements(app.state);\n const selectedElementIds = selectedElements.reduce((acc, element) => Object.assign(Object.assign({}, acc), {\n [element.id]: true\n }), {});\n const advancement = direction === \"right\" ? 1 : -1;\n\n if (conversionType === \"generic\") {\n const convertibleGenericElements = filterGenericConvetibleElements(selectedElements);\n const sameType = convertibleGenericElements.every(element => element.type === convertibleGenericElements[0].type);\n const index = sameType ? GENERIC_TYPES.indexOf(convertibleGenericElements[0].type) : -1;\n nextType = nextType !== null && nextType !== void 0 ? nextType : GENERIC_TYPES[(index + GENERIC_TYPES.length + advancement) % GENERIC_TYPES.length];\n\n if (nextType && isConvertibleGenericType(nextType)) {\n const convertedElements = {};\n\n for (const element of convertibleGenericElements) {\n const convertedElement = convertElementType(element, nextType, app);\n convertedElements[convertedElement.id] = convertedElement;\n }\n\n const nextElements = [];\n\n for (const element of app.scene.getElementsIncludingDeleted()) {\n if (convertedElements[element.id]) {\n nextElements.push(convertedElements[element.id]);\n } else {\n nextElements.push(element);\n }\n }\n\n app.scene.replaceAllElements(nextElements);\n\n for (const element of Object.values(convertedElements)) {\n const boundText = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextElement)(element, app.scene.getNonDeletedElementsMap());\n\n if (boundText) {\n if (FONT_SIZE_CONVERSION_CACHE.get(element.id)) {\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.mutateElement)(boundText, app.scene.getNonDeletedElementsMap(), {\n fontSize: (_b = (_a = FONT_SIZE_CONVERSION_CACHE.get(element.id)) === null || _a === void 0 ? void 0 : _a.fontSize) !== null && _b !== void 0 ? _b : boundText.fontSize\n });\n }\n\n adjustBoundTextSize(element, boundText, app.scene);\n }\n }\n\n app.setState(prevState => {\n return {\n selectedElementIds,\n activeTool: (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(prevState, {\n type: \"selection\"\n })\n };\n });\n }\n }\n\n if (conversionType === \"linear\") {\n const convertibleLinearElements = filterLinearConvertibleElements(selectedElements);\n\n if (!nextType) {\n const commonSubType = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.reduceToCommonValue)(convertibleLinearElements, _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType);\n const index = commonSubType ? LINEAR_TYPES.indexOf(commonSubType) : -1;\n nextType = LINEAR_TYPES[(index + LINEAR_TYPES.length + advancement) % LINEAR_TYPES.length];\n }\n\n if (isConvertibleLinearType(nextType)) {\n const convertedElements = [];\n const nextElementsMap = app.scene.getElementsMapIncludingDeleted();\n\n for (const element of convertibleLinearElements) {\n const cachedElement = LINEAR_ELEMENT_CONVERSION_CACHE.get(toCacheKey(element.id, nextType)); // if switching to the original subType or a subType we've already\n // converted to, reuse the cached element to get the original properties\n // (needed for simple->elbow->simple conversions or between line\n // and arrows)\n\n if (cachedElement && (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(cachedElement) === nextType) {\n nextElementsMap.set(cachedElement.id, cachedElement);\n convertedElements.push(cachedElement);\n } else {\n const converted = convertElementType(element, nextType, app);\n nextElementsMap.set(converted.id, converted);\n convertedElements.push(converted);\n }\n }\n\n app.scene.replaceAllElements(nextElementsMap); // post normalization\n\n for (const element of convertedElements) {\n if ((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isLinearElement)(element)) {\n if ((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isElbowArrow)(element)) {\n const nextPoints = convertLineToElbow(element);\n\n if (nextPoints.length < 2) {\n // skip if not enough points to form valid segments\n continue;\n }\n\n const fixedSegments = [];\n\n for (let i = 1; i < nextPoints.length - 2; i++) {\n fixedSegments.push({\n start: nextPoints[i],\n end: nextPoints[i + 1],\n index: i + 1\n });\n }\n\n const updates = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.updateElbowArrowPoints)(element, app.scene.getNonDeletedElementsMap(), {\n points: nextPoints,\n fixedSegments\n });\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.mutateElement)(element, app.scene.getNonDeletedElementsMap(), Object.assign(Object.assign({}, updates), {\n endArrowhead: \"arrow\"\n }));\n } else {\n // if we're converting to non-elbow linear element, check if\n // we've already cached one of these linear elements so we can\n // reuse the points (case: curved->elbow->line and similar)\n const similarCachedLinearElement = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.mapFind)([\"line\", \"sharpArrow\", \"curvedArrow\"], type => LINEAR_ELEMENT_CONVERSION_CACHE.get(toCacheKey(element.id, type)));\n\n if (similarCachedLinearElement) {\n const points = similarCachedLinearElement.points;\n app.scene.mutateElement(element, {\n points\n });\n }\n }\n }\n }\n }\n\n const convertedSelectedLinearElements = filterLinearConvertibleElements(app.scene.getSelectedElements(app.state));\n app.setState(prevState => ({\n selectedElementIds,\n selectedLinearElement: convertedSelectedLinearElements.length === 1 ? new _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.LinearElementEditor(convertedSelectedLinearElements[0], app.scene.getNonDeletedElementsMap()) : null,\n activeTool: (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(prevState, {\n type: \"selection\"\n })\n }));\n }\n\n return true;\n};\nconst getConversionTypeFromElements = elements => {\n if (elements.length === 0) {\n return null;\n }\n\n let canBeLinear = false;\n\n for (const element of elements) {\n if (isConvertibleGenericType(element.type)) {\n // generic type conversion have preference\n return \"generic\";\n }\n\n if (isEligibleLinearElement(element)) {\n canBeLinear = true;\n }\n }\n\n if (canBeLinear) {\n return \"linear\";\n }\n\n return null;\n};\n\nconst isEligibleLinearElement = element => {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isLinearElement)(element) && (!(0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isArrowElement)(element) || !(0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isArrowBoundToElement)(element) && !(0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.hasBoundTextElement)(element));\n};\n\nconst toCacheKey = (elementId, convertitleType) => {\n return `${elementId}:${convertitleType}`;\n};\n\nconst filterGenericConvetibleElements = elements => elements.filter(element => isConvertibleGenericType(element.type));\n\nconst filterLinearConvertibleElements = elements => elements.filter(element => isEligibleLinearElement(element));\n\nconst THRESHOLD = 20;\n\nconst isVert = (a, b) => a[0] === b[0];\n\nconst isHorz = (a, b) => a[1] === b[1];\n\nconst dist = (a, b) => isVert(a, b) ? Math.abs(a[1] - b[1]) : Math.abs(a[0] - b[0]);\n\nconst convertLineToElbow = line => {\n // 1. build an *orthogonal* route, snapping offsets < SNAP\n const ortho = [line.points[0]];\n const src = sanitizePoints(line.points);\n\n for (let i = 1; i < src.length; ++i) {\n const start = ortho[ortho.length - 1];\n const end = [...src[i]]; // clone\n // snap tiny offsets onto the current axis\n\n if (Math.abs(end[0] - start[0]) < THRESHOLD) {\n end[0] = start[0];\n } else if (Math.abs(end[1] - start[1]) < THRESHOLD) {\n end[1] = start[1];\n } // straight or needs a 90 Β° bend?\n\n\n if (isVert(start, end) || isHorz(start, end)) {\n ortho.push(end);\n } else {\n ortho.push((0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(start[0], end[1]));\n ortho.push(end);\n }\n } // 2. drop obviously colinear middle points\n\n\n const trimmed = [ortho[0]];\n\n for (let i = 1; i < ortho.length - 1; ++i) {\n if (!(isVert(ortho[i - 1], ortho[i]) && isVert(ortho[i], ortho[i + 1]) || isHorz(ortho[i - 1], ortho[i]) && isHorz(ortho[i], ortho[i + 1]))) {\n trimmed.push(ortho[i]);\n }\n }\n\n trimmed.push(ortho[ortho.length - 1]); // 3. collapse micro βjogsβ (V-H-V / H-V-H whose short leg < SNAP)\n\n const clean = [trimmed[0]];\n\n for (let i = 1; i < trimmed.length - 1; ++i) {\n const a = clean[clean.length - 1];\n const b = trimmed[i];\n const c = trimmed[i + 1];\n const v1 = isVert(a, b);\n const v2 = isVert(b, c);\n\n if (v1 !== v2) {\n const d1 = dist(a, b);\n const d2 = dist(b, c);\n\n if (d1 < THRESHOLD || d2 < THRESHOLD) {\n // pick the shorter leg to remove\n if (d2 < d1) {\n // β¦ absorb leg 2 β pull *c* onto axis of *a-b*\n if (v1) {\n c[0] = a[0];\n } else {\n c[1] = a[1];\n }\n } else {\n // β¦ absorb leg 1 β slide the whole first leg onto *b-c* axis\n // eslint-disable-next-line no-lonely-if\n if (v2) {\n for (let k = clean.length - 1; k >= 0 && clean[k][0] === a[0]; --k) {\n clean[k][0] = b[0];\n }\n } else {\n for (let k = clean.length - 1; k >= 0 && clean[k][1] === a[1]; --k) {\n clean[k][1] = b[1];\n }\n }\n } // *b* is gone, donβt add it\n\n\n continue;\n }\n }\n\n clean.push(b);\n }\n\n clean.push(trimmed[trimmed.length - 1]);\n return clean;\n};\n\nconst sanitizePoints = points => {\n if (points.length === 0) {\n return [];\n }\n\n const sanitized = [points[0]];\n\n for (let i = 1; i < points.length; i++) {\n const [x1, y1] = sanitized[sanitized.length - 1];\n const [x2, y2] = points[i];\n\n if (x1 !== x2 || y1 !== y2) {\n sanitized.push(points[i]);\n }\n }\n\n return sanitized;\n};\n/**\n * Converts an element to a new type, adding or removing properties as needed\n * so that the element object is always valid.\n *\n * Valid conversions at this point:\n * - switching between generic elements\n * e.g. rectangle -> diamond\n * - switching between linear elements\n * e.g. elbow arrow -> line\n */\n\n\nconst convertElementType = (element, targetType, app) => {\n if (!isValidConversion(element.type, targetType)) {\n if (!(0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.isProdEnv)()) {\n throw Error(`Invalid conversion from ${element.type} to ${targetType}.`);\n }\n\n return element;\n }\n\n if (element.type === targetType) {\n return element;\n }\n\n _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.ShapeCache.delete(element);\n\n if (isConvertibleGenericType(targetType)) {\n const nextElement = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newElement)(Object.assign(Object.assign({}, element), {\n type: targetType,\n roundness: targetType === \"diamond\" && element.roundness ? {\n type: (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isUsingAdaptiveRadius)(targetType) ? _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.ROUNDNESS.ADAPTIVE_RADIUS : _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : element.roundness\n })));\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.updateBindings)(nextElement, app.scene, app.state);\n return nextElement;\n }\n\n if (isConvertibleLinearType(targetType)) {\n switch (targetType) {\n case \"line\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newLinearElement)(Object.assign(Object.assign({}, element), {\n type: \"line\"\n })));\n }\n\n case \"sharpArrow\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newArrowElement)(Object.assign(Object.assign({}, element), {\n type: \"arrow\",\n elbowed: false,\n roundness: null,\n startArrowhead: app.state.currentItemStartArrowhead,\n endArrowhead: app.state.currentItemEndArrowhead\n })));\n }\n\n case \"curvedArrow\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newArrowElement)(Object.assign(Object.assign({}, element), {\n type: \"arrow\",\n elbowed: false,\n roundness: {\n type: _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.ROUNDNESS.PROPORTIONAL_RADIUS\n },\n startArrowhead: app.state.currentItemStartArrowhead,\n endArrowhead: app.state.currentItemEndArrowhead\n })));\n }\n\n case \"elbowArrow\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newArrowElement)(Object.assign(Object.assign({}, element), {\n type: \"arrow\",\n elbowed: true,\n fixedSegments: null,\n roundness: null\n })));\n }\n }\n }\n\n (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.assertNever)(targetType, `unhandled conversion type: ${targetType}`);\n return element;\n};\n\nconst isValidConversion = (startType, targetType) => {\n if (isConvertibleGenericType(startType) && isConvertibleGenericType(targetType)) {\n return true;\n }\n\n if (isConvertibleLinearType(startType) && isConvertibleLinearType(targetType)) {\n return true;\n } // NOTE: add more conversions when needed\n\n\n return false;\n};\n\nconst getConvertibleType = element => {\n if ((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isLinearElement)(element)) {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(element);\n }\n\n return element.type;\n};\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ConvertElementTypePopup);\n\n//# sourceURL=webpack://ExcalidrawLib/./components/ConvertElementTypePopup.tsx?\n}");
|
|
1994
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ adjustBoundTextSize: () => (/* binding */ adjustBoundTextSize),\n/* harmony export */ convertElementTypePopupAtom: () => (/* binding */ convertElementTypePopupAtom),\n/* harmony export */ convertElementTypes: () => (/* binding */ convertElementTypes),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ getConversionTypeFromElements: () => (/* binding */ getConversionTypeFromElements)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @excalidraw/element */ \"../element/src/index.ts\");\n/* harmony import */ var _excalidraw_math__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @excalidraw/math */ \"../math/src/index.ts\");\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _analytics__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../analytics */ \"./analytics.ts\");\n/* harmony import */ var _editor_jotai__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../editor-jotai */ \"./editor-jotai.ts\");\n/* harmony import */ var _ConvertElementTypePopup_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./ConvertElementTypePopup.scss */ \"./components/ConvertElementTypePopup.scss\");\n/* harmony import */ var _ToolButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./ToolButton */ \"./components/ToolButton.tsx\");\n/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./icons */ \"./components/icons.tsx\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst GAP_HORIZONTAL = 8;\nconst GAP_VERTICAL = 10; // indicates order of switching\n\nconst GENERIC_TYPES = [\"rectangle\", \"diamond\", \"ellipse\"]; // indicates order of switching\n\nconst LINEAR_TYPES = [\"line\", \"sharpArrow\", \"curvedArrow\", \"elbowArrow\"];\nconst CONVERTIBLE_GENERIC_TYPES = new Set(GENERIC_TYPES);\nconst CONVERTIBLE_LINEAR_TYPES = new Set(LINEAR_TYPES);\n\nconst isConvertibleGenericType = elementType => CONVERTIBLE_GENERIC_TYPES.has(elementType);\n\nconst isConvertibleLinearType = elementType => elementType === \"arrow\" || CONVERTIBLE_LINEAR_TYPES.has(elementType);\n\nconst convertElementTypePopupAtom = (0,_editor_jotai__WEBPACK_IMPORTED_MODULE_5__.atom)(null);\nconst FONT_SIZE_CONVERSION_CACHE = new Map();\nconst LINEAR_ELEMENT_CONVERSION_CACHE = new Map();\n\nconst ConvertElementTypePopup = ({\n app\n}) => {\n const selectedElements = app.scene.getSelectedElements(app.state);\n const elementsCategoryRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); // close shape switch panel if selecting different \"types\" of elements\n\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n if (selectedElements.length === 0) {\n app.updateEditorAtom(convertElementTypePopupAtom, null);\n return;\n }\n\n const conversionType = getConversionTypeFromElements(selectedElements);\n\n if (conversionType && !elementsCategoryRef.current) {\n elementsCategoryRef.current = conversionType;\n } else if (elementsCategoryRef.current && !conversionType || elementsCategoryRef.current && conversionType !== elementsCategoryRef.current) {\n app.updateEditorAtom(convertElementTypePopupAtom, null);\n elementsCategoryRef.current = null;\n }\n }, [selectedElements, app]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n return () => {\n FONT_SIZE_CONVERSION_CACHE.clear();\n LINEAR_ELEMENT_CONVERSION_CACHE.clear();\n };\n }, []);\n return React.createElement(Panel, {\n app: app,\n elements: selectedElements\n });\n};\n\nconst Panel = ({\n app,\n elements\n}) => {\n const conversionType = getConversionTypeFromElements(elements);\n const genericElements = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => {\n return conversionType === \"generic\" ? filterGenericConvetibleElements(elements) : [];\n }, [conversionType, elements]);\n const linearElements = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => {\n return conversionType === \"linear\" ? filterLinearConvertibleElements(elements) : [];\n }, [conversionType, elements]);\n const sameType = conversionType === \"generic\" ? genericElements.every(element => element.type === genericElements[0].type) : conversionType === \"linear\" ? linearElements.every(element => (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(element) === (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(linearElements[0])) : false;\n const [panelPosition, setPanelPosition] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({\n x: 0,\n y: 0\n });\n const positionRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(\"\");\n const panelRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n const elements = [...genericElements, ...linearElements].sort((a, b) => a.id.localeCompare(b.id));\n const newPositionRef = `\n ${app.state.scrollX}${app.state.scrollY}${app.state.offsetTop}${app.state.offsetLeft}${app.state.zoom.value}${elements.map(el => el.id).join(\",\")}`;\n\n if (newPositionRef === positionRef.current) {\n return;\n }\n\n positionRef.current = newPositionRef;\n let bottomLeft;\n\n if (elements.length === 1) {\n const [x1,,, y2, cx, cy] = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getElementAbsoluteCoords)(elements[0], app.scene.getNonDeletedElementsMap());\n bottomLeft = (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointRotateRads)((0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(x1, y2), (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(cx, cy), elements[0].angle);\n } else {\n const {\n minX,\n maxY\n } = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getCommonBoundingBox)(elements);\n bottomLeft = (0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(minX, maxY);\n }\n\n const {\n x,\n y\n } = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.sceneCoordsToViewportCoords)({\n sceneX: bottomLeft[0],\n sceneY: bottomLeft[1]\n }, app.state);\n setPanelPosition({\n x,\n y\n });\n }, [genericElements, linearElements, app.scene, app.state]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n for (const linearElement of linearElements) {\n const cacheKey = toCacheKey(linearElement.id, getConvertibleType(linearElement));\n\n if (!LINEAR_ELEMENT_CONVERSION_CACHE.has(cacheKey)) {\n LINEAR_ELEMENT_CONVERSION_CACHE.set(cacheKey, linearElement);\n }\n }\n }, [linearElements]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n for (const element of genericElements) {\n if (!FONT_SIZE_CONVERSION_CACHE.has(element.id)) {\n const boundText = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextElement)(element, app.scene.getNonDeletedElementsMap());\n\n if (boundText) {\n FONT_SIZE_CONVERSION_CACHE.set(element.id, {\n fontSize: boundText.fontSize\n });\n }\n }\n }\n }, [genericElements, app.scene]);\n const SHAPES = conversionType === \"linear\" ? [[\"line\", _icons__WEBPACK_IMPORTED_MODULE_8__.LineIcon], [\"sharpArrow\", _icons__WEBPACK_IMPORTED_MODULE_8__.sharpArrowIcon], [\"curvedArrow\", _icons__WEBPACK_IMPORTED_MODULE_8__.roundArrowIcon], [\"elbowArrow\", _icons__WEBPACK_IMPORTED_MODULE_8__.elbowArrowIcon]] : conversionType === \"generic\" ? [[\"rectangle\", _icons__WEBPACK_IMPORTED_MODULE_8__.RectangleIcon], [\"diamond\", _icons__WEBPACK_IMPORTED_MODULE_8__.DiamondIcon], [\"ellipse\", _icons__WEBPACK_IMPORTED_MODULE_8__.EllipseIcon]] : [];\n return React.createElement(\"div\", {\n ref: panelRef,\n tabIndex: -1,\n style: {\n position: \"absolute\",\n top: `${panelPosition.y + (GAP_VERTICAL + 8) * app.state.zoom.value - app.state.offsetTop}px`,\n left: `${panelPosition.x - app.state.offsetLeft - GAP_HORIZONTAL}px`,\n zIndex: 2\n },\n className: _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.CLASSES.CONVERT_ELEMENT_TYPE_POPUP\n }, SHAPES.map(([type, icon]) => {\n const isSelected = sameType && (conversionType === \"generic\" && genericElements[0].type === type || conversionType === \"linear\" && (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(linearElements[0]) === type);\n return React.createElement(_ToolButton__WEBPACK_IMPORTED_MODULE_7__.ToolButton, {\n className: \"Shape\",\n key: `${elements[0].id}${elements[0].version}_${type}`,\n type: \"radio\",\n icon: icon,\n checked: isSelected,\n name: \"convertElementType-option\",\n title: type,\n keyBindingLabel: \"\",\n \"aria-label\": type,\n \"data-testid\": `toolbar-${type}`,\n onChange: () => {\n var _a;\n\n if (app.state.activeTool.type !== type) {\n (0,_analytics__WEBPACK_IMPORTED_MODULE_4__.trackEvent)(\"convertElementType\", type, \"ui\");\n }\n\n convertElementTypes(app, {\n conversionType,\n nextType: type\n });\n (_a = panelRef.current) === null || _a === void 0 ? void 0 : _a.focus();\n }\n });\n }));\n};\n\nconst adjustBoundTextSize = (container, boundText, scene) => {\n const maxWidth = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextMaxWidth)(container, boundText);\n const maxHeight = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextMaxHeight)(container, boundText);\n const wrappedText = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.wrapText)(boundText.text, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.getFontString)(boundText), maxWidth);\n let metrics = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.measureText)(wrappedText, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.getFontString)(boundText), boundText.lineHeight);\n let nextFontSize = boundText.fontSize;\n\n while ((metrics.width > maxWidth || metrics.height > maxHeight) && nextFontSize > 0) {\n nextFontSize -= 1;\n\n const _updatedTextElement = Object.assign(Object.assign({}, boundText), {\n fontSize: nextFontSize\n });\n\n metrics = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.measureText)(boundText.text, (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.getFontString)(_updatedTextElement), boundText.lineHeight);\n }\n\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.mutateElement)(boundText, scene.getNonDeletedElementsMap(), {\n fontSize: nextFontSize,\n width: metrics.width,\n height: metrics.height\n });\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.redrawTextBoundingBox)(boundText, container, scene);\n};\nconst convertElementTypes = (app, {\n conversionType,\n nextType,\n direction = \"right\"\n}) => {\n var _a, _b;\n\n if (!conversionType) {\n return false;\n }\n\n const selectedElements = app.scene.getSelectedElements(app.state);\n const selectedElementIds = selectedElements.reduce((acc, element) => Object.assign(Object.assign({}, acc), {\n [element.id]: true\n }), {});\n const advancement = direction === \"right\" ? 1 : -1;\n\n if (conversionType === \"generic\") {\n const convertibleGenericElements = filterGenericConvetibleElements(selectedElements);\n const sameType = convertibleGenericElements.every(element => element.type === convertibleGenericElements[0].type);\n const index = sameType ? GENERIC_TYPES.indexOf(convertibleGenericElements[0].type) : -1;\n nextType = nextType !== null && nextType !== void 0 ? nextType : GENERIC_TYPES[(index + GENERIC_TYPES.length + advancement) % GENERIC_TYPES.length];\n\n if (nextType && isConvertibleGenericType(nextType)) {\n const convertedElements = {};\n\n for (const element of convertibleGenericElements) {\n const convertedElement = convertElementType(element, nextType, app);\n convertedElements[convertedElement.id] = convertedElement;\n }\n\n const nextElements = [];\n\n for (const element of app.scene.getElementsIncludingDeleted()) {\n if (convertedElements[element.id]) {\n nextElements.push(convertedElements[element.id]);\n } else {\n nextElements.push(element);\n }\n }\n\n app.scene.replaceAllElements(nextElements);\n\n for (const element of Object.values(convertedElements)) {\n const boundText = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getBoundTextElement)(element, app.scene.getNonDeletedElementsMap());\n\n if (boundText) {\n if (FONT_SIZE_CONVERSION_CACHE.get(element.id)) {\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.mutateElement)(boundText, app.scene.getNonDeletedElementsMap(), {\n fontSize: (_b = (_a = FONT_SIZE_CONVERSION_CACHE.get(element.id)) === null || _a === void 0 ? void 0 : _a.fontSize) !== null && _b !== void 0 ? _b : boundText.fontSize\n });\n }\n\n adjustBoundTextSize(element, boundText, app.scene);\n }\n }\n\n app.setState(prevState => {\n return {\n selectedElementIds,\n activeTool: (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(prevState, {\n type: \"selection\"\n })\n };\n });\n }\n }\n\n if (conversionType === \"linear\") {\n const convertibleLinearElements = filterLinearConvertibleElements(selectedElements);\n\n if (!nextType) {\n const commonSubType = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.reduceToCommonValue)(convertibleLinearElements, _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType);\n const index = commonSubType ? LINEAR_TYPES.indexOf(commonSubType) : -1;\n nextType = LINEAR_TYPES[(index + LINEAR_TYPES.length + advancement) % LINEAR_TYPES.length];\n }\n\n if (isConvertibleLinearType(nextType)) {\n const convertedElements = [];\n const nextElementsMap = app.scene.getElementsMapIncludingDeleted();\n\n for (const element of convertibleLinearElements) {\n const cachedElement = LINEAR_ELEMENT_CONVERSION_CACHE.get(toCacheKey(element.id, nextType)); // if switching to the original subType or a subType we've already\n // converted to, reuse the cached element to get the original properties\n // (needed for simple->elbow->simple conversions or between line\n // and arrows)\n\n if (cachedElement && (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(cachedElement) === nextType) {\n nextElementsMap.set(cachedElement.id, cachedElement);\n convertedElements.push(cachedElement);\n } else {\n const converted = convertElementType(element, nextType, app);\n nextElementsMap.set(converted.id, converted);\n convertedElements.push(converted);\n }\n }\n\n app.scene.replaceAllElements(nextElementsMap); // post normalization\n\n for (const element of convertedElements) {\n if ((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isLinearElement)(element)) {\n if ((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isElbowArrow)(element)) {\n const nextPoints = convertLineToElbow(element);\n\n if (nextPoints.length < 2) {\n // skip if not enough points to form valid segments\n continue;\n }\n\n const fixedSegments = [];\n\n for (let i = 1; i < nextPoints.length - 2; i++) {\n fixedSegments.push({\n start: nextPoints[i],\n end: nextPoints[i + 1],\n index: i + 1\n });\n }\n\n const updates = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.updateElbowArrowPoints)(element, app.scene.getNonDeletedElementsMap(), {\n points: nextPoints,\n fixedSegments\n });\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.mutateElement)(element, app.scene.getNonDeletedElementsMap(), Object.assign(Object.assign({}, updates), {\n endArrowhead: \"arrow\"\n }));\n } else {\n // if we're converting to non-elbow linear element, check if\n // we've already cached one of these linear elements so we can\n // reuse the points (case: curved->elbow->line and similar)\n const similarCachedLinearElement = (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.mapFind)([\"line\", \"sharpArrow\", \"curvedArrow\"], type => LINEAR_ELEMENT_CONVERSION_CACHE.get(toCacheKey(element.id, type)));\n\n if (similarCachedLinearElement) {\n const points = similarCachedLinearElement.points;\n app.scene.mutateElement(element, {\n points\n });\n }\n }\n }\n }\n }\n\n const convertedSelectedLinearElements = filterLinearConvertibleElements(app.scene.getSelectedElements(app.state));\n app.setState(prevState => ({\n selectedElementIds,\n selectedLinearElement: convertedSelectedLinearElements.length === 1 ? new _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.LinearElementEditor(convertedSelectedLinearElements[0], app.scene.getNonDeletedElementsMap()) : null,\n activeTool: (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.updateActiveTool)(prevState, {\n type: \"selection\"\n })\n }));\n }\n\n return true;\n};\nconst getConversionTypeFromElements = elements => {\n if (elements.length === 0) {\n return null;\n }\n\n let canBeLinear = false;\n\n for (const element of elements) {\n if (isConvertibleGenericType(element.type)) {\n // generic type conversion have preference\n return \"generic\";\n }\n\n if (isEligibleLinearElement(element)) {\n canBeLinear = true;\n }\n }\n\n if (canBeLinear) {\n return \"linear\";\n }\n\n return null;\n};\n\nconst isEligibleLinearElement = element => {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isLinearElement)(element) && (!(0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isArrowElement)(element) || !(0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isArrowBoundToElement)(element) && !(0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.hasBoundTextElement)(element));\n};\n\nconst toCacheKey = (elementId, convertitleType) => {\n return `${elementId}:${convertitleType}`;\n};\n\nconst filterGenericConvetibleElements = elements => elements.filter(element => isConvertibleGenericType(element.type));\n\nconst filterLinearConvertibleElements = elements => elements.filter(element => isEligibleLinearElement(element));\n\nconst THRESHOLD = 20;\n\nconst isVert = (a, b) => a[0] === b[0];\n\nconst isHorz = (a, b) => a[1] === b[1];\n\nconst dist = (a, b) => isVert(a, b) ? Math.abs(a[1] - b[1]) : Math.abs(a[0] - b[0]);\n\nconst convertLineToElbow = line => {\n // 1. build an *orthogonal* route, snapping offsets < SNAP\n const ortho = [line.points[0]];\n const src = sanitizePoints(line.points);\n\n for (let i = 1; i < src.length; ++i) {\n const start = ortho[ortho.length - 1];\n const end = [...src[i]]; // clone\n // snap tiny offsets onto the current axis\n\n if (Math.abs(end[0] - start[0]) < THRESHOLD) {\n end[0] = start[0];\n } else if (Math.abs(end[1] - start[1]) < THRESHOLD) {\n end[1] = start[1];\n } // straight or needs a 90 Β° bend?\n\n\n if (isVert(start, end) || isHorz(start, end)) {\n ortho.push(end);\n } else {\n ortho.push((0,_excalidraw_math__WEBPACK_IMPORTED_MODULE_2__.pointFrom)(start[0], end[1]));\n ortho.push(end);\n }\n } // 2. drop obviously colinear middle points\n\n\n const trimmed = [ortho[0]];\n\n for (let i = 1; i < ortho.length - 1; ++i) {\n if (!(isVert(ortho[i - 1], ortho[i]) && isVert(ortho[i], ortho[i + 1]) || isHorz(ortho[i - 1], ortho[i]) && isHorz(ortho[i], ortho[i + 1]))) {\n trimmed.push(ortho[i]);\n }\n }\n\n trimmed.push(ortho[ortho.length - 1]); // 3. collapse micro βjogsβ (V-H-V / H-V-H whose short leg < SNAP)\n\n const clean = [trimmed[0]];\n\n for (let i = 1; i < trimmed.length - 1; ++i) {\n const a = clean[clean.length - 1];\n const b = trimmed[i];\n const c = trimmed[i + 1];\n const v1 = isVert(a, b);\n const v2 = isVert(b, c);\n\n if (v1 !== v2) {\n const d1 = dist(a, b);\n const d2 = dist(b, c);\n\n if (d1 < THRESHOLD || d2 < THRESHOLD) {\n // pick the shorter leg to remove\n if (d2 < d1) {\n // β¦ absorb leg 2 β pull *c* onto axis of *a-b*\n if (v1) {\n c[0] = a[0];\n } else {\n c[1] = a[1];\n }\n } else {\n // β¦ absorb leg 1 β slide the whole first leg onto *b-c* axis\n // eslint-disable-next-line no-lonely-if\n if (v2) {\n for (let k = clean.length - 1; k >= 0 && clean[k][0] === a[0]; --k) {\n clean[k][0] = b[0];\n }\n } else {\n for (let k = clean.length - 1; k >= 0 && clean[k][1] === a[1]; --k) {\n clean[k][1] = b[1];\n }\n }\n } // *b* is gone, donβt add it\n\n\n continue;\n }\n }\n\n clean.push(b);\n }\n\n clean.push(trimmed[trimmed.length - 1]);\n return clean;\n};\n\nconst sanitizePoints = points => {\n if (points.length === 0) {\n return [];\n }\n\n const sanitized = [points[0]];\n\n for (let i = 1; i < points.length; i++) {\n const [x1, y1] = sanitized[sanitized.length - 1];\n const [x2, y2] = points[i];\n\n if (x1 !== x2 || y1 !== y2) {\n sanitized.push(points[i]);\n }\n }\n\n return sanitized;\n};\n/**\n * Converts an element to a new type, adding or removing properties as needed\n * so that the element object is always valid.\n *\n * Valid conversions at this point:\n * - switching between generic elements\n * e.g. rectangle -> diamond\n * - switching between linear elements\n * e.g. elbow arrow -> line\n */\n\n\nconst convertElementType = (element, targetType, app) => {\n if (!isValidConversion(element.type, targetType)) {\n if (!(0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.isProdEnv)()) {\n throw Error(`Invalid conversion from ${element.type} to ${targetType}.`);\n }\n\n return element;\n }\n\n if (element.type === targetType) {\n return element;\n }\n\n _excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.ShapeCache.delete(element);\n\n if (isConvertibleGenericType(targetType)) {\n const nextElement = (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newElement)(Object.assign(Object.assign({}, element), {\n type: targetType,\n roundness: element.roundness ? {\n type: (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isUsingAdaptiveRadius)(targetType) ? _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.ROUNDNESS.ADAPTIVE_RADIUS : _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.ROUNDNESS.PROPORTIONAL_RADIUS\n } : element.roundness\n })));\n (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.updateBindings)(nextElement, app.scene, app.state);\n return nextElement;\n }\n\n if (isConvertibleLinearType(targetType)) {\n switch (targetType) {\n case \"line\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newLinearElement)(Object.assign(Object.assign({}, element), {\n type: \"line\"\n })));\n }\n\n case \"sharpArrow\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newArrowElement)(Object.assign(Object.assign({}, element), {\n type: \"arrow\",\n elbowed: false,\n roundness: null,\n startArrowhead: app.state.currentItemStartArrowhead,\n endArrowhead: app.state.currentItemEndArrowhead\n })));\n }\n\n case \"curvedArrow\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newArrowElement)(Object.assign(Object.assign({}, element), {\n type: \"arrow\",\n elbowed: false,\n roundness: {\n type: _excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.ROUNDNESS.PROPORTIONAL_RADIUS\n },\n startArrowhead: app.state.currentItemStartArrowhead,\n endArrowhead: app.state.currentItemEndArrowhead\n })));\n }\n\n case \"elbowArrow\":\n {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.bumpVersion)((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.newArrowElement)(Object.assign(Object.assign({}, element), {\n type: \"arrow\",\n elbowed: true,\n fixedSegments: null,\n roundness: null\n })));\n }\n }\n }\n\n (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_3__.assertNever)(targetType, `unhandled conversion type: ${targetType}`);\n return element;\n};\n\nconst isValidConversion = (startType, targetType) => {\n if (isConvertibleGenericType(startType) && isConvertibleGenericType(targetType)) {\n return true;\n }\n\n if (isConvertibleLinearType(startType) && isConvertibleLinearType(targetType)) {\n return true;\n } // NOTE: add more conversions when needed\n\n\n return false;\n};\n\nconst getConvertibleType = element => {\n if ((0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.isLinearElement)(element)) {\n return (0,_excalidraw_element__WEBPACK_IMPORTED_MODULE_1__.getLinearElementSubType)(element);\n }\n\n return element.type;\n};\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ConvertElementTypePopup);\n\n//# sourceURL=webpack://ExcalidrawLib/./components/ConvertElementTypePopup.tsx?\n}");
|
|
1995
1995
|
|
|
1996
1996
|
/***/ },
|
|
1997
1997
|
|
|
@@ -4037,7 +4037,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
4037
4037
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
4038
4038
|
|
|
4039
4039
|
"use strict";
|
|
4040
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ExcalidrawFontFace: () => (/* binding */ ExcalidrawFontFace)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _subset_subset_main__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../subset/subset-main */ \"./subset/subset-main.ts\");\n/* harmony import */ var _data_encode__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../data/encode */ \"./data/encode.ts\");\n/* harmony import */ var _obsidianUtils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../obsidianUtils */ \"./obsidianUtils.ts\");\n\n\n\n\nclass ExcalidrawFontFace {\n constructor(family, uri, descriptors) {\n this.urls = ExcalidrawFontFace.createUrls(uri);\n const sources = this.urls.map(url => `url(${url}) ${ExcalidrawFontFace.getFormat(url)}`).join(\", \");\n this.fontFace = new FontFace(family, sources, Object.assign({\n display: \"swap\",\n style: \"normal\",\n weight: \"400\"\n }, descriptors));\n }\n /**\n * Generates CSS `@font-face` definition with the (subsetted) font source as a data url for the characters within the unicode range.\n *\n * Retrieves `undefined` otherwise.\n */\n\n\n toCSS(characters) {\n // quick exit in case the characters are not within this font face's unicode range\n if (!this.getUnicodeRangeRegex().test(characters)) {\n return;\n } //zsviczian - only woffs are chopped into glyphs other fonts are returned as is\n\n\n if (typeof this.urls[0] === \"string\" && !this.urls[0].startsWith(\"data:font/woff2\")) {\n return Promise.resolve(`@font-face { font-family: ${this.fontFace.family}; src: url(${this.urls[0]}); }`);\n }\n\n const codepoints = Array.from(characters).map(char => char.codePointAt(0));\n return this.getContent(codepoints).then(content => `@font-face { font-family: ${this.fontFace.family}; src: url(${content}); }`);\n }\n /**\n * Tries to fetch woff2 content, based on the registered urls (from first to last, treated as fallbacks).\n *\n * @returns base64 with subsetted glyphs based on the passed codepoint, last defined url otherwise\n */\n\n\n async getContent(codePoints) {\n let i = 0;\n const errorMessages = [];\n\n while (i < this.urls.length) {\n const url = this.urls[i];\n\n try {\n const arrayBuffer = await this.fetchFont(url);\n const base64 = await (0,_subset_subset_main__WEBPACK_IMPORTED_MODULE_1__.subsetWoff2GlyphsByCodepoints)(arrayBuffer, codePoints);\n return base64;\n } catch (e) {\n errorMessages.push(`\"${url.toString()}\" returned error \"${e}\"`);\n }\n\n i++;\n }\n\n console.error(`Failed to fetch font family \"${this.fontFace.family}\"`, JSON.stringify(errorMessages, undefined, 2)); // in case of issues, at least return the last url as a content\n // defaults to unpkg for bundled fonts (so that we don't have to host them forever) and http url for others\n\n return this.urls.length ? this.urls[this.urls.length - 1].toString() : \"\";\n }\n\n fetchFont(url) {\n return (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.promiseTry)(async () => {\n const result = await (0,_obsidianUtils__WEBPACK_IMPORTED_MODULE_3__.fetchFontFromVault)(url); //zsviczian\n\n if (result) {\n return result;\n }\n\n const response = await fetch(url, {\n // always prefer cache (even stale), otherwise it always triggers an unnecessary validation request\n // which we don't need as we are controlling freshness of the fonts with the stable hash suffix in the url\n // https://developer.mozilla.org/en-US/docs/Web/API/Request/cache\n cache: \"force-cache\",\n headers: {\n Accept: \"font/woff2\"\n }\n });\n\n if (!response.ok) {\n const urlString = url instanceof URL ? url.toString() : \"dataurl\";\n throw new Error(`Failed to fetch \"${urlString}\": ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return arrayBuffer;\n });\n }\n\n getUnicodeRangeRegex() {\n // using \\u{h} or \\u{hhhhh} to match any number of hex digits,\n // otherwise we would get an \"Invalid Unicode escape\" error\n // e.g. U+0-1007F -> \\u{0}-\\u{1007F}\n const unicodeRangeRegex = this.fontFace.unicodeRange.split(/,\\s*/).map(range => {\n const [start, end] = range.replace(\"U+\", \"\").split(\"-\");\n\n if (end) {\n return `\\\\u{${start}}-\\\\u{${end}}`;\n }\n\n return `\\\\u{${start}}`;\n }).join(\"\");\n return new RegExp(`[${unicodeRangeRegex}]`, \"u\");\n }\n\n static createUrls(uri) {\n if (uri.startsWith(\"data\")) {\n // don't create the URL instance, as parsing the huge dataurl string is expensive\n return [uri];\n }\n\n if (uri.startsWith(_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.LOCAL_FONT_PROTOCOL)) {\n // no url for local fonts\n return [];\n }\n\n if (uri.startsWith(\"http\")) {\n // one url for http imports or data url\n return [new URL(uri)];\n } // absolute assets paths, which are found in tests and excalidraw-app build, won't work with base url, so we are stripping initial slash away\n\n\n const assetUrl = uri.replace(/^\\/+/, \"\");\n const urls = [];\n\n if (typeof window.EXCALIDRAW_ASSET_PATH === \"string\") {\n const normalizedBaseUrl = this.normalizeBaseUrl(window.EXCALIDRAW_ASSET_PATH);\n urls.push(new URL(assetUrl, normalizedBaseUrl));\n } else if (Array.isArray(window.EXCALIDRAW_ASSET_PATH)) {\n window.EXCALIDRAW_ASSET_PATH.forEach(path => {\n const normalizedBaseUrl = this.normalizeBaseUrl(path);\n urls.push(new URL(assetUrl, normalizedBaseUrl));\n });\n } // fallback url for bundled fonts\n\n\n urls.push(new URL(assetUrl, ExcalidrawFontFace.ASSETS_FALLBACK_URL));\n return urls;\n }\n\n static getFormat(url) {\n if (!(url instanceof URL)) {\n // format is irrelevant for data url\n return \"\";\n }\n\n try {\n const parts = new URL(url).pathname.split(\".\");\n\n if (parts.length === 1) {\n return \"\";\n }\n\n return `format('${parts.pop()}')`;\n } catch (error) {\n return \"\";\n }\n }\n\n static normalizeBaseUrl(baseUrl) {\n var _a;\n\n let result = baseUrl; // in case user passed a root-relative url (~absolute path),\n // like \"/\" or \"/some/path\", or relative (starts with \"./\"),\n // prepend it with `location.origin`\n\n if (/^\\.?\\//.test(result)) {\n result = new URL(result.replace(/^\\.?\\/+/, \"\"), (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.origin).toString();\n } // ensure there is a trailing slash, otherwise url won't be correctly concatenated\n\n\n result = `${result.replace(/\\/+$/, \"\")}/`;\n return result;\n }\n /**\n * zsviczian https://github.com/zsviczian/excalidraw/commit/b4cfaaa4b4f46ca01f94e27fb7bf651a9da99daa\n */\n\n\n async getContentLegacy() {\n let i = 0;\n const errorMessages = [];\n\n while (i < this.urls.length) {\n const url = this.urls[i];\n\n if (typeof url === \"string\" && url.startsWith(\"data:\")) {\n // it's dataurl, the font is inlined as base64, no need to fetch\n return url;\n }\n\n try {\n const result = await (0,_obsidianUtils__WEBPACK_IMPORTED_MODULE_3__.fetchFontFromVault)(url); //zsviczian\n\n if (result) {\n return `data:font/woff2;base64,${(0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.stringToBase64)((0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.toByteString)(result), true)}`;\n }\n\n const response = await fetch(url, {\n headers: {\n Accept: \"font/woff2\"\n }\n });\n\n if (response.ok) {\n const mimeType = response.headers.get(\"Content-Type\");\n const buffer = await response.arrayBuffer();\n return `data:${mimeType};base64,${(0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.stringToBase64)((0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.toByteString)(buffer), true)}`;\n } // response not ok, try to continue\n\n\n errorMessages.push(`\"${url.toString()}\" returned status \"${response.status}\"`);\n } catch (e) {\n errorMessages.push(`\"${url.toString()}\" returned error \"${e}\"`);\n }\n\n i++;\n }\n\n console.error(`Failed to fetch font \"${this.fontFace.family}\" from urls \"${this.urls.toString()}`, JSON.stringify(errorMessages, undefined, 2)); // in case of issues, at least return the last url as a content\n // defaults to unpkg for bundled fonts (so that we don't have to host them forever) and http url for others\n\n return this.urls.length ? this.urls[this.urls.length - 1].toString() : \"\";\n }\n\n}\nExcalidrawFontFace.ASSETS_FALLBACK_URL = `https://esm.sh/${({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.0\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_NAME ? `${({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.0\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_NAME}@${({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.0\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_VERSION}` // is provided during package build\n: \"@excalidraw/excalidraw\" // fallback to the latest package version (i.e. for app)\n}/dist/prod/`;\n\n//# sourceURL=webpack://ExcalidrawLib/./fonts/ExcalidrawFontFace.ts?\n}");
|
|
4040
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ExcalidrawFontFace: () => (/* binding */ ExcalidrawFontFace)\n/* harmony export */ });\n/* harmony import */ var _excalidraw_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common */ \"../common/src/index.ts\");\n/* harmony import */ var _subset_subset_main__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../subset/subset-main */ \"./subset/subset-main.ts\");\n/* harmony import */ var _data_encode__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../data/encode */ \"./data/encode.ts\");\n/* harmony import */ var _obsidianUtils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../obsidianUtils */ \"./obsidianUtils.ts\");\n\n\n\n\nclass ExcalidrawFontFace {\n constructor(family, uri, descriptors) {\n this.urls = ExcalidrawFontFace.createUrls(uri);\n const sources = this.urls.map(url => `url(${url}) ${ExcalidrawFontFace.getFormat(url)}`).join(\", \");\n this.fontFace = new FontFace(family, sources, Object.assign({\n display: \"swap\",\n style: \"normal\",\n weight: \"400\"\n }, descriptors));\n }\n /**\n * Generates CSS `@font-face` definition with the (subsetted) font source as a data url for the characters within the unicode range.\n *\n * Retrieves `undefined` otherwise.\n */\n\n\n toCSS(characters) {\n // quick exit in case the characters are not within this font face's unicode range\n if (!this.getUnicodeRangeRegex().test(characters)) {\n return;\n } //zsviczian - only woffs are chopped into glyphs other fonts are returned as is\n\n\n if (typeof this.urls[0] === \"string\" && !this.urls[0].startsWith(\"data:font/woff2\")) {\n return Promise.resolve(`@font-face { font-family: ${this.fontFace.family}; src: url(${this.urls[0]}); }`);\n }\n\n const codepoints = Array.from(characters).map(char => char.codePointAt(0));\n return this.getContent(codepoints).then(content => `@font-face { font-family: ${this.fontFace.family}; src: url(${content}); }`);\n }\n /**\n * Tries to fetch woff2 content, based on the registered urls (from first to last, treated as fallbacks).\n *\n * @returns base64 with subsetted glyphs based on the passed codepoint, last defined url otherwise\n */\n\n\n async getContent(codePoints) {\n let i = 0;\n const errorMessages = [];\n\n while (i < this.urls.length) {\n const url = this.urls[i];\n\n try {\n const arrayBuffer = await this.fetchFont(url);\n const base64 = await (0,_subset_subset_main__WEBPACK_IMPORTED_MODULE_1__.subsetWoff2GlyphsByCodepoints)(arrayBuffer, codePoints);\n return base64;\n } catch (e) {\n errorMessages.push(`\"${url.toString()}\" returned error \"${e}\"`);\n }\n\n i++;\n }\n\n console.error(`Failed to fetch font family \"${this.fontFace.family}\"`, JSON.stringify(errorMessages, undefined, 2)); // in case of issues, at least return the last url as a content\n // defaults to unpkg for bundled fonts (so that we don't have to host them forever) and http url for others\n\n return this.urls.length ? this.urls[this.urls.length - 1].toString() : \"\";\n }\n\n fetchFont(url) {\n return (0,_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.promiseTry)(async () => {\n const result = await (0,_obsidianUtils__WEBPACK_IMPORTED_MODULE_3__.fetchFontFromVault)(url); //zsviczian\n\n if (result) {\n return result;\n }\n\n const response = await fetch(url, {\n // always prefer cache (even stale), otherwise it always triggers an unnecessary validation request\n // which we don't need as we are controlling freshness of the fonts with the stable hash suffix in the url\n // https://developer.mozilla.org/en-US/docs/Web/API/Request/cache\n cache: \"force-cache\",\n headers: {\n Accept: \"font/woff2\"\n }\n });\n\n if (!response.ok) {\n const urlString = url instanceof URL ? url.toString() : \"dataurl\";\n throw new Error(`Failed to fetch \"${urlString}\": ${response.statusText}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return arrayBuffer;\n });\n }\n\n getUnicodeRangeRegex() {\n // using \\u{h} or \\u{hhhhh} to match any number of hex digits,\n // otherwise we would get an \"Invalid Unicode escape\" error\n // e.g. U+0-1007F -> \\u{0}-\\u{1007F}\n const unicodeRangeRegex = this.fontFace.unicodeRange.split(/,\\s*/).map(range => {\n const [start, end] = range.replace(\"U+\", \"\").split(\"-\");\n\n if (end) {\n return `\\\\u{${start}}-\\\\u{${end}}`;\n }\n\n return `\\\\u{${start}}`;\n }).join(\"\");\n return new RegExp(`[${unicodeRangeRegex}]`, \"u\");\n }\n\n static createUrls(uri) {\n if (uri.startsWith(\"data\")) {\n // don't create the URL instance, as parsing the huge dataurl string is expensive\n return [uri];\n }\n\n if (uri.startsWith(_excalidraw_common__WEBPACK_IMPORTED_MODULE_0__.LOCAL_FONT_PROTOCOL)) {\n // no url for local fonts\n return [];\n }\n\n if (uri.startsWith(\"http\")) {\n // one url for http imports or data url\n return [new URL(uri)];\n } // absolute assets paths, which are found in tests and excalidraw-app build, won't work with base url, so we are stripping initial slash away\n\n\n const assetUrl = uri.replace(/^\\/+/, \"\");\n const urls = [];\n\n if (typeof window.EXCALIDRAW_ASSET_PATH === \"string\") {\n const normalizedBaseUrl = this.normalizeBaseUrl(window.EXCALIDRAW_ASSET_PATH);\n urls.push(new URL(assetUrl, normalizedBaseUrl));\n } else if (Array.isArray(window.EXCALIDRAW_ASSET_PATH)) {\n window.EXCALIDRAW_ASSET_PATH.forEach(path => {\n const normalizedBaseUrl = this.normalizeBaseUrl(path);\n urls.push(new URL(assetUrl, normalizedBaseUrl));\n });\n } // fallback url for bundled fonts\n\n\n urls.push(new URL(assetUrl, ExcalidrawFontFace.ASSETS_FALLBACK_URL));\n return urls;\n }\n\n static getFormat(url) {\n if (!(url instanceof URL)) {\n // format is irrelevant for data url\n return \"\";\n }\n\n try {\n const parts = new URL(url).pathname.split(\".\");\n\n if (parts.length === 1) {\n return \"\";\n }\n\n return `format('${parts.pop()}')`;\n } catch (error) {\n return \"\";\n }\n }\n\n static normalizeBaseUrl(baseUrl) {\n var _a;\n\n let result = baseUrl; // in case user passed a root-relative url (~absolute path),\n // like \"/\" or \"/some/path\", or relative (starts with \"./\"),\n // prepend it with `location.origin`\n\n if (/^\\.?\\//.test(result)) {\n result = new URL(result.replace(/^\\.?\\/+/, \"\"), (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.origin).toString();\n } // ensure there is a trailing slash, otherwise url won't be correctly concatenated\n\n\n result = `${result.replace(/\\/+$/, \"\")}/`;\n return result;\n }\n /**\n * zsviczian https://github.com/zsviczian/excalidraw/commit/b4cfaaa4b4f46ca01f94e27fb7bf651a9da99daa\n */\n\n\n async getContentLegacy() {\n let i = 0;\n const errorMessages = [];\n\n while (i < this.urls.length) {\n const url = this.urls[i];\n\n if (typeof url === \"string\" && url.startsWith(\"data:\")) {\n // it's dataurl, the font is inlined as base64, no need to fetch\n return url;\n }\n\n try {\n const result = await (0,_obsidianUtils__WEBPACK_IMPORTED_MODULE_3__.fetchFontFromVault)(url); //zsviczian\n\n if (result) {\n return `data:font/woff2;base64,${(0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.stringToBase64)((0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.toByteString)(result), true)}`;\n }\n\n const response = await fetch(url, {\n headers: {\n Accept: \"font/woff2\"\n }\n });\n\n if (response.ok) {\n const mimeType = response.headers.get(\"Content-Type\");\n const buffer = await response.arrayBuffer();\n return `data:${mimeType};base64,${(0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.stringToBase64)((0,_data_encode__WEBPACK_IMPORTED_MODULE_2__.toByteString)(buffer), true)}`;\n } // response not ok, try to continue\n\n\n errorMessages.push(`\"${url.toString()}\" returned status \"${response.status}\"`);\n } catch (e) {\n errorMessages.push(`\"${url.toString()}\" returned error \"${e}\"`);\n }\n\n i++;\n }\n\n console.error(`Failed to fetch font \"${this.fontFace.family}\" from urls \"${this.urls.toString()}`, JSON.stringify(errorMessages, undefined, 2)); // in case of issues, at least return the last url as a content\n // defaults to unpkg for bundled fonts (so that we don't have to host them forever) and http url for others\n\n return this.urls.length ? this.urls[this.urls.length - 1].toString() : \"\";\n }\n\n}\nExcalidrawFontFace.ASSETS_FALLBACK_URL = `https://esm.sh/${({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.1\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_NAME ? `${({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.1\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_NAME}@${({\"MODE\":\"development\",\"VITE_APP_BACKEND_V2_GET_URL\":\"https://json-dev.excalidraw.com/api/v2/\",\"VITE_APP_BACKEND_V2_POST_URL\":\"https://json-dev.excalidraw.com/api/v2/post/\",\"VITE_APP_LIBRARY_URL\":\"https://libraries.excalidraw.com\",\"VITE_APP_LIBRARY_BACKEND\":\"https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries\",\"VITE_APP_WS_SERVER_URL\":\"http://localhost:3002\",\"VITE_APP_PLUS_LP\":\"https://plus.excalidraw.com\",\"VITE_APP_PLUS_APP\":\"http://localhost:3000\",\"VITE_APP_AI_BACKEND\":\"http://localhost:3016\",\"VITE_APP_FIREBASE_CONFIG\":\"{\\\"apiKey\\\":\\\"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8\\\",\\\"authDomain\\\":\\\"excalidraw-oss-dev.firebaseapp.com\\\",\\\"projectId\\\":\\\"excalidraw-oss-dev\\\",\\\"storageBucket\\\":\\\"excalidraw-oss-dev.appspot.com\\\",\\\"messagingSenderId\\\":\\\"664559512677\\\",\\\"appId\\\":\\\"1:664559512677:web:a385181f2928d328a7aa8c\\\"}\",\"VITE_APP_DEV_DISABLE_LIVE_RELOAD\":\"\",\"VITE_APP_ENABLE_TRACKING\":\"true\",\"FAST_REFRESH\":\"false\",\"VITE_APP_PORT\":\"3001\",\"VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX\":\"\",\"VITE_APP_COLLAPSE_OVERLAY\":\"true\",\"VITE_APP_ENABLE_ESLINT\":\"true\",\"VITE_APP_ENABLE_PWA\":\"false\",\"VITE_APP_PLUS_EXPORT_PUBLIC_KEY\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2g5T+Rub6Kbf1Mf57t0\\n7r2zeHuVg4dla3r5ryXMswtzz6x767octl6oLThn33mQsPSy3GKglFZoCTXJR4ij\\nba8SxB04sL/N8eRrKja7TFWjCVtRwTTfyy771NYYNFVJclkxHyE5qw4m27crHF1y\\nUNWEjuqNMi/lwAErS9fFa2oJlWyT8U7zzv/5kQREkxZI6y9v0AF3qcbsy2731FnD\\ns9ChJvOUW9toIab2gsIdrKW8ZNpu084ZFVKb6LNjvIXI1Se4oMTHeszXzNptzlot\\nkdxxjOoaQMAyfljFSot1F1FlU6MQlag7UnFGvFjRHN1JI5q4K+n3a67DX+TMyRqS\\nHQIDAQAB\",\"VITE_APP_DISABLE_PREVENT_UNLOAD\":\"\",\"VITE_PKG_NAME\":\"@zsviczian/excalidraw\",\"VITE_PKG_VERSION\":\"0.18.101-beta.1\",\"VITE_IS_EXCALIDRAW_NPM_PACKAGE\":true}).PKG_VERSION}` // is provided during package build\n: \"@excalidraw/excalidraw\" // fallback to the latest package version (i.e. for app)\n}/dist/prod/`;\n\n//# sourceURL=webpack://ExcalidrawLib/./fonts/ExcalidrawFontFace.ts?\n}");
|
|
4041
4041
|
|
|
4042
4042
|
/***/ },
|
|
4043
4043
|
|
|
@@ -4389,7 +4389,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
4389
4389
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
4390
4390
|
|
|
4391
4391
|
"use strict";
|
|
4392
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _excalidraw_common_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common/constants */ \"../common/src/constants.ts\");\n\n\nif (\"development\" !== _excalidraw_common_constants__WEBPACK_IMPORTED_MODULE_0__.ENV.TEST) {\n /* eslint-disable */\n\n /* global __webpack_public_path__:writable */\n __webpack_require__.p = window.EXCALIDRAW_ASSET_PATH || `https://unpkg.com/${\"@zsviczian/excalidraw\"}@${\"0.18.101-beta.
|
|
4392
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _excalidraw_common_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @excalidraw/common/constants */ \"../common/src/constants.ts\");\n\n\nif (\"development\" !== _excalidraw_common_constants__WEBPACK_IMPORTED_MODULE_0__.ENV.TEST) {\n /* eslint-disable */\n\n /* global __webpack_public_path__:writable */\n __webpack_require__.p = window.EXCALIDRAW_ASSET_PATH || `https://unpkg.com/${\"@zsviczian/excalidraw\"}@${\"0.18.101-beta.1\"}/dist/`;\n}\n\n//# sourceURL=webpack://ExcalidrawLib/./publicPath.js?\n}");
|
|
4393
4393
|
|
|
4394
4394
|
/***/ },
|
|
4395
4395
|
|