{"version":3,"file":"Help.Dgi2pre9.js","sources":["../../../../../../node_modules/d3-selection/src/sourceEvent.js","../../../../../../node_modules/d3-selection/src/pointer.js","../../../../../../node_modules/d3-drag/src/noevent.js","../../../../../../node_modules/d3-drag/src/nodrag.js","../../../../../../node_modules/d3-drag/src/constant.js","../../../../../../node_modules/d3-drag/src/event.js","../../../../../../node_modules/d3-drag/src/drag.js","../../../../../../node_modules/d3-interpolate/src/zoom.js","../../../../../../node_modules/d3-zoom/src/constant.js","../../../../../../node_modules/d3-zoom/src/event.js","../../../../../../node_modules/d3-zoom/src/noevent.js","../../../../../../node_modules/d3-zoom/src/zoom.js","../../../../../../node_modules/bits-ui/dist/bits/menu/components/menu-sub.svelte","../../../../../../node_modules/bits-ui/dist/bits/menu/components/menu-sub-content.svelte","../../../../../../node_modules/bits-ui/dist/bits/menu/components/menu-sub-trigger.svelte","../../../../../../node_modules/paneforge/dist/internal/utils/lifecycle.js","../../../../../../node_modules/paneforge/dist/internal/utils/store.js","../../../../../../node_modules/paneforge/dist/internal/utils/style.js","../../../../../../node_modules/paneforge/dist/internal/utils/aria.js","../../../../../../node_modules/paneforge/dist/internal/utils/id.js","../../../../../../node_modules/paneforge/dist/internal/constants.js","../../../../../../node_modules/paneforge/dist/internal/utils/storage.js","../../../../../../node_modules/paneforge/dist/internal/utils/object.js","../../../../../../node_modules/paneforge/dist/internal/utils/chain.js","../../../../../../node_modules/paneforge/dist/internal/utils/event.js","../../../../../../node_modules/paneforge/dist/internal/utils/compare.js","../../../../../../node_modules/paneforge/dist/internal/utils/assert.js","../../../../../../node_modules/paneforge/dist/internal/utils/resize.js","../../../../../../node_modules/paneforge/dist/internal/utils/adjust-layout.js","../../../../../../node_modules/paneforge/dist/internal/utils/is.js","../../../../../../node_modules/paneforge/dist/internal/paneforge.js","../../../../../../node_modules/paneforge/dist/components/ctx.js","../../../../../../node_modules/paneforge/dist/components/pane-group.svelte","../../../../../../node_modules/paneforge/dist/components/pane.svelte","../../../../../../node_modules/paneforge/dist/components/pane-resizer.js","../../../../../../node_modules/paneforge/dist/components/pane-resizer.svelte","../../../../../../node_modules/eventsource-parser/dist/index.js","../../../../../../node_modules/eventsource-parser/dist/stream.js","../../../../../../src/lib/apis/streaming/index.ts","../../../../../../src/lib/components/common/Banner.svelte","../../../../../../src/lib/components/icons/DocumentArrowUpSolid.svelte","../../../../../../src/lib/components/icons/GlobeAltSolid.svelte","../../../../../../src/lib/components/icons/WrenchSolid.svelte","../../../../../../src/lib/components/chat/MessageInput/InputMenu.svelte","../../../../../../src/lib/components/icons/Headphone.svelte","../../../../../../src/lib/components/chat/MessageInput/VoiceRecording.svelte","../../../../../../src/lib/components/chat/MessageInput/FilesOverlay.svelte","../../../../../../src/lib/components/chat/MessageInput/Commands/Prompts.svelte","../../../../../../src/lib/components/chat/MessageInput/Commands/Documents.svelte","../../../../../../src/lib/components/chat/MessageInput/Commands/Models.svelte","../../../../../../src/lib/components/chat/MessageInput/Commands.svelte","../../../../../../src/lib/components/chat/MessageInput.svelte","../../../../../../src/lib/components/chat/ModelSelector.svelte","../../../../../../src/lib/components/icons/Map.svelte","../../../../../../src/lib/components/icons/Clipboard.svelte","../../../../../../src/lib/components/icons/AdjustmentsHorizontal.svelte","../../../../../../src/lib/components/layout/Navbar/Menu.svelte","../../../../../../src/lib/components/layout/Navbar.svelte","../../../../../../node_modules/classcat/index.js","../../../../../../node_modules/@xyflow/system/dist/esm/index.mjs","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/Handle/Handle.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/nodes/DefaultNode.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/nodes/InputNode.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/nodes/OutputNode.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/actions/portal/index.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/EdgeLabelRenderer/EdgeLabelRenderer.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/hooks/useHandleEdgeSelect.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/EdgeLabel/EdgeLabel.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/BaseEdge/BaseEdge.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/edges/BezierEdgeInternal.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/edges/SmoothStepEdgeInternal.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/edges/StraightEdgeInternal.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/edges/StepEdgeInternal.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/store/utils.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/store/initial-store.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/store/visible-edges.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/store/visible-nodes.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/store/index.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/actions/zoom/index.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/Zoom/Zoom.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/Pane/Pane.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/Viewport/Viewport.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/actions/drag/index.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/NodeWrapper/utils.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/NodeWrapper/NodeWrapper.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/NodeRenderer/NodeRenderer.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/EdgeWrapper/EdgeWrapper.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/CallOnMount/CallOnMount.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/EdgeRenderer/MarkerDefinition/MarkerDefinition.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/EdgeRenderer/MarkerDefinition/Marker.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/EdgeRenderer/EdgeRenderer.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/Selection/Selection.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/UserSelection/UserSelection.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/NodeSelection/NodeSelection.svelte","../../../../../../node_modules/@svelte-put/shortcut/src/shortcut.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/KeyHandler/KeyHandler.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/ConnectionLine/ConnectionLine.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/Panel/Panel.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/Attribution/Attribution.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/SvelteFlow/utils.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/hooks/useColorModeClass.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/container/SvelteFlow/SvelteFlow.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/components/SvelteFlowProvider/SvelteFlowProvider.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Controls/ControlButton.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Controls/Icons/Plus.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Controls/Icons/Minus.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Controls/Icons/Fit.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Controls/Icons/Lock.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Controls/Icons/Unlock.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Controls/Controls.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Background/types.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Background/DotPattern.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Background/LinePattern.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/plugins/Background/Background.svelte","../../../../../../node_modules/@xyflow/svelte/dist/lib/utils/index.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/hooks/useSvelteFlow.js","../../../../../../node_modules/@xyflow/svelte/dist/lib/hooks/useInitialized.js","../../../../../../src/lib/components/chat/Controls/Valves.svelte","../../../../../../src/lib/components/chat/Controls/Controls.svelte","../../../../../../src/lib/components/chat/MessageInput/CallOverlay/VideoInputMenu.svelte","../../../../../../src/lib/components/chat/MessageInput/CallOverlay.svelte","../../../../../../src/lib/components/common/Drawer.svelte","../../../../../../src/lib/components/chat/Overview/Node.svelte","../../../../../../src/lib/components/chat/Overview/Flow.svelte","../../../../../../src/lib/components/chat/Overview.svelte","../../../../../../src/lib/components/icons/EllipsisVertical.svelte","../../../../../../src/lib/components/chat/ChatControls.svelte","../../../../../../src/lib/components/chat/Chat.svelte","../../../../../../src/lib/components/chat/ShortcutsModal.svelte","../../../../../../src/lib/components/icons/QuestionMarkCircle.svelte","../../../../../../src/lib/components/icons/Keyboard.svelte","../../../../../../src/lib/components/layout/Help/HelpMenu.svelte","../../../../../../src/lib/components/layout/Help.svelte"],"sourcesContent":["export default function(event) {\n let sourceEvent;\n while (sourceEvent = event.sourceEvent) event = sourceEvent;\n return event;\n}\n","import sourceEvent from \"./sourceEvent.js\";\n\nexport default function(event, node) {\n event = sourceEvent(event);\n if (node === undefined) node = event.currentTarget;\n if (node) {\n var svg = node.ownerSVGElement || node;\n if (svg.createSVGPoint) {\n var point = svg.createSVGPoint();\n point.x = event.clientX, point.y = event.clientY;\n point = point.matrixTransform(node.getScreenCTM().inverse());\n return [point.x, point.y];\n }\n if (node.getBoundingClientRect) {\n var rect = node.getBoundingClientRect();\n return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];\n }\n }\n return [event.pageX, event.pageY];\n}\n","// These are typically used in conjunction with noevent to ensure that we can\n// preventDefault on the event.\nexport const nonpassive = {passive: false};\nexport const nonpassivecapture = {capture: true, passive: false};\n\nexport function nopropagation(event) {\n event.stopImmediatePropagation();\n}\n\nexport default function(event) {\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n","import {select} from \"d3-selection\";\nimport noevent, {nonpassivecapture} from \"./noevent.js\";\n\nexport default function(view) {\n var root = view.document.documentElement,\n selection = select(view).on(\"dragstart.drag\", noevent, nonpassivecapture);\n if (\"onselectstart\" in root) {\n selection.on(\"selectstart.drag\", noevent, nonpassivecapture);\n } else {\n root.__noselect = root.style.MozUserSelect;\n root.style.MozUserSelect = \"none\";\n }\n}\n\nexport function yesdrag(view, noclick) {\n var root = view.document.documentElement,\n selection = select(view).on(\"dragstart.drag\", null);\n if (noclick) {\n selection.on(\"click.drag\", noevent, nonpassivecapture);\n setTimeout(function() { selection.on(\"click.drag\", null); }, 0);\n }\n if (\"onselectstart\" in root) {\n selection.on(\"selectstart.drag\", null);\n } else {\n root.style.MozUserSelect = root.__noselect;\n delete root.__noselect;\n }\n}\n","export default x => () => x;\n","export default function DragEvent(type, {\n sourceEvent,\n subject,\n target,\n identifier,\n active,\n x, y, dx, dy,\n dispatch\n}) {\n Object.defineProperties(this, {\n type: {value: type, enumerable: true, configurable: true},\n sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},\n subject: {value: subject, enumerable: true, configurable: true},\n target: {value: target, enumerable: true, configurable: true},\n identifier: {value: identifier, enumerable: true, configurable: true},\n active: {value: active, enumerable: true, configurable: true},\n x: {value: x, enumerable: true, configurable: true},\n y: {value: y, enumerable: true, configurable: true},\n dx: {value: dx, enumerable: true, configurable: true},\n dy: {value: dy, enumerable: true, configurable: true},\n _: {value: dispatch}\n });\n}\n\nDragEvent.prototype.on = function() {\n var value = this._.on.apply(this._, arguments);\n return value === this._ ? this : value;\n};\n","import {dispatch} from \"d3-dispatch\";\nimport {select, pointer} from \"d3-selection\";\nimport nodrag, {yesdrag} from \"./nodrag.js\";\nimport noevent, {nonpassive, nonpassivecapture, nopropagation} from \"./noevent.js\";\nimport constant from \"./constant.js\";\nimport DragEvent from \"./event.js\";\n\n// Ignore right-click, since that should open the context menu.\nfunction defaultFilter(event) {\n return !event.ctrlKey && !event.button;\n}\n\nfunction defaultContainer() {\n return this.parentNode;\n}\n\nfunction defaultSubject(event, d) {\n return d == null ? {x: event.x, y: event.y} : d;\n}\n\nfunction defaultTouchable() {\n return navigator.maxTouchPoints || (\"ontouchstart\" in this);\n}\n\nexport default function() {\n var filter = defaultFilter,\n container = defaultContainer,\n subject = defaultSubject,\n touchable = defaultTouchable,\n gestures = {},\n listeners = dispatch(\"start\", \"drag\", \"end\"),\n active = 0,\n mousedownx,\n mousedowny,\n mousemoving,\n touchending,\n clickDistance2 = 0;\n\n function drag(selection) {\n selection\n .on(\"mousedown.drag\", mousedowned)\n .filter(touchable)\n .on(\"touchstart.drag\", touchstarted)\n .on(\"touchmove.drag\", touchmoved, nonpassive)\n .on(\"touchend.drag touchcancel.drag\", touchended)\n .style(\"touch-action\", \"none\")\n .style(\"-webkit-tap-highlight-color\", \"rgba(0,0,0,0)\");\n }\n\n function mousedowned(event, d) {\n if (touchending || !filter.call(this, event, d)) return;\n var gesture = beforestart(this, container.call(this, event, d), event, d, \"mouse\");\n if (!gesture) return;\n select(event.view)\n .on(\"mousemove.drag\", mousemoved, nonpassivecapture)\n .on(\"mouseup.drag\", mouseupped, nonpassivecapture);\n nodrag(event.view);\n nopropagation(event);\n mousemoving = false;\n mousedownx = event.clientX;\n mousedowny = event.clientY;\n gesture(\"start\", event);\n }\n\n function mousemoved(event) {\n noevent(event);\n if (!mousemoving) {\n var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;\n mousemoving = dx * dx + dy * dy > clickDistance2;\n }\n gestures.mouse(\"drag\", event);\n }\n\n function mouseupped(event) {\n select(event.view).on(\"mousemove.drag mouseup.drag\", null);\n yesdrag(event.view, mousemoving);\n noevent(event);\n gestures.mouse(\"end\", event);\n }\n\n function touchstarted(event, d) {\n if (!filter.call(this, event, d)) return;\n var touches = event.changedTouches,\n c = container.call(this, event, d),\n n = touches.length, i, gesture;\n\n for (i = 0; i < n; ++i) {\n if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {\n nopropagation(event);\n gesture(\"start\", event, touches[i]);\n }\n }\n }\n\n function touchmoved(event) {\n var touches = event.changedTouches,\n n = touches.length, i, gesture;\n\n for (i = 0; i < n; ++i) {\n if (gesture = gestures[touches[i].identifier]) {\n noevent(event);\n gesture(\"drag\", event, touches[i]);\n }\n }\n }\n\n function touchended(event) {\n var touches = event.changedTouches,\n n = touches.length, i, gesture;\n\n if (touchending) clearTimeout(touchending);\n touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!\n for (i = 0; i < n; ++i) {\n if (gesture = gestures[touches[i].identifier]) {\n nopropagation(event);\n gesture(\"end\", event, touches[i]);\n }\n }\n }\n\n function beforestart(that, container, event, d, identifier, touch) {\n var dispatch = listeners.copy(),\n p = pointer(touch || event, container), dx, dy,\n s;\n\n if ((s = subject.call(that, new DragEvent(\"beforestart\", {\n sourceEvent: event,\n target: drag,\n identifier,\n active,\n x: p[0],\n y: p[1],\n dx: 0,\n dy: 0,\n dispatch\n }), d)) == null) return;\n\n dx = s.x - p[0] || 0;\n dy = s.y - p[1] || 0;\n\n return function gesture(type, event, touch) {\n var p0 = p, n;\n switch (type) {\n case \"start\": gestures[identifier] = gesture, n = active++; break;\n case \"end\": delete gestures[identifier], --active; // falls through\n case \"drag\": p = pointer(touch || event, container), n = active; break;\n }\n dispatch.call(\n type,\n that,\n new DragEvent(type, {\n sourceEvent: event,\n subject: s,\n target: drag,\n identifier,\n active: n,\n x: p[0] + dx,\n y: p[1] + dy,\n dx: p[0] - p0[0],\n dy: p[1] - p0[1],\n dispatch\n }),\n d\n );\n };\n }\n\n drag.filter = function(_) {\n return arguments.length ? (filter = typeof _ === \"function\" ? _ : constant(!!_), drag) : filter;\n };\n\n drag.container = function(_) {\n return arguments.length ? (container = typeof _ === \"function\" ? _ : constant(_), drag) : container;\n };\n\n drag.subject = function(_) {\n return arguments.length ? (subject = typeof _ === \"function\" ? _ : constant(_), drag) : subject;\n };\n\n drag.touchable = function(_) {\n return arguments.length ? (touchable = typeof _ === \"function\" ? _ : constant(!!_), drag) : touchable;\n };\n\n drag.on = function() {\n var value = listeners.on.apply(listeners, arguments);\n return value === listeners ? drag : value;\n };\n\n drag.clickDistance = function(_) {\n return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);\n };\n\n return drag;\n}\n","var epsilon2 = 1e-12;\n\nfunction cosh(x) {\n return ((x = Math.exp(x)) + 1 / x) / 2;\n}\n\nfunction sinh(x) {\n return ((x = Math.exp(x)) - 1 / x) / 2;\n}\n\nfunction tanh(x) {\n return ((x = Math.exp(2 * x)) - 1) / (x + 1);\n}\n\nexport default (function zoomRho(rho, rho2, rho4) {\n\n // p0 = [ux0, uy0, w0]\n // p1 = [ux1, uy1, w1]\n function zoom(p0, p1) {\n var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],\n ux1 = p1[0], uy1 = p1[1], w1 = p1[2],\n dx = ux1 - ux0,\n dy = uy1 - uy0,\n d2 = dx * dx + dy * dy,\n i,\n S;\n\n // Special case for u0 ≅ u1.\n if (d2 < epsilon2) {\n S = Math.log(w1 / w0) / rho;\n i = function(t) {\n return [\n ux0 + t * dx,\n uy0 + t * dy,\n w0 * Math.exp(rho * t * S)\n ];\n }\n }\n\n // General case.\n else {\n var d1 = Math.sqrt(d2),\n b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),\n b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),\n r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),\n r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);\n S = (r1 - r0) / rho;\n i = function(t) {\n var s = t * S,\n coshr0 = cosh(r0),\n u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));\n return [\n ux0 + u * dx,\n uy0 + u * dy,\n w0 * coshr0 / cosh(rho * s + r0)\n ];\n }\n }\n\n i.duration = S * 1000 * rho / Math.SQRT2;\n\n return i;\n }\n\n zoom.rho = function(_) {\n var _1 = Math.max(1e-3, +_), _2 = _1 * _1, _4 = _2 * _2;\n return zoomRho(_1, _2, _4);\n };\n\n return zoom;\n})(Math.SQRT2, 2, 4);\n","export default x => () => x;\n","export default function ZoomEvent(type, {\n sourceEvent,\n target,\n transform,\n dispatch\n}) {\n Object.defineProperties(this, {\n type: {value: type, enumerable: true, configurable: true},\n sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},\n target: {value: target, enumerable: true, configurable: true},\n transform: {value: transform, enumerable: true, configurable: true},\n _: {value: dispatch}\n });\n}\n","export function nopropagation(event) {\n event.stopImmediatePropagation();\n}\n\nexport default function(event) {\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n","import {dispatch} from \"d3-dispatch\";\nimport {dragDisable, dragEnable} from \"d3-drag\";\nimport {interpolateZoom} from \"d3-interpolate\";\nimport {select, pointer} from \"d3-selection\";\nimport {interrupt} from \"d3-transition\";\nimport constant from \"./constant.js\";\nimport ZoomEvent from \"./event.js\";\nimport {Transform, identity} from \"./transform.js\";\nimport noevent, {nopropagation} from \"./noevent.js\";\n\n// Ignore right-click, since that should open the context menu.\n// except for pinch-to-zoom, which is sent as a wheel+ctrlKey event\nfunction defaultFilter(event) {\n return (!event.ctrlKey || event.type === 'wheel') && !event.button;\n}\n\nfunction defaultExtent() {\n var e = this;\n if (e instanceof SVGElement) {\n e = e.ownerSVGElement || e;\n if (e.hasAttribute(\"viewBox\")) {\n e = e.viewBox.baseVal;\n return [[e.x, e.y], [e.x + e.width, e.y + e.height]];\n }\n return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];\n }\n return [[0, 0], [e.clientWidth, e.clientHeight]];\n}\n\nfunction defaultTransform() {\n return this.__zoom || identity;\n}\n\nfunction defaultWheelDelta(event) {\n return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);\n}\n\nfunction defaultTouchable() {\n return navigator.maxTouchPoints || (\"ontouchstart\" in this);\n}\n\nfunction defaultConstrain(transform, extent, translateExtent) {\n var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],\n dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],\n dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],\n dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];\n return transform.translate(\n dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),\n dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)\n );\n}\n\nexport default function() {\n var filter = defaultFilter,\n extent = defaultExtent,\n constrain = defaultConstrain,\n wheelDelta = defaultWheelDelta,\n touchable = defaultTouchable,\n scaleExtent = [0, Infinity],\n translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],\n duration = 250,\n interpolate = interpolateZoom,\n listeners = dispatch(\"start\", \"zoom\", \"end\"),\n touchstarting,\n touchfirst,\n touchending,\n touchDelay = 500,\n wheelDelay = 150,\n clickDistance2 = 0,\n tapDistance = 10;\n\n function zoom(selection) {\n selection\n .property(\"__zoom\", defaultTransform)\n .on(\"wheel.zoom\", wheeled, {passive: false})\n .on(\"mousedown.zoom\", mousedowned)\n .on(\"dblclick.zoom\", dblclicked)\n .filter(touchable)\n .on(\"touchstart.zoom\", touchstarted)\n .on(\"touchmove.zoom\", touchmoved)\n .on(\"touchend.zoom touchcancel.zoom\", touchended)\n .style(\"-webkit-tap-highlight-color\", \"rgba(0,0,0,0)\");\n }\n\n zoom.transform = function(collection, transform, point, event) {\n var selection = collection.selection ? collection.selection() : collection;\n selection.property(\"__zoom\", defaultTransform);\n if (collection !== selection) {\n schedule(collection, transform, point, event);\n } else {\n selection.interrupt().each(function() {\n gesture(this, arguments)\n .event(event)\n .start()\n .zoom(null, typeof transform === \"function\" ? transform.apply(this, arguments) : transform)\n .end();\n });\n }\n };\n\n zoom.scaleBy = function(selection, k, p, event) {\n zoom.scaleTo(selection, function() {\n var k0 = this.__zoom.k,\n k1 = typeof k === \"function\" ? k.apply(this, arguments) : k;\n return k0 * k1;\n }, p, event);\n };\n\n zoom.scaleTo = function(selection, k, p, event) {\n zoom.transform(selection, function() {\n var e = extent.apply(this, arguments),\n t0 = this.__zoom,\n p0 = p == null ? centroid(e) : typeof p === \"function\" ? p.apply(this, arguments) : p,\n p1 = t0.invert(p0),\n k1 = typeof k === \"function\" ? k.apply(this, arguments) : k;\n return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);\n }, p, event);\n };\n\n zoom.translateBy = function(selection, x, y, event) {\n zoom.transform(selection, function() {\n return constrain(this.__zoom.translate(\n typeof x === \"function\" ? x.apply(this, arguments) : x,\n typeof y === \"function\" ? y.apply(this, arguments) : y\n ), extent.apply(this, arguments), translateExtent);\n }, null, event);\n };\n\n zoom.translateTo = function(selection, x, y, p, event) {\n zoom.transform(selection, function() {\n var e = extent.apply(this, arguments),\n t = this.__zoom,\n p0 = p == null ? centroid(e) : typeof p === \"function\" ? p.apply(this, arguments) : p;\n return constrain(identity.translate(p0[0], p0[1]).scale(t.k).translate(\n typeof x === \"function\" ? -x.apply(this, arguments) : -x,\n typeof y === \"function\" ? -y.apply(this, arguments) : -y\n ), e, translateExtent);\n }, p, event);\n };\n\n function scale(transform, k) {\n k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));\n return k === transform.k ? transform : new Transform(k, transform.x, transform.y);\n }\n\n function translate(transform, p0, p1) {\n var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k;\n return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);\n }\n\n function centroid(extent) {\n return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];\n }\n\n function schedule(transition, transform, point, event) {\n transition\n .on(\"start.zoom\", function() { gesture(this, arguments).event(event).start(); })\n .on(\"interrupt.zoom end.zoom\", function() { gesture(this, arguments).event(event).end(); })\n .tween(\"zoom\", function() {\n var that = this,\n args = arguments,\n g = gesture(that, args).event(event),\n e = extent.apply(that, args),\n p = point == null ? centroid(e) : typeof point === \"function\" ? point.apply(that, args) : point,\n w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),\n a = that.__zoom,\n b = typeof transform === \"function\" ? transform.apply(that, args) : transform,\n i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));\n return function(t) {\n if (t === 1) t = b; // Avoid rounding error on end.\n else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }\n g.zoom(null, t);\n };\n });\n }\n\n function gesture(that, args, clean) {\n return (!clean && that.__zooming) || new Gesture(that, args);\n }\n\n function Gesture(that, args) {\n this.that = that;\n this.args = args;\n this.active = 0;\n this.sourceEvent = null;\n this.extent = extent.apply(that, args);\n this.taps = 0;\n }\n\n Gesture.prototype = {\n event: function(event) {\n if (event) this.sourceEvent = event;\n return this;\n },\n start: function() {\n if (++this.active === 1) {\n this.that.__zooming = this;\n this.emit(\"start\");\n }\n return this;\n },\n zoom: function(key, transform) {\n if (this.mouse && key !== \"mouse\") this.mouse[1] = transform.invert(this.mouse[0]);\n if (this.touch0 && key !== \"touch\") this.touch0[1] = transform.invert(this.touch0[0]);\n if (this.touch1 && key !== \"touch\") this.touch1[1] = transform.invert(this.touch1[0]);\n this.that.__zoom = transform;\n this.emit(\"zoom\");\n return this;\n },\n end: function() {\n if (--this.active === 0) {\n delete this.that.__zooming;\n this.emit(\"end\");\n }\n return this;\n },\n emit: function(type) {\n var d = select(this.that).datum();\n listeners.call(\n type,\n this.that,\n new ZoomEvent(type, {\n sourceEvent: this.sourceEvent,\n target: zoom,\n type,\n transform: this.that.__zoom,\n dispatch: listeners\n }),\n d\n );\n }\n };\n\n function wheeled(event, ...args) {\n if (!filter.apply(this, arguments)) return;\n var g = gesture(this, args).event(event),\n t = this.__zoom,\n k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),\n p = pointer(event);\n\n // If the mouse is in the same location as before, reuse it.\n // If there were recent wheel events, reset the wheel idle timeout.\n if (g.wheel) {\n if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {\n g.mouse[1] = t.invert(g.mouse[0] = p);\n }\n clearTimeout(g.wheel);\n }\n\n // If this wheel event won’t trigger a transform change, ignore it.\n else if (t.k === k) return;\n\n // Otherwise, capture the mouse point and location at the start.\n else {\n g.mouse = [p, t.invert(p)];\n interrupt(this);\n g.start();\n }\n\n noevent(event);\n g.wheel = setTimeout(wheelidled, wheelDelay);\n g.zoom(\"mouse\", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));\n\n function wheelidled() {\n g.wheel = null;\n g.end();\n }\n }\n\n function mousedowned(event, ...args) {\n if (touchending || !filter.apply(this, arguments)) return;\n var currentTarget = event.currentTarget,\n g = gesture(this, args, true).event(event),\n v = select(event.view).on(\"mousemove.zoom\", mousemoved, true).on(\"mouseup.zoom\", mouseupped, true),\n p = pointer(event, currentTarget),\n x0 = event.clientX,\n y0 = event.clientY;\n\n dragDisable(event.view);\n nopropagation(event);\n g.mouse = [p, this.__zoom.invert(p)];\n interrupt(this);\n g.start();\n\n function mousemoved(event) {\n noevent(event);\n if (!g.moved) {\n var dx = event.clientX - x0, dy = event.clientY - y0;\n g.moved = dx * dx + dy * dy > clickDistance2;\n }\n g.event(event)\n .zoom(\"mouse\", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));\n }\n\n function mouseupped(event) {\n v.on(\"mousemove.zoom mouseup.zoom\", null);\n dragEnable(event.view, g.moved);\n noevent(event);\n g.event(event).end();\n }\n }\n\n function dblclicked(event, ...args) {\n if (!filter.apply(this, arguments)) return;\n var t0 = this.__zoom,\n p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),\n p1 = t0.invert(p0),\n k1 = t0.k * (event.shiftKey ? 0.5 : 2),\n t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);\n\n noevent(event);\n if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);\n else select(this).call(zoom.transform, t1, p0, event);\n }\n\n function touchstarted(event, ...args) {\n if (!filter.apply(this, arguments)) return;\n var touches = event.touches,\n n = touches.length,\n g = gesture(this, args, event.changedTouches.length === n).event(event),\n started, i, t, p;\n\n nopropagation(event);\n for (i = 0; i < n; ++i) {\n t = touches[i], p = pointer(t, this);\n p = [p, this.__zoom.invert(p), t.identifier];\n if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting;\n else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0;\n }\n\n if (touchstarting) touchstarting = clearTimeout(touchstarting);\n\n if (started) {\n if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);\n interrupt(this);\n g.start();\n }\n }\n\n function touchmoved(event, ...args) {\n if (!this.__zooming) return;\n var g = gesture(this, args).event(event),\n touches = event.changedTouches,\n n = touches.length, i, t, p, l;\n\n noevent(event);\n for (i = 0; i < n; ++i) {\n t = touches[i], p = pointer(t, this);\n if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;\n else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;\n }\n t = g.that.__zoom;\n if (g.touch1) {\n var p0 = g.touch0[0], l0 = g.touch0[1],\n p1 = g.touch1[0], l1 = g.touch1[1],\n dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,\n dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;\n t = scale(t, Math.sqrt(dp / dl));\n p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];\n l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];\n }\n else if (g.touch0) p = g.touch0[0], l = g.touch0[1];\n else return;\n\n g.zoom(\"touch\", constrain(translate(t, p, l), g.extent, translateExtent));\n }\n\n function touchended(event, ...args) {\n if (!this.__zooming) return;\n var g = gesture(this, args).event(event),\n touches = event.changedTouches,\n n = touches.length, i, t;\n\n nopropagation(event);\n if (touchending) clearTimeout(touchending);\n touchending = setTimeout(function() { touchending = null; }, touchDelay);\n for (i = 0; i < n; ++i) {\n t = touches[i];\n if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;\n else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;\n }\n if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;\n if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);\n else {\n g.end();\n // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.\n if (g.taps === 2) {\n t = pointer(t, this);\n if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {\n var p = select(this).on(\"dblclick.zoom\");\n if (p) p.apply(this, arguments);\n }\n }\n }\n }\n\n zoom.wheelDelta = function(_) {\n return arguments.length ? (wheelDelta = typeof _ === \"function\" ? _ : constant(+_), zoom) : wheelDelta;\n };\n\n zoom.filter = function(_) {\n return arguments.length ? (filter = typeof _ === \"function\" ? _ : constant(!!_), zoom) : filter;\n };\n\n zoom.touchable = function(_) {\n return arguments.length ? (touchable = typeof _ === \"function\" ? _ : constant(!!_), zoom) : touchable;\n };\n\n zoom.extent = function(_) {\n return arguments.length ? (extent = typeof _ === \"function\" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;\n };\n\n zoom.scaleExtent = function(_) {\n return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];\n };\n\n zoom.translateExtent = function(_) {\n return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];\n };\n\n zoom.constrain = function(_) {\n return arguments.length ? (constrain = _, zoom) : constrain;\n };\n\n zoom.duration = function(_) {\n return arguments.length ? (duration = +_, zoom) : duration;\n };\n\n zoom.interpolate = function(_) {\n return arguments.length ? (interpolate = _, zoom) : interpolate;\n };\n\n zoom.on = function() {\n var value = listeners.on.apply(listeners, arguments);\n return value === listeners ? zoom : value;\n };\n\n zoom.clickDistance = function(_) {\n return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);\n };\n\n zoom.tapDistance = function(_) {\n return arguments.length ? (tapDistance = +_, zoom) : tapDistance;\n };\n\n return zoom;\n}\n","\n\n\n","\n\n{#if asChild && $subOpen}\n\t\n{:else if transition && $subOpen}\n\t\n\t\t\n\t\n{:else if inTransition && outTransition && $subOpen}\n\t\n\t\t\n\t\n{:else if inTransition && $subOpen}\n\t\n\t\t\n\t\n{:else if outTransition && $subOpen}\n\t\n\t\t\n\t\n{:else if $subOpen}\n\t\n\t\t\n\t\n{/if}\n","\n\n{#if asChild}\n\t\n{:else}\n\t\n\t\t\n\t\n{/if}\n","import { onDestroy } from \"svelte\";\n/**\n * Safely calls `onDestroy` and catches any errors that occur.\n */\nexport function safeOnDestroy(fn) {\n try {\n onDestroy(fn);\n }\n catch {\n return fn();\n }\n}\n","import { isBrowser, safeOnDestroy } from \"./index.js\";\nimport { derived, writable, } from \"svelte/store\";\n/**\n * A utility function that creates a derived store that automatically\n * unsubscribes from its dependencies.\n *\n * Originally written by @tglide for use in Melt UI. <3\n *\n * @template S - The type of the stores object\n * @template T - The type of the derived store\n * @param stores - The stores object to derive from\n * @param fn - The function to derive the store from\n * @returns A derived store that automatically unsubscribes from its dependencies\n */\nexport function derivedWithUnsubscribe(stores, fn) {\n let unsubscribers = [];\n const onUnsubscribe = (cb) => {\n unsubscribers.push(cb);\n };\n const unsubscribe = () => {\n // Call all of the unsubscribe functions from the previous run of the function\n unsubscribers.forEach((fn) => fn());\n // Clear the list of unsubscribe functions\n unsubscribers = [];\n };\n const derivedStore = derived(stores, ($storeValues) => {\n unsubscribe();\n return fn($storeValues, onUnsubscribe);\n });\n safeOnDestroy(unsubscribe);\n const subscribe = (...args) => {\n const unsub = derivedStore.subscribe(...args);\n return () => {\n unsub();\n unsubscribe();\n };\n };\n return {\n ...derivedStore,\n subscribe,\n };\n}\n/**\n * A utility function that creates an effect from a set of stores and a function.\n * The effect is automatically cleaned up when the component is destroyed.\n *\n * Originally written by @tglide for use in Melt UI. <3\n *\n * @template S - The type of the stores object\n * @param stores - The stores object to derive from\n * @param fn - The function to run when the stores change\n * @returns A function that can be used to unsubscribe the effect\n */\nexport function clientEffect(stores, fn) {\n if (!isBrowser)\n return () => { };\n // Create a derived store that contains the stores object and an onUnsubscribe function\n const unsub = derivedWithUnsubscribe(stores, (stores, onUnsubscribe) => {\n return {\n stores,\n onUnsubscribe,\n };\n }).subscribe(({ stores, onUnsubscribe }) => {\n const returned = fn(stores);\n // If the function returns a cleanup function, call it when the effect is unsubscribed\n if (returned) {\n onUnsubscribe(returned);\n }\n });\n // Automatically unsubscribe the effect when the component is destroyed\n safeOnDestroy(unsub);\n return unsub;\n}\n/**\n * Given an object of properties, returns an object of writable stores\n * with the same properties and values.\n */\nexport function toWritableStores(properties) {\n const result = {};\n Object.keys(properties).forEach((key) => {\n const propertyKey = key;\n const value = properties[propertyKey];\n result[propertyKey] = writable(value);\n });\n return result;\n}\n/**\n * Returns a function that can be used to update the values of options\n * in a store based on the modification of a prop.\n */\nexport function getOptionUpdater(options) {\n return function (key, value) {\n if (value === undefined)\n return;\n const store = options[key];\n if (store) {\n store.set(value);\n }\n };\n}\n","/**\n * A utility function that converts a style object to a string,\n * which can be used as the value of the `style` attribute for\n * an element.\n *\n * @param style - The style object to convert\n * @returns The style object as a string\n */\nexport function styleToString(style) {\n return Object.keys(style).reduce((str, key) => {\n if (style[key] === undefined)\n return str;\n return str + `${key}:${style[key]};`;\n }, \"\");\n}\n/* Global cursor state */\nlet currentState = null;\n/* Global cursor element */\nlet element = null;\n/**\n * Returns the cursor style for a given cursor state.\n */\nexport function getCursorStyle(state) {\n switch (state) {\n case \"horizontal\":\n return \"ew-resize\";\n case \"horizontal-max\":\n return \"w-resize\";\n case \"horizontal-min\":\n return \"e-resize\";\n case \"vertical\":\n return \"ns-resize\";\n case \"vertical-max\":\n return \"n-resize\";\n case \"vertical-min\":\n return \"s-resize\";\n }\n}\n/**\n * Resets the global cursor style to the default.\n */\nexport function resetGlobalCursorStyle() {\n if (element === null)\n return;\n document.head.removeChild(element);\n currentState = null;\n element = null;\n}\n/**\n * Sets the global cursor style to the given state.\n */\nexport function setGlobalCursorStyle(state) {\n if (currentState === state)\n return;\n currentState = state;\n const style = getCursorStyle(state);\n if (element === null) {\n element = document.createElement(\"style\");\n document.head.appendChild(element);\n }\n element.innerHTML = `*{cursor: ${style}!important;}`;\n}\n/**\n * Computes the flexbox style for a pane given its layout and drag state.\n */\nexport function computePaneFlexBoxStyle({ defaultSize, dragState, layout, paneData, paneIndex, precision = 3, }) {\n const size = layout[paneIndex];\n let flexGrow;\n if (size == null) {\n // Initial render (before panes have registered themselves)\n // To support server rendering, fallback to default size\n flexGrow = defaultSize ?? \"1\";\n }\n else if (paneData.length === 1) {\n // Single pane group should always fill full width/height\n flexGrow = \"1\";\n }\n else {\n flexGrow = size.toPrecision(precision);\n }\n return styleToString({\n \"flex-basis\": 0,\n \"flex-grow\": flexGrow,\n \"flex-shrink\": 1,\n // Without this, pane sizes may be unintentionally overridden by their content\n overflow: \"hidden\",\n // Disable pointer events inside of a pane during resize\n // This avoid edge cases like nested iframes\n \"pointer-events\": dragState !== null ? \"none\" : undefined,\n });\n}\n","/**\n * A utility function that calculates the `aria-valuemax`, `aria-valuemin`,\n * and `aria-valuenow` values for a pane based on its layout and constraints.\n */\nexport function calculateAriaValues({ layout, panesArray, pivotIndices, }) {\n let currentMinSize = 0;\n let currentMaxSize = 100;\n let totalMinSize = 0;\n let totalMaxSize = 0;\n const firstIndex = pivotIndices[0];\n // A pane's effective min/max sizes also need to account for other pane's sizes.\n for (let i = 0; i < panesArray.length; i++) {\n const { constraints } = panesArray[i];\n const { maxSize = 100, minSize = 0 } = constraints;\n if (i === firstIndex) {\n currentMinSize = minSize;\n currentMaxSize = maxSize;\n }\n else {\n totalMinSize += minSize;\n totalMaxSize += maxSize;\n }\n }\n const valueMax = Math.min(currentMaxSize, 100 - totalMinSize);\n const valueMin = Math.max(currentMinSize, 100 - totalMaxSize);\n const valueNow = layout[firstIndex];\n return {\n valueMax,\n valueMin,\n valueNow,\n };\n}\n","import { nanoid } from \"nanoid/non-secure\";\n/**\n * If an id is provided return it, otherwise generate a new id and return that.\n */\nexport function generateId(idFromProps = null) {\n if (idFromProps == null)\n return nanoid(10);\n return idFromProps;\n}\n","export const LOCAL_STORAGE_DEBOUNCE_INTERVAL = 100;\nexport const PRECISION = 10;\n","import { get } from \"svelte/store\";\nimport { LOCAL_STORAGE_DEBOUNCE_INTERVAL } from \"../constants.js\";\n/**\n * Initializes the storage object with the appropriate getItem\n * and setItem functions depending on the environment (browser or not).\n */\nexport function initializeStorage(storageObject) {\n try {\n if (typeof localStorage === \"undefined\") {\n throw new Error(\"localStorage is not supported in this environment\");\n }\n storageObject.getItem = (name) => localStorage.getItem(name);\n storageObject.setItem = (name, value) => localStorage.setItem(name, value);\n }\n catch (err) {\n // eslint-disable-next-line no-console\n console.error(err);\n storageObject.getItem = () => null;\n storageObject.setItem = () => { };\n }\n}\n/**\n * Returns the key to use for storing the pane group state in local storage.\n */\nfunction getPaneGroupKey(autoSaveId) {\n return `paneforge:${autoSaveId}`;\n}\n/**\n * Returns a key to use for storing the pane state in local storage.\n * The key is based on the pane order and constraints.\n */\nfunction getPaneKey(panes) {\n const sortedPaneIds = panes\n .map((pane) => {\n const { constraints, id, idIsFromProps, order } = pane;\n return idIsFromProps\n ? id\n : order\n ? `${order}:${JSON.stringify(constraints)}`\n : JSON.stringify(constraints);\n })\n .sort()\n .join(\",\");\n return sortedPaneIds;\n}\n/**\n * Loads the serialized pane group state from local storage.\n * If the state is not found, returns null.\n */\nfunction loadSerializedPaneGroupState(autoSaveId, storage) {\n try {\n const paneGroupKey = getPaneGroupKey(autoSaveId);\n const serialized = storage.getItem(paneGroupKey);\n const parsed = JSON.parse(serialized || \"\");\n if (typeof parsed === \"object\" && parsed !== null) {\n return parsed;\n }\n }\n catch {\n // noop\n }\n return null;\n}\n/**\n * Loads the pane group state from local storage.\n * If the state is not found, returns null.\n */\nexport function loadPaneGroupState(autoSaveId, panes, storage) {\n const state = loadSerializedPaneGroupState(autoSaveId, storage) || {};\n const paneKey = getPaneKey(panes);\n return state[paneKey] || null;\n}\n/**\n * Saves the pane group state to local storage.\n */\nexport function savePaneGroupState(autoSaveId, panes, paneSizesBeforeCollapse, sizes, storage) {\n const paneGroupKey = getPaneGroupKey(autoSaveId);\n const paneKey = getPaneKey(panes);\n const state = loadSerializedPaneGroupState(autoSaveId, storage) || {};\n state[paneKey] = {\n expandToSizes: Object.fromEntries(paneSizesBeforeCollapse.entries()),\n layout: sizes,\n };\n try {\n storage.setItem(paneGroupKey, JSON.stringify(state));\n }\n catch (error) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n}\nconst debounceMap = {};\n/**\n * Returns a debounced version of the given function.\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nfunction debounce(callback, durationMs = 10) {\n let timeoutId = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const callable = (...args) => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n timeoutId = setTimeout(() => {\n callback(...args);\n }, durationMs);\n };\n return callable;\n}\n/**\n * Updates the values in local storage based on the current state of\n * the pane group.\n * This function is debounced to limit the frequency of local storage writes.\n */\nexport function updateStorageValues({ autoSaveId, layout, storage, paneDataArrayStore, paneSizeBeforeCollapseStore, }) {\n const $paneDataArray = get(paneDataArrayStore);\n // If this pane has been configured to persist sizing\n // information, save sizes to local storage.\n if (layout.length === 0 || layout.length !== $paneDataArray.length)\n return;\n let debouncedSave = debounceMap[autoSaveId];\n // Limit frequency of local storage writes.\n if (debouncedSave == null) {\n debouncedSave = debounce(savePaneGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);\n debounceMap[autoSaveId] = debouncedSave;\n }\n // Clone mutable data before passing to the debounced function,\n // else we run the risk of saving an incorrect combination of mutable and immutable values to state.\n const clonedPaneDataArray = [...$paneDataArray];\n const $paneSizeBeforeCollapse = get(paneSizeBeforeCollapseStore);\n const clonedPaneSizesBeforeCollapse = new Map($paneSizeBeforeCollapse);\n debouncedSave(autoSaveId, clonedPaneDataArray, clonedPaneSizesBeforeCollapse, layout, storage);\n}\n","/**\n * Removes all undefined properties from the given object.\n */\nexport function removeUndefined(obj) {\n const result = {};\n for (const key in obj) {\n const value = obj[key];\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n","/**\n * Executes an array of callback functions with the same arguments.\n * @template T The types of the arguments that the callback functions take.\n * @param n array of callback functions to execute.\n * @returns A new function that executes all of the original callback functions with the same arguments.\n */\nexport function chain(...callbacks) {\n return (...args) => {\n for (const callback of callbacks) {\n if (typeof callback === \"function\") {\n callback(...args);\n }\n }\n };\n}\n","/**\n * Adds an event listener to the specified target element(s) for the given event(s), and returns a function to remove it.\n * @param target The target element(s) to add the event listener to.\n * @param event The event(s) to listen for.\n * @param handler The function to be called when the event is triggered.\n * @param options An optional object that specifies characteristics about the event listener.\n * @returns A function that removes the event listener from the target element(s).\n */\nexport function addEventListener(target, event, handler, options) {\n const events = Array.isArray(event) ? event : [event];\n // Add the event listener to each specified event for the target element(s).\n events.forEach((_event) => target.addEventListener(_event, handler, options));\n // Return a function that removes the event listener from the target element(s).\n return () => {\n events.forEach((_event) => target.removeEventListener(_event, handler, options));\n };\n}\n","import { PRECISION } from \"../constants.js\";\n/**\n * Compares two numbers for equality with a given fractional precision.\n */\nexport function areNumbersAlmostEqual(actual, expected, fractionDigits = PRECISION) {\n return compareNumbersWithTolerance(actual, expected, fractionDigits) === 0;\n}\n/**\n * Compares two numbers with a given tolerance.\n *\n * @returns `-1` if `actual` is less than `expected`, `0` if they are equal,\n * and `1` if `actual` is greater than `expected`.\n */\nexport function compareNumbersWithTolerance(actual, expected, fractionDigits = PRECISION) {\n const roundedActual = roundTo(actual, fractionDigits);\n const roundedExpected = roundTo(expected, fractionDigits);\n return Math.sign(roundedActual - roundedExpected);\n}\n/**\n * Compares two arrays for equality.\n */\nexport function areArraysEqual(arrA, arrB) {\n if (arrA.length !== arrB.length)\n return false;\n for (let index = 0; index < arrA.length; index++) {\n if (arrA[index] !== arrB[index])\n return false;\n }\n return true;\n}\n/**\n * Rounds a number to a given number of decimal places.\n */\nfunction roundTo(value, decimals) {\n return parseFloat(value.toFixed(decimals));\n}\n","export function assert(\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexpectedCondition, message = \"Assertion failed!\") {\n if (!expectedCondition) {\n // eslint-disable-next-line no-console\n console.error(message);\n throw Error(message);\n }\n}\n","import { PRECISION } from \"../constants.js\";\nimport { assert } from \"./assert.js\";\nimport { compareNumbersWithTolerance } from \"./compare.js\";\n/**\n * Resizes a pane based on its constraints.\n */\nexport function resizePane({ paneConstraints: paneConstraintsArray, paneIndex, initialSize, }) {\n const paneConstraints = paneConstraintsArray[paneIndex];\n assert(paneConstraints != null, \"Pane constraints should not be null.\");\n const { collapsedSize = 0, collapsible, maxSize = 100, minSize = 0 } = paneConstraints;\n let newSize = initialSize;\n if (compareNumbersWithTolerance(newSize, minSize) < 0) {\n newSize = getAdjustedSizeForCollapsible(newSize, collapsible, collapsedSize, minSize);\n }\n newSize = Math.min(maxSize, newSize);\n return parseFloat(newSize.toFixed(PRECISION));\n}\n/**\n * Adjusts the size of a pane based on its collapsible state.\n *\n * If the pane is collapsible, the size will be snapped to the collapsed size\n * or the minimum size based on the halfway point.\n */\nfunction getAdjustedSizeForCollapsible(size, collapsible, collapsedSize, minSize) {\n if (!collapsible)\n return minSize;\n // Snap collapsible panes closed or open based on the halfway point.\n const halfwayPoint = (collapsedSize + minSize) / 2;\n return compareNumbersWithTolerance(size, halfwayPoint) < 0 ? collapsedSize : minSize;\n}\n","import { assert } from \"./assert.js\";\nimport { compareNumbersWithTolerance, areNumbersAlmostEqual, resizePane, } from \"./index.js\";\n/**\n * Adjusts the layout of panes based on the delta of the resize handle.\n * All units must be in percentages; pixel values should be pre-converted.\n *\n * Credit: https://github.com/bvaughn/react-resizable-panels\n */\nexport function adjustLayoutByDelta({ delta, layout: prevLayout, paneConstraints: paneConstraintsArray, pivotIndices, trigger, }) {\n if (areNumbersAlmostEqual(delta, 0))\n return prevLayout;\n const nextLayout = [...prevLayout];\n const [firstPivotIndex, secondPivotIndex] = pivotIndices;\n let deltaApplied = 0;\n // A resizing pane affects the panes before or after it.\n //\n // A negative delta means the pane(s) immediately after the resize handle should grow/expand by decreasing its offset.\n // Other panes may also need to shrink/contract (and shift) to make room, depending on the min weights.\n //\n // A positive delta means the pane(s) immediately before the resize handle should \"expand\".\n // This is accomplished by shrinking/contracting (and shifting) one or more of the panes after the resize handle.\n {\n // If this is a resize triggered by a keyboard event, our logic for expanding/collapsing is different.\n // We no longer check the halfway threshold because this may prevent the pane from expanding at all.\n if (trigger === \"keyboard\") {\n {\n // Check if we should expand a collapsed pane\n const index = delta < 0 ? secondPivotIndex : firstPivotIndex;\n const paneConstraints = paneConstraintsArray[index];\n assert(paneConstraints);\n if (paneConstraints.collapsible) {\n const prevSize = prevLayout[index];\n assert(prevSize != null);\n const paneConstraints = paneConstraintsArray[index];\n assert(paneConstraints);\n const { collapsedSize = 0, minSize = 0 } = paneConstraints;\n if (areNumbersAlmostEqual(prevSize, collapsedSize)) {\n const localDelta = minSize - prevSize;\n //DEBUG.push(` -> expand delta: ${localDelta}`);\n if (compareNumbersWithTolerance(localDelta, Math.abs(delta)) > 0) {\n delta = delta < 0 ? 0 - localDelta : localDelta;\n //DEBUG.push(` -> delta: ${delta}`);\n }\n }\n }\n }\n {\n // Check if we should collapse a pane at its minimum size\n const index = delta < 0 ? firstPivotIndex : secondPivotIndex;\n const paneConstraints = paneConstraintsArray[index];\n assert(paneConstraints);\n const { collapsible } = paneConstraints;\n if (collapsible) {\n const prevSize = prevLayout[index];\n assert(prevSize != null);\n const paneConstraints = paneConstraintsArray[index];\n assert(paneConstraints);\n const { collapsedSize = 0, minSize = 0 } = paneConstraints;\n if (areNumbersAlmostEqual(prevSize, minSize)) {\n const localDelta = prevSize - collapsedSize;\n if (compareNumbersWithTolerance(localDelta, Math.abs(delta)) > 0) {\n delta = delta < 0 ? 0 - localDelta : localDelta;\n }\n }\n }\n }\n }\n }\n {\n // Pre-calculate max available delta in the opposite direction of our pivot.\n // This will be the maximum amount we're allowed to expand/contract the panes in the primary direction.\n // If this amount is less than the requested delta, adjust the requested delta.\n // If this amount is greater than the requested delta, that's useful information too–\n // as an expanding pane might change from collapsed to min size.\n const increment = delta < 0 ? 1 : -1;\n let index = delta < 0 ? secondPivotIndex : firstPivotIndex;\n let maxAvailableDelta = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const prevSize = prevLayout[index];\n assert(prevSize != null);\n const maxSafeSize = resizePane({\n paneConstraints: paneConstraintsArray,\n paneIndex: index,\n initialSize: 100,\n });\n const delta = maxSafeSize - prevSize;\n maxAvailableDelta += delta;\n index += increment;\n if (index < 0 || index >= paneConstraintsArray.length) {\n break;\n }\n }\n const minAbsDelta = Math.min(Math.abs(delta), Math.abs(maxAvailableDelta));\n delta = delta < 0 ? 0 - minAbsDelta : minAbsDelta;\n }\n {\n // Delta added to a pane needs to be subtracted from other panes (within the constraints that those panes allow).\n const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;\n let index = pivotIndex;\n while (index >= 0 && index < paneConstraintsArray.length) {\n const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);\n const prevSize = prevLayout[index];\n assert(prevSize != null);\n const unsafeSize = prevSize - deltaRemaining;\n const safeSize = resizePane({\n paneConstraints: paneConstraintsArray,\n paneIndex: index,\n initialSize: unsafeSize,\n });\n if (!areNumbersAlmostEqual(prevSize, safeSize)) {\n deltaApplied += prevSize - safeSize;\n nextLayout[index] = safeSize;\n if (deltaApplied.toPrecision(3).localeCompare(Math.abs(delta).toPrecision(3), undefined, {\n numeric: true,\n }) >= 0) {\n break;\n }\n }\n if (delta < 0) {\n index--;\n }\n else {\n index++;\n }\n }\n }\n // If we were unable to resize any of the panes, return the previous state.\n // This will essentially bailout and ignore e.g. drags past a pane's boundaries\n if (areNumbersAlmostEqual(deltaApplied, 0)) {\n return prevLayout;\n }\n {\n // Now distribute the applied delta to the panes in the other direction\n const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;\n const prevSize = prevLayout[pivotIndex];\n assert(prevSize != null);\n const unsafeSize = prevSize + deltaApplied;\n const safeSize = resizePane({\n paneConstraints: paneConstraintsArray,\n paneIndex: pivotIndex,\n initialSize: unsafeSize,\n });\n // Adjust the pivot pane before, but only by the amount that surrounding panes were able to shrink/contract.\n nextLayout[pivotIndex] = safeSize;\n // Edge case where expanding or contracting one pane caused another one to change collapsed state\n if (!areNumbersAlmostEqual(safeSize, unsafeSize)) {\n let deltaRemaining = unsafeSize - safeSize;\n const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;\n let index = pivotIndex;\n while (index >= 0 && index < paneConstraintsArray.length) {\n const prevSize = nextLayout[index];\n assert(prevSize != null);\n const unsafeSize = prevSize + deltaRemaining;\n const safeSize = resizePane({\n paneConstraints: paneConstraintsArray,\n paneIndex: index,\n initialSize: unsafeSize,\n });\n if (!areNumbersAlmostEqual(prevSize, safeSize)) {\n deltaRemaining -= safeSize - prevSize;\n nextLayout[index] = safeSize;\n }\n if (areNumbersAlmostEqual(deltaRemaining, 0))\n break;\n delta > 0 ? index-- : index++;\n }\n }\n }\n const totalSize = nextLayout.reduce((total, size) => size + total, 0);\n if (!areNumbersAlmostEqual(totalSize, 100))\n return prevLayout;\n return nextLayout;\n}\n","export const isBrowser = typeof document !== \"undefined\";\nexport function isHTMLElement(element) {\n return element instanceof HTMLElement;\n}\nexport function isKeyDown(event) {\n return event.type === \"keydown\";\n}\nexport function isMouseEvent(event) {\n return event.type.startsWith(\"mouse\");\n}\nexport function isTouchEvent(event) {\n return event.type.startsWith(\"touch\");\n}\n","import { initializeStorage, loadPaneGroupState, resizePane, resetGlobalCursorStyle, setGlobalCursorStyle, updateStorageValues, adjustLayoutByDelta, areNumbersAlmostEqual, areArraysEqual, generateId, removeUndefined, clientEffect, toWritableStores, calculateAriaValues, addEventListener, computePaneFlexBoxStyle, styleToString, isBrowser, isHTMLElement, isKeyDown, isMouseEvent, isTouchEvent, } from \"./utils/index.js\";\nimport { derived, get, writable } from \"svelte/store\";\nimport { assert } from \"./utils/assert.js\";\nimport { onMount } from \"svelte\";\nexport const defaultStorage = {\n getItem: (name) => {\n initializeStorage(defaultStorage);\n return defaultStorage.getItem(name);\n },\n setItem: (name, value) => {\n initializeStorage(defaultStorage);\n defaultStorage.setItem(name, value);\n },\n};\nconst defaultProps = {\n id: null,\n onLayout: null,\n keyboardResizeBy: null,\n autoSaveId: null,\n direction: \"horizontal\",\n storage: defaultStorage,\n};\nexport function createPaneForge(props) {\n const withDefaults = {\n ...defaultProps,\n ...removeUndefined(props),\n };\n const options = toWritableStores(withDefaults);\n const { autoSaveId, direction, keyboardResizeBy, storage, onLayout } = options;\n const groupId = writable(generateId());\n const dragState = writable(null);\n const layout = writable([]);\n const paneDataArray = writable([]);\n const paneDataArrayChanged = writable(false);\n const paneIdToLastNotifiedSizeMap = writable({});\n const paneSizeBeforeCollapseMap = writable(new Map());\n const prevDelta = writable(0);\n clientEffect([groupId, layout, paneDataArray], ([$groupId, $layout, $paneDataArray]) => {\n const unsub = updateResizeHandleAriaValues({\n groupId: $groupId,\n layout: $layout,\n paneDataArray: $paneDataArray,\n });\n return unsub;\n });\n onMount(() => {\n const unsub = setResizeHandlerEventListeners();\n return unsub;\n });\n clientEffect([autoSaveId, layout, storage], ([$autoSaveId, $layout, $storage]) => {\n if (!$autoSaveId)\n return;\n updateStorageValues({\n autoSaveId: $autoSaveId,\n layout: $layout,\n storage: $storage,\n paneDataArrayStore: paneDataArray,\n paneSizeBeforeCollapseStore: paneSizeBeforeCollapseMap,\n });\n });\n function collapsePane(paneData) {\n const $prevLayout = get(layout);\n const $paneDataArray = get(paneDataArray);\n if (!paneData.constraints.collapsible)\n return;\n const paneConstraintsArray = $paneDataArray.map((paneData) => paneData.constraints);\n const { collapsedSize = 0, paneSize, pivotIndices, } = paneDataHelper($paneDataArray, paneData, $prevLayout);\n assert(paneSize != null);\n if (paneSize === collapsedSize)\n return;\n // Store the size before collapse, which is returned when `expand()` is called\n paneSizeBeforeCollapseMap.update((curr) => {\n curr.set(paneData.id, paneSize);\n return curr;\n });\n const isLastPane = findPaneDataIndex($paneDataArray, paneData) === $paneDataArray.length - 1;\n const delta = isLastPane ? paneSize - collapsedSize : collapsedSize - paneSize;\n const nextLayout = adjustLayoutByDelta({\n delta,\n layout: $prevLayout,\n paneConstraints: paneConstraintsArray,\n pivotIndices,\n trigger: \"imperative-api\",\n });\n if (areArraysEqual($prevLayout, nextLayout))\n return;\n layout.set(nextLayout);\n const $onLayout = get(onLayout);\n if ($onLayout) {\n $onLayout(nextLayout);\n }\n callPaneCallbacks($paneDataArray, nextLayout, get(paneIdToLastNotifiedSizeMap));\n }\n function getPaneSize(paneData) {\n const $layout = get(layout);\n const $paneDataArray = get(paneDataArray);\n const { paneSize } = paneDataHelper($paneDataArray, paneData, $layout);\n return paneSize;\n }\n const getPaneStyle = derived([paneDataArray, layout, dragState], ([$paneDataArray, $layout, $dragState]) => {\n return (paneData, defaultSize) => {\n const paneIndex = findPaneDataIndex($paneDataArray, paneData);\n return computePaneFlexBoxStyle({\n defaultSize,\n dragState: $dragState,\n layout: $layout,\n paneData: $paneDataArray,\n paneIndex,\n });\n };\n });\n function isPaneExpanded(paneData) {\n const $paneDataArray = get(paneDataArray);\n const $layout = get(layout);\n const { collapsedSize = 0, collapsible, paneSize, } = paneDataHelper($paneDataArray, paneData, $layout);\n return !collapsible || paneSize > collapsedSize;\n }\n function registerPane(paneData) {\n paneDataArray.update((curr) => {\n const newArr = [...curr, paneData];\n newArr.sort((paneA, paneB) => {\n const orderA = paneA.order;\n const orderB = paneB.order;\n if (orderA == null && orderB == null) {\n return 0;\n }\n else if (orderA == null) {\n return -1;\n }\n else if (orderB == null) {\n return 1;\n }\n else {\n return orderA - orderB;\n }\n });\n return newArr;\n });\n paneDataArrayChanged.set(true);\n }\n clientEffect([paneDataArrayChanged], ([$paneDataArrayChanged]) => {\n if (!$paneDataArrayChanged)\n return;\n paneDataArrayChanged.set(false);\n const $autoSaveId = get(autoSaveId);\n const $storage = get(storage);\n const $prevLayout = get(layout);\n const $paneDataArray = get(paneDataArray);\n // If this pane has been configured to persist sizing information,\n // default size should be restored from local storage if possible.\n let unsafeLayout = null;\n if ($autoSaveId) {\n const state = loadPaneGroupState($autoSaveId, $paneDataArray, $storage);\n if (state) {\n paneSizeBeforeCollapseMap.set(new Map(Object.entries(state.expandToSizes)));\n unsafeLayout = state.layout;\n }\n }\n if (unsafeLayout == null) {\n unsafeLayout = getUnsafeDefaultLayout({\n paneDataArray: $paneDataArray,\n });\n }\n // Validate even saved layouts in case something has changed since last render\n const nextLayout = validatePaneGroupLayout({\n layout: unsafeLayout,\n paneConstraints: $paneDataArray.map((paneData) => paneData.constraints),\n });\n if (areArraysEqual($prevLayout, nextLayout))\n return;\n layout.set(nextLayout);\n const $onLayout = get(onLayout);\n if ($onLayout) {\n $onLayout(nextLayout);\n }\n callPaneCallbacks($paneDataArray, nextLayout, get(paneIdToLastNotifiedSizeMap));\n });\n function registerResizeHandle(dragHandleId) {\n return function resizeHandler(event) {\n event.preventDefault();\n const $direction = get(direction);\n const $dragState = get(dragState);\n const $groupId = get(groupId);\n const $keyboardResizeBy = get(keyboardResizeBy);\n const $prevLayout = get(layout);\n const $paneDataArray = get(paneDataArray);\n const { initialLayout } = $dragState ?? {};\n const pivotIndices = getPivotIndices($groupId, dragHandleId);\n let delta = getDeltaPercentage(event, dragHandleId, $direction, $dragState, $keyboardResizeBy);\n if (delta === 0)\n return;\n // support RTL\n const isHorizontal = $direction === \"horizontal\";\n if (document.dir === \"rtl\" && isHorizontal) {\n delta = -delta;\n }\n const paneConstraints = $paneDataArray.map((paneData) => paneData.constraints);\n const nextLayout = adjustLayoutByDelta({\n delta,\n layout: initialLayout ?? $prevLayout,\n paneConstraints: paneConstraints,\n pivotIndices,\n trigger: isKeyDown(event) ? \"keyboard\" : \"mouse-or-touch\",\n });\n const layoutChanged = !areArraysEqual($prevLayout, nextLayout);\n // Only update the cursor for layout changes triggered by touch/mouse events (not keyboard)\n // Update the cursor even if the layout hasn't changed (we may need to show an invalid cursor state)\n if (isMouseEvent(event) || isTouchEvent(event)) {\n // Watch for multiple subsequent deltas; this might occur for tiny cursor movements.\n // In this case, Pane sizes might not change–\n // but updating cursor in this scenario would cause a flicker.\n const $prevDelta = get(prevDelta);\n if ($prevDelta != delta) {\n prevDelta.set(delta);\n if (!layoutChanged) {\n // If the pointer has moved too far to resize the pane any further,\n // update the cursor style for a visual clue.\n // This mimics VS Code behavior.\n if (isHorizontal) {\n setGlobalCursorStyle(delta < 0 ? \"horizontal-min\" : \"horizontal-max\");\n }\n else {\n setGlobalCursorStyle(delta < 0 ? \"vertical-min\" : \"vertical-max\");\n }\n }\n else {\n setGlobalCursorStyle(isHorizontal ? \"horizontal\" : \"vertical\");\n }\n }\n }\n if (layoutChanged) {\n layout.set(nextLayout);\n const $onLayout = get(onLayout);\n if ($onLayout) {\n $onLayout(nextLayout);\n }\n callPaneCallbacks($paneDataArray, nextLayout, get(paneIdToLastNotifiedSizeMap));\n }\n };\n }\n function resizePane(paneData, unsafePaneSize) {\n const $prevLayout = get(layout);\n const $paneDataArray = get(paneDataArray);\n const paneConstraintsArr = $paneDataArray.map((paneData) => paneData.constraints);\n const { paneSize, pivotIndices } = paneDataHelper($paneDataArray, paneData, $prevLayout);\n assert(paneSize != null);\n const isLastPane = findPaneDataIndex($paneDataArray, paneData) === $paneDataArray.length - 1;\n const delta = isLastPane ? paneSize - unsafePaneSize : unsafePaneSize - paneSize;\n const nextLayout = adjustLayoutByDelta({\n delta,\n layout: $prevLayout,\n paneConstraints: paneConstraintsArr,\n pivotIndices,\n trigger: \"imperative-api\",\n });\n if (areArraysEqual($prevLayout, nextLayout))\n return;\n layout.set(nextLayout);\n const $onLayout = get(onLayout);\n $onLayout?.(nextLayout);\n callPaneCallbacks($paneDataArray, nextLayout, get(paneIdToLastNotifiedSizeMap));\n }\n function startDragging(dragHandleId, event) {\n const $direction = get(direction);\n const $layout = get(layout);\n const handleElement = getResizeHandleElement(dragHandleId);\n assert(handleElement);\n const initialCursorPosition = getResizeEventCursorPosition($direction, event);\n dragState.set({\n dragHandleId,\n dragHandleRect: handleElement.getBoundingClientRect(),\n initialCursorPosition,\n initialLayout: $layout,\n });\n }\n function stopDragging() {\n resetGlobalCursorStyle();\n dragState.set(null);\n }\n function unregisterPane(paneData) {\n const $paneDataArray = get(paneDataArray);\n const index = findPaneDataIndex($paneDataArray, paneData);\n if (index < 0)\n return;\n paneDataArray.update((curr) => {\n curr.splice(index, 1);\n paneIdToLastNotifiedSizeMap.update((curr) => {\n delete curr[paneData.id];\n return curr;\n });\n paneDataArrayChanged.set(true);\n return curr;\n });\n }\n function isPaneCollapsed(paneData) {\n const $paneDataArray = get(paneDataArray);\n const $layout = get(layout);\n const { collapsedSize = 0, collapsible, paneSize, } = paneDataHelper($paneDataArray, paneData, $layout);\n return collapsible === true && paneSize === collapsedSize;\n }\n function expandPane(paneData) {\n const $prevLayout = get(layout);\n const $paneDataArray = get(paneDataArray);\n if (!paneData.constraints.collapsible)\n return;\n const paneConstraintsArray = $paneDataArray.map((paneData) => paneData.constraints);\n const { collapsedSize = 0, paneSize, minSize = 0, pivotIndices, } = paneDataHelper($paneDataArray, paneData, $prevLayout);\n if (paneSize !== collapsedSize)\n return;\n // Restore this pane to the size it was before it was collapsed, if possible.\n const prevPaneSize = get(paneSizeBeforeCollapseMap).get(paneData.id);\n const baseSize = prevPaneSize != null && prevPaneSize >= minSize ? prevPaneSize : minSize;\n const isLastPane = findPaneDataIndex($paneDataArray, paneData) === $paneDataArray.length - 1;\n const delta = isLastPane ? paneSize - baseSize : baseSize - paneSize;\n const nextLayout = adjustLayoutByDelta({\n delta,\n layout: $prevLayout,\n paneConstraints: paneConstraintsArray,\n pivotIndices,\n trigger: \"imperative-api\",\n });\n if (areArraysEqual($prevLayout, nextLayout))\n return;\n layout.set(nextLayout);\n const $onLayout = get(onLayout);\n $onLayout?.(nextLayout);\n callPaneCallbacks($paneDataArray, nextLayout, get(paneIdToLastNotifiedSizeMap));\n }\n const paneGroupStyle = derived([direction], ([$direction]) => {\n return styleToString({\n display: \"flex\",\n \"flex-direction\": $direction === \"horizontal\" ? \"row\" : \"column\",\n height: \"100%\",\n overflow: \"hidden\",\n width: \"100%\",\n });\n });\n const paneGroupSelectors = derived([direction, groupId], ([$direction, $groupId]) => {\n return {\n \"data-pane-group\": \"\",\n \"data-direction\": $direction,\n \"data-pane-group-id\": $groupId,\n };\n });\n const paneGroupAttrs = derived([paneGroupStyle, paneGroupSelectors], ([$style, $selectors]) => {\n return {\n style: $style,\n ...$selectors,\n };\n });\n function setResizeHandlerEventListeners() {\n const $groupId = get(groupId);\n const handles = getResizeHandleElementsForGroup($groupId);\n const unsubHandlers = handles.map((handle) => {\n const handleId = handle.getAttribute(\"data-pane-resizer-id\");\n if (!handleId)\n return noop;\n const [idBefore, idAfter] = getResizeHandlePaneIds($groupId, handleId, get(paneDataArray));\n if (idBefore == null || idAfter == null)\n return noop;\n const onKeydown = (e) => {\n if (e.defaultPrevented || e.key !== \"Enter\")\n return;\n e.preventDefault();\n const $paneDataArray = get(paneDataArray);\n const index = $paneDataArray.findIndex((paneData) => paneData.id === idBefore);\n if (index < 0)\n return;\n const paneData = $paneDataArray[index];\n assert(paneData);\n const $layout = get(layout);\n const size = $layout[index];\n const { collapsedSize = 0, collapsible, minSize = 0 } = paneData.constraints;\n if (!(size != null && collapsible))\n return;\n const nextLayout = adjustLayoutByDelta({\n delta: areNumbersAlmostEqual(size, collapsedSize) ? minSize - size : collapsedSize - size,\n layout: $layout,\n paneConstraints: $paneDataArray.map((paneData) => paneData.constraints),\n pivotIndices: getPivotIndices($groupId, handleId),\n trigger: \"keyboard\",\n });\n if ($layout !== nextLayout) {\n layout.set(nextLayout);\n }\n };\n const unsubListener = addEventListener(handle, \"keydown\", onKeydown);\n return () => {\n unsubListener();\n };\n });\n return () => {\n unsubHandlers.forEach((unsub) => unsub());\n };\n }\n function setLayout(newLayout) {\n layout.set(newLayout);\n }\n function getLayout() {\n return get(layout);\n }\n return {\n methods: {\n collapsePane,\n expandPane,\n getSize: getPaneSize,\n getPaneStyle,\n isCollapsed: isPaneCollapsed,\n isExpanded: isPaneExpanded,\n registerPane,\n registerResizeHandle,\n resizePane,\n startDragging,\n stopDragging,\n unregisterPane,\n setLayout,\n getLayout,\n },\n states: {\n direction,\n dragState,\n groupId,\n paneGroupAttrs,\n paneGroupSelectors,\n paneGroupStyle,\n layout,\n },\n options,\n };\n}\nfunction updateResizeHandleAriaValues({ groupId, layout, paneDataArray, }) {\n const resizeHandleElements = getResizeHandleElementsForGroup(groupId);\n for (let index = 0; index < paneDataArray.length - 1; index++) {\n const { valueMax, valueMin, valueNow } = calculateAriaValues({\n layout,\n panesArray: paneDataArray,\n pivotIndices: [index, index + 1],\n });\n const resizeHandleEl = resizeHandleElements[index];\n if (isHTMLElement(resizeHandleEl)) {\n const paneData = paneDataArray[index];\n resizeHandleEl.setAttribute(\"aria-controls\", paneData.id);\n resizeHandleEl.setAttribute(\"aria-valuemax\", \"\" + Math.round(valueMax));\n resizeHandleEl.setAttribute(\"aria-valuemin\", \"\" + Math.round(valueMin));\n resizeHandleEl.setAttribute(\"aria-valuenow\", valueNow != null ? \"\" + Math.round(valueNow) : \"\");\n }\n }\n return () => {\n resizeHandleElements.forEach((resizeHandleElement) => {\n resizeHandleElement.removeAttribute(\"aria-controls\");\n resizeHandleElement.removeAttribute(\"aria-valuemax\");\n resizeHandleElement.removeAttribute(\"aria-valuemin\");\n resizeHandleElement.removeAttribute(\"aria-valuenow\");\n });\n };\n}\nexport function getResizeHandleElementsForGroup(groupId) {\n if (!isBrowser)\n return [];\n return Array.from(document.querySelectorAll(`[data-pane-resizer-id][data-pane-group-id=\"${groupId}\"]`));\n}\nfunction getPaneGroupElement(id) {\n if (!isBrowser)\n return null;\n const element = document.querySelector(`[data-pane-group][data-pane-group-id=\"${id}\"]`);\n if (element) {\n return element;\n }\n return null;\n}\nfunction noop() {\n // do nothing\n}\nexport function getResizeHandlePaneIds(groupId, handleId, panesArray) {\n const handle = getResizeHandleElement(handleId);\n const handles = getResizeHandleElementsForGroup(groupId);\n const index = handle ? handles.indexOf(handle) : -1;\n const idBefore = panesArray[index]?.id ?? null;\n const idAfter = panesArray[index + 1]?.id ?? null;\n return [idBefore, idAfter];\n}\nexport function getResizeHandleElement(id) {\n if (!isBrowser)\n return null;\n const element = document.querySelector(`[data-pane-resizer-id=\"${id}\"]`);\n if (element) {\n return element;\n }\n return null;\n}\nexport function getResizeHandleElementIndex(groupId, id) {\n if (!isBrowser)\n return null;\n const handles = getResizeHandleElementsForGroup(groupId);\n const index = handles.findIndex((handle) => handle.getAttribute(\"data-pane-resizer-id\") === id);\n return index ?? null;\n}\nfunction getPivotIndices(groupId, dragHandleId) {\n const index = getResizeHandleElementIndex(groupId, dragHandleId);\n return index != null ? [index, index + 1] : [-1, -1];\n}\nfunction paneDataHelper(paneDataArray, paneData, layout) {\n const paneConstraintsArray = paneDataArray.map((paneData) => paneData.constraints);\n const paneIndex = findPaneDataIndex(paneDataArray, paneData);\n const paneConstraints = paneConstraintsArray[paneIndex];\n const isLastPane = paneIndex === paneDataArray.length - 1;\n const pivotIndices = isLastPane ? [paneIndex - 1, paneIndex] : [paneIndex, paneIndex + 1];\n const paneSize = layout[paneIndex];\n return {\n ...paneConstraints,\n paneSize,\n pivotIndices,\n };\n}\nfunction findPaneDataIndex(paneDataArray, paneData) {\n return paneDataArray.findIndex((prevPaneData) => prevPaneData.id === paneData.id);\n}\n// Layout should be pre-converted into percentages\nfunction callPaneCallbacks(paneArray, layout, paneIdToLastNotifiedSizeMap) {\n layout.forEach((size, index) => {\n const paneData = paneArray[index];\n assert(paneData);\n const { callbacks, constraints, id: paneId } = paneData;\n const { collapsedSize = 0, collapsible } = constraints;\n const lastNotifiedSize = paneIdToLastNotifiedSizeMap[paneId];\n // invert the logic from below\n if (!(lastNotifiedSize == null || size !== lastNotifiedSize))\n return;\n paneIdToLastNotifiedSizeMap[paneId] = size;\n const { onCollapse, onExpand, onResize } = callbacks;\n onResize?.(size, lastNotifiedSize);\n if (collapsible && (onCollapse || onExpand)) {\n if (onExpand &&\n (lastNotifiedSize == null || lastNotifiedSize === collapsedSize) &&\n size !== collapsedSize) {\n onExpand();\n }\n if (onCollapse &&\n (lastNotifiedSize == null || lastNotifiedSize !== collapsedSize) &&\n size === collapsedSize) {\n onCollapse();\n }\n }\n });\n}\nfunction getUnsafeDefaultLayout({ paneDataArray }) {\n const layout = Array(paneDataArray.length);\n const paneConstraintsArray = paneDataArray.map((paneData) => paneData.constraints);\n let numPanesWithSizes = 0;\n let remainingSize = 100;\n // Distribute default sizes first\n for (let index = 0; index < paneDataArray.length; index++) {\n const paneConstraints = paneConstraintsArray[index];\n assert(paneConstraints);\n const { defaultSize } = paneConstraints;\n if (defaultSize != null) {\n numPanesWithSizes++;\n layout[index] = defaultSize;\n remainingSize -= defaultSize;\n }\n }\n // Remaining size should be distributed evenly between panes without default sizes\n for (let index = 0; index < paneDataArray.length; index++) {\n const paneConstraints = paneConstraintsArray[index];\n assert(paneConstraints);\n const { defaultSize } = paneConstraints;\n if (defaultSize != null) {\n continue;\n }\n const numRemainingPanes = paneDataArray.length - numPanesWithSizes;\n const size = remainingSize / numRemainingPanes;\n numPanesWithSizes++;\n layout[index] = size;\n remainingSize -= size;\n }\n return layout;\n}\n// All units must be in percentages\nfunction validatePaneGroupLayout({ layout: prevLayout, paneConstraints, }) {\n const nextLayout = [...prevLayout];\n const nextLayoutTotalSize = nextLayout.reduce((accumulated, current) => accumulated + current, 0);\n // Validate layout expectations\n if (nextLayout.length !== paneConstraints.length) {\n throw Error(`Invalid ${paneConstraints.length} pane layout: ${nextLayout\n .map((size) => `${size}%`)\n .join(\", \")}`);\n }\n else if (!areNumbersAlmostEqual(nextLayoutTotalSize, 100)) {\n for (let index = 0; index < paneConstraints.length; index++) {\n const unsafeSize = nextLayout[index];\n assert(unsafeSize != null);\n const safeSize = (100 / nextLayoutTotalSize) * unsafeSize;\n nextLayout[index] = safeSize;\n }\n }\n let remainingSize = 0;\n // First pass: Validate the proposed layout given each pane's constraints\n for (let index = 0; index < paneConstraints.length; index++) {\n const unsafeSize = nextLayout[index];\n assert(unsafeSize != null);\n const safeSize = resizePane({\n paneConstraints,\n paneIndex: index,\n initialSize: unsafeSize,\n });\n if (unsafeSize != safeSize) {\n remainingSize += unsafeSize - safeSize;\n nextLayout[index] = safeSize;\n }\n }\n // If there is additional, left over space, assign it to any pane(s) that permits it\n // (It's not worth taking multiple additional passes to evenly distribute)\n if (!areNumbersAlmostEqual(remainingSize, 0)) {\n for (let index = 0; index < paneConstraints.length; index++) {\n const prevSize = nextLayout[index];\n assert(prevSize != null);\n const unsafeSize = prevSize + remainingSize;\n const safeSize = resizePane({\n paneConstraints,\n paneIndex: index,\n initialSize: unsafeSize,\n });\n if (prevSize !== safeSize) {\n remainingSize -= safeSize - prevSize;\n nextLayout[index] = safeSize;\n // Once we've used up the remainder, bail\n if (areNumbersAlmostEqual(remainingSize, 0)) {\n break;\n }\n }\n }\n }\n return nextLayout;\n}\n// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX\nfunction getDeltaPercentage(e, dragHandleId, dir, initialDragState, keyboardResizeBy) {\n if (isKeyDown(e)) {\n const isHorizontal = dir === \"horizontal\";\n let delta = 0;\n if (e.shiftKey) {\n delta = 100;\n }\n else if (keyboardResizeBy != null) {\n delta = keyboardResizeBy;\n }\n else {\n delta = 10;\n }\n let movement = 0;\n switch (e.key) {\n case \"ArrowDown\":\n movement = isHorizontal ? 0 : delta;\n break;\n case \"ArrowLeft\":\n movement = isHorizontal ? -delta : 0;\n break;\n case \"ArrowRight\":\n movement = isHorizontal ? delta : 0;\n break;\n case \"ArrowUp\":\n movement = isHorizontal ? 0 : -delta;\n break;\n case \"End\":\n movement = 100;\n break;\n case \"Home\":\n movement = -100;\n break;\n }\n return movement;\n }\n else {\n if (initialDragState == null)\n return 0;\n return getDragOffsetPercentage(e, dragHandleId, dir, initialDragState);\n }\n}\nfunction getDragOffsetPercentage(e, dragHandleId, dir, initialDragState) {\n const isHorizontal = dir === \"horizontal\";\n const handleElement = getResizeHandleElement(dragHandleId);\n assert(handleElement);\n const groupId = handleElement.getAttribute(\"data-pane-group-id\");\n assert(groupId);\n const { initialCursorPosition } = initialDragState;\n const cursorPosition = getResizeEventCursorPosition(dir, e);\n const groupElement = getPaneGroupElement(groupId);\n assert(groupElement);\n const groupRect = groupElement.getBoundingClientRect();\n const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;\n const offsetPixels = cursorPosition - initialCursorPosition;\n const offsetPercentage = (offsetPixels / groupSizeInPixels) * 100;\n return offsetPercentage;\n}\nfunction getResizeEventCursorPosition(dir, e) {\n const isHorizontal = dir === \"horizontal\";\n if (isMouseEvent(e)) {\n return isHorizontal ? e.clientX : e.clientY;\n }\n else if (isTouchEvent(e)) {\n const firstTouch = e.touches[0];\n assert(firstTouch);\n return isHorizontal ? firstTouch.screenX : firstTouch.screenY;\n }\n else {\n throw Error(`Unsupported event type \"${e.type}\"`);\n }\n}\n","import { createPaneForge } from \"../internal/paneforge.js\";\nimport { getContext, hasContext, setContext } from \"svelte\";\nimport { removeUndefined, getOptionUpdater } from \"../internal/utils/index.js\";\nconst PF_GROUP_CTX = Symbol(\"PF_GROUP_CTX\");\nexport function setCtx(props) {\n const paneForge = createPaneForge(removeUndefined(props));\n const updateOption = getOptionUpdater(paneForge.options);\n const ctxValue = { ...paneForge, updateOption };\n setContext(PF_GROUP_CTX, ctxValue);\n return ctxValue;\n}\nexport function getCtx(componentName) {\n if (!hasContext(PF_GROUP_CTX)) {\n throw new Error(`${componentName} components must be rendered with a container`);\n }\n return getContext(PF_GROUP_CTX);\n}\n","\n\n
\n\t\n
\n","\n\n
\n\t\n
\n","import { chain } from \"../internal/utils/chain.js\";\nimport { addEventListener } from \"../internal/utils/event.js\";\n/**\n * A Svelte action that adds resize handle functionality to an element.\n * This action is used to handle the dragging of a resize handle.\n */\nexport function resizeHandleAction(node, params) {\n let unsub = () => { };\n function update(params) {\n unsub();\n const { disabled, resizeHandler, isDragging, stopDragging, onDragging = undefined } = params;\n if (disabled || resizeHandler === null || !isDragging)\n return;\n const onMove = (event) => {\n resizeHandler(event);\n };\n const onMouseLeave = (event) => {\n resizeHandler(event);\n };\n const stopDraggingAndBlur = () => {\n node.blur();\n stopDragging();\n if (onDragging) {\n onDragging(false);\n }\n };\n unsub = chain(addEventListener(document.body, \"contextmenu\", stopDraggingAndBlur), addEventListener(document.body, \"mousemove\", onMove), addEventListener(document.body, \"touchmove\", onMove, { passive: false }), addEventListener(document.body, \"mouseleave\", onMouseLeave), addEventListener(window, \"mouseup\", stopDraggingAndBlur), addEventListener(window, \"touchend\", stopDraggingAndBlur));\n }\n update(params);\n return {\n update,\n onDestroy() {\n unsub();\n },\n };\n}\n","\n\n\n\n\n (isFocused = false)}\n\ton:focus={() => (isFocused = true)}\n\ton:mousedown={(e) => {\n\t\te.preventDefault();\n\t\tstartDragging(resizeHandleId, e);\n\t\tonDraggingChange?.(true);\n\t}}\n\ton:mouseup={stopDraggingAndBlur}\n\ton:touchcancel={stopDraggingAndBlur}\n\ton:touchend={stopDraggingAndBlur}\n\ton:touchstart={(e) => {\n\t\te.preventDefault();\n\t\tstartDragging(resizeHandleId, e);\n\t\tonDraggingChange?.(true);\n\t}}\n\ttabindex={tabIndex}\n\t{...attrs}\n\t{...$$restProps}\n>\n\t\n\n","function createParser(onParse) {\n let isFirstChunk;\n let buffer;\n let startingPosition;\n let startingFieldLength;\n let eventId;\n let eventName;\n let data;\n reset();\n return {\n feed,\n reset\n };\n function reset() {\n isFirstChunk = true;\n buffer = \"\";\n startingPosition = 0;\n startingFieldLength = -1;\n eventId = void 0;\n eventName = void 0;\n data = \"\";\n }\n function feed(chunk) {\n buffer = buffer ? buffer + chunk : chunk;\n if (isFirstChunk && hasBom(buffer)) {\n buffer = buffer.slice(BOM.length);\n }\n isFirstChunk = false;\n const length = buffer.length;\n let position = 0;\n let discardTrailingNewline = false;\n while (position < length) {\n if (discardTrailingNewline) {\n if (buffer[position] === \"\\n\") {\n ++position;\n }\n discardTrailingNewline = false;\n }\n let lineLength = -1;\n let fieldLength = startingFieldLength;\n let character;\n for (let index = startingPosition; lineLength < 0 && index < length; ++index) {\n character = buffer[index];\n if (character === \":\" && fieldLength < 0) {\n fieldLength = index - position;\n } else if (character === \"\\r\") {\n discardTrailingNewline = true;\n lineLength = index - position;\n } else if (character === \"\\n\") {\n lineLength = index - position;\n }\n }\n if (lineLength < 0) {\n startingPosition = length - position;\n startingFieldLength = fieldLength;\n break;\n } else {\n startingPosition = 0;\n startingFieldLength = -1;\n }\n parseEventStreamLine(buffer, position, fieldLength, lineLength);\n position += lineLength + 1;\n }\n if (position === length) {\n buffer = \"\";\n } else if (position > 0) {\n buffer = buffer.slice(position);\n }\n }\n function parseEventStreamLine(lineBuffer, index, fieldLength, lineLength) {\n if (lineLength === 0) {\n if (data.length > 0) {\n onParse({\n type: \"event\",\n id: eventId,\n event: eventName || void 0,\n data: data.slice(0, -1)\n // remove trailing newline\n });\n\n data = \"\";\n eventId = void 0;\n }\n eventName = void 0;\n return;\n }\n const noValue = fieldLength < 0;\n const field = lineBuffer.slice(index, index + (noValue ? lineLength : fieldLength));\n let step = 0;\n if (noValue) {\n step = lineLength;\n } else if (lineBuffer[index + fieldLength + 1] === \" \") {\n step = fieldLength + 2;\n } else {\n step = fieldLength + 1;\n }\n const position = index + step;\n const valueLength = lineLength - step;\n const value = lineBuffer.slice(position, position + valueLength).toString();\n if (field === \"data\") {\n data += value ? \"\".concat(value, \"\\n\") : \"\\n\";\n } else if (field === \"event\") {\n eventName = value;\n } else if (field === \"id\" && !value.includes(\"\\0\")) {\n eventId = value;\n } else if (field === \"retry\") {\n const retry = parseInt(value, 10);\n if (!Number.isNaN(retry)) {\n onParse({\n type: \"reconnect-interval\",\n value: retry\n });\n }\n }\n }\n}\nconst BOM = [239, 187, 191];\nfunction hasBom(buffer) {\n return BOM.every((charCode, index) => buffer.charCodeAt(index) === charCode);\n}\nexport { createParser };\n//# sourceMappingURL=index.js.map\n","import { createParser } from './index.js';\nclass EventSourceParserStream extends TransformStream {\n constructor() {\n let parser;\n super({\n start(controller) {\n parser = createParser(event => {\n if (event.type === \"event\") {\n controller.enqueue(event);\n }\n });\n },\n transform(chunk) {\n parser.feed(chunk);\n }\n });\n }\n}\nexport { EventSourceParserStream };\n//# sourceMappingURL=stream.js.map\n","import { EventSourceParserStream } from 'eventsource-parser/stream';\nimport type { ParsedEvent } from 'eventsource-parser';\n\ntype TextStreamUpdate = {\n\tdone: boolean;\n\tvalue: string;\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tcitations?: any;\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\terror?: any;\n\tusage?: ResponseUsage;\n};\n\ntype ResponseUsage = {\n\t/** Including images and tools if any */\n\tprompt_tokens: number;\n\t/** The tokens generated */\n\tcompletion_tokens: number;\n\t/** Sum of the above two fields */\n\ttotal_tokens: number;\n};\n\n// createOpenAITextStream takes a responseBody with a SSE response,\n// and returns an async generator that emits delta updates with large deltas chunked into random sized chunks\nexport async function createOpenAITextStream(\n\tresponseBody: ReadableStream,\n\tsplitLargeDeltas: boolean\n): Promise> {\n\tconst eventStream = responseBody\n\t\t.pipeThrough(new TextDecoderStream())\n\t\t.pipeThrough(new EventSourceParserStream())\n\t\t.getReader();\n\tlet iterator = openAIStreamToIterator(eventStream);\n\tif (splitLargeDeltas) {\n\t\titerator = streamLargeDeltasAsRandomChunks(iterator);\n\t}\n\treturn iterator;\n}\n\nasync function* openAIStreamToIterator(\n\treader: ReadableStreamDefaultReader\n): AsyncGenerator {\n\twhile (true) {\n\t\tconst { value, done } = await reader.read();\n\t\tif (done) {\n\t\t\tyield { done: true, value: '' };\n\t\t\tbreak;\n\t\t}\n\t\tif (!value) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst data = value.data;\n\t\tif (data.startsWith('[DONE]')) {\n\t\t\tyield { done: true, value: '' };\n\t\t\tbreak;\n\t\t}\n\n\t\ttry {\n\t\t\tconst parsedData = JSON.parse(data);\n\t\t\tconsole.log(parsedData);\n\n\t\t\tif (parsedData.error) {\n\t\t\t\tyield { done: true, value: '', error: parsedData.error };\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (parsedData.citations) {\n\t\t\t\tyield { done: false, value: '', citations: parsedData.citations };\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tyield {\n\t\t\t\tdone: false,\n\t\t\t\tvalue: parsedData.choices?.[0]?.delta?.content ?? '',\n\t\t\t\tusage: parsedData.usage\n\t\t\t};\n\t\t} catch (e) {\n\t\t\tconsole.error('Error extracting delta from SSE event:', e);\n\t\t}\n\t}\n}\n\n// streamLargeDeltasAsRandomChunks will chunk large deltas (length > 5) into random sized chunks between 1-3 characters\n// This is to simulate a more fluid streaming, even though some providers may send large chunks of text at once\nasync function* streamLargeDeltasAsRandomChunks(\n\titerator: AsyncGenerator\n): AsyncGenerator {\n\tfor await (const textStreamUpdate of iterator) {\n\t\tif (textStreamUpdate.done) {\n\t\t\tyield textStreamUpdate;\n\t\t\treturn;\n\t\t}\n\t\tif (textStreamUpdate.citations) {\n\t\t\tyield textStreamUpdate;\n\t\t\tcontinue;\n\t\t}\n\t\tlet content = textStreamUpdate.value;\n\t\tif (content.length < 5) {\n\t\t\tyield { done: false, value: content };\n\t\t\tcontinue;\n\t\t}\n\t\twhile (content != '') {\n\t\t\tconst chunkSize = Math.min(Math.floor(Math.random() * 3) + 1, content.length);\n\t\t\tconst chunk = content.slice(0, chunkSize);\n\t\t\tyield { done: false, value: chunk };\n\t\t\t// Do not sleep if the tab is hidden\n\t\t\t// Timers are throttled to 1s in hidden tabs\n\t\t\tif (document?.visibilityState !== 'hidden') {\n\t\t\t\tawait sleep(5);\n\t\t\t}\n\t\t\tcontent = content.slice(chunkSize);\n\t\t}\n\t}\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n","\n\n{#if !dismissed}\n\t{#if mounted}\n\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\t{banner.type}\n\t\t\t\t\t
\n\n\t\t\t\t\t{#if banner.url}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\tLearn More\n\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t{/if}\n\t\t\t\t\n\n\t\t\t\t
\n\t\t\t\t\t{banner.content}\n\t\t\t\t
\n\t\t\t\n\n\t\t\t{#if banner.url}\n\t\t\t\t
\n\t\t\t\t\tLearn More\n\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t{/if}\n\t\t\t
\n\t\t\t\t{#if banner.dismissible}\n\t\t\t\t\t {\n\t\t\t\t\t\t\tdismiss(banner.id);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclass=\" -mt-1 -mb-2 -translate-y-[1px] ml-1.5 mr-1 text-gray-400 dark:hover:text-white\"\n\t\t\t\t\t\t>×\n\t\t\t\t{/if}\n\t\t\t
\n\t\t\n\t{/if}\n{/if}\n","\n\n\n\t\n\t\n\n","\n\n\n\t\n\n","\n\n\n\t\n\n","\n\n {\n\t\tif (e.detail === false) {\n\t\t\tonClose();\n\t\t}\n\t}}\n>\n\t\n\t\t\n\t\n\n\t
\n\t\t\n\t\t\t{#if Object.keys(tools).length > 0}\n\t\t\t\t
\n\t\t\t\t\t{#each Object.keys(tools) as toolId}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t
{tools[toolId].name}
\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\tselectedToolIds = e.detail\n\t\t\t\t\t\t\t\t\t\t? [...selectedToolIds, toolId]\n\t\t\t\t\t\t\t\t\t\t: selectedToolIds.filter((id) => id !== toolId);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t
\n\t\t\t\t\t{/each}\n\t\t\t\t
\n\n\t\t\t\t
\n\t\t\t{/if}\n\n\t\t\t{#if $config?.features?.enable_web_search}\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t
{$i18n.t('Web Search')}
\n\t\t\t\t\t
\n\n\t\t\t\t\t\n\t\t\t\t\n\n\t\t\t\t
\n\t\t\t{/if}\n\n\t\t\t {\n\t\t\t\t\tuploadFilesHandler();\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t
{$i18n.t('Upload Files')}
\n\t\t\t\n\t\t\n\t\n\n","\n\n\n\t\n\n","\n\n\n\t
\n\t\t {\n\t\t\t\tdispatch('cancel');\n\t\t\t\tstopRecording();\n\t\t\t}}\n\t\t>\n\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t
\n\n\t\n\t\t
\n\t\t\t{#each visualizerData.slice().reverse() as rms}\n\t\t\t\t\n\t\t\t{/each}\n\t\t
\n\t\n\n\t
\n\t\t\n\t\t\t{formatSeconds(durationSeconds)}\n\t\t
\n\t\n\n\t
\n\t\t{#if loading}\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t{:else}\n\t\t\t {\n\t\t\t\t\tawait confirmRecording();\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t{/if}\n\t
\n\n\n\n","\n\n{#if show}\n\t\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t\n{/if}\n","\n\n{#if filteredPrompts.length > 0}\n\t\n\t\t
\n\t\t\t
\n\t\t\t\t
/
\n\t\t\t
\n\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{#each filteredPrompts as prompt, promptIdx}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tconfirmPrompt(prompt);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ton:mousemove={() => {\n\t\t\t\t\t\t\t\tselectedPromptIdx = promptIdx;\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ton:focus={() => {}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t{prompt.command}\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t{prompt.title}\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t{/each}\n\t\t\t\t
\n\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\n\t\t\t\t\t
\n\t\t\t\t\t\t{$i18n.t(\n\t\t\t\t\t\t\t'Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.'\n\t\t\t\t\t\t)}\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t\n\t\t\n\t\n{/if}\n","\n\n{#if filteredItems.length > 0 || prompt.split(' ')?.at(0)?.substring(1).startsWith('http')}\n\t\n\t\t
\n\t\t\t
\n\t\t\t\t
#
\n\t\t\t
\n\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{#each filteredItems as doc, docIdx}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tconsole.log(doc);\n\n\t\t\t\t\t\t\t\tconfirmSelect(doc);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ton:mousemove={() => {\n\t\t\t\t\t\t\t\tselectedIdx = docIdx;\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ton:focus={() => {}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{#if doc.type === 'collection'}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t{doc?.title ?? `#${doc.name}`}\n\t\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t{$i18n.t('Collection')}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t#{doc.name} ({doc.filename})\n\t\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t{doc.title}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\n\t\t\t\t\t{/each}\n\n\t\t\t\t\t{#if prompt\n\t\t\t\t\t\t.split(' ')\n\t\t\t\t\t\t.some((s) => s.substring(1).startsWith('https://www.youtube.com') || s\n\t\t\t\t\t\t\t\t\t.substring(1)\n\t\t\t\t\t\t\t\t\t.startsWith('https://youtu.be'))}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tconst url = prompt.split(' ')?.at(0)?.substring(1);\n\t\t\t\t\t\t\t\tif (isValidHttpUrl(url)) {\n\t\t\t\t\t\t\t\t\tconfirmSelectYoutube(url);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\ttoast.error(\n\t\t\t\t\t\t\t\t\t\t$i18n.t(\n\t\t\t\t\t\t\t\t\t\t\t'Oops! Looks like the URL is invalid. Please double-check and try again.'\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t{prompt.split(' ')?.at(0)?.substring(1)}\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
{$i18n.t('Youtube')}
\n\t\t\t\t\t\t\n\t\t\t\t\t{:else if prompt.split(' ')?.at(0)?.substring(1).startsWith('http')}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tconst url = prompt.split(' ')?.at(0)?.substring(1);\n\t\t\t\t\t\t\t\tif (isValidHttpUrl(url)) {\n\t\t\t\t\t\t\t\t\tconfirmSelectWeb(url);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\ttoast.error(\n\t\t\t\t\t\t\t\t\t\t$i18n.t(\n\t\t\t\t\t\t\t\t\t\t\t'Oops! Looks like the URL is invalid. Please double-check and try again.'\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t{prompt.split(' ')?.at(0)?.substring(1)}\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
{$i18n.t('Web')}
\n\t\t\t\t\t\t\n\t\t\t\t\t{/if}\n\t\t\t\t
\n\t\t\t
\n\t\t\n\t\n{/if}\n","\n\n{#if filteredModels.length > 0}\n\t\n\t\t
\n\t\t\t
\n\t\t\t\t
@
\n\t\t\t
\n\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{#each filteredModels as model, modelIdx}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tconfirmSelect(model);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ton:mousemove={() => {\n\t\t\t\t\t\t\t\tselectedIdx = modelIdx;\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ton:focus={() => {}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{model.name}\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t{/each}\n\t\t\t\t
\n\t\t\t
\n\t\t\n\t\n{/if}\n","\n\n{#if ['/', '#', '@'].includes(command?.charAt(0))}\n\t{#if command?.charAt(0) === '/'}\n\t\t\n\t{:else if command?.charAt(0) === '#'}\n\t\t {\n\t\t\t\tconsole.log(e);\n\t\t\t\tuploadYoutubeTranscription(e.detail);\n\t\t\t}}\n\t\t\ton:url={(e) => {\n\t\t\t\tconsole.log(e);\n\t\t\t\tuploadWeb(e.detail);\n\t\t\t}}\n\t\t\ton:select={(e) => {\n\t\t\t\tconsole.log(e);\n\t\t\t\tfiles = [\n\t\t\t\t\t...files,\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: e?.detail?.type ?? 'file',\n\t\t\t\t\t\t...e.detail,\n\t\t\t\t\t\tstatus: 'processed'\n\t\t\t\t\t}\n\t\t\t\t];\n\n\t\t\t\tdispatch('select');\n\t\t\t}}\n\t\t/>\n\t{:else if command?.charAt(0) === '@'}\n\t\t {\n\t\t\t\tprompt = removeLastWordFromString(prompt, command);\n\n\t\t\t\tdispatch('select', {\n\t\t\t\t\ttype: 'model',\n\t\t\t\t\tdata: e.detail\n\t\t\t\t});\n\t\t\t}}\n\t\t/>\n\t{/if}\n{/if}\n","\n\n\n\n
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t{#if autoScroll === false && history?.currentId}\n\t\t\t\t\t\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tautoScroll = true;\n\t\t\t\t\t\t\t\tscrollToBottom();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t{/if}\n\t\t\t
\n\n\t\t\t
\n\t\t\t\t{#if atSelectedModel !== undefined}\n\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t model.id === atSelectedModel.id)?.info?.meta\n\t\t\t\t\t\t\t\t\t?.profile_image_url ??\n\t\t\t\t\t\t\t\t\t($i18n.language === 'dg-DG'\n\t\t\t\t\t\t\t\t\t\t? `/doge.png`\n\t\t\t\t\t\t\t\t\t\t: `${WEBUI_BASE_URL}/static/favicon.png`)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\tTalking to {atSelectedModel.name}\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\tatSelectedModel = undefined;\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t{/if}\n\n\t\t\t\t {\n\t\t\t\t\t\tconst data = e.detail;\n\n\t\t\t\t\t\tif (data?.type === 'model') {\n\t\t\t\t\t\t\tatSelectedModel = data.data;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tchatTextAreaElement?.focus();\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t
\n\t\t
\n\t\n\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t {\n\t\t\t\t\t\tif (inputFiles && inputFiles.length > 0) {\n\t\t\t\t\t\t\tconst _inputFiles = Array.from(inputFiles);\n\t\t\t\t\t\t\tinputFilesHandler(_inputFiles);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttoast.error($i18n.t(`File not found.`));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfilesInputElement.value = '';\n\t\t\t\t\t}}\n\t\t\t\t/>\n\n\t\t\t\t{#if recording}\n\t\t\t\t\t {\n\t\t\t\t\t\t\trecording = false;\n\n\t\t\t\t\t\t\tawait tick();\n\t\t\t\t\t\t\tdocument.getElementById('chat-textarea')?.focus();\n\t\t\t\t\t\t}}\n\t\t\t\t\t\ton:confirm={async (e) => {\n\t\t\t\t\t\t\tconst response = e.detail;\n\t\t\t\t\t\t\tprompt = `${prompt}${response} `;\n\n\t\t\t\t\t\t\trecording = false;\n\n\t\t\t\t\t\t\tawait tick();\n\t\t\t\t\t\t\tdocument.getElementById('chat-textarea')?.focus();\n\n\t\t\t\t\t\t\tif ($settings?.speechAutoSend ?? false) {\n\t\t\t\t\t\t\t\tsubmitPrompt(prompt);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t{:else}\n\t\t\t\t\t {\n\t\t\t\t\t\t\t// check if selectedModels support image input\n\t\t\t\t\t\t\tsubmitPrompt(prompt);\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{#if files.length > 0}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t{#each files as file, fileIdx}\n\t\t\t\t\t\t\t\t\t\t{#if file.type === 'image'}\n\t\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t{#if atSelectedModel ? visionCapableModels.length === 0 : selectedModels.length !== visionCapableModels.length}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t !visionCapableModels.includes(id))\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.join(', ')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfiles.splice(fileIdx, 1);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfiles = files;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\t\t\t\tfiles.splice(fileIdx, 1);\n\t\t\t\t\t\t\t\t\t\t\t\t\tfiles = files;\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t\t\t{/each}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{/if}\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\t\tif (availableToolIds.includes(e.id) || ($_user?.role ?? 'user') === 'admin') {\n\t\t\t\t\t\t\t\t\t\t\t\ta[e.id] = {\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: e.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: e.meta.description,\n\t\t\t\t\t\t\t\t\t\t\t\t\tenabled: false\n\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\treturn a;\n\t\t\t\t\t\t\t\t\t\t}, {})}\n\t\t\t\t\t\t\t\t\t\tuploadFilesHandler={() => {\n\t\t\t\t\t\t\t\t\t\t\tfilesInputElement.click();\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\tonClose={async () => {\n\t\t\t\t\t\t\t\t\t\t\tawait tick();\n\t\t\t\t\t\t\t\t\t\t\tchatTextAreaElement?.focus();\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t!$mobile ||\n\t\t\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\t\t\t'ontouchstart' in window ||\n\t\t\t\t\t\t\t\t\t\t\t\tnavigator.maxTouchPoints > 0 ||\n\t\t\t\t\t\t\t\t\t\t\t\tnavigator.msMaxTouchPoints > 0\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t// Prevent Enter key from creating a new line\n\t\t\t\t\t\t\t\t\t\t\tif (e.key === 'Enter' && !e.shiftKey) {\n\t\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Submit the prompt when Enter key is pressed\n\t\t\t\t\t\t\t\t\t\t\tif (prompt !== '' && e.key === 'Enter' && !e.shiftKey) {\n\t\t\t\t\t\t\t\t\t\t\t\tsubmitPrompt(prompt);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\ton:keydown={async (e) => {\n\t\t\t\t\t\t\t\t\t\tconst isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac\n\t\t\t\t\t\t\t\t\t\tconst commandsContainerElement = document.getElementById('commands-container');\n\n\t\t\t\t\t\t\t\t\t\t// Command/Ctrl + Shift + Enter to submit a message pair\n\t\t\t\t\t\t\t\t\t\tif (isCtrlPressed && e.key === 'Enter' && e.shiftKey) {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tcreateMessagePair(prompt);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Check if Ctrl + R is pressed\n\t\t\t\t\t\t\t\t\t\tif (prompt === '' && isCtrlPressed && e.key.toLowerCase() === 'r') {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tconsole.log('regenerate');\n\n\t\t\t\t\t\t\t\t\t\t\tconst regenerateButton = [\n\t\t\t\t\t\t\t\t\t\t\t\t...document.getElementsByClassName('regenerate-response-button')\n\t\t\t\t\t\t\t\t\t\t\t]?.at(-1);\n\n\t\t\t\t\t\t\t\t\t\t\tregenerateButton?.click();\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif (prompt === '' && e.key == 'ArrowUp') {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\n\t\t\t\t\t\t\t\t\t\t\tconst userMessageElement = [\n\t\t\t\t\t\t\t\t\t\t\t\t...document.getElementsByClassName('user-message')\n\t\t\t\t\t\t\t\t\t\t\t]?.at(-1);\n\n\t\t\t\t\t\t\t\t\t\t\tconst editButton = [\n\t\t\t\t\t\t\t\t\t\t\t\t...document.getElementsByClassName('edit-user-message-button')\n\t\t\t\t\t\t\t\t\t\t\t]?.at(-1);\n\n\t\t\t\t\t\t\t\t\t\t\tconsole.log(userMessageElement);\n\n\t\t\t\t\t\t\t\t\t\t\tuserMessageElement.scrollIntoView({ block: 'center' });\n\t\t\t\t\t\t\t\t\t\t\teditButton?.click();\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif (commandsContainerElement && e.key === 'ArrowUp') {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tcommandsElement.selectUp();\n\n\t\t\t\t\t\t\t\t\t\t\tconst commandOptionButton = [\n\t\t\t\t\t\t\t\t\t\t\t\t...document.getElementsByClassName('selected-command-option-button')\n\t\t\t\t\t\t\t\t\t\t\t]?.at(-1);\n\t\t\t\t\t\t\t\t\t\t\tcommandOptionButton.scrollIntoView({ block: 'center' });\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif (commandsContainerElement && e.key === 'ArrowDown') {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tcommandsElement.selectDown();\n\n\t\t\t\t\t\t\t\t\t\t\tconst commandOptionButton = [\n\t\t\t\t\t\t\t\t\t\t\t\t...document.getElementsByClassName('selected-command-option-button')\n\t\t\t\t\t\t\t\t\t\t\t]?.at(-1);\n\t\t\t\t\t\t\t\t\t\t\tcommandOptionButton.scrollIntoView({ block: 'center' });\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif (commandsContainerElement && e.key === 'Enter') {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\n\t\t\t\t\t\t\t\t\t\t\tconst commandOptionButton = [\n\t\t\t\t\t\t\t\t\t\t\t\t...document.getElementsByClassName('selected-command-option-button')\n\t\t\t\t\t\t\t\t\t\t\t]?.at(-1);\n\n\t\t\t\t\t\t\t\t\t\t\tif (e.shiftKey) {\n\t\t\t\t\t\t\t\t\t\t\t\tprompt = `${prompt}\\n`;\n\t\t\t\t\t\t\t\t\t\t\t} else if (commandOptionButton) {\n\t\t\t\t\t\t\t\t\t\t\t\tcommandOptionButton?.click();\n\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\tdocument.getElementById('send-message-button')?.click();\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif (commandsContainerElement && e.key === 'Tab') {\n\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\n\t\t\t\t\t\t\t\t\t\t\tconst commandOptionButton = [\n\t\t\t\t\t\t\t\t\t\t\t\t...document.getElementsByClassName('selected-command-option-button')\n\t\t\t\t\t\t\t\t\t\t\t]?.at(-1);\n\n\t\t\t\t\t\t\t\t\t\t\tcommandOptionButton?.click();\n\t\t\t\t\t\t\t\t\t\t} else if (e.key === 'Tab') {\n\t\t\t\t\t\t\t\t\t\t\tconst words = findWordIndices(prompt);\n\n\t\t\t\t\t\t\t\t\t\t\tif (words.length > 0) {\n\t\t\t\t\t\t\t\t\t\t\t\tconst word = words.at(0);\n\t\t\t\t\t\t\t\t\t\t\t\tconst fullPrompt = prompt;\n\n\t\t\t\t\t\t\t\t\t\t\t\tprompt = prompt.substring(0, word?.endIndex + 1);\n\t\t\t\t\t\t\t\t\t\t\t\tawait tick();\n\n\t\t\t\t\t\t\t\t\t\t\t\te.target.scrollTop = e.target.scrollHeight;\n\t\t\t\t\t\t\t\t\t\t\t\tprompt = fullPrompt;\n\t\t\t\t\t\t\t\t\t\t\t\tawait tick();\n\n\t\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\t\te.target.setSelectionRange(word?.startIndex, word.endIndex + 1);\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\te.target.style.height = '';\n\t\t\t\t\t\t\t\t\t\t\te.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif (e.key === 'Escape') {\n\t\t\t\t\t\t\t\t\t\t\tconsole.log('Escape');\n\t\t\t\t\t\t\t\t\t\t\tatSelectedModel = undefined;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\trows=\"1\"\n\t\t\t\t\t\t\t\t\ton:input={async (e) => {\n\t\t\t\t\t\t\t\t\t\te.target.style.height = '';\n\t\t\t\t\t\t\t\t\t\te.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';\n\t\t\t\t\t\t\t\t\t\tuser = null;\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\ton:focus={async (e) => {\n\t\t\t\t\t\t\t\t\t\te.target.style.height = '';\n\t\t\t\t\t\t\t\t\t\te.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\ton:paste={async (e) => {\n\t\t\t\t\t\t\t\t\t\tconst clipboardData = e.clipboardData || window.clipboardData;\n\n\t\t\t\t\t\t\t\t\t\tif (clipboardData && clipboardData.items) {\n\t\t\t\t\t\t\t\t\t\t\tfor (const item of clipboardData.items) {\n\t\t\t\t\t\t\t\t\t\t\t\tif (item.type.indexOf('image') !== -1) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tconst blob = item.getAsFile();\n\t\t\t\t\t\t\t\t\t\t\t\t\tconst reader = new FileReader();\n\n\t\t\t\t\t\t\t\t\t\t\t\t\treader.onload = function (e) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfiles = [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...files,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: 'image',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\turl: `${e.target.result}`\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t\t\t\t\treader.readAsDataURL(blob);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t{#if !history?.currentId || history.messages[history.currentId]?.done == true}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlet stream = await navigator.mediaDevices\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.getUserMedia({ audio: true })\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.catch(function (err) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttoast.error(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$i18n.t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t`Permission denied when accessing microphone: {{error}}`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\terror: err\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (stream) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trecording = true;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst tracks = stream.getTracks();\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttracks.forEach((track) => track.stop());\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstream = null;\n\t\t\t\t\t\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttoast.error($i18n.t('Permission denied when accessing microphone'));\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Voice Input\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{#if !history.currentId || history.messages[history.currentId]?.done == true}\n\t\t\t\t\t\t\t\t{#if prompt === ''}\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\t\t\t\tif (selectedModels.length > 1) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttoast.error($i18n.t('Select only one model to call'));\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\tif ($config.audio.stt.engine === 'web') {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttoast.error(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$i18n.t('Call feature is not supported when using Web STT engine')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t// check if user has access to getUserMedia\n\t\t\t\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlet stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// If the user grants the permission, proceed to show the call overlay\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (stream) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst tracks = stream.getTracks();\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttracks.forEach((track) => track.stop());\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstream = null;\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tshowCallOverlay.set(true);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdispatch('call');\n\t\t\t\t\t\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// If the user denies the permission or an error occurs, show an error message\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttoast.error($i18n.t('Permission denied when accessing media devices'));\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Call\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\t\tstopResponse();\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t{/if}\n\n\t\t\t\t
\n\t\t\t\t\t{$i18n.t('LLMs can make mistakes. Verify important information.')}\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t\n\n\n\n","\n\n
\n\t{#each selectedModels as selectedModel, selectedModelIdx}\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t ({\n\t\t\t\t\t\t\tvalue: model.id,\n\t\t\t\t\t\t\tlabel: model.name,\n\t\t\t\t\t\t\tmodel: model\n\t\t\t\t\t\t}))}\n\t\t\t\t\t\tshowTemporaryChatControl={$user.role === 'user'\n\t\t\t\t\t\t\t? ($config?.permissions?.chat?.temporary ?? true)\n\t\t\t\t\t\t\t: true}\n\t\t\t\t\t\tbind:value={selectedModel}\n\t\t\t\t\t/>\n\t\t\t\t
\n\t\t\t
\n\n\t\t\t{#if selectedModelIdx === 0}\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tselectedModels = [...selectedModels, ''];\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\taria-label=\"Add Model\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t{:else}\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tselectedModels.splice(selectedModelIdx, 1);\n\t\t\t\t\t\t\t\tselectedModels = selectedModels;\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\taria-label=\"Remove Model\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t{/if}\n\t\t\n\t{/each}\n\n\n{#if showSetDefault}\n\t
\n\t\t\n\t
\n{/if}\n","\n\n\n\t\n\n","\n\n\n\t\n\n","\n\n\n\t\n\n","\n\n {\n\t\tif (e.detail === false) {\n\t\t\tonClose();\n\t\t}\n\t}}\n>\n\t\n\n\t
\n\t\t\n\t\t\t\n\n\t\t\t{#if $mobile}\n\t\t\t\t {\n\t\t\t\t\t\tawait showControls.set(true);\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t\n\t\t\t\t\t
{$i18n.t('Controls')}
\n\t\t\t\t\n\t\t\t{/if}\n\n\t\t\t {\n\t\t\t\t\tawait showControls.set(true);\n\t\t\t\t\tawait showOverview.set(true);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t
{$i18n.t('Overview')}
\n\t\t\t\n\n\t\t\t {\n\t\t\t\t\tconst res = await copyToClipboard(await getChatAsText()).catch((e) => {\n\t\t\t\t\t\tconsole.error(e);\n\t\t\t\t\t});\n\n\t\t\t\t\tif (res) {\n\t\t\t\t\t\ttoast.success($i18n.t('Copied to clipboard'));\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t
{$i18n.t('Copy')}
\n\t\t\t\n\n\t\t\t {\n\t\t\t\t\tshareHandler();\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t
{$i18n.t('Share')}
\n\t\t\t\n\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\n\t\t\t\t\t
{$i18n.t('Download')}
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t {\n\t\t\t\t\t\t\tdownloadJSONExport();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t
{$i18n.t('Export chat (.json)')}
\n\t\t\t\t\t\n\t\t\t\t\t {\n\t\t\t\t\t\t\tdownloadTxt();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t
{$i18n.t('Plain text (.txt)')}
\n\t\t\t\t\t\n\n\t\t\t\t\t {\n\t\t\t\t\t\t\tdownloadPdf();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t
{$i18n.t('PDF document (.pdf)')}
\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\n\t\t\t
\n\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\n\t
\n\n","\n\n\n\n","export default function cc(names) {\n if (typeof names === \"string\" || typeof names === \"number\") return \"\" + names\n\n let out = \"\"\n\n if (Array.isArray(names)) {\n for (let i = 0, tmp; i < names.length; i++) {\n if ((tmp = cc(names[i])) !== \"\") {\n out += (out && \" \") + tmp\n }\n }\n } else {\n for (let k in names) {\n if (names[k]) out += (out && \" \") + k\n }\n }\n\n return out\n}\n","import { drag } from 'd3-drag';\nimport { select, pointer } from 'd3-selection';\nimport { zoom, zoomIdentity, zoomTransform } from 'd3-zoom';\n\nconst errorMessages = {\n error001: () => '[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#001',\n error002: () => \"It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.\",\n error003: (nodeType) => `Node type \"${nodeType}\" not found. Using fallback type \"default\".`,\n error004: () => 'The React Flow parent container needs a width and a height to render the graph.',\n error005: () => 'Only child nodes can use a parent extent.',\n error006: () => \"Can't create edge. An edge needs a source and a target.\",\n error007: (id) => `The old edge with id=${id} does not exist.`,\n error009: (type) => `Marker type \"${type}\" doesn't exist.`,\n error008: (handleType, { id, sourceHandle, targetHandle }) => `Couldn't create edge for ${handleType} handle id: \"${handleType === 'source' ? sourceHandle : targetHandle}\", edge id: ${id}.`,\n error010: () => 'Handle: No node id found. Make sure to only use a Handle inside a custom Node.',\n error011: (edgeType) => `Edge type \"${edgeType}\" not found. Using fallback type \"default\".`,\n error012: (id) => `Node with id \"${id}\" does not exist, it may have been removed. This can happen when a node is deleted before the \"onNodeClick\" handler is called.`,\n error013: (lib = 'react') => `It seems that you haven't loaded the styles. Please import '@xyflow/${lib}/dist/style.css' or base.css to make sure everything is working properly.`,\n};\nconst infiniteExtent = [\n [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],\n [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],\n];\nconst elementSelectionKeys = ['Enter', ' ', 'Escape'];\n\nvar ConnectionMode;\n(function (ConnectionMode) {\n ConnectionMode[\"Strict\"] = \"strict\";\n ConnectionMode[\"Loose\"] = \"loose\";\n})(ConnectionMode || (ConnectionMode = {}));\nvar PanOnScrollMode;\n(function (PanOnScrollMode) {\n PanOnScrollMode[\"Free\"] = \"free\";\n PanOnScrollMode[\"Vertical\"] = \"vertical\";\n PanOnScrollMode[\"Horizontal\"] = \"horizontal\";\n})(PanOnScrollMode || (PanOnScrollMode = {}));\nvar SelectionMode;\n(function (SelectionMode) {\n SelectionMode[\"Partial\"] = \"partial\";\n SelectionMode[\"Full\"] = \"full\";\n})(SelectionMode || (SelectionMode = {}));\nconst initialConnection = {\n inProgress: false,\n isValid: null,\n from: null,\n fromHandle: null,\n fromPosition: null,\n fromNode: null,\n to: null,\n toHandle: null,\n toPosition: null,\n toNode: null,\n};\n\nvar ConnectionLineType;\n(function (ConnectionLineType) {\n ConnectionLineType[\"Bezier\"] = \"default\";\n ConnectionLineType[\"Straight\"] = \"straight\";\n ConnectionLineType[\"Step\"] = \"step\";\n ConnectionLineType[\"SmoothStep\"] = \"smoothstep\";\n ConnectionLineType[\"SimpleBezier\"] = \"simplebezier\";\n})(ConnectionLineType || (ConnectionLineType = {}));\nvar MarkerType;\n(function (MarkerType) {\n MarkerType[\"Arrow\"] = \"arrow\";\n MarkerType[\"ArrowClosed\"] = \"arrowclosed\";\n})(MarkerType || (MarkerType = {}));\n\nvar Position;\n(function (Position) {\n Position[\"Left\"] = \"left\";\n Position[\"Top\"] = \"top\";\n Position[\"Right\"] = \"right\";\n Position[\"Bottom\"] = \"bottom\";\n})(Position || (Position = {}));\nconst oppositePosition = {\n [Position.Left]: Position.Right,\n [Position.Right]: Position.Left,\n [Position.Top]: Position.Bottom,\n [Position.Bottom]: Position.Top,\n};\n\n/**\n * @internal\n */\nfunction areConnectionMapsEqual(a, b) {\n if (!a && !b) {\n return true;\n }\n if (!a || !b || a.size !== b.size) {\n return false;\n }\n if (!a.size && !b.size) {\n return true;\n }\n for (const key of a.keys()) {\n if (!b.has(key)) {\n return false;\n }\n }\n return true;\n}\n/**\n * We call the callback for all connections in a that are not in b\n *\n * @internal\n */\nfunction handleConnectionChange(a, b, cb) {\n if (!cb) {\n return;\n }\n const diff = [];\n a.forEach((connection, key) => {\n if (!b?.has(key)) {\n diff.push(connection);\n }\n });\n if (diff.length) {\n cb(diff);\n }\n}\nfunction getConnectionStatus(isValid) {\n return isValid === null ? null : isValid ? 'valid' : 'invalid';\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Test whether an object is useable as an Edge\n * @public\n * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true\n * @param element - The element to test\n * @returns A boolean indicating whether the element is an Edge\n */\nconst isEdgeBase = (element) => 'id' in element && 'source' in element && 'target' in element;\n/**\n * Test whether an object is useable as a Node\n * @public\n * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true\n * @param element - The element to test\n * @returns A boolean indicating whether the element is an Node\n */\nconst isNodeBase = (element) => 'id' in element && 'position' in element && !('source' in element) && !('target' in element);\nconst isInternalNodeBase = (element) => 'id' in element && 'internals' in element && !('source' in element) && !('target' in element);\n/**\n * Pass in a node, and get connected nodes where edge.source === node.id\n * @public\n * @param node - The node to get the connected nodes from\n * @param nodes - The array of all nodes\n * @param edges - The array of all edges\n * @returns An array of nodes that are connected over eges where the source is the given node\n */\nconst getOutgoers = (node, nodes, edges) => {\n if (!node.id) {\n return [];\n }\n const outgoerIds = new Set();\n edges.forEach((edge) => {\n if (edge.source === node.id) {\n outgoerIds.add(edge.target);\n }\n });\n return nodes.filter((n) => outgoerIds.has(n.id));\n};\n/**\n * Pass in a node, and get connected nodes where edge.target === node.id\n * @public\n * @param node - The node to get the connected nodes from\n * @param nodes - The array of all nodes\n * @param edges - The array of all edges\n * @returns An array of nodes that are connected over eges where the target is the given node\n */\nconst getIncomers = (node, nodes, edges) => {\n if (!node.id) {\n return [];\n }\n const incomersIds = new Set();\n edges.forEach((edge) => {\n if (edge.target === node.id) {\n incomersIds.add(edge.source);\n }\n });\n return nodes.filter((n) => incomersIds.has(n.id));\n};\nconst getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {\n const { width, height } = getNodeDimensions(node);\n const origin = node.origin ?? nodeOrigin;\n const offsetX = width * origin[0];\n const offsetY = height * origin[1];\n return {\n x: node.position.x - offsetX,\n y: node.position.y - offsetY,\n };\n};\n/**\n * Internal function for determining a bounding box that contains all given nodes in an array.\n * @public\n * @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport.\n * @param nodes - Nodes to calculate the bounds for\n * @param params.nodeOrigin - Origin of the nodes: [0, 0] - top left, [0.5, 0.5] - center\n * @returns Bounding box enclosing all nodes\n */\nconst getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], nodeLookup: undefined }) => {\n if (process.env.NODE_ENV === 'development' && !params.nodeLookup) {\n console.warn('Please use `getNodesBounds` from `useReactFlow`/`useSvelteFlow` hook to ensure correct values for sub flows. If not possible, you have to provide a nodeLookup to support sub flows.');\n }\n if (nodes.length === 0) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n const box = nodes.reduce((currBox, nodeOrId) => {\n const isId = typeof nodeOrId === 'string';\n let currentNode = !params.nodeLookup && !isId ? nodeOrId : undefined;\n if (params.nodeLookup) {\n currentNode = isId\n ? params.nodeLookup.get(nodeOrId)\n : !isInternalNodeBase(nodeOrId)\n ? params.nodeLookup.get(nodeOrId.id)\n : nodeOrId;\n }\n const nodeBox = currentNode ? nodeToBox(currentNode, params.nodeOrigin) : { x: 0, y: 0, x2: 0, y2: 0 };\n return getBoundsOfBoxes(currBox, nodeBox);\n }, { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity });\n return boxToRect(box);\n};\n/**\n * Determines a bounding box that contains all given nodes in an array\n * @internal\n */\nconst getInternalNodesBounds = (nodeLookup, params = {}) => {\n if (nodeLookup.size === 0) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };\n nodeLookup.forEach((node) => {\n if (params.filter === undefined || params.filter(node)) {\n const nodeBox = nodeToBox(node);\n box = getBoundsOfBoxes(box, nodeBox);\n }\n });\n return boxToRect(box);\n};\nconst getNodesInside = (nodes, rect, [tx, ty, tScale] = [0, 0, 1], partially = false, \n// set excludeNonSelectableNodes if you want to pay attention to the nodes \"selectable\" attribute\nexcludeNonSelectableNodes = false) => {\n const paneRect = {\n ...pointToRendererPoint(rect, [tx, ty, tScale]),\n width: rect.width / tScale,\n height: rect.height / tScale,\n };\n const visibleNodes = [];\n for (const node of nodes.values()) {\n const { measured, selectable = true, hidden = false } = node;\n if ((excludeNonSelectableNodes && !selectable) || hidden) {\n continue;\n }\n const width = measured.width ?? node.width ?? node.initialWidth ?? null;\n const height = measured.height ?? node.height ?? node.initialHeight ?? null;\n const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node));\n const area = (width ?? 0) * (height ?? 0);\n const partiallyVisible = partially && overlappingArea > 0;\n const forceInitialRender = !node.internals.handleBounds;\n const isVisible = forceInitialRender || partiallyVisible || overlappingArea >= area;\n if (isVisible || node.dragging) {\n visibleNodes.push(node);\n }\n }\n return visibleNodes;\n};\n/**\n * Get all connecting edges for a given set of nodes\n * @param nodes - Nodes you want to get the connected edges for\n * @param edges - All edges\n * @returns Array of edges that connect any of the given nodes with each other\n */\nconst getConnectedEdges = (nodes, edges) => {\n const nodeIds = new Set();\n nodes.forEach((node) => {\n nodeIds.add(node.id);\n });\n return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));\n};\nfunction getFitViewNodes(nodeLookup, options) {\n const fitViewNodes = new Map();\n const optionNodeIds = options?.nodes ? new Set(options.nodes.map((node) => node.id)) : null;\n nodeLookup.forEach((n) => {\n const isVisible = n.measured.width && n.measured.height && (options?.includeHiddenNodes || !n.hidden);\n if (isVisible && (!optionNodeIds || optionNodeIds.has(n.id))) {\n fitViewNodes.set(n.id, n);\n }\n });\n return fitViewNodes;\n}\nasync function fitView({ nodes, width, height, panZoom, minZoom, maxZoom }, options) {\n if (nodes.size === 0) {\n return Promise.resolve(false);\n }\n const bounds = getInternalNodesBounds(nodes);\n const viewport = getViewportForBounds(bounds, width, height, options?.minZoom ?? minZoom, options?.maxZoom ?? maxZoom, options?.padding ?? 0.1);\n await panZoom.setViewport(viewport, { duration: options?.duration });\n return Promise.resolve(true);\n}\n/**\n * This function calculates the next position of a node, taking into account the node's extent, parent node, and origin.\n *\n * @internal\n * @returns position, positionAbsolute\n */\nfunction calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin = [0, 0], nodeExtent, onError, }) {\n const node = nodeLookup.get(nodeId);\n const parentNode = node.parentId ? nodeLookup.get(node.parentId) : undefined;\n const { x: parentX, y: parentY } = parentNode ? parentNode.internals.positionAbsolute : { x: 0, y: 0 };\n const origin = node.origin ?? nodeOrigin;\n let extent = nodeExtent;\n if (node.extent === 'parent' && !node.expandParent) {\n if (!parentNode) {\n onError?.('005', errorMessages['error005']());\n }\n else {\n const parentWidth = parentNode.measured.width;\n const parentHeight = parentNode.measured.height;\n if (parentWidth && parentHeight) {\n extent = [\n [parentX, parentY],\n [parentX + parentWidth, parentY + parentHeight],\n ];\n }\n }\n }\n else if (parentNode && isCoordinateExtent(node.extent)) {\n extent = [\n [node.extent[0][0] + parentX, node.extent[0][1] + parentY],\n [node.extent[1][0] + parentX, node.extent[1][1] + parentY],\n ];\n }\n const positionAbsolute = isCoordinateExtent(extent)\n ? clampPosition(nextPosition, extent, node.measured)\n : nextPosition;\n return {\n position: {\n x: positionAbsolute.x - parentX + node.measured.width * origin[0],\n y: positionAbsolute.y - parentY + node.measured.height * origin[1],\n },\n positionAbsolute,\n };\n}\n/**\n * Pass in nodes & edges to delete, get arrays of nodes and edges that actually can be deleted\n * @internal\n * @param param.nodesToRemove - The nodes to remove\n * @param param.edgesToRemove - The edges to remove\n * @param param.nodes - All nodes\n * @param param.edges - All edges\n * @param param.onBeforeDelete - Callback to check which nodes and edges can be deleted\n * @returns nodes: nodes that can be deleted, edges: edges that can be deleted\n */\nasync function getElementsToRemove({ nodesToRemove = [], edgesToRemove = [], nodes, edges, onBeforeDelete, }) {\n const nodeIds = new Set(nodesToRemove.map((node) => node.id));\n const matchingNodes = [];\n for (const node of nodes) {\n if (node.deletable === false) {\n continue;\n }\n const isIncluded = nodeIds.has(node.id);\n const parentHit = !isIncluded && node.parentId && matchingNodes.find((n) => n.id === node.parentId);\n if (isIncluded || parentHit) {\n matchingNodes.push(node);\n }\n }\n const edgeIds = new Set(edgesToRemove.map((edge) => edge.id));\n const deletableEdges = edges.filter((edge) => edge.deletable !== false);\n const connectedEdges = getConnectedEdges(matchingNodes, deletableEdges);\n const matchingEdges = connectedEdges;\n for (const edge of deletableEdges) {\n const isIncluded = edgeIds.has(edge.id);\n if (isIncluded && !matchingEdges.find((e) => e.id === edge.id)) {\n matchingEdges.push(edge);\n }\n }\n if (!onBeforeDelete) {\n return {\n edges: matchingEdges,\n nodes: matchingNodes,\n };\n }\n const onBeforeDeleteResult = await onBeforeDelete({\n nodes: matchingNodes,\n edges: matchingEdges,\n });\n if (typeof onBeforeDeleteResult === 'boolean') {\n return onBeforeDeleteResult ? { edges: matchingEdges, nodes: matchingNodes } : { edges: [], nodes: [] };\n }\n return onBeforeDeleteResult;\n}\n\nconst clamp = (val, min = 0, max = 1) => Math.min(Math.max(val, min), max);\nconst clampPosition = (position = { x: 0, y: 0 }, extent, dimensions) => ({\n x: clamp(position.x, extent[0][0], extent[1][0] - (dimensions?.width ?? 0)),\n y: clamp(position.y, extent[0][1], extent[1][1] - (dimensions?.height ?? 0)),\n});\nfunction clampPositionToParent(childPosition, childDimensions, parent) {\n const { width: parentWidth, height: parentHeight } = getNodeDimensions(parent);\n const { x: parentX, y: parentY } = parent.internals.positionAbsolute;\n return clampPosition(childPosition, [\n [parentX, parentY],\n [parentX + parentWidth, parentY + parentHeight],\n ], childDimensions);\n}\n/**\n * Calculates the velocity of panning when the mouse is close to the edge of the canvas\n * @internal\n * @param value - One dimensional poition of the mouse (x or y)\n * @param min - Minimal position on canvas before panning starts\n * @param max - Maximal position on canvas before panning starts\n * @returns - A number between 0 and 1 that represents the velocity of panning\n */\nconst calcAutoPanVelocity = (value, min, max) => {\n if (value < min) {\n return clamp(Math.abs(value - min), 1, min) / min;\n }\n else if (value > max) {\n return -clamp(Math.abs(value - max), 1, min) / min;\n }\n return 0;\n};\nconst calcAutoPan = (pos, bounds, speed = 15, distance = 40) => {\n const xMovement = calcAutoPanVelocity(pos.x, distance, bounds.width - distance) * speed;\n const yMovement = calcAutoPanVelocity(pos.y, distance, bounds.height - distance) * speed;\n return [xMovement, yMovement];\n};\nconst getBoundsOfBoxes = (box1, box2) => ({\n x: Math.min(box1.x, box2.x),\n y: Math.min(box1.y, box2.y),\n x2: Math.max(box1.x2, box2.x2),\n y2: Math.max(box1.y2, box2.y2),\n});\nconst rectToBox = ({ x, y, width, height }) => ({\n x,\n y,\n x2: x + width,\n y2: y + height,\n});\nconst boxToRect = ({ x, y, x2, y2 }) => ({\n x,\n y,\n width: x2 - x,\n height: y2 - y,\n});\nconst nodeToRect = (node, nodeOrigin = [0, 0]) => {\n const { x, y } = isInternalNodeBase(node)\n ? node.internals.positionAbsolute\n : getNodePositionWithOrigin(node, nodeOrigin);\n return {\n x,\n y,\n width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,\n height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,\n };\n};\nconst nodeToBox = (node, nodeOrigin = [0, 0]) => {\n const { x, y } = isInternalNodeBase(node)\n ? node.internals.positionAbsolute\n : getNodePositionWithOrigin(node, nodeOrigin);\n return {\n x,\n y,\n x2: x + (node.measured?.width ?? node.width ?? node.initialWidth ?? 0),\n y2: y + (node.measured?.height ?? node.height ?? node.initialHeight ?? 0),\n };\n};\nconst getBoundsOfRects = (rect1, rect2) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));\nconst getOverlappingArea = (rectA, rectB) => {\n const xOverlap = Math.max(0, Math.min(rectA.x + rectA.width, rectB.x + rectB.width) - Math.max(rectA.x, rectB.x));\n const yOverlap = Math.max(0, Math.min(rectA.y + rectA.height, rectB.y + rectB.height) - Math.max(rectA.y, rectB.y));\n return Math.ceil(xOverlap * yOverlap);\n};\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst isRectObject = (obj) => isNumeric(obj.width) && isNumeric(obj.height) && isNumeric(obj.x) && isNumeric(obj.y);\n/* eslint-disable-next-line @typescript-eslint/no-explicit-any */\nconst isNumeric = (n) => !isNaN(n) && isFinite(n);\n// used for a11y key board controls for nodes and edges\nconst devWarn = (id, message) => {\n if (process.env.NODE_ENV === 'development') {\n console.warn(`[React Flow]: ${message} Help: https://reactflow.dev/error#${id}`);\n }\n};\nconst snapPosition = (position, snapGrid = [1, 1]) => {\n return {\n x: snapGrid[0] * Math.round(position.x / snapGrid[0]),\n y: snapGrid[1] * Math.round(position.y / snapGrid[1]),\n };\n};\nconst pointToRendererPoint = ({ x, y }, [tx, ty, tScale], snapToGrid = false, snapGrid = [1, 1]) => {\n const position = {\n x: (x - tx) / tScale,\n y: (y - ty) / tScale,\n };\n return snapToGrid ? snapPosition(position, snapGrid) : position;\n};\nconst rendererPointToPoint = ({ x, y }, [tx, ty, tScale]) => {\n return {\n x: x * tScale + tx,\n y: y * tScale + ty,\n };\n};\n/**\n * Returns a viewport that encloses the given bounds with optional padding.\n * @public\n * @remarks You can determine bounds of nodes with {@link getNodesBounds} and {@link getBoundsOfRects}\n * @param bounds - Bounds to fit inside viewport\n * @param width - Width of the viewport\n * @param height - Height of the viewport\n * @param minZoom - Minimum zoom level of the resulting viewport\n * @param maxZoom - Maximum zoom level of the resulting viewport\n * @param padding - Optional padding around the bounds\n * @returns A transforned {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport}\n * @example\n * const { x, y, zoom } = getViewportForBounds(\n { x: 0, y: 0, width: 100, height: 100},\n 1200, 800, 0.5, 2);\n */\nconst getViewportForBounds = (bounds, width, height, minZoom, maxZoom, padding) => {\n const xZoom = width / (bounds.width * (1 + padding));\n const yZoom = height / (bounds.height * (1 + padding));\n const zoom = Math.min(xZoom, yZoom);\n const clampedZoom = clamp(zoom, minZoom, maxZoom);\n const boundsCenterX = bounds.x + bounds.width / 2;\n const boundsCenterY = bounds.y + bounds.height / 2;\n const x = width / 2 - boundsCenterX * clampedZoom;\n const y = height / 2 - boundsCenterY * clampedZoom;\n return { x, y, zoom: clampedZoom };\n};\nconst isMacOs = () => typeof navigator !== 'undefined' && navigator?.userAgent?.indexOf('Mac') >= 0;\nfunction isCoordinateExtent(extent) {\n return extent !== undefined && extent !== 'parent';\n}\nfunction getNodeDimensions(node) {\n return {\n width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,\n height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,\n };\n}\nfunction nodeHasDimensions(node) {\n return ((node.measured?.width ?? node.width ?? node.initialWidth) !== undefined &&\n (node.measured?.height ?? node.height ?? node.initialHeight) !== undefined);\n}\n/**\n * Convert child position to aboslute position\n *\n * @internal\n * @param position\n * @param parentId\n * @param nodeLookup\n * @param nodeOrigin\n * @returns an internal node with an absolute position\n */\nfunction evaluateAbsolutePosition(position, dimensions = { width: 0, height: 0 }, parentId, nodeLookup, nodeOrigin) {\n let nextParentId = parentId;\n const positionAbsolute = { ...position };\n while (nextParentId) {\n const parent = nodeLookup.get(nextParentId);\n nextParentId = parent?.parentId;\n if (parent) {\n const origin = parent.origin || nodeOrigin;\n positionAbsolute.x += parent.internals.positionAbsolute.x - (dimensions.width ?? 0) * origin[0];\n positionAbsolute.y += parent.internals.positionAbsolute.y - (dimensions.height ?? 0) * origin[1];\n }\n }\n return positionAbsolute;\n}\n\nfunction getPointerPosition(event, { snapGrid = [0, 0], snapToGrid = false, transform }) {\n const { x, y } = getEventPosition(event);\n const pointerPos = pointToRendererPoint({ x, y }, transform);\n const { x: xSnapped, y: ySnapped } = snapToGrid ? snapPosition(pointerPos, snapGrid) : pointerPos;\n // we need the snapped position in order to be able to skip unnecessary drag events\n return {\n xSnapped,\n ySnapped,\n ...pointerPos,\n };\n}\nconst getDimensions = (node) => ({\n width: node.offsetWidth,\n height: node.offsetHeight,\n});\nconst getHostForElement = (element) => element.getRootNode?.() || window?.document;\nconst inputTags = ['INPUT', 'SELECT', 'TEXTAREA'];\nfunction isInputDOMNode(event) {\n // using composed path for handling shadow dom\n const target = (event.composedPath?.()?.[0] || event.target);\n const isInput = inputTags.includes(target?.nodeName) || target?.hasAttribute('contenteditable');\n // when an input field is focused we don't want to trigger deletion or movement of nodes\n return isInput || !!target?.closest('.nokey');\n}\nconst isMouseEvent = (event) => 'clientX' in event;\nconst getEventPosition = (event, bounds) => {\n const isMouse = isMouseEvent(event);\n const evtX = isMouse ? event.clientX : event.touches?.[0].clientX;\n const evtY = isMouse ? event.clientY : event.touches?.[0].clientY;\n return {\n x: evtX - (bounds?.left ?? 0),\n y: evtY - (bounds?.top ?? 0),\n };\n};\n// The handle bounds are calculated relative to the node element.\n// We store them in the internals object of the node in order to avoid\n// unnecessary recalculations.\nconst getHandleBounds = (type, nodeElement, nodeBounds, zoom, nodeId) => {\n const handles = nodeElement.querySelectorAll(`.${type}`);\n if (!handles || !handles.length) {\n return null;\n }\n return Array.from(handles).map((handle) => {\n const handleBounds = handle.getBoundingClientRect();\n return {\n id: handle.getAttribute('data-handleid'),\n type,\n nodeId,\n position: handle.getAttribute('data-handlepos'),\n x: (handleBounds.left - nodeBounds.left) / zoom,\n y: (handleBounds.top - nodeBounds.top) / zoom,\n ...getDimensions(handle),\n };\n });\n};\n\nfunction getBezierEdgeCenter({ sourceX, sourceY, targetX, targetY, sourceControlX, sourceControlY, targetControlX, targetControlY, }) {\n // cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate\n // https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve\n const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125;\n const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125;\n const offsetX = Math.abs(centerX - sourceX);\n const offsetY = Math.abs(centerY - sourceY);\n return [centerX, centerY, offsetX, offsetY];\n}\nfunction calculateControlOffset(distance, curvature) {\n if (distance >= 0) {\n return 0.5 * distance;\n }\n return curvature * 25 * Math.sqrt(-distance);\n}\nfunction getControlWithCurvature({ pos, x1, y1, x2, y2, c }) {\n switch (pos) {\n case Position.Left:\n return [x1 - calculateControlOffset(x1 - x2, c), y1];\n case Position.Right:\n return [x1 + calculateControlOffset(x2 - x1, c), y1];\n case Position.Top:\n return [x1, y1 - calculateControlOffset(y1 - y2, c)];\n case Position.Bottom:\n return [x1, y1 + calculateControlOffset(y2 - y1, c)];\n }\n}\n/**\n * Get a bezier path from source to target handle\n * @param params.sourceX - The x position of the source handle\n * @param params.sourceY - The y position of the source handle\n * @param params.sourcePosition - The position of the source handle (default: Position.Bottom)\n * @param params.targetX - The x position of the target handle\n * @param params.targetY - The y position of the target handle\n * @param params.targetPosition - The position of the target handle (default: Position.Top)\n * @param params.curvature - The curvature of the bezier edge\n * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label\n * @example\n * const source = { x: 0, y: 20 };\n const target = { x: 150, y: 100 };\n \n const [path, labelX, labelY, offsetX, offsetY] = getBezierPath({\n sourceX: source.x,\n sourceY: source.y,\n sourcePosition: Position.Right,\n targetX: target.x,\n targetY: target.y,\n targetPosition: Position.Left,\n});\n */\nfunction getBezierPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, curvature = 0.25, }) {\n const [sourceControlX, sourceControlY] = getControlWithCurvature({\n pos: sourcePosition,\n x1: sourceX,\n y1: sourceY,\n x2: targetX,\n y2: targetY,\n c: curvature,\n });\n const [targetControlX, targetControlY] = getControlWithCurvature({\n pos: targetPosition,\n x1: targetX,\n y1: targetY,\n x2: sourceX,\n y2: sourceY,\n c: curvature,\n });\n const [labelX, labelY, offsetX, offsetY] = getBezierEdgeCenter({\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourceControlX,\n sourceControlY,\n targetControlX,\n targetControlY,\n });\n return [\n `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`,\n labelX,\n labelY,\n offsetX,\n offsetY,\n ];\n}\n\n// this is used for straight edges and simple smoothstep edges (LTR, RTL, BTT, TTB)\nfunction getEdgeCenter({ sourceX, sourceY, targetX, targetY, }) {\n const xOffset = Math.abs(targetX - sourceX) / 2;\n const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;\n const yOffset = Math.abs(targetY - sourceY) / 2;\n const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;\n return [centerX, centerY, xOffset, yOffset];\n}\nfunction getElevatedEdgeZIndex({ sourceNode, targetNode, selected = false, zIndex = 0, elevateOnSelect = false, }) {\n if (!elevateOnSelect) {\n return zIndex;\n }\n const edgeOrConnectedNodeSelected = selected || targetNode.selected || sourceNode.selected;\n const selectedZIndex = Math.max(sourceNode.internals.z || 0, targetNode.internals.z || 0, 1000);\n return zIndex + (edgeOrConnectedNodeSelected ? selectedZIndex : 0);\n}\nfunction isEdgeVisible({ sourceNode, targetNode, width, height, transform }) {\n const edgeBox = getBoundsOfBoxes(nodeToBox(sourceNode), nodeToBox(targetNode));\n if (edgeBox.x === edgeBox.x2) {\n edgeBox.x2 += 1;\n }\n if (edgeBox.y === edgeBox.y2) {\n edgeBox.y2 += 1;\n }\n const viewRect = {\n x: -transform[0] / transform[2],\n y: -transform[1] / transform[2],\n width: width / transform[2],\n height: height / transform[2],\n };\n return getOverlappingArea(viewRect, boxToRect(edgeBox)) > 0;\n}\nconst getEdgeId = ({ source, sourceHandle, target, targetHandle }) => `xy-edge__${source}${sourceHandle || ''}-${target}${targetHandle || ''}`;\nconst connectionExists = (edge, edges) => {\n return edges.some((el) => el.source === edge.source &&\n el.target === edge.target &&\n (el.sourceHandle === edge.sourceHandle || (!el.sourceHandle && !edge.sourceHandle)) &&\n (el.targetHandle === edge.targetHandle || (!el.targetHandle && !edge.targetHandle)));\n};\n/**\n * This util is a convenience function to add a new Edge to an array of edges\n * @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.\n * @public\n * @param edgeParams - Either an Edge or a Connection you want to add\n * @param edges - The array of all current edges\n * @returns A new array of edges with the new edge added\n */\nconst addEdge = (edgeParams, edges) => {\n if (!edgeParams.source || !edgeParams.target) {\n devWarn('006', errorMessages['error006']());\n return edges;\n }\n let edge;\n if (isEdgeBase(edgeParams)) {\n edge = { ...edgeParams };\n }\n else {\n edge = {\n ...edgeParams,\n id: getEdgeId(edgeParams),\n };\n }\n if (connectionExists(edge, edges)) {\n return edges;\n }\n if (edge.sourceHandle === null) {\n delete edge.sourceHandle;\n }\n if (edge.targetHandle === null) {\n delete edge.targetHandle;\n }\n return edges.concat(edge);\n};\n/**\n * A handy utility to reconnect an existing edge with new properties\n * @param oldEdge - The edge you want to update\n * @param newConnection - The new connection you want to update the edge with\n * @param edges - The array of all current edges\n * @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id\n * @returns the updated edges array\n */\nconst reconnectEdge = (oldEdge, newConnection, edges, options = { shouldReplaceId: true }) => {\n const { id: oldEdgeId, ...rest } = oldEdge;\n if (!newConnection.source || !newConnection.target) {\n devWarn('006', errorMessages['error006']());\n return edges;\n }\n const foundEdge = edges.find((e) => e.id === oldEdge.id);\n if (!foundEdge) {\n devWarn('007', errorMessages['error007'](oldEdgeId));\n return edges;\n }\n // Remove old edge and create the new edge with parameters of old edge.\n const edge = {\n ...rest,\n id: options.shouldReplaceId ? getEdgeId(newConnection) : oldEdgeId,\n source: newConnection.source,\n target: newConnection.target,\n sourceHandle: newConnection.sourceHandle,\n targetHandle: newConnection.targetHandle,\n };\n return edges.filter((e) => e.id !== oldEdgeId).concat(edge);\n};\n\n/**\n * Get a straight path from source to target handle\n * @param params.sourceX - The x position of the source handle\n * @param params.sourceY - The y position of the source handle\n * @param params.targetX - The x position of the target handle\n * @param params.targetY - The y position of the target handle\n * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label\n * @example\n * const source = { x: 0, y: 20 };\n const target = { x: 150, y: 100 };\n \n const [path, labelX, labelY, offsetX, offsetY] = getStraightPath({\n sourceX: source.x,\n sourceY: source.y,\n sourcePosition: Position.Right,\n targetX: target.x,\n targetY: target.y,\n targetPosition: Position.Left,\n });\n */\nfunction getStraightPath({ sourceX, sourceY, targetX, targetY, }) {\n const [labelX, labelY, offsetX, offsetY] = getEdgeCenter({\n sourceX,\n sourceY,\n targetX,\n targetY,\n });\n return [`M ${sourceX},${sourceY}L ${targetX},${targetY}`, labelX, labelY, offsetX, offsetY];\n}\n\nconst handleDirections = {\n [Position.Left]: { x: -1, y: 0 },\n [Position.Right]: { x: 1, y: 0 },\n [Position.Top]: { x: 0, y: -1 },\n [Position.Bottom]: { x: 0, y: 1 },\n};\nconst getDirection = ({ source, sourcePosition = Position.Bottom, target, }) => {\n if (sourcePosition === Position.Left || sourcePosition === Position.Right) {\n return source.x < target.x ? { x: 1, y: 0 } : { x: -1, y: 0 };\n }\n return source.y < target.y ? { x: 0, y: 1 } : { x: 0, y: -1 };\n};\nconst distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));\n// ith this function we try to mimic a orthogonal edge routing behaviour\n// It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges\nfunction getPoints({ source, sourcePosition = Position.Bottom, target, targetPosition = Position.Top, center, offset, }) {\n const sourceDir = handleDirections[sourcePosition];\n const targetDir = handleDirections[targetPosition];\n const sourceGapped = { x: source.x + sourceDir.x * offset, y: source.y + sourceDir.y * offset };\n const targetGapped = { x: target.x + targetDir.x * offset, y: target.y + targetDir.y * offset };\n const dir = getDirection({\n source: sourceGapped,\n sourcePosition,\n target: targetGapped,\n });\n const dirAccessor = dir.x !== 0 ? 'x' : 'y';\n const currDir = dir[dirAccessor];\n let points = [];\n let centerX, centerY;\n const sourceGapOffset = { x: 0, y: 0 };\n const targetGapOffset = { x: 0, y: 0 };\n const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getEdgeCenter({\n sourceX: source.x,\n sourceY: source.y,\n targetX: target.x,\n targetY: target.y,\n });\n // opposite handle positions, default case\n if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {\n centerX = center.x ?? defaultCenterX;\n centerY = center.y ?? defaultCenterY;\n // --->\n // |\n // >---\n const verticalSplit = [\n { x: centerX, y: sourceGapped.y },\n { x: centerX, y: targetGapped.y },\n ];\n // |\n // ---\n // |\n const horizontalSplit = [\n { x: sourceGapped.x, y: centerY },\n { x: targetGapped.x, y: centerY },\n ];\n if (sourceDir[dirAccessor] === currDir) {\n points = dirAccessor === 'x' ? verticalSplit : horizontalSplit;\n }\n else {\n points = dirAccessor === 'x' ? horizontalSplit : verticalSplit;\n }\n }\n else {\n // sourceTarget means we take x from source and y from target, targetSource is the opposite\n const sourceTarget = [{ x: sourceGapped.x, y: targetGapped.y }];\n const targetSource = [{ x: targetGapped.x, y: sourceGapped.y }];\n // this handles edges with same handle positions\n if (dirAccessor === 'x') {\n points = sourceDir.x === currDir ? targetSource : sourceTarget;\n }\n else {\n points = sourceDir.y === currDir ? sourceTarget : targetSource;\n }\n if (sourcePosition === targetPosition) {\n const diff = Math.abs(source[dirAccessor] - target[dirAccessor]);\n // if an edge goes from right to right for example (sourcePosition === targetPosition) and the distance between source.x and target.x is less than the offset, the added point and the gapped source/target will overlap. This leads to a weird edge path. To avoid this we add a gapOffset to the source/target\n if (diff <= offset) {\n const gapOffset = Math.min(offset - 1, offset - diff);\n if (sourceDir[dirAccessor] === currDir) {\n sourceGapOffset[dirAccessor] = (sourceGapped[dirAccessor] > source[dirAccessor] ? -1 : 1) * gapOffset;\n }\n else {\n targetGapOffset[dirAccessor] = (targetGapped[dirAccessor] > target[dirAccessor] ? -1 : 1) * gapOffset;\n }\n }\n }\n // these are conditions for handling mixed handle positions like Right -> Bottom for example\n if (sourcePosition !== targetPosition) {\n const dirAccessorOpposite = dirAccessor === 'x' ? 'y' : 'x';\n const isSameDir = sourceDir[dirAccessor] === targetDir[dirAccessorOpposite];\n const sourceGtTargetOppo = sourceGapped[dirAccessorOpposite] > targetGapped[dirAccessorOpposite];\n const sourceLtTargetOppo = sourceGapped[dirAccessorOpposite] < targetGapped[dirAccessorOpposite];\n const flipSourceTarget = (sourceDir[dirAccessor] === 1 && ((!isSameDir && sourceGtTargetOppo) || (isSameDir && sourceLtTargetOppo))) ||\n (sourceDir[dirAccessor] !== 1 && ((!isSameDir && sourceLtTargetOppo) || (isSameDir && sourceGtTargetOppo)));\n if (flipSourceTarget) {\n points = dirAccessor === 'x' ? sourceTarget : targetSource;\n }\n }\n const sourceGapPoint = { x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y };\n const targetGapPoint = { x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y };\n const maxXDistance = Math.max(Math.abs(sourceGapPoint.x - points[0].x), Math.abs(targetGapPoint.x - points[0].x));\n const maxYDistance = Math.max(Math.abs(sourceGapPoint.y - points[0].y), Math.abs(targetGapPoint.y - points[0].y));\n // we want to place the label on the longest segment of the edge\n if (maxXDistance >= maxYDistance) {\n centerX = (sourceGapPoint.x + targetGapPoint.x) / 2;\n centerY = points[0].y;\n }\n else {\n centerX = points[0].x;\n centerY = (sourceGapPoint.y + targetGapPoint.y) / 2;\n }\n }\n const pathPoints = [\n source,\n { x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y },\n ...points,\n { x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y },\n target,\n ];\n return [pathPoints, centerX, centerY, defaultOffsetX, defaultOffsetY];\n}\nfunction getBend(a, b, c, size) {\n const bendSize = Math.min(distance(a, b) / 2, distance(b, c) / 2, size);\n const { x, y } = b;\n // no bend\n if ((a.x === x && x === c.x) || (a.y === y && y === c.y)) {\n return `L${x} ${y}`;\n }\n // first segment is horizontal\n if (a.y === y) {\n const xDir = a.x < c.x ? -1 : 1;\n const yDir = a.y < c.y ? 1 : -1;\n return `L ${x + bendSize * xDir},${y}Q ${x},${y} ${x},${y + bendSize * yDir}`;\n }\n const xDir = a.x < c.x ? 1 : -1;\n const yDir = a.y < c.y ? -1 : 1;\n return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}`;\n}\n/**\n * Get a smooth step path from source to target handle\n * @param params.sourceX - The x position of the source handle\n * @param params.sourceY - The y position of the source handle\n * @param params.sourcePosition - The position of the source handle (default: Position.Bottom)\n * @param params.targetX - The x position of the target handle\n * @param params.targetY - The y position of the target handle\n * @param params.targetPosition - The position of the target handle (default: Position.Top)\n * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label\n * @example\n * const source = { x: 0, y: 20 };\n const target = { x: 150, y: 100 };\n \n const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({\n sourceX: source.x,\n sourceY: source.y,\n sourcePosition: Position.Right,\n targetX: target.x,\n targetY: target.y,\n targetPosition: Position.Left,\n });\n */\nfunction getSmoothStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, borderRadius = 5, centerX, centerY, offset = 20, }) {\n const [points, labelX, labelY, offsetX, offsetY] = getPoints({\n source: { x: sourceX, y: sourceY },\n sourcePosition,\n target: { x: targetX, y: targetY },\n targetPosition,\n center: { x: centerX, y: centerY },\n offset,\n });\n const path = points.reduce((res, p, i) => {\n let segment = '';\n if (i > 0 && i < points.length - 1) {\n segment = getBend(points[i - 1], p, points[i + 1], borderRadius);\n }\n else {\n segment = `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}`;\n }\n res += segment;\n return res;\n }, '');\n return [path, labelX, labelY, offsetX, offsetY];\n}\n\nfunction isNodeInitialized(node) {\n return (node &&\n !!(node.internals.handleBounds || node.handles?.length) &&\n !!(node.measured.width || node.width || node.initialWidth));\n}\nfunction getEdgePosition(params) {\n const { sourceNode, targetNode } = params;\n if (!isNodeInitialized(sourceNode) || !isNodeInitialized(targetNode)) {\n return null;\n }\n const sourceHandleBounds = sourceNode.internals.handleBounds || toHandleBounds(sourceNode.handles);\n const targetHandleBounds = targetNode.internals.handleBounds || toHandleBounds(targetNode.handles);\n const sourceHandle = getHandle$1(sourceHandleBounds?.source ?? [], params.sourceHandle);\n const targetHandle = getHandle$1(\n // when connection type is loose we can define all handles as sources and connect source -> source\n params.connectionMode === ConnectionMode.Strict\n ? targetHandleBounds?.target ?? []\n : (targetHandleBounds?.target ?? []).concat(targetHandleBounds?.source ?? []), params.targetHandle);\n if (!sourceHandle || !targetHandle) {\n params.onError?.('008', errorMessages['error008'](!sourceHandle ? 'source' : 'target', {\n id: params.id,\n sourceHandle: params.sourceHandle,\n targetHandle: params.targetHandle,\n }));\n return null;\n }\n const sourcePosition = sourceHandle?.position || Position.Bottom;\n const targetPosition = targetHandle?.position || Position.Top;\n const source = getHandlePosition(sourceNode, sourceHandle, sourcePosition);\n const target = getHandlePosition(targetNode, targetHandle, targetPosition);\n return {\n sourceX: source.x,\n sourceY: source.y,\n targetX: target.x,\n targetY: target.y,\n sourcePosition,\n targetPosition,\n };\n}\nfunction toHandleBounds(handles) {\n if (!handles) {\n return null;\n }\n const source = [];\n const target = [];\n for (const handle of handles) {\n handle.width = handle.width ?? 1;\n handle.height = handle.height ?? 1;\n if (handle.type === 'source') {\n source.push(handle);\n }\n else if (handle.type === 'target') {\n target.push(handle);\n }\n }\n return {\n source,\n target,\n };\n}\nfunction getHandlePosition(node, handle, fallbackPosition = Position.Left, center = false) {\n const x = (handle?.x ?? 0) + node.internals.positionAbsolute.x;\n const y = (handle?.y ?? 0) + node.internals.positionAbsolute.y;\n const { width, height } = handle ?? getNodeDimensions(node);\n if (center) {\n return { x: x + width / 2, y: y + height / 2 };\n }\n const position = handle?.position ?? fallbackPosition;\n switch (position) {\n case Position.Top:\n return { x: x + width / 2, y };\n case Position.Right:\n return { x: x + width, y: y + height / 2 };\n case Position.Bottom:\n return { x: x + width / 2, y: y + height };\n case Position.Left:\n return { x, y: y + height / 2 };\n }\n}\nfunction getHandle$1(bounds, handleId) {\n if (!bounds) {\n return null;\n }\n // if no handleId is given, we use the first handle, otherwise we check for the id\n return (!handleId ? bounds[0] : bounds.find((d) => d.id === handleId)) || null;\n}\n\nfunction getMarkerId(marker, id) {\n if (!marker) {\n return '';\n }\n if (typeof marker === 'string') {\n return marker;\n }\n const idPrefix = id ? `${id}__` : '';\n return `${idPrefix}${Object.keys(marker)\n .sort()\n .map((key) => `${key}=${marker[key]}`)\n .join('&')}`;\n}\nfunction createMarkerIds(edges, { id, defaultColor, defaultMarkerStart, defaultMarkerEnd, }) {\n const ids = new Set();\n return edges\n .reduce((markers, edge) => {\n [edge.markerStart || defaultMarkerStart, edge.markerEnd || defaultMarkerEnd].forEach((marker) => {\n if (marker && typeof marker === 'object') {\n const markerId = getMarkerId(marker, id);\n if (!ids.has(markerId)) {\n markers.push({ id: markerId, color: marker.color || defaultColor, ...marker });\n ids.add(markerId);\n }\n }\n });\n return markers;\n }, [])\n .sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {\n let alignmentOffset = 0.5;\n if (align === 'start') {\n alignmentOffset = 0;\n }\n else if (align === 'end') {\n alignmentOffset = 1;\n }\n // position === Position.Top\n // we set the x any y position of the toolbar based on the nodes position\n let pos = [\n (nodeRect.x + nodeRect.width * alignmentOffset) * viewport.zoom + viewport.x,\n nodeRect.y * viewport.zoom + viewport.y - offset,\n ];\n // and than shift it based on the alignment. The shift values are in %.\n let shift = [-100 * alignmentOffset, -100];\n switch (position) {\n case Position.Right:\n pos = [\n (nodeRect.x + nodeRect.width) * viewport.zoom + viewport.x + offset,\n (nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y,\n ];\n shift = [0, -100 * alignmentOffset];\n break;\n case Position.Bottom:\n pos[1] = (nodeRect.y + nodeRect.height) * viewport.zoom + viewport.y + offset;\n shift[1] = 0;\n break;\n case Position.Left:\n pos = [\n nodeRect.x * viewport.zoom + viewport.x - offset,\n (nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y,\n ];\n shift = [-100, -100 * alignmentOffset];\n break;\n }\n return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`;\n}\n\nconst defaultOptions = {\n nodeOrigin: [0, 0],\n nodeExtent: infiniteExtent,\n elevateNodesOnSelect: true,\n defaults: {},\n};\nconst adoptUserNodesDefaultOptions = {\n ...defaultOptions,\n checkEquality: true,\n};\nfunction mergeObjects(base, incoming) {\n const result = { ...base };\n for (const key in incoming) {\n if (incoming[key] !== undefined) {\n // typecast is safe here, because we check for undefined\n result[key] = incoming[key];\n }\n }\n return result;\n}\nfunction updateAbsolutePositions(nodeLookup, parentLookup, options) {\n const _options = mergeObjects(defaultOptions, options);\n for (const node of nodeLookup.values()) {\n if (!node.parentId) {\n continue;\n }\n updateChildNode(node, nodeLookup, parentLookup, _options);\n }\n}\nfunction adoptUserNodes(nodes, nodeLookup, parentLookup, options) {\n const _options = mergeObjects(adoptUserNodesDefaultOptions, options);\n const tmpLookup = new Map(nodeLookup);\n const selectedNodeZ = _options?.elevateNodesOnSelect ? 1000 : 0;\n nodeLookup.clear();\n parentLookup.clear();\n for (const userNode of nodes) {\n let internalNode = tmpLookup.get(userNode.id);\n if (_options.checkEquality && userNode === internalNode?.internals.userNode) {\n nodeLookup.set(userNode.id, internalNode);\n }\n else {\n const positionWithOrigin = getNodePositionWithOrigin(userNode, _options.nodeOrigin);\n const extent = isCoordinateExtent(userNode.extent) ? userNode.extent : _options.nodeExtent;\n const clampedPosition = clampPosition(positionWithOrigin, extent, getNodeDimensions(userNode));\n internalNode = {\n ..._options.defaults,\n ...userNode,\n measured: {\n width: userNode.measured?.width,\n height: userNode.measured?.height,\n },\n internals: {\n positionAbsolute: clampedPosition,\n // if user re-initializes the node or removes `measured` for whatever reason, we reset the handleBounds so that the node gets re-measured\n handleBounds: !userNode.measured ? undefined : internalNode?.internals.handleBounds,\n z: calculateZ(userNode, selectedNodeZ),\n userNode,\n },\n };\n nodeLookup.set(userNode.id, internalNode);\n }\n if (userNode.parentId) {\n updateChildNode(internalNode, nodeLookup, parentLookup, options);\n }\n }\n}\nfunction updateParentLookup(node, parentLookup) {\n if (!node.parentId) {\n return;\n }\n const childNodes = parentLookup.get(node.parentId);\n if (childNodes) {\n childNodes.set(node.id, node);\n }\n else {\n parentLookup.set(node.parentId, new Map([[node.id, node]]));\n }\n}\n/**\n * Updates positionAbsolute and zIndex of a child node and the parentLookup.\n */\nfunction updateChildNode(node, nodeLookup, parentLookup, options) {\n const { elevateNodesOnSelect, nodeOrigin, nodeExtent } = mergeObjects(defaultOptions, options);\n const parentId = node.parentId;\n const parentNode = nodeLookup.get(parentId);\n if (!parentNode) {\n console.warn(`Parent node ${parentId} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);\n return;\n }\n updateParentLookup(node, parentLookup);\n const selectedNodeZ = elevateNodesOnSelect ? 1000 : 0;\n const { x, y, z } = calculateChildXYZ(node, parentNode, nodeOrigin, nodeExtent, selectedNodeZ);\n const { positionAbsolute } = node.internals;\n const positionChanged = x !== positionAbsolute.x || y !== positionAbsolute.y;\n if (positionChanged || z !== node.internals.z) {\n node.internals = {\n ...node.internals,\n positionAbsolute: positionChanged ? { x, y } : positionAbsolute,\n z,\n };\n }\n}\nfunction calculateZ(node, selectedNodeZ) {\n return (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0);\n}\nfunction calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ) {\n const { x: parentX, y: parentY } = parentNode.internals.positionAbsolute;\n const childDimensions = getNodeDimensions(childNode);\n const positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin);\n const clampedPosition = isCoordinateExtent(childNode.extent)\n ? clampPosition(positionWithOrigin, childNode.extent, childDimensions)\n : positionWithOrigin;\n let absolutePosition = clampPosition({ x: parentX + clampedPosition.x, y: parentY + clampedPosition.y }, nodeExtent, childDimensions);\n if (childNode.extent === 'parent') {\n absolutePosition = clampPositionToParent(absolutePosition, childDimensions, parentNode);\n }\n const childZ = calculateZ(childNode, selectedNodeZ);\n const parentZ = parentNode.internals.z ?? 0;\n return {\n x: absolutePosition.x,\n y: absolutePosition.y,\n z: parentZ > childZ ? parentZ : childZ,\n };\n}\nfunction handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin = [0, 0]) {\n const changes = [];\n const parentExpansions = new Map();\n // determine the expanded rectangle the child nodes would take for each parent\n for (const child of children) {\n const parent = nodeLookup.get(child.parentId);\n if (!parent) {\n continue;\n }\n const parentRect = parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent);\n const expandedRect = getBoundsOfRects(parentRect, child.rect);\n parentExpansions.set(child.parentId, { expandedRect, parent });\n }\n if (parentExpansions.size > 0) {\n parentExpansions.forEach(({ expandedRect, parent }, parentId) => {\n // determine the position & dimensions of the parent\n const positionAbsolute = parent.internals.positionAbsolute;\n const dimensions = getNodeDimensions(parent);\n const origin = parent.origin ?? nodeOrigin;\n // determine how much the parent expands in width and position\n const xChange = expandedRect.x < positionAbsolute.x ? Math.round(Math.abs(positionAbsolute.x - expandedRect.x)) : 0;\n const yChange = expandedRect.y < positionAbsolute.y ? Math.round(Math.abs(positionAbsolute.y - expandedRect.y)) : 0;\n const newWidth = Math.max(dimensions.width, Math.round(expandedRect.width));\n const newHeight = Math.max(dimensions.height, Math.round(expandedRect.height));\n const widthChange = (newWidth - dimensions.width) * origin[0];\n const heightChange = (newHeight - dimensions.height) * origin[1];\n // We need to correct the position of the parent node if the origin is not [0,0]\n if (xChange > 0 || yChange > 0 || widthChange || heightChange) {\n changes.push({\n id: parentId,\n type: 'position',\n position: {\n x: parent.position.x - xChange + widthChange,\n y: parent.position.y - yChange + heightChange,\n },\n });\n // We move all child nodes in the oppsite direction\n // so the x,y changes of the parent do not move the children\n parentLookup.get(parentId)?.forEach((childNode) => {\n if (!children.some((child) => child.id === childNode.id)) {\n changes.push({\n id: childNode.id,\n type: 'position',\n position: {\n x: childNode.position.x + xChange,\n y: childNode.position.y + yChange,\n },\n });\n }\n });\n }\n // We need to correct the dimensions of the parent node if the origin is not [0,0]\n if (dimensions.width < expandedRect.width || dimensions.height < expandedRect.height || xChange || yChange) {\n changes.push({\n id: parentId,\n type: 'dimensions',\n setAttributes: true,\n dimensions: {\n width: newWidth + (xChange ? origin[0] * xChange - widthChange : 0),\n height: newHeight + (yChange ? origin[1] * yChange - heightChange : 0),\n },\n });\n }\n });\n }\n return changes;\n}\nfunction updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent) {\n const viewportNode = domNode?.querySelector('.xyflow__viewport');\n let updatedInternals = false;\n if (!viewportNode) {\n return { changes: [], updatedInternals };\n }\n const changes = [];\n const style = window.getComputedStyle(viewportNode);\n const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);\n // in this array we collect nodes, that might trigger changes (like expanding parent)\n const parentExpandChildren = [];\n for (const update of updates.values()) {\n const node = nodeLookup.get(update.id);\n if (!node) {\n continue;\n }\n if (node.hidden) {\n node.internals = {\n ...node.internals,\n handleBounds: undefined,\n };\n updatedInternals = true;\n }\n else {\n const dimensions = getDimensions(update.nodeElement);\n const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;\n const doUpdate = !!(dimensions.width &&\n dimensions.height &&\n (dimensionChanged || !node.internals.handleBounds || update.force));\n if (doUpdate) {\n const nodeBounds = update.nodeElement.getBoundingClientRect();\n const extent = isCoordinateExtent(node.extent) ? node.extent : nodeExtent;\n let { positionAbsolute } = node.internals;\n if (node.parentId && node.extent === 'parent') {\n positionAbsolute = clampPositionToParent(positionAbsolute, dimensions, nodeLookup.get(node.parentId));\n }\n else if (extent) {\n positionAbsolute = clampPosition(positionAbsolute, extent, dimensions);\n }\n node.measured = dimensions;\n node.internals = {\n ...node.internals,\n positionAbsolute,\n handleBounds: {\n source: getHandleBounds('source', update.nodeElement, nodeBounds, zoom, node.id),\n target: getHandleBounds('target', update.nodeElement, nodeBounds, zoom, node.id),\n },\n };\n if (node.parentId) {\n updateChildNode(node, nodeLookup, parentLookup, { nodeOrigin });\n }\n updatedInternals = true;\n if (dimensionChanged) {\n changes.push({\n id: node.id,\n type: 'dimensions',\n dimensions,\n });\n if (node.expandParent && node.parentId) {\n parentExpandChildren.push({\n id: node.id,\n parentId: node.parentId,\n rect: nodeToRect(node, nodeOrigin),\n });\n }\n }\n }\n }\n }\n if (parentExpandChildren.length > 0) {\n const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);\n changes.push(...parentExpandChanges);\n }\n return { changes, updatedInternals };\n}\nasync function panBy({ delta, panZoom, transform, translateExtent, width, height, }) {\n if (!panZoom || (!delta.x && !delta.y)) {\n return Promise.resolve(false);\n }\n const nextViewport = await panZoom.setViewportConstrained({\n x: transform[0] + delta.x,\n y: transform[1] + delta.y,\n zoom: transform[2],\n }, [\n [0, 0],\n [width, height],\n ], translateExtent);\n const transformChanged = !!nextViewport &&\n (nextViewport.x !== transform[0] || nextViewport.y !== transform[1] || nextViewport.k !== transform[2]);\n return Promise.resolve(transformChanged);\n}\nfunction updateConnectionLookup(connectionLookup, edgeLookup, edges) {\n connectionLookup.clear();\n edgeLookup.clear();\n for (const edge of edges) {\n const { source, target, sourceHandle = null, targetHandle = null } = edge;\n const sourceKey = `${source}-source-${sourceHandle}`;\n const targetKey = `${target}-target-${targetHandle}`;\n const prevSource = connectionLookup.get(sourceKey) || new Map();\n const prevTarget = connectionLookup.get(targetKey) || new Map();\n const connection = { edgeId: edge.id, source, target, sourceHandle, targetHandle };\n edgeLookup.set(edge.id, edge);\n connectionLookup.set(sourceKey, prevSource.set(`${target}-${targetHandle}`, connection));\n connectionLookup.set(targetKey, prevTarget.set(`${source}-${sourceHandle}`, connection));\n }\n}\n\nfunction shallowNodeData(a, b) {\n if (a === null || b === null) {\n return false;\n }\n const _a = Array.isArray(a) ? a : [a];\n const _b = Array.isArray(b) ? b : [b];\n if (_a.length !== _b.length) {\n return false;\n }\n for (let i = 0; i < _a.length; i++) {\n if (_a[i].id !== _b[i].id || _a[i].type !== _b[i].type || !Object.is(_a[i].data, _b[i].data)) {\n return false;\n }\n }\n return true;\n}\n\nfunction isParentSelected(node, nodeLookup) {\n if (!node.parentId) {\n return false;\n }\n const parentNode = nodeLookup.get(node.parentId);\n if (!parentNode) {\n return false;\n }\n if (parentNode.selected) {\n return true;\n }\n return isParentSelected(parentNode, nodeLookup);\n}\nfunction hasSelector(target, selector, domNode) {\n let current = target;\n do {\n if (current?.matches(selector))\n return true;\n if (current === domNode)\n return false;\n current = current.parentElement;\n } while (current);\n return false;\n}\n// looks for all selected nodes and created a NodeDragItem for each of them\nfunction getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {\n const dragItems = new Map();\n for (const [id, node] of nodeLookup) {\n if ((node.selected || node.id === nodeId) &&\n (!node.parentId || !isParentSelected(node, nodeLookup)) &&\n (node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'))) {\n const internalNode = nodeLookup.get(id);\n if (internalNode) {\n dragItems.set(id, {\n id,\n position: internalNode.position || { x: 0, y: 0 },\n distance: {\n x: mousePos.x - internalNode.internals.positionAbsolute.x,\n y: mousePos.y - internalNode.internals.positionAbsolute.y,\n },\n extent: internalNode.extent,\n parentId: internalNode.parentId,\n origin: internalNode.origin,\n expandParent: internalNode.expandParent,\n internals: {\n positionAbsolute: internalNode.internals.positionAbsolute || { x: 0, y: 0 },\n },\n measured: {\n width: internalNode.measured.width ?? 0,\n height: internalNode.measured.height ?? 0,\n },\n });\n }\n }\n }\n return dragItems;\n}\n// returns two params:\n// 1. the dragged node (or the first of the list, if we are dragging a node selection)\n// 2. array of selected nodes (for multi selections)\nfunction getEventHandlerParams({ nodeId, dragItems, nodeLookup, dragging = true, }) {\n const nodesFromDragItems = [];\n for (const [id, dragItem] of dragItems) {\n const node = nodeLookup.get(id)?.internals.userNode;\n if (node) {\n nodesFromDragItems.push({\n ...node,\n position: dragItem.position,\n dragging,\n });\n }\n }\n if (!nodeId) {\n return [nodesFromDragItems[0], nodesFromDragItems];\n }\n const node = nodeLookup.get(nodeId).internals.userNode;\n return [\n {\n ...node,\n position: dragItems.get(nodeId)?.position || node.position,\n dragging,\n },\n nodesFromDragItems,\n ];\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragStop, }) {\n let lastPos = { x: null, y: null };\n let autoPanId = 0;\n let dragItems = new Map();\n let autoPanStarted = false;\n let mousePosition = { x: 0, y: 0 };\n let containerBounds = null;\n let dragStarted = false;\n let d3Selection = null;\n let abortDrag = false; // prevents unintentional dragging on multitouch\n // public functions\n function update({ noDragClassName, handleSelector, domNode, isSelectable, nodeId, nodeClickDistance = 0, }) {\n d3Selection = select(domNode);\n function updateNodes({ x, y }, dragEvent) {\n const { nodeLookup, nodeExtent, snapGrid, snapToGrid, nodeOrigin, onNodeDrag, onSelectionDrag, onError, updateNodePositions, } = getStoreItems();\n lastPos = { x, y };\n let hasChange = false;\n let nodesBox = { x: 0, y: 0, x2: 0, y2: 0 };\n if (dragItems.size > 1 && nodeExtent) {\n const rect = getInternalNodesBounds(dragItems);\n nodesBox = rectToBox(rect);\n }\n for (const [id, dragItem] of dragItems) {\n let nextPosition = { x: x - dragItem.distance.x, y: y - dragItem.distance.y };\n if (snapToGrid) {\n nextPosition = snapPosition(nextPosition, snapGrid);\n }\n // if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node\n // based on its position so that the node stays at it's position relative to the selection.\n let adjustedNodeExtent = [\n [nodeExtent[0][0], nodeExtent[0][1]],\n [nodeExtent[1][0], nodeExtent[1][1]],\n ];\n if (dragItems.size > 1 && nodeExtent && !dragItem.extent) {\n const { positionAbsolute } = dragItem.internals;\n const x1 = positionAbsolute.x - nodesBox.x + nodeExtent[0][0];\n const x2 = positionAbsolute.x + dragItem.measured.width - nodesBox.x2 + nodeExtent[1][0];\n const y1 = positionAbsolute.y - nodesBox.y + nodeExtent[0][1];\n const y2 = positionAbsolute.y + dragItem.measured.height - nodesBox.y2 + nodeExtent[1][1];\n adjustedNodeExtent = [\n [x1, y1],\n [x2, y2],\n ];\n }\n const { position, positionAbsolute } = calculateNodePosition({\n nodeId: id,\n nextPosition,\n nodeLookup,\n nodeExtent: adjustedNodeExtent,\n nodeOrigin,\n onError,\n });\n // we want to make sure that we only fire a change event when there is a change\n hasChange = hasChange || dragItem.position.x !== position.x || dragItem.position.y !== position.y;\n dragItem.position = position;\n dragItem.internals.positionAbsolute = positionAbsolute;\n }\n if (!hasChange) {\n return;\n }\n updateNodePositions(dragItems, true);\n if (dragEvent && (onDrag || onNodeDrag || (!nodeId && onSelectionDrag))) {\n const [currentNode, currentNodes] = getEventHandlerParams({\n nodeId,\n dragItems,\n nodeLookup,\n });\n onDrag?.(dragEvent, dragItems, currentNode, currentNodes);\n onNodeDrag?.(dragEvent, currentNode, currentNodes);\n if (!nodeId) {\n onSelectionDrag?.(dragEvent, currentNodes);\n }\n }\n }\n async function autoPan() {\n if (!containerBounds) {\n return;\n }\n const { transform, panBy, autoPanSpeed } = getStoreItems();\n const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds, autoPanSpeed);\n if (xMovement !== 0 || yMovement !== 0) {\n lastPos.x = (lastPos.x ?? 0) - xMovement / transform[2];\n lastPos.y = (lastPos.y ?? 0) - yMovement / transform[2];\n if (await panBy({ x: xMovement, y: yMovement })) {\n updateNodes(lastPos, null);\n }\n }\n autoPanId = requestAnimationFrame(autoPan);\n }\n function startDrag(event) {\n const { nodeLookup, multiSelectionActive, nodesDraggable, transform, snapGrid, snapToGrid, selectNodesOnDrag, onNodeDragStart, onSelectionDragStart, unselectNodesAndEdges, } = getStoreItems();\n dragStarted = true;\n if ((!selectNodesOnDrag || !isSelectable) && !multiSelectionActive && nodeId) {\n if (!nodeLookup.get(nodeId)?.selected) {\n // we need to reset selected nodes when selectNodesOnDrag=false\n unselectNodesAndEdges();\n }\n }\n if (isSelectable && selectNodesOnDrag && nodeId) {\n onNodeMouseDown?.(nodeId);\n }\n const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });\n lastPos = pointerPos;\n dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);\n if (dragItems.size > 0 && (onDragStart || onNodeDragStart || (!nodeId && onSelectionDragStart))) {\n const [currentNode, currentNodes] = getEventHandlerParams({\n nodeId,\n dragItems,\n nodeLookup,\n });\n onDragStart?.(event.sourceEvent, dragItems, currentNode, currentNodes);\n onNodeDragStart?.(event.sourceEvent, currentNode, currentNodes);\n if (!nodeId) {\n onSelectionDragStart?.(event.sourceEvent, currentNodes);\n }\n }\n }\n const d3DragInstance = drag()\n .clickDistance(nodeClickDistance)\n .on('start', (event) => {\n const { domNode, nodeDragThreshold, transform, snapGrid, snapToGrid } = getStoreItems();\n abortDrag = false;\n if (nodeDragThreshold === 0) {\n startDrag(event);\n }\n const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });\n lastPos = pointerPos;\n containerBounds = domNode?.getBoundingClientRect() || null;\n mousePosition = getEventPosition(event.sourceEvent, containerBounds);\n })\n .on('drag', (event) => {\n const { autoPanOnNodeDrag, transform, snapGrid, snapToGrid, nodeDragThreshold } = getStoreItems();\n const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });\n if (event.sourceEvent.type === 'touchmove' && event.sourceEvent.touches.length > 1) {\n abortDrag = true;\n }\n if (abortDrag) {\n return;\n }\n if (!autoPanStarted && autoPanOnNodeDrag && dragStarted) {\n autoPanStarted = true;\n autoPan();\n }\n if (!dragStarted) {\n const x = pointerPos.xSnapped - (lastPos.x ?? 0);\n const y = pointerPos.ySnapped - (lastPos.y ?? 0);\n const distance = Math.sqrt(x * x + y * y);\n if (distance > nodeDragThreshold) {\n startDrag(event);\n }\n }\n // skip events without movement\n if ((lastPos.x !== pointerPos.xSnapped || lastPos.y !== pointerPos.ySnapped) && dragItems && dragStarted) {\n // dragEvent = event.sourceEvent as MouseEvent;\n mousePosition = getEventPosition(event.sourceEvent, containerBounds);\n updateNodes(pointerPos, event.sourceEvent);\n }\n })\n .on('end', (event) => {\n if (!dragStarted || abortDrag) {\n return;\n }\n autoPanStarted = false;\n dragStarted = false;\n cancelAnimationFrame(autoPanId);\n if (dragItems.size > 0) {\n const { nodeLookup, updateNodePositions, onNodeDragStop, onSelectionDragStop } = getStoreItems();\n updateNodePositions(dragItems, false);\n if (onDragStop || onNodeDragStop || (!nodeId && onSelectionDragStop)) {\n const [currentNode, currentNodes] = getEventHandlerParams({\n nodeId,\n dragItems,\n nodeLookup,\n dragging: false,\n });\n onDragStop?.(event.sourceEvent, dragItems, currentNode, currentNodes);\n onNodeDragStop?.(event.sourceEvent, currentNode, currentNodes);\n if (!nodeId) {\n onSelectionDragStop?.(event.sourceEvent, currentNodes);\n }\n }\n }\n })\n .filter((event) => {\n const target = event.target;\n const isDraggable = !event.button &&\n (!noDragClassName || !hasSelector(target, `.${noDragClassName}`, domNode)) &&\n (!handleSelector || hasSelector(target, handleSelector, domNode));\n return isDraggable;\n });\n d3Selection.call(d3DragInstance);\n }\n function destroy() {\n d3Selection?.on('.drag', null);\n }\n return {\n update,\n destroy,\n };\n}\n\nfunction getNodesWithinDistance(position, nodeLookup, distance) {\n const nodes = [];\n const rect = {\n x: position.x - distance,\n y: position.y - distance,\n width: distance * 2,\n height: distance * 2,\n };\n for (const node of nodeLookup.values()) {\n if (getOverlappingArea(rect, nodeToRect(node)) > 0) {\n nodes.push(node);\n }\n }\n return nodes;\n}\n// this distance is used for the area around the user pointer\n// while doing a connection for finding the closest nodes\nconst ADDITIONAL_DISTANCE = 250;\nfunction getClosestHandle(position, connectionRadius, nodeLookup, fromHandle) {\n let closestHandles = [];\n let minDistance = Infinity;\n const closeNodes = getNodesWithinDistance(position, nodeLookup, connectionRadius + ADDITIONAL_DISTANCE);\n for (const node of closeNodes) {\n const allHandles = [...(node.internals.handleBounds?.source ?? []), ...(node.internals.handleBounds?.target ?? [])];\n for (const handle of allHandles) {\n // if the handle is the same as the fromHandle we skip it\n if (fromHandle.nodeId === handle.nodeId && fromHandle.type === handle.type && fromHandle.id === handle.id) {\n continue;\n }\n // determine absolute position of the handle\n const { x, y } = getHandlePosition(node, handle, handle.position, true);\n const distance = Math.sqrt(Math.pow(x - position.x, 2) + Math.pow(y - position.y, 2));\n if (distance > connectionRadius) {\n continue;\n }\n if (distance < minDistance) {\n closestHandles = [{ ...handle, x, y }];\n minDistance = distance;\n }\n else if (distance === minDistance) {\n // when multiple handles are on the same distance we collect all of them\n closestHandles.push({ ...handle, x, y });\n }\n }\n }\n if (!closestHandles.length) {\n return null;\n }\n // when multiple handles overlay each other we prefer the opposite handle\n if (closestHandles.length > 1) {\n const oppositeHandleType = fromHandle.type === 'source' ? 'target' : 'source';\n return closestHandles.find((handle) => handle.type === oppositeHandleType) ?? closestHandles[0];\n }\n return closestHandles[0];\n}\nfunction getHandle(nodeId, handleType, handleId, nodeLookup, connectionMode, withAbsolutePosition = false) {\n const node = nodeLookup.get(nodeId);\n if (!node) {\n return null;\n }\n const handles = connectionMode === 'strict'\n ? node.internals.handleBounds?.[handleType]\n : [...(node.internals.handleBounds?.source ?? []), ...(node.internals.handleBounds?.target ?? [])];\n const handle = (handleId ? handles?.find((h) => h.id === handleId) : handles?.[0]) ?? null;\n return handle && withAbsolutePosition\n ? { ...handle, ...getHandlePosition(node, handle, handle.position, true) }\n : handle;\n}\nfunction getHandleType(edgeUpdaterType, handleDomNode) {\n if (edgeUpdaterType) {\n return edgeUpdaterType;\n }\n else if (handleDomNode?.classList.contains('target')) {\n return 'target';\n }\n else if (handleDomNode?.classList.contains('source')) {\n return 'source';\n }\n return null;\n}\nfunction isConnectionValid(isInsideConnectionRadius, isHandleValid) {\n let isValid = null;\n if (isHandleValid) {\n isValid = true;\n }\n else if (isInsideConnectionRadius && !isHandleValid) {\n isValid = false;\n }\n return isValid;\n}\n\nconst alwaysValid = () => true;\nfunction onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onReconnectEnd, updateConnection, getTransform, getFromHandle, autoPanSpeed, }) {\n // when xyflow is used inside a shadow root we can't use document\n const doc = getHostForElement(event.target);\n let autoPanId = 0;\n let closestHandle;\n const { x, y } = getEventPosition(event);\n const clickedHandle = doc?.elementFromPoint(x, y);\n const handleType = getHandleType(edgeUpdaterType, clickedHandle);\n const containerBounds = domNode?.getBoundingClientRect();\n if (!containerBounds || !handleType) {\n return;\n }\n const fromHandleInternal = getHandle(nodeId, handleType, handleId, nodeLookup, connectionMode);\n if (!fromHandleInternal) {\n return;\n }\n let position = getEventPosition(event, containerBounds);\n let autoPanStarted = false;\n let connection = null;\n let isValid = false;\n let handleDomNode = null;\n // when the user is moving the mouse close to the edge of the canvas while connecting we move the canvas\n function autoPan() {\n if (!autoPanOnConnect || !containerBounds) {\n return;\n }\n const [x, y] = calcAutoPan(position, containerBounds, autoPanSpeed);\n panBy({ x, y });\n autoPanId = requestAnimationFrame(autoPan);\n }\n // Stays the same for all consecutive pointermove events\n const fromHandle = {\n ...fromHandleInternal,\n nodeId,\n type: handleType,\n position: fromHandleInternal.position,\n };\n const fromNodeInternal = nodeLookup.get(nodeId);\n const from = getHandlePosition(fromNodeInternal, fromHandle, Position.Left, true);\n const newConnection = {\n inProgress: true,\n isValid: null,\n from,\n fromHandle,\n fromPosition: fromHandle.position,\n fromNode: fromNodeInternal,\n to: position,\n toHandle: null,\n toPosition: oppositePosition[fromHandle.position],\n toNode: null,\n };\n updateConnection(newConnection);\n let previousConnection = newConnection;\n onConnectStart?.(event, { nodeId, handleId, handleType });\n function onPointerMove(event) {\n if (!getFromHandle() || !fromHandle) {\n onPointerUp(event);\n return;\n }\n const transform = getTransform();\n position = getEventPosition(event, containerBounds);\n closestHandle = getClosestHandle(pointToRendererPoint(position, transform, false, [1, 1]), connectionRadius, nodeLookup, fromHandle);\n if (!autoPanStarted) {\n autoPan();\n autoPanStarted = true;\n }\n const result = isValidHandle(event, {\n handle: closestHandle,\n connectionMode,\n fromNodeId: nodeId,\n fromHandleId: handleId,\n fromType: isTarget ? 'target' : 'source',\n isValidConnection,\n doc,\n lib,\n flowId,\n nodeLookup,\n });\n handleDomNode = result.handleDomNode;\n connection = result.connection;\n isValid = isConnectionValid(!!closestHandle, result.isValid);\n const newConnection = {\n // from stays the same\n ...previousConnection,\n isValid,\n to: closestHandle && isValid\n ? rendererPointToPoint({ x: closestHandle.x, y: closestHandle.y }, transform)\n : position,\n toHandle: result.toHandle,\n toPosition: isValid && result.toHandle ? result.toHandle.position : oppositePosition[fromHandle.position],\n toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId) : null,\n };\n // we don't want to trigger an update when the connection\n // is snapped to the same handle as before\n if (isValid &&\n closestHandle &&\n previousConnection.toHandle &&\n newConnection.toHandle &&\n previousConnection.toHandle.type === newConnection.toHandle.type &&\n previousConnection.toHandle.nodeId === newConnection.toHandle.nodeId &&\n previousConnection.toHandle.id === newConnection.toHandle.id &&\n previousConnection.to.x === newConnection.to.x &&\n previousConnection.to.y === newConnection.to.y) {\n return;\n }\n updateConnection(newConnection);\n previousConnection = newConnection;\n }\n function onPointerUp(event) {\n if ((closestHandle || handleDomNode) && connection && isValid) {\n onConnect?.(connection);\n }\n // it's important to get a fresh reference from the store here\n // in order to get the latest state of onConnectEnd\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { inProgress, ...connectionState } = previousConnection;\n const finalConnectionState = {\n ...connectionState,\n toPosition: previousConnection.toHandle ? previousConnection.toPosition : null,\n };\n onConnectEnd?.(event, finalConnectionState);\n if (edgeUpdaterType) {\n onReconnectEnd?.(event, finalConnectionState);\n }\n cancelConnection();\n cancelAnimationFrame(autoPanId);\n autoPanStarted = false;\n isValid = false;\n connection = null;\n handleDomNode = null;\n doc.removeEventListener('mousemove', onPointerMove);\n doc.removeEventListener('mouseup', onPointerUp);\n doc.removeEventListener('touchmove', onPointerMove);\n doc.removeEventListener('touchend', onPointerUp);\n }\n doc.addEventListener('mousemove', onPointerMove);\n doc.addEventListener('mouseup', onPointerUp);\n doc.addEventListener('touchmove', onPointerMove);\n doc.addEventListener('touchend', onPointerUp);\n}\n// checks if and returns connection in fom of an object { source: 123, target: 312 }\nfunction isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId, fromType, doc, lib, flowId, isValidConnection = alwaysValid, nodeLookup, }) {\n const isTarget = fromType === 'target';\n const handleDomNode = handle\n ? doc.querySelector(`.${lib}-flow__handle[data-id=\"${flowId}-${handle?.nodeId}-${handle?.id}-${handle?.type}\"]`)\n : null;\n const { x, y } = getEventPosition(event);\n const handleBelow = doc.elementFromPoint(x, y);\n // we always want to prioritize the handle below the mouse cursor over the closest distance handle,\n // because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor\n const handleToCheck = handleBelow?.classList.contains(`${lib}-flow__handle`) ? handleBelow : handleDomNode;\n const result = {\n handleDomNode: handleToCheck,\n isValid: false,\n connection: null,\n toHandle: null,\n };\n if (handleToCheck) {\n const handleType = getHandleType(undefined, handleToCheck);\n const handleNodeId = handleToCheck.getAttribute('data-nodeid');\n const handleId = handleToCheck.getAttribute('data-handleid');\n const connectable = handleToCheck.classList.contains('connectable');\n const connectableEnd = handleToCheck.classList.contains('connectableend');\n if (!handleNodeId || !handleType) {\n return result;\n }\n const connection = {\n source: isTarget ? handleNodeId : fromNodeId,\n sourceHandle: isTarget ? handleId : fromHandleId,\n target: isTarget ? fromNodeId : handleNodeId,\n targetHandle: isTarget ? fromHandleId : handleId,\n };\n result.connection = connection;\n const isConnectable = connectable && connectableEnd;\n // in strict mode we don't allow target to target or source to source connections\n const isValid = isConnectable &&\n (connectionMode === ConnectionMode.Strict\n ? (isTarget && handleType === 'source') || (!isTarget && handleType === 'target')\n : handleNodeId !== fromNodeId || handleId !== fromHandleId);\n result.isValid = isValid && isValidConnection(connection);\n result.toHandle = getHandle(handleNodeId, handleType, handleId, nodeLookup, connectionMode, false);\n }\n return result;\n}\nconst XYHandle = {\n onPointerDown,\n isValid: isValidHandle,\n};\n\nfunction XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {\n const selection = select(domNode);\n function update({ translateExtent, width, height, zoomStep = 10, pannable = true, zoomable = true, inversePan = false, }) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const zoomHandler = (event) => {\n const transform = getTransform();\n if (event.sourceEvent.type !== 'wheel' || !panZoom) {\n return;\n }\n const pinchDelta = -event.sourceEvent.deltaY *\n (event.sourceEvent.deltaMode === 1 ? 0.05 : event.sourceEvent.deltaMode ? 1 : 0.002) *\n zoomStep;\n const nextZoom = transform[2] * Math.pow(2, pinchDelta);\n panZoom.scaleTo(nextZoom);\n };\n let panStart = [0, 0];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const panStartHandler = (event) => {\n if (event.sourceEvent.type === 'mousedown' || event.sourceEvent.type === 'touchstart') {\n panStart = [\n event.sourceEvent.clientX ?? event.sourceEvent.touches[0].clientX,\n event.sourceEvent.clientY ?? event.sourceEvent.touches[0].clientY,\n ];\n }\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const panHandler = (event) => {\n const transform = getTransform();\n if ((event.sourceEvent.type !== 'mousemove' && event.sourceEvent.type !== 'touchmove') || !panZoom) {\n return;\n }\n const panCurrent = [\n event.sourceEvent.clientX ?? event.sourceEvent.touches[0].clientX,\n event.sourceEvent.clientY ?? event.sourceEvent.touches[0].clientY,\n ];\n const panDelta = [panCurrent[0] - panStart[0], panCurrent[1] - panStart[1]];\n panStart = panCurrent;\n const moveScale = getViewScale() * Math.max(transform[2], Math.log(transform[2])) * (inversePan ? -1 : 1);\n const position = {\n x: transform[0] - panDelta[0] * moveScale,\n y: transform[1] - panDelta[1] * moveScale,\n };\n const extent = [\n [0, 0],\n [width, height],\n ];\n panZoom.setViewportConstrained({\n x: position.x,\n y: position.y,\n zoom: transform[2],\n }, extent, translateExtent);\n };\n const zoomAndPanHandler = zoom()\n .on('start', panStartHandler)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n .on('zoom', pannable ? panHandler : null)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n .on('zoom.wheel', zoomable ? zoomHandler : null);\n selection.call(zoomAndPanHandler, {});\n }\n function destroy() {\n selection.on('zoom', null);\n }\n return {\n update,\n destroy,\n pointer,\n };\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nconst viewChanged = (prevViewport, eventViewport) => prevViewport.x !== eventViewport.x || prevViewport.y !== eventViewport.y || prevViewport.zoom !== eventViewport.k;\nconst transformToViewport = (transform) => ({\n x: transform.x,\n y: transform.y,\n zoom: transform.k,\n});\nconst viewportToTransform = ({ x, y, zoom }) => zoomIdentity.translate(x, y).scale(zoom);\nconst isWrappedWithClass = (event, className) => event.target.closest(`.${className}`);\nconst isRightClickPan = (panOnDrag, usedButton) => usedButton === 2 && Array.isArray(panOnDrag) && panOnDrag.includes(2);\nconst getD3Transition = (selection, duration = 0, onEnd = () => { }) => {\n const hasDuration = typeof duration === 'number' && duration > 0;\n if (!hasDuration) {\n onEnd();\n }\n return hasDuration ? selection.transition().duration(duration).on('end', onEnd) : selection;\n};\nconst wheelDelta = (event) => {\n const factor = event.ctrlKey && isMacOs() ? 10 : 1;\n return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * factor;\n};\n\nfunction createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection, d3Zoom, panOnScrollMode, panOnScrollSpeed, zoomOnPinch, onPanZoomStart, onPanZoom, onPanZoomEnd, }) {\n return (event) => {\n if (isWrappedWithClass(event, noWheelClassName)) {\n return false;\n }\n event.preventDefault();\n event.stopImmediatePropagation();\n const currentZoom = d3Selection.property('__zoom').k || 1;\n // macos sets ctrlKey=true for pinch gesture on a trackpad\n if (event.ctrlKey && zoomOnPinch) {\n const point = pointer(event);\n const pinchDelta = wheelDelta(event);\n const zoom = currentZoom * Math.pow(2, pinchDelta);\n // @ts-ignore\n d3Zoom.scaleTo(d3Selection, zoom, point, event);\n return;\n }\n // increase scroll speed in firefox\n // firefox: deltaMode === 1; chrome: deltaMode === 0\n const deltaNormalize = event.deltaMode === 1 ? 20 : 1;\n let deltaX = panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize;\n let deltaY = panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize;\n // this enables vertical scrolling with shift + scroll on windows\n if (!isMacOs() && event.shiftKey && panOnScrollMode !== PanOnScrollMode.Vertical) {\n deltaX = event.deltaY * deltaNormalize;\n deltaY = 0;\n }\n d3Zoom.translateBy(d3Selection, -(deltaX / currentZoom) * panOnScrollSpeed, -(deltaY / currentZoom) * panOnScrollSpeed, \n // @ts-ignore\n { internal: true });\n const nextViewport = transformToViewport(d3Selection.property('__zoom'));\n clearTimeout(zoomPanValues.panScrollTimeout);\n // for pan on scroll we need to handle the event calls on our own\n // we can't use the start, zoom and end events from d3-zoom\n // because start and move gets called on every scroll event and not once at the beginning\n if (!zoomPanValues.isPanScrolling) {\n zoomPanValues.isPanScrolling = true;\n onPanZoomStart?.(event, nextViewport);\n }\n if (zoomPanValues.isPanScrolling) {\n onPanZoom?.(event, nextViewport);\n zoomPanValues.panScrollTimeout = setTimeout(() => {\n onPanZoomEnd?.(event, nextViewport);\n zoomPanValues.isPanScrolling = false;\n }, 150);\n }\n };\n}\nfunction createZoomOnScrollHandler({ noWheelClassName, preventScrolling, d3ZoomHandler }) {\n return function (event, d) {\n // we still want to enable pinch zooming even if preventScrolling is set to false\n const preventZoom = !preventScrolling && event.type === 'wheel' && !event.ctrlKey;\n if (preventZoom || isWrappedWithClass(event, noWheelClassName)) {\n return null;\n }\n event.preventDefault();\n d3ZoomHandler.call(this, event, d);\n };\n}\nfunction createPanZoomStartHandler({ zoomPanValues, onDraggingChange, onPanZoomStart }) {\n return (event) => {\n if (event.sourceEvent?.internal) {\n return;\n }\n const viewport = transformToViewport(event.transform);\n // we need to remember it here, because it's always 0 in the \"zoom\" event\n zoomPanValues.mouseButton = event.sourceEvent?.button || 0;\n zoomPanValues.isZoomingOrPanning = true;\n zoomPanValues.prevViewport = viewport;\n if (event.sourceEvent?.type === 'mousedown') {\n onDraggingChange(true);\n }\n if (onPanZoomStart) {\n onPanZoomStart?.(event.sourceEvent, viewport);\n }\n };\n}\nfunction createPanZoomHandler({ zoomPanValues, panOnDrag, onPaneContextMenu, onTransformChange, onPanZoom, }) {\n return (event) => {\n zoomPanValues.usedRightMouseButton = !!(onPaneContextMenu && isRightClickPan(panOnDrag, zoomPanValues.mouseButton ?? 0));\n if (!event.sourceEvent?.sync) {\n onTransformChange([event.transform.x, event.transform.y, event.transform.k]);\n }\n if (onPanZoom && !event.sourceEvent?.internal) {\n onPanZoom?.(event.sourceEvent, transformToViewport(event.transform));\n }\n };\n}\nfunction createPanZoomEndHandler({ zoomPanValues, panOnDrag, panOnScroll, onDraggingChange, onPanZoomEnd, onPaneContextMenu, }) {\n return (event) => {\n if (event.sourceEvent?.internal) {\n return;\n }\n zoomPanValues.isZoomingOrPanning = false;\n if (onPaneContextMenu &&\n isRightClickPan(panOnDrag, zoomPanValues.mouseButton ?? 0) &&\n !zoomPanValues.usedRightMouseButton &&\n event.sourceEvent) {\n onPaneContextMenu(event.sourceEvent);\n }\n zoomPanValues.usedRightMouseButton = false;\n onDraggingChange(false);\n if (onPanZoomEnd && viewChanged(zoomPanValues.prevViewport, event.transform)) {\n const viewport = transformToViewport(event.transform);\n zoomPanValues.prevViewport = viewport;\n clearTimeout(zoomPanValues.timerId);\n zoomPanValues.timerId = setTimeout(() => {\n onPanZoomEnd?.(event.sourceEvent, viewport);\n }, \n // we need a setTimeout for panOnScroll to supress multiple end events fired during scroll\n panOnScroll ? 150 : 0);\n }\n };\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction createFilter({ zoomActivationKeyPressed, zoomOnScroll, zoomOnPinch, panOnDrag, panOnScroll, zoomOnDoubleClick, userSelectionActive, noWheelClassName, noPanClassName, lib, }) {\n return (event) => {\n const zoomScroll = zoomActivationKeyPressed || zoomOnScroll;\n const pinchZoom = zoomOnPinch && event.ctrlKey;\n if (event.button === 1 &&\n event.type === 'mousedown' &&\n (isWrappedWithClass(event, `${lib}-flow__node`) || isWrappedWithClass(event, `${lib}-flow__edge`))) {\n return true;\n }\n // if all interactions are disabled, we prevent all zoom events\n if (!panOnDrag && !zoomScroll && !panOnScroll && !zoomOnDoubleClick && !zoomOnPinch) {\n return false;\n }\n // during a selection we prevent all other interactions\n if (userSelectionActive) {\n return false;\n }\n // if the target element is inside an element with the nowheel class, we prevent zooming\n if (isWrappedWithClass(event, noWheelClassName) && event.type === 'wheel') {\n return false;\n }\n // if the target element is inside an element with the nopan class, we prevent panning\n if (isWrappedWithClass(event, noPanClassName) &&\n (event.type !== 'wheel' || (panOnScroll && event.type === 'wheel' && !zoomActivationKeyPressed))) {\n return false;\n }\n if (!zoomOnPinch && event.ctrlKey && event.type === 'wheel') {\n return false;\n }\n if (!zoomOnPinch && event.type === 'touchstart' && event.touches?.length > 1) {\n event.preventDefault(); // if you manage to start with 2 touches, we prevent native zoom\n return false;\n }\n // when there is no scroll handling enabled, we prevent all wheel events\n if (!zoomScroll && !panOnScroll && !pinchZoom && event.type === 'wheel') {\n return false;\n }\n // if the pane is not movable, we prevent dragging it with mousestart or touchstart\n if (!panOnDrag && (event.type === 'mousedown' || event.type === 'touchstart')) {\n return false;\n }\n // if the pane is only movable using allowed clicks\n if (Array.isArray(panOnDrag) && !panOnDrag.includes(event.button) && event.type === 'mousedown') {\n return false;\n }\n // We only allow right clicks if pan on drag is set to right click\n const buttonAllowed = (Array.isArray(panOnDrag) && panOnDrag.includes(event.button)) || !event.button || event.button <= 1;\n // default filter for d3-zoom\n return (!event.ctrlKey || event.type === 'wheel') && buttonAllowed;\n };\n}\n\nfunction XYPanZoom({ domNode, minZoom, maxZoom, paneClickDistance, translateExtent, viewport, onPanZoom, onPanZoomStart, onPanZoomEnd, onDraggingChange, }) {\n const zoomPanValues = {\n isZoomingOrPanning: false,\n usedRightMouseButton: false,\n prevViewport: { x: 0, y: 0, zoom: 0 },\n mouseButton: 0,\n timerId: undefined,\n panScrollTimeout: undefined,\n isPanScrolling: false,\n };\n const bbox = domNode.getBoundingClientRect();\n const d3ZoomInstance = zoom()\n .clickDistance(!isNumeric(paneClickDistance) || paneClickDistance < 0 ? 0 : paneClickDistance)\n .scaleExtent([minZoom, maxZoom])\n .translateExtent(translateExtent);\n const d3Selection = select(domNode).call(d3ZoomInstance);\n setViewportConstrained({\n x: viewport.x,\n y: viewport.y,\n zoom: clamp(viewport.zoom, minZoom, maxZoom),\n }, [\n [0, 0],\n [bbox.width, bbox.height],\n ], translateExtent);\n const d3ZoomHandler = d3Selection.on('wheel.zoom');\n const d3DblClickZoomHandler = d3Selection.on('dblclick.zoom');\n d3ZoomInstance.wheelDelta(wheelDelta);\n function setTransform(transform, options) {\n if (d3Selection) {\n return new Promise((resolve) => {\n d3ZoomInstance?.transform(getD3Transition(d3Selection, options?.duration, () => resolve(true)), transform);\n });\n }\n return Promise.resolve(false);\n }\n // public functions\n function update({ noWheelClassName, noPanClassName, onPaneContextMenu, userSelectionActive, panOnScroll, panOnDrag, panOnScrollMode, panOnScrollSpeed, preventScrolling, zoomOnPinch, zoomOnScroll, zoomOnDoubleClick, zoomActivationKeyPressed, lib, onTransformChange, }) {\n if (userSelectionActive && !zoomPanValues.isZoomingOrPanning) {\n destroy();\n }\n const isPanOnScroll = panOnScroll && !zoomActivationKeyPressed && !userSelectionActive;\n const wheelHandler = isPanOnScroll\n ? createPanOnScrollHandler({\n zoomPanValues,\n noWheelClassName,\n d3Selection,\n d3Zoom: d3ZoomInstance,\n panOnScrollMode,\n panOnScrollSpeed,\n zoomOnPinch,\n onPanZoomStart,\n onPanZoom,\n onPanZoomEnd,\n })\n : createZoomOnScrollHandler({\n noWheelClassName,\n preventScrolling,\n d3ZoomHandler,\n });\n d3Selection.on('wheel.zoom', wheelHandler, { passive: false });\n if (!userSelectionActive) {\n // pan zoom start\n const startHandler = createPanZoomStartHandler({\n zoomPanValues,\n onDraggingChange,\n onPanZoomStart,\n });\n d3ZoomInstance.on('start', startHandler);\n // pan zoom\n const panZoomHandler = createPanZoomHandler({\n zoomPanValues,\n panOnDrag,\n onPaneContextMenu: !!onPaneContextMenu,\n onPanZoom,\n onTransformChange,\n });\n d3ZoomInstance.on('zoom', panZoomHandler);\n // pan zoom end\n const panZoomEndHandler = createPanZoomEndHandler({\n zoomPanValues,\n panOnDrag,\n panOnScroll,\n onPaneContextMenu,\n onPanZoomEnd,\n onDraggingChange,\n });\n d3ZoomInstance.on('end', panZoomEndHandler);\n }\n const filter = createFilter({\n zoomActivationKeyPressed,\n panOnDrag,\n zoomOnScroll,\n panOnScroll,\n zoomOnDoubleClick,\n zoomOnPinch,\n userSelectionActive,\n noPanClassName,\n noWheelClassName,\n lib,\n });\n d3ZoomInstance.filter(filter);\n // We cannot add zoomOnDoubleClick to the filter above because\n // double tapping on touch screens circumvents the filter and\n // dblclick.zoom is fired on the selection directly\n if (zoomOnDoubleClick) {\n d3Selection.on('dblclick.zoom', d3DblClickZoomHandler);\n }\n else {\n d3Selection.on('dblclick.zoom', null);\n }\n }\n function destroy() {\n d3ZoomInstance.on('zoom', null);\n }\n async function setViewportConstrained(viewport, extent, translateExtent) {\n const nextTransform = viewportToTransform(viewport);\n const contrainedTransform = d3ZoomInstance?.constrain()(nextTransform, extent, translateExtent);\n if (contrainedTransform) {\n await setTransform(contrainedTransform);\n }\n return new Promise((resolve) => resolve(contrainedTransform));\n }\n async function setViewport(viewport, options) {\n const nextTransform = viewportToTransform(viewport);\n await setTransform(nextTransform, options);\n return new Promise((resolve) => resolve(nextTransform));\n }\n function syncViewport(viewport) {\n if (d3Selection) {\n const nextTransform = viewportToTransform(viewport);\n const currentTransform = d3Selection.property('__zoom');\n if (currentTransform.k !== viewport.zoom ||\n currentTransform.x !== viewport.x ||\n currentTransform.y !== viewport.y) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n d3ZoomInstance?.transform(d3Selection, nextTransform, null, { sync: true });\n }\n }\n }\n function getViewport() {\n const transform = d3Selection ? zoomTransform(d3Selection.node()) : { x: 0, y: 0, k: 1 };\n return { x: transform.x, y: transform.y, zoom: transform.k };\n }\n function scaleTo(zoom, options) {\n if (d3Selection) {\n return new Promise((resolve) => {\n d3ZoomInstance?.scaleTo(getD3Transition(d3Selection, options?.duration, () => resolve(true)), zoom);\n });\n }\n return Promise.resolve(false);\n }\n function scaleBy(factor, options) {\n if (d3Selection) {\n return new Promise((resolve) => {\n d3ZoomInstance?.scaleBy(getD3Transition(d3Selection, options?.duration, () => resolve(true)), factor);\n });\n }\n return Promise.resolve(false);\n }\n function setScaleExtent(scaleExtent) {\n d3ZoomInstance?.scaleExtent(scaleExtent);\n }\n function setTranslateExtent(translateExtent) {\n d3ZoomInstance?.translateExtent(translateExtent);\n }\n function setClickDistance(distance) {\n const validDistance = !isNumeric(distance) || distance < 0 ? 0 : distance;\n d3ZoomInstance?.clickDistance(validDistance);\n }\n return {\n update,\n destroy,\n setViewport,\n setViewportConstrained,\n getViewport,\n scaleTo,\n scaleBy,\n setScaleExtent,\n setTranslateExtent,\n syncViewport,\n setClickDistance,\n };\n}\n\nvar ResizeControlVariant;\n(function (ResizeControlVariant) {\n ResizeControlVariant[\"Line\"] = \"line\";\n ResizeControlVariant[\"Handle\"] = \"handle\";\n})(ResizeControlVariant || (ResizeControlVariant = {}));\nconst XY_RESIZER_HANDLE_POSITIONS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\nconst XY_RESIZER_LINE_POSITIONS = ['top', 'right', 'bottom', 'left'];\n\n/**\n * Get all connecting edges for a given set of nodes\n * @param width - new width of the node\n * @param prevWidth - previous width of the node\n * @param height - new height of the node\n * @param prevHeight - previous height of the node\n * @param affectsX - whether to invert the resize direction for the x axis\n * @param affectsY - whether to invert the resize direction for the y axis\n * @returns array of two numbers representing the direction of the resize for each axis, 0 = no change, 1 = increase, -1 = decrease\n */\nfunction getResizeDirection({ width, prevWidth, height, prevHeight, affectsX, affectsY, }) {\n const deltaWidth = width - prevWidth;\n const deltaHeight = height - prevHeight;\n const direction = [deltaWidth > 0 ? 1 : deltaWidth < 0 ? -1 : 0, deltaHeight > 0 ? 1 : deltaHeight < 0 ? -1 : 0];\n if (deltaWidth && affectsX) {\n direction[0] = direction[0] * -1;\n }\n if (deltaHeight && affectsY) {\n direction[1] = direction[1] * -1;\n }\n return direction;\n}\n/**\n * Parses the control position that is being dragged to dimensions that are being resized\n * @param controlPosition - position of the control that is being dragged\n * @returns isHorizontal, isVertical, affectsX, affectsY,\n */\nfunction getControlDirection(controlPosition) {\n const isHorizontal = controlPosition.includes('right') || controlPosition.includes('left');\n const isVertical = controlPosition.includes('bottom') || controlPosition.includes('top');\n const affectsX = controlPosition.includes('left');\n const affectsY = controlPosition.includes('top');\n return {\n isHorizontal,\n isVertical,\n affectsX,\n affectsY,\n };\n}\nfunction getLowerExtentClamp(lowerExtent, lowerBound) {\n return Math.max(0, lowerBound - lowerExtent);\n}\nfunction getUpperExtentClamp(upperExtent, upperBound) {\n return Math.max(0, upperExtent - upperBound);\n}\nfunction getSizeClamp(size, minSize, maxSize) {\n return Math.max(0, minSize - size, size - maxSize);\n}\nfunction xor(a, b) {\n return a ? !b : b;\n}\n/**\n * Calculates new width & height and x & y of node after resize based on pointer position\n * @description - Buckle up, this is a chunky one... If you want to determine the new dimensions of a node after a resize,\n * you have to account for all possible restrictions: min/max width/height of the node, the maximum extent the node is allowed\n * to move in (in this case: resize into) determined by the parent node, the minimal extent determined by child nodes\n * with expandParent or extent: 'parent' set and oh yeah, these things also have to work with keepAspectRatio!\n * The way this is done is by determining how much each of these restricting actually restricts the resize and then applying the\n * strongest restriction. Because the resize affects x, y and width, height and width, height of a opposing side with keepAspectRatio,\n * the resize amount is always kept in distX & distY amount (the distance in mouse movement)\n * Instead of clamping each value, we first calculate the biggest 'clamp' (for the lack of a better name) and then apply it to all values.\n * To complicate things nodeOrigin has to be taken into account as well. This is done by offsetting the nodes as if their origin is [0, 0],\n * then calculating the restrictions as usual\n * @param startValues - starting values of resize\n * @param controlDirection - dimensions affected by the resize\n * @param pointerPosition - the current pointer position corrected for snapping\n * @param boundaries - minimum and maximum dimensions of the node\n * @param keepAspectRatio - prevent changes of asprect ratio\n * @returns x, y, width and height of the node after resize\n */\nfunction getDimensionsAfterResize(startValues, controlDirection, pointerPosition, boundaries, keepAspectRatio, nodeOrigin, extent, childExtent) {\n let { affectsX, affectsY } = controlDirection;\n const { isHorizontal, isVertical } = controlDirection;\n const isDiagonal = isHorizontal && isVertical;\n const { xSnapped, ySnapped } = pointerPosition;\n const { minWidth, maxWidth, minHeight, maxHeight } = boundaries;\n const { x: startX, y: startY, width: startWidth, height: startHeight, aspectRatio } = startValues;\n let distX = Math.floor(isHorizontal ? xSnapped - startValues.pointerX : 0);\n let distY = Math.floor(isVertical ? ySnapped - startValues.pointerY : 0);\n const newWidth = startWidth + (affectsX ? -distX : distX);\n const newHeight = startHeight + (affectsY ? -distY : distY);\n const originOffsetX = -nodeOrigin[0] * startWidth;\n const originOffsetY = -nodeOrigin[1] * startHeight;\n // Check if maxWidth, minWWidth, maxHeight, minHeight are restricting the resize\n let clampX = getSizeClamp(newWidth, minWidth, maxWidth);\n let clampY = getSizeClamp(newHeight, minHeight, maxHeight);\n // Check if extent is restricting the resize\n if (extent) {\n let xExtentClamp = 0;\n let yExtentClamp = 0;\n if (affectsX && distX < 0) {\n xExtentClamp = getLowerExtentClamp(startX + distX + originOffsetX, extent[0][0]);\n }\n else if (!affectsX && distX > 0) {\n xExtentClamp = getUpperExtentClamp(startX + newWidth + originOffsetX, extent[1][0]);\n }\n if (affectsY && distY < 0) {\n yExtentClamp = getLowerExtentClamp(startY + distY + originOffsetY, extent[0][1]);\n }\n else if (!affectsY && distY > 0) {\n yExtentClamp = getUpperExtentClamp(startY + newHeight + originOffsetY, extent[1][1]);\n }\n clampX = Math.max(clampX, xExtentClamp);\n clampY = Math.max(clampY, yExtentClamp);\n }\n // Check if the child extent is restricting the resize\n if (childExtent) {\n let xExtentClamp = 0;\n let yExtentClamp = 0;\n if (affectsX && distX > 0) {\n xExtentClamp = getUpperExtentClamp(startX + distX, childExtent[0][0]);\n }\n else if (!affectsX && distX < 0) {\n xExtentClamp = getLowerExtentClamp(startX + newWidth, childExtent[1][0]);\n }\n if (affectsY && distY > 0) {\n yExtentClamp = getUpperExtentClamp(startY + distY, childExtent[0][1]);\n }\n else if (!affectsY && distY < 0) {\n yExtentClamp = getLowerExtentClamp(startY + newHeight, childExtent[1][1]);\n }\n clampX = Math.max(clampX, xExtentClamp);\n clampY = Math.max(clampY, yExtentClamp);\n }\n // Check if the aspect ratio resizing of the other side is restricting the resize\n if (keepAspectRatio) {\n if (isHorizontal) {\n // Check if the max dimensions might be restricting the resize\n const aspectHeightClamp = getSizeClamp(newWidth / aspectRatio, minHeight, maxHeight) * aspectRatio;\n clampX = Math.max(clampX, aspectHeightClamp);\n // Check if the extent is restricting the resize\n if (extent) {\n let aspectExtentClamp = 0;\n if ((!affectsX && !affectsY) || (affectsX && !affectsY && isDiagonal)) {\n aspectExtentClamp =\n getUpperExtentClamp(startY + originOffsetY + newWidth / aspectRatio, extent[1][1]) * aspectRatio;\n }\n else {\n aspectExtentClamp =\n getLowerExtentClamp(startY + originOffsetY + (affectsX ? distX : -distX) / aspectRatio, extent[0][1]) *\n aspectRatio;\n }\n clampX = Math.max(clampX, aspectExtentClamp);\n }\n // Check if the child extent is restricting the resize\n if (childExtent) {\n let aspectExtentClamp = 0;\n if ((!affectsX && !affectsY) || (affectsX && !affectsY && isDiagonal)) {\n aspectExtentClamp = getLowerExtentClamp(startY + newWidth / aspectRatio, childExtent[1][1]) * aspectRatio;\n }\n else {\n aspectExtentClamp =\n getUpperExtentClamp(startY + (affectsX ? distX : -distX) / aspectRatio, childExtent[0][1]) * aspectRatio;\n }\n clampX = Math.max(clampX, aspectExtentClamp);\n }\n }\n // Do the same thing for vertical resizing\n if (isVertical) {\n const aspectWidthClamp = getSizeClamp(newHeight * aspectRatio, minWidth, maxWidth) / aspectRatio;\n clampY = Math.max(clampY, aspectWidthClamp);\n if (extent) {\n let aspectExtentClamp = 0;\n if ((!affectsX && !affectsY) || (affectsY && !affectsX && isDiagonal)) {\n aspectExtentClamp =\n getUpperExtentClamp(startX + newHeight * aspectRatio + originOffsetX, extent[1][0]) / aspectRatio;\n }\n else {\n aspectExtentClamp =\n getLowerExtentClamp(startX + (affectsY ? distY : -distY) * aspectRatio + originOffsetX, extent[0][0]) /\n aspectRatio;\n }\n clampY = Math.max(clampY, aspectExtentClamp);\n }\n if (childExtent) {\n let aspectExtentClamp = 0;\n if ((!affectsX && !affectsY) || (affectsY && !affectsX && isDiagonal)) {\n aspectExtentClamp = getLowerExtentClamp(startX + newHeight * aspectRatio, childExtent[1][0]) / aspectRatio;\n }\n else {\n aspectExtentClamp =\n getUpperExtentClamp(startX + (affectsY ? distY : -distY) * aspectRatio, childExtent[0][0]) / aspectRatio;\n }\n clampY = Math.max(clampY, aspectExtentClamp);\n }\n }\n }\n distY = distY + (distY < 0 ? clampY : -clampY);\n distX = distX + (distX < 0 ? clampX : -clampX);\n if (keepAspectRatio) {\n if (isDiagonal) {\n if (newWidth > newHeight * aspectRatio) {\n distY = (xor(affectsX, affectsY) ? -distX : distX) / aspectRatio;\n }\n else {\n distX = (xor(affectsX, affectsY) ? -distY : distY) * aspectRatio;\n }\n }\n else {\n if (isHorizontal) {\n distY = distX / aspectRatio;\n affectsY = affectsX;\n }\n else {\n distX = distY * aspectRatio;\n affectsX = affectsY;\n }\n }\n }\n const x = affectsX ? startX + distX : startX;\n const y = affectsY ? startY + distY : startY;\n return {\n width: startWidth + (affectsX ? -distX : distX),\n height: startHeight + (affectsY ? -distY : distY),\n x: nodeOrigin[0] * distX * (!affectsX ? 1 : -1) + x,\n y: nodeOrigin[1] * distY * (!affectsY ? 1 : -1) + y,\n };\n}\n\nconst initPrevValues = { width: 0, height: 0, x: 0, y: 0 };\nconst initStartValues = {\n ...initPrevValues,\n pointerX: 0,\n pointerY: 0,\n aspectRatio: 1,\n};\nfunction nodeToParentExtent(node) {\n return [\n [0, 0],\n [node.measured.width, node.measured.height],\n ];\n}\nfunction nodeToChildExtent(child, parent, nodeOrigin) {\n const x = parent.position.x + child.position.x;\n const y = parent.position.y + child.position.y;\n const width = child.measured.width ?? 0;\n const height = child.measured.height ?? 0;\n const originOffsetX = nodeOrigin[0] * width;\n const originOffsetY = nodeOrigin[1] * height;\n return [\n [x - originOffsetX, y - originOffsetY],\n [x + width - originOffsetX, y + height - originOffsetY],\n ];\n}\nfunction XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {\n const selection = select(domNode);\n function update({ controlPosition, boundaries, keepAspectRatio, onResizeStart, onResize, onResizeEnd, shouldResize, }) {\n let prevValues = { ...initPrevValues };\n let startValues = { ...initStartValues };\n const controlDirection = getControlDirection(controlPosition);\n let node = undefined;\n let childNodes = [];\n let parentNode = undefined; // Needed to fix expandParent\n let parentExtent = undefined;\n let childExtent = undefined;\n const dragHandler = drag()\n .on('start', (event) => {\n const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin } = getStoreItems();\n node = nodeLookup.get(nodeId);\n if (!node) {\n return;\n }\n const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });\n prevValues = {\n width: node.measured.width ?? 0,\n height: node.measured.height ?? 0,\n x: node.position.x ?? 0,\n y: node.position.y ?? 0,\n };\n startValues = {\n ...prevValues,\n pointerX: xSnapped,\n pointerY: ySnapped,\n aspectRatio: prevValues.width / prevValues.height,\n };\n parentNode = undefined;\n if (node.parentId && (node.extent === 'parent' || node.expandParent)) {\n parentNode = nodeLookup.get(node.parentId);\n parentExtent = parentNode && node.extent === 'parent' ? nodeToParentExtent(parentNode) : undefined;\n }\n // Collect all child nodes to correct their relative positions when top/left changes\n // Determine largest minimal extent the parent node is allowed to resize to\n childNodes = [];\n childExtent = undefined;\n for (const [childId, child] of nodeLookup) {\n if (child.parentId === nodeId) {\n childNodes.push({\n id: childId,\n position: { ...child.position },\n extent: child.extent,\n });\n if (child.extent === 'parent' || child.expandParent) {\n const extent = nodeToChildExtent(child, node, child.origin ?? nodeOrigin);\n if (childExtent) {\n childExtent = [\n [Math.min(extent[0][0], childExtent[0][0]), Math.min(extent[0][1], childExtent[0][1])],\n [Math.max(extent[1][0], childExtent[1][0]), Math.max(extent[1][1], childExtent[1][1])],\n ];\n }\n else {\n childExtent = extent;\n }\n }\n }\n }\n onResizeStart?.(event, { ...prevValues });\n })\n .on('drag', (event) => {\n const { transform, snapGrid, snapToGrid, nodeOrigin: storeNodeOrigin } = getStoreItems();\n const pointerPosition = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });\n const childChanges = [];\n if (!node) {\n return;\n }\n const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues;\n const change = {};\n const nodeOrigin = node.origin ?? storeNodeOrigin;\n const { width, height, x, y } = getDimensionsAfterResize(startValues, controlDirection, pointerPosition, boundaries, keepAspectRatio, nodeOrigin, parentExtent, childExtent);\n const isWidthChange = width !== prevWidth;\n const isHeightChange = height !== prevHeight;\n const isXPosChange = x !== prevX && isWidthChange;\n const isYPosChange = y !== prevY && isHeightChange;\n if (!isXPosChange && !isYPosChange && !isWidthChange && !isHeightChange) {\n return;\n }\n if (isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1] === 1) {\n change.x = isXPosChange ? x : prevValues.x;\n change.y = isYPosChange ? y : prevValues.y;\n prevValues.x = change.x;\n prevValues.y = change.y;\n // when top/left changes, correct the relative positions of child nodes\n // so that they stay in the same position\n if (childNodes.length > 0) {\n const xChange = x - prevX;\n const yChange = y - prevY;\n for (const childNode of childNodes) {\n childNode.position = {\n x: childNode.position.x - xChange + nodeOrigin[0] * (width - prevWidth),\n y: childNode.position.y - yChange + nodeOrigin[1] * (height - prevHeight),\n };\n childChanges.push(childNode);\n }\n }\n }\n if (isWidthChange || isHeightChange) {\n change.width = isWidthChange ? width : prevValues.width;\n change.height = isHeightChange ? height : prevValues.height;\n prevValues.width = change.width;\n prevValues.height = change.height;\n }\n // Fix expandParent when resizing from top/left\n if (parentNode && node.expandParent) {\n const xLimit = nodeOrigin[0] * (change.width ?? 0);\n if (change.x && change.x < xLimit) {\n prevValues.x = xLimit;\n startValues.x = startValues.x - (change.x - xLimit);\n }\n const yLimit = nodeOrigin[1] * (change.height ?? 0);\n if (change.y && change.y < yLimit) {\n prevValues.y = yLimit;\n startValues.y = startValues.y - (change.y - yLimit);\n }\n }\n const direction = getResizeDirection({\n width: prevValues.width,\n prevWidth,\n height: prevValues.height,\n prevHeight,\n affectsX: controlDirection.affectsX,\n affectsY: controlDirection.affectsY,\n });\n const nextValues = { ...prevValues, direction };\n const callResize = shouldResize?.(event, nextValues);\n if (callResize === false) {\n return;\n }\n onResize?.(event, nextValues);\n onChange(change, childChanges);\n })\n .on('end', (event) => {\n onResizeEnd?.(event, { ...prevValues });\n onEnd?.();\n });\n selection.call(dragHandler);\n }\n function destroy() {\n selection.on('.drag', null);\n }\n return {\n update,\n destroy,\n };\n}\n\nexport { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, adoptUserNodes, areConnectionMapsEqual, boxToRect, calcAutoPan, calculateNodePosition, clamp, clampPosition, clampPositionToParent, createMarkerIds, devWarn, elementSelectionKeys, errorMessages, evaluateAbsolutePosition, fitView, getBezierEdgeCenter, getBezierPath, getBoundsOfBoxes, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter, getEdgePosition, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getFitViewNodes, getHandleBounds, getHandlePosition, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesInside, getOutgoers, getOverlappingArea, getPointerPosition, getSmoothStepPath, getStraightPath, getViewportForBounds, handleConnectionChange, handleExpandParent, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isInternalNodeBase, isMacOs, isMouseEvent, isNodeBase, isNumeric, isRectObject, nodeHasDimensions, nodeToBox, nodeToRect, oppositePosition, panBy, pointToRendererPoint, reconnectEdge, rectToBox, rendererPointToPoint, shallowNodeData, snapPosition, updateAbsolutePositions, updateConnectionLookup, updateNodeInternals };\n","\n\n\n\n \n\n","\n\n\n{data?.label}\n\n","\n\n{data?.label}\n\n","\n\n{data?.label}\n\n","function tryToMount(node, domNode, target) {\n if (!domNode) {\n return;\n }\n const targetEl = target ? domNode.querySelector(target) : domNode;\n if (targetEl) {\n targetEl.appendChild(node);\n }\n}\nexport default function (node, { target, domNode }) {\n tryToMount(node, domNode, target);\n return {\n async update({ target, domNode }) {\n tryToMount(node, domNode, target);\n },\n destroy() {\n if (node.parentNode) {\n node.parentNode.removeChild(node);\n }\n }\n };\n}\n","\n\n
\n \n
\n","import { get } from 'svelte/store';\nimport { errorMessages } from '@xyflow/system';\nimport { useStore } from '../store';\nexport function useHandleEdgeSelect() {\n const { edgeLookup, selectionRect, selectionRectMode, multiselectionKeyPressed, addSelectedEdges, unselectNodesAndEdges, elementsSelectable } = useStore();\n return (id) => {\n const edge = get(edgeLookup).get(id);\n if (!edge) {\n console.warn('012', errorMessages['error012'](id));\n return;\n }\n const selectable = edge.selectable || (get(elementsSelectable) && typeof edge.selectable === 'undefined');\n if (selectable) {\n selectionRect.set(null);\n selectionRectMode.set(null);\n if (!edge.selected) {\n addSelectedEdges([id]);\n }\n else if (edge.selected && get(multiselectionKeyPressed)) {\n unselectNodesAndEdges({ nodes: [], edges: [edge] });\n }\n }\n };\n}\n","\n\n\n {}}\n on:click={() => {\n if (id) handleEdgeSelect(id);\n }}\n >\n \n \n\n","\n\n\n\n{#if interactionWidthValue}\n \n{/if}\n\n{#if label}\n \n {label}\n \n{/if}\n","\n\n\n","\n\n\n","\n\n\n","\n\n\n","import { writable, get } from 'svelte/store';\nimport { adoptUserNodes, updateConnectionLookup, infiniteExtent } from '@xyflow/system';\n// we need to sync the user nodes and the internal nodes so that the user can receive the updates\n// made by Svelte Flow (like dragging or selecting a node).\nexport function syncNodeStores(nodesStore, userNodesStore) {\n const nodesStoreSetter = nodesStore.set;\n const userNodesStoreSetter = userNodesStore.set;\n const currentNodesStore = get(nodesStore);\n const currentUserNodesStore = get(userNodesStore);\n // depending how the user initializes the nodes, we need to decide if we want to use\n // the user nodes or the internal nodes for initialization. A user can use a SvelteFlowProvider\n // without providing any nodes, in that case we want to use the nodes passed by the user.\n // By default we are using the store nodes, because they already have the absolute positions.\n const initWithUserNodes = currentNodesStore.length === 0 && currentUserNodesStore.length > 0;\n let val = initWithUserNodes ? currentUserNodesStore : currentNodesStore;\n nodesStore.set(val);\n const _set = (nds) => {\n const updatedNodes = nodesStoreSetter(nds);\n val = updatedNodes;\n userNodesStoreSetter(val);\n return updatedNodes;\n };\n nodesStore.set = userNodesStore.set = _set;\n nodesStore.update = userNodesStore.update = (fn) => _set(fn(val));\n}\n// same for edges\nexport function syncEdgeStores(edgesStore, userEdgesStore) {\n const nodesStoreSetter = edgesStore.set;\n const userEdgesStoreSetter = userEdgesStore.set;\n let val = get(userEdgesStore);\n edgesStore.set(val);\n const _set = (eds) => {\n nodesStoreSetter(eds);\n userEdgesStoreSetter(eds);\n val = eds;\n };\n edgesStore.set = userEdgesStore.set = _set;\n edgesStore.update = userEdgesStore.update = (fn) => _set(fn(val));\n}\n// it is possible to pass a viewport store to SvelteFlow for having more control\n// if that's the case we need to sync the internal viewport with the user viewport\nexport const syncViewportStores = (panZoomStore, viewportStore, userViewportStore) => {\n if (!userViewportStore) {\n return;\n }\n const panZoom = get(panZoomStore);\n const viewportStoreSetter = viewportStore.set;\n const userViewportStoreSetter = userViewportStore.set;\n let val = userViewportStore ? get(userViewportStore) : { x: 0, y: 0, zoom: 1 };\n viewportStore.set(val);\n viewportStore.set = (vp) => {\n viewportStoreSetter(vp);\n userViewportStoreSetter(vp);\n val = vp;\n return vp;\n };\n userViewportStore.set = (vp) => {\n panZoom?.syncViewport(vp);\n viewportStoreSetter(vp);\n userViewportStoreSetter(vp);\n val = vp;\n return vp;\n };\n viewportStore.update = (fn) => {\n viewportStore.set(fn(val));\n };\n userViewportStore.update = (fn) => {\n userViewportStore.set(fn(val));\n };\n};\n// we are creating a custom store for the internals nodes in order to update the zIndex and positionAbsolute.\n// The user only passes in relative positions, so we need to calculate the absolute positions based on the parent nodes.\nexport const createNodesStore = (nodes, nodeLookup, parentLookup, nodeOrigin = [0, 0], nodeExtent = infiniteExtent) => {\n const { subscribe, set, update } = writable([]);\n let value = nodes;\n let defaults = {};\n let elevateNodesOnSelect = true;\n const _set = (nds) => {\n adoptUserNodes(nds, nodeLookup, parentLookup, {\n elevateNodesOnSelect,\n nodeOrigin,\n nodeExtent,\n defaults,\n checkEquality: false\n });\n value = nds;\n set(value);\n return value;\n };\n const _update = (fn) => _set(fn(value));\n const setDefaultOptions = (options) => {\n defaults = options;\n };\n const setOptions = (options) => {\n elevateNodesOnSelect = options.elevateNodesOnSelect ?? elevateNodesOnSelect;\n };\n _set(value);\n return {\n subscribe,\n set: _set,\n update: _update,\n setDefaultOptions,\n setOptions\n };\n};\nexport const createEdgesStore = (edges, connectionLookup, edgeLookup, defaultOptions) => {\n const { subscribe, set, update } = writable([]);\n let value = edges;\n let defaults = defaultOptions || {};\n const _set = (eds) => {\n const nextEdges = defaults ? eds.map((edge) => ({ ...defaults, ...edge })) : eds;\n updateConnectionLookup(connectionLookup, edgeLookup, nextEdges);\n value = nextEdges;\n set(value);\n };\n const _update = (fn) => _set(fn(value));\n const setDefaultOptions = (options) => {\n defaults = options;\n };\n _set(value);\n return {\n subscribe,\n set: _set,\n update: _update,\n setDefaultOptions\n };\n};\n","import { readable, writable } from 'svelte/store';\nimport { infiniteExtent, SelectionMode, ConnectionMode, ConnectionLineType, devWarn, adoptUserNodes, getViewportForBounds, updateConnectionLookup, initialConnection, getInternalNodesBounds } from '@xyflow/system';\nimport DefaultNode from '../components/nodes/DefaultNode.svelte';\nimport InputNode from '../components/nodes/InputNode.svelte';\nimport OutputNode from '../components/nodes/OutputNode.svelte';\nimport GroupNode from '../components/nodes/GroupNode.svelte';\nimport { BezierEdgeInternal, SmoothStepEdgeInternal, StraightEdgeInternal, StepEdgeInternal } from '../components/edges';\nimport { createNodesStore, createEdgesStore } from './utils';\nexport const initialNodeTypes = {\n input: InputNode,\n output: OutputNode,\n default: DefaultNode,\n group: GroupNode\n};\nexport const initialEdgeTypes = {\n straight: StraightEdgeInternal,\n smoothstep: SmoothStepEdgeInternal,\n default: BezierEdgeInternal,\n step: StepEdgeInternal\n};\nexport const getInitialStore = ({ nodes = [], edges = [], width, height, fitView, nodeOrigin, nodeExtent }) => {\n const nodeLookup = new Map();\n const parentLookup = new Map();\n const connectionLookup = new Map();\n const edgeLookup = new Map();\n const storeNodeOrigin = nodeOrigin ?? [0, 0];\n const storeNodeExtent = nodeExtent ?? infiniteExtent;\n adoptUserNodes(nodes, nodeLookup, parentLookup, {\n nodeExtent: storeNodeExtent,\n nodeOrigin: storeNodeOrigin,\n elevateNodesOnSelect: false,\n checkEquality: false\n });\n updateConnectionLookup(connectionLookup, edgeLookup, edges);\n let viewport = { x: 0, y: 0, zoom: 1 };\n if (fitView && width && height) {\n const bounds = getInternalNodesBounds(nodeLookup, {\n filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight))\n });\n viewport = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);\n }\n return {\n flowId: writable(null),\n nodes: createNodesStore(nodes, nodeLookup, parentLookup, storeNodeOrigin, storeNodeExtent),\n nodeLookup: readable(nodeLookup),\n parentLookup: readable(parentLookup),\n edgeLookup: readable(edgeLookup),\n visibleNodes: readable([]),\n edges: createEdgesStore(edges, connectionLookup, edgeLookup),\n visibleEdges: readable([]),\n connectionLookup: readable(connectionLookup),\n height: writable(500),\n width: writable(500),\n minZoom: writable(0.5),\n maxZoom: writable(2),\n nodeOrigin: writable(storeNodeOrigin),\n nodeDragThreshold: writable(1),\n nodeExtent: writable(storeNodeExtent),\n translateExtent: writable(infiniteExtent),\n autoPanOnNodeDrag: writable(true),\n autoPanOnConnect: writable(true),\n fitViewOnInit: writable(false),\n fitViewOnInitDone: writable(false),\n fitViewOptions: writable(undefined),\n panZoom: writable(null),\n snapGrid: writable(null),\n dragging: writable(false),\n selectionRect: writable(null),\n selectionKeyPressed: writable(false),\n multiselectionKeyPressed: writable(false),\n deleteKeyPressed: writable(false),\n panActivationKeyPressed: writable(false),\n zoomActivationKeyPressed: writable(false),\n selectionRectMode: writable(null),\n selectionMode: writable(SelectionMode.Partial),\n nodeTypes: writable(initialNodeTypes),\n edgeTypes: writable(initialEdgeTypes),\n viewport: writable(viewport),\n connectionMode: writable(ConnectionMode.Strict),\n domNode: writable(null),\n connection: readable(initialConnection),\n connectionLineType: writable(ConnectionLineType.Bezier),\n connectionRadius: writable(20),\n isValidConnection: writable(() => true),\n nodesDraggable: writable(true),\n nodesConnectable: writable(true),\n elementsSelectable: writable(true),\n selectNodesOnDrag: writable(true),\n markers: readable([]),\n defaultMarkerColor: writable('#b1b1b7'),\n lib: readable('svelte'),\n onlyRenderVisibleElements: writable(false),\n onerror: writable(devWarn),\n ondelete: writable(undefined),\n onedgecreate: writable(undefined),\n onconnect: writable(undefined),\n onconnectstart: writable(undefined),\n onconnectend: writable(undefined),\n onbeforedelete: writable(undefined),\n nodesInitialized: writable(false),\n edgesInitialized: writable(false),\n viewportInitialized: writable(false),\n initialized: readable(false)\n };\n};\n","import { derived } from 'svelte/store';\nimport { isEdgeVisible, getEdgePosition, getElevatedEdgeZIndex } from '@xyflow/system';\nexport function getVisibleEdges(store) {\n const visibleEdges = derived([\n store.edges,\n store.nodes,\n store.nodeLookup,\n store.onlyRenderVisibleElements,\n store.viewport,\n store.width,\n store.height\n ], ([edges, , nodeLookup, onlyRenderVisibleElements, viewport, width, height]) => {\n const visibleEdges = onlyRenderVisibleElements && width && height\n ? edges.filter((edge) => {\n const sourceNode = nodeLookup.get(edge.source);\n const targetNode = nodeLookup.get(edge.target);\n return (sourceNode &&\n targetNode &&\n isEdgeVisible({\n sourceNode,\n targetNode,\n width,\n height,\n transform: [viewport.x, viewport.y, viewport.zoom]\n }));\n })\n : edges;\n return visibleEdges;\n });\n return derived([visibleEdges, store.nodes, store.nodeLookup, store.connectionMode, store.onerror], ([visibleEdges, , nodeLookup, connectionMode, onerror]) => {\n const layoutedEdges = visibleEdges.reduce((res, edge) => {\n const sourceNode = nodeLookup.get(edge.source);\n const targetNode = nodeLookup.get(edge.target);\n if (!sourceNode || !targetNode) {\n return res;\n }\n const edgePosition = getEdgePosition({\n id: edge.id,\n sourceNode,\n targetNode,\n sourceHandle: edge.sourceHandle || null,\n targetHandle: edge.targetHandle || null,\n connectionMode,\n onError: onerror\n });\n if (edgePosition) {\n res.push({\n ...edge,\n zIndex: getElevatedEdgeZIndex({\n selected: edge.selected,\n zIndex: edge.zIndex,\n sourceNode,\n targetNode,\n elevateOnSelect: false\n }),\n ...edgePosition\n });\n }\n return res;\n }, []);\n return layoutedEdges;\n });\n}\n","import { derived } from 'svelte/store';\nimport { getNodesInside } from '@xyflow/system';\nexport function getVisibleNodes(store) {\n return derived([\n store.nodeLookup,\n store.onlyRenderVisibleElements,\n store.width,\n store.height,\n store.viewport,\n store.nodes\n ], ([nodeLookup, onlyRenderVisibleElements, width, height, viewport]) => {\n const transform = [viewport.x, viewport.y, viewport.zoom];\n return onlyRenderVisibleElements\n ? getNodesInside(nodeLookup, { x: 0, y: 0, width, height }, transform, true)\n : Array.from(nodeLookup.values());\n });\n}\n","import { getContext, setContext } from 'svelte';\nimport { derived, get, writable } from 'svelte/store';\nimport { createMarkerIds, fitView as fitViewSystem, getElementsToRemove, panBy as panBySystem, updateNodeInternals as updateNodeInternalsSystem, addEdge as addEdgeUtil, initialConnection, errorMessages, pointToRendererPoint, getFitViewNodes } from '@xyflow/system';\nimport { initialEdgeTypes, initialNodeTypes, getInitialStore } from './initial-store';\nimport { syncNodeStores, syncEdgeStores, syncViewportStores } from './utils';\nimport { getVisibleEdges } from './visible-edges';\nimport { getVisibleNodes } from './visible-nodes';\nexport const key = Symbol();\nexport function createStore({ nodes, edges, width, height, fitView: fitViewOnCreate, nodeOrigin, nodeExtent }) {\n const store = getInitialStore({\n nodes,\n edges,\n width,\n height,\n fitView: fitViewOnCreate,\n nodeOrigin,\n nodeExtent\n });\n function setNodeTypes(nodeTypes) {\n store.nodeTypes.set({\n ...initialNodeTypes,\n ...nodeTypes\n });\n }\n function setEdgeTypes(edgeTypes) {\n store.edgeTypes.set({\n ...initialEdgeTypes,\n ...edgeTypes\n });\n }\n function addEdge(edgeParams) {\n const edges = get(store.edges);\n store.edges.set(addEdgeUtil(edgeParams, edges));\n }\n const updateNodePositions = (nodeDragItems, dragging = false) => {\n const nodeLookup = get(store.nodeLookup);\n for (const [id, dragItem] of nodeDragItems) {\n const node = nodeLookup.get(id)?.internals.userNode;\n if (!node) {\n continue;\n }\n node.position = dragItem.position;\n node.dragging = dragging;\n }\n store.nodes.update((nds) => nds);\n };\n function updateNodeInternals(updates) {\n const nodeLookup = get(store.nodeLookup);\n const { changes, updatedInternals } = updateNodeInternalsSystem(updates, nodeLookup, get(store.parentLookup), get(store.domNode), get(store.nodeOrigin));\n if (!updatedInternals) {\n return;\n }\n if (!get(store.fitViewOnInitDone) && get(store.fitViewOnInit)) {\n const fitViewOptions = get(store.fitViewOptions);\n const fitViewOnInitDone = fitViewSync({\n ...fitViewOptions,\n nodes: fitViewOptions?.nodes\n });\n store.fitViewOnInitDone.set(fitViewOnInitDone);\n }\n for (const change of changes) {\n const node = nodeLookup.get(change.id)?.internals.userNode;\n if (!node) {\n continue;\n }\n switch (change.type) {\n case 'dimensions': {\n const measured = { ...node.measured, ...change.dimensions };\n if (change.setAttributes) {\n node.width = change.dimensions?.width ?? node.width;\n node.height = change.dimensions?.height ?? node.height;\n }\n node.measured = measured;\n break;\n }\n case 'position':\n node.position = change.position ?? node.position;\n break;\n }\n }\n store.nodes.update((nds) => nds);\n if (!get(store.nodesInitialized)) {\n store.nodesInitialized.set(true);\n }\n }\n function fitView(options) {\n const panZoom = get(store.panZoom);\n if (!panZoom) {\n return Promise.resolve(false);\n }\n const fitViewNodes = getFitViewNodes(get(store.nodeLookup), options);\n return fitViewSystem({\n nodes: fitViewNodes,\n width: get(store.width),\n height: get(store.height),\n minZoom: get(store.minZoom),\n maxZoom: get(store.maxZoom),\n panZoom\n }, options);\n }\n function fitViewSync(options) {\n const panZoom = get(store.panZoom);\n if (!panZoom) {\n return false;\n }\n const fitViewNodes = getFitViewNodes(get(store.nodeLookup), options);\n fitViewSystem({\n nodes: fitViewNodes,\n width: get(store.width),\n height: get(store.height),\n minZoom: get(store.minZoom),\n maxZoom: get(store.maxZoom),\n panZoom\n }, options);\n return fitViewNodes.size > 0;\n }\n function zoomBy(factor, options) {\n const panZoom = get(store.panZoom);\n if (!panZoom) {\n return Promise.resolve(false);\n }\n return panZoom.scaleBy(factor, options);\n }\n function zoomIn(options) {\n return zoomBy(1.2, options);\n }\n function zoomOut(options) {\n return zoomBy(1 / 1.2, options);\n }\n function setMinZoom(minZoom) {\n const panZoom = get(store.panZoom);\n if (panZoom) {\n panZoom.setScaleExtent([minZoom, get(store.maxZoom)]);\n store.minZoom.set(minZoom);\n }\n }\n function setMaxZoom(maxZoom) {\n const panZoom = get(store.panZoom);\n if (panZoom) {\n panZoom.setScaleExtent([get(store.minZoom), maxZoom]);\n store.maxZoom.set(maxZoom);\n }\n }\n function setTranslateExtent(extent) {\n const panZoom = get(store.panZoom);\n if (panZoom) {\n panZoom.setTranslateExtent(extent);\n store.translateExtent.set(extent);\n }\n }\n function resetSelectedElements(elements) {\n let elementsChanged = false;\n elements.forEach((element) => {\n if (element.selected) {\n element.selected = false;\n elementsChanged = true;\n }\n });\n return elementsChanged;\n }\n function setPaneClickDistance(distance) {\n get(store.panZoom)?.setClickDistance(distance);\n }\n function unselectNodesAndEdges(params) {\n const resetNodes = resetSelectedElements(params?.nodes || get(store.nodes));\n if (resetNodes)\n store.nodes.set(get(store.nodes));\n const resetEdges = resetSelectedElements(params?.edges || get(store.edges));\n if (resetEdges)\n store.edges.set(get(store.edges));\n }\n store.deleteKeyPressed.subscribe(async (deleteKeyPressed) => {\n if (deleteKeyPressed) {\n const nodes = get(store.nodes);\n const edges = get(store.edges);\n const selectedNodes = nodes.filter((node) => node.selected);\n const selectedEdges = edges.filter((edge) => edge.selected);\n const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({\n nodesToRemove: selectedNodes,\n edgesToRemove: selectedEdges,\n nodes,\n edges,\n onBeforeDelete: get(store.onbeforedelete)\n });\n if (matchingNodes.length || matchingEdges.length) {\n store.nodes.update((nds) => nds.filter((node) => !matchingNodes.some((mN) => mN.id === node.id)));\n store.edges.update((eds) => eds.filter((edge) => !matchingEdges.some((mE) => mE.id === edge.id)));\n get(store.ondelete)?.({\n nodes: matchingNodes,\n edges: matchingEdges\n });\n }\n }\n });\n function addSelectedNodes(ids) {\n const isMultiSelection = get(store.multiselectionKeyPressed);\n store.nodes.update((ns) => ns.map((node) => {\n const nodeWillBeSelected = ids.includes(node.id);\n const selected = isMultiSelection\n ? node.selected || nodeWillBeSelected\n : nodeWillBeSelected;\n // we need to mutate the node here in order to have the correct selected state in the drag handler\n node.selected = selected;\n return node;\n }));\n if (!isMultiSelection) {\n store.edges.update((es) => es.map((edge) => {\n edge.selected = false;\n return edge;\n }));\n }\n }\n function addSelectedEdges(ids) {\n const isMultiSelection = get(store.multiselectionKeyPressed);\n store.edges.update((edges) => edges.map((edge) => {\n const edgeWillBeSelected = ids.includes(edge.id);\n const selected = isMultiSelection\n ? edge.selected || edgeWillBeSelected\n : edgeWillBeSelected;\n edge.selected = selected;\n return edge;\n }));\n if (!isMultiSelection) {\n store.nodes.update((ns) => ns.map((node) => {\n node.selected = false;\n return node;\n }));\n }\n }\n function handleNodeSelection(id) {\n const node = get(store.nodes)?.find((n) => n.id === id);\n if (!node) {\n console.warn('012', errorMessages['error012'](id));\n return;\n }\n store.selectionRect.set(null);\n store.selectionRectMode.set(null);\n if (!node.selected) {\n addSelectedNodes([id]);\n }\n else if (node.selected && get(store.multiselectionKeyPressed)) {\n unselectNodesAndEdges({ nodes: [node], edges: [] });\n }\n }\n function panBy(delta) {\n const viewport = get(store.viewport);\n return panBySystem({\n delta,\n panZoom: get(store.panZoom),\n transform: [viewport.x, viewport.y, viewport.zoom],\n translateExtent: get(store.translateExtent),\n width: get(store.width),\n height: get(store.height)\n });\n }\n const _connection = writable(initialConnection);\n const updateConnection = (newConnection) => {\n _connection.set({ ...newConnection });\n };\n function cancelConnection() {\n _connection.set(initialConnection);\n }\n function reset() {\n store.fitViewOnInitDone.set(false);\n store.selectionRect.set(null);\n store.selectionRectMode.set(null);\n store.snapGrid.set(null);\n store.isValidConnection.set(() => true);\n unselectNodesAndEdges();\n cancelConnection();\n }\n return {\n // state\n ...store,\n // derived state\n visibleEdges: getVisibleEdges(store),\n visibleNodes: getVisibleNodes(store),\n connection: derived([_connection, store.viewport], ([connection, viewport]) => {\n return connection.inProgress\n ? {\n ...connection,\n to: pointToRendererPoint(connection.to, [viewport.x, viewport.y, viewport.zoom])\n }\n : { ...connection };\n }),\n markers: derived([store.edges, store.defaultMarkerColor, store.flowId], ([edges, defaultColor, id]) => createMarkerIds(edges, { defaultColor, id })),\n initialized: (() => {\n let initialized = false;\n const initialNodesLength = get(store.nodes).length;\n const initialEdgesLength = get(store.edges).length;\n return derived([store.nodesInitialized, store.edgesInitialized, store.viewportInitialized], ([nodesInitialized, edgesInitialized, viewportInitialized]) => {\n // If it was already initialized, return true from then on\n if (initialized)\n return initialized;\n // if it hasn't been initialised check if it's now\n if (initialNodesLength === 0) {\n initialized = viewportInitialized;\n }\n else if (initialEdgesLength === 0) {\n initialized = viewportInitialized && nodesInitialized;\n }\n else {\n initialized = viewportInitialized && nodesInitialized && edgesInitialized;\n }\n return initialized;\n });\n })(),\n // actions\n syncNodeStores: (nodes) => syncNodeStores(store.nodes, nodes),\n syncEdgeStores: (edges) => syncEdgeStores(store.edges, edges),\n syncViewport: (viewport) => syncViewportStores(store.panZoom, store.viewport, viewport),\n setNodeTypes,\n setEdgeTypes,\n addEdge,\n updateNodePositions,\n updateNodeInternals,\n zoomIn,\n zoomOut,\n fitView: (options) => fitView(options),\n setMinZoom,\n setMaxZoom,\n setTranslateExtent,\n setPaneClickDistance,\n unselectNodesAndEdges,\n addSelectedNodes,\n addSelectedEdges,\n handleNodeSelection,\n panBy,\n updateConnection,\n cancelConnection,\n reset\n };\n}\nexport function useStore() {\n const store = getContext(key);\n if (!store) {\n throw new Error('In order to use useStore you need to wrap your component in a ');\n }\n return store.getStore();\n}\nexport function createStoreContext({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent }) {\n const store = createStore({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent });\n setContext(key, {\n getStore: () => store\n });\n return store;\n}\n","import { PanOnScrollMode, XYPanZoom } from '@xyflow/system';\nexport default function zoom(domNode, params) {\n const { panZoom, minZoom, maxZoom, initialViewport, viewport, dragging, translateExtent, paneClickDistance } = params;\n const panZoomInstance = XYPanZoom({\n domNode,\n minZoom,\n maxZoom,\n translateExtent,\n viewport: initialViewport,\n paneClickDistance,\n onDraggingChange: dragging.set\n });\n const currentViewport = panZoomInstance.getViewport();\n viewport.set(currentViewport);\n panZoom.set(panZoomInstance);\n panZoomInstance.update(params);\n return {\n update(params) {\n panZoomInstance.update(params);\n }\n };\n}\n","\n\n\n \n\n\n\n","\n\n\n\n\n\n\n \n\n\n\n","\n\n\n \n\n\n\n","import { get } from 'svelte/store';\nimport { XYDrag } from '@xyflow/system';\nexport default function drag(domNode, params) {\n const { store, onDrag, onDragStart, onDragStop, onNodeMouseDown } = params;\n const dragInstance = XYDrag({\n onDrag,\n onDragStart,\n onDragStop,\n onNodeMouseDown,\n getStoreItems: () => {\n const snapGrid = get(store.snapGrid);\n const vp = get(store.viewport);\n return {\n nodes: get(store.nodes),\n nodeLookup: get(store.nodeLookup),\n edges: get(store.edges),\n nodeExtent: get(store.nodeExtent),\n snapGrid: snapGrid ? snapGrid : [0, 0],\n snapToGrid: !!snapGrid,\n nodeOrigin: get(store.nodeOrigin),\n multiSelectionActive: get(store.multiselectionKeyPressed),\n domNode: get(store.domNode),\n transform: [vp.x, vp.y, vp.zoom],\n autoPanOnNodeDrag: get(store.autoPanOnNodeDrag),\n nodesDraggable: get(store.nodesDraggable),\n selectNodesOnDrag: get(store.selectNodesOnDrag),\n nodeDragThreshold: get(store.nodeDragThreshold),\n unselectNodesAndEdges: store.unselectNodesAndEdges,\n updateNodePositions: store.updateNodePositions,\n panBy: store.panBy\n };\n }\n });\n function updateDrag(domNode, params) {\n if (params.disabled) {\n dragInstance.destroy();\n return;\n }\n dragInstance.update({\n domNode,\n noDragClassName: params.noDragClass,\n handleSelector: params.handleSelector,\n nodeId: params.nodeId,\n isSelectable: params.isSelectable,\n nodeClickDistance: params.nodeClickDistance\n });\n }\n updateDrag(domNode, params);\n return {\n update(params) {\n updateDrag(domNode, params);\n },\n destroy() {\n dragInstance.destroy();\n }\n };\n}\n","export function getNodeInlineStyleDimensions({ width, height, initialWidth, initialHeight, measuredWidth, measuredHeight }) {\n if (measuredWidth === undefined && measuredHeight === undefined) {\n const styleWidth = width ?? initialWidth;\n const styleHeight = height ?? initialHeight;\n return {\n width: styleWidth ? `width:${styleWidth}px;` : '',\n height: styleHeight ? `height:${styleHeight}px;` : ''\n };\n }\n return {\n width: width ? `width:${width}px;` : '',\n height: height ? `height:${height}px;` : ''\n };\n}\n","\n\n\n\n\n\n{#if !hidden}\n {\n dispatchNodeEvent('nodedrag', { event, targetNode, nodes });\n },\n onDragStart: (event, _, targetNode, nodes) => {\n dispatchNodeEvent('nodedragstart', { event, targetNode, nodes });\n },\n onDragStop: (event, _, targetNode, nodes) => {\n dispatchNodeEvent('nodedragstop', { event, targetNode, nodes });\n },\n store\n }}\n bind:this={nodeRef}\n data-id={id}\n class={cc(['svelte-flow__node', `svelte-flow__node-${nodeType}`, className])}\n class:dragging\n class:selected\n class:draggable\n class:connectable\n class:selectable\n class:nopan={draggable}\n class:parent={isParent}\n style:z-index={zIndex}\n style:transform=\"translate({positionX}px, {positionY}px)\"\n style:visibility={initialized ? 'visible' : 'hidden'}\n style=\"{style ?? ''};{inlineStyleDimensions.width}{inlineStyleDimensions.height}\"\n on:click={onSelectNodeHandler}\n on:mouseenter={(event) => dispatchNodeEvent('nodemouseenter', { node, event })}\n on:mouseleave={(event) => dispatchNodeEvent('nodemouseleave', { node, event })}\n on:mousemove={(event) => dispatchNodeEvent('nodemousemove', { node, event })}\n on:contextmenu={(event) => dispatchNodeEvent('nodecontextmenu', { node, event })}\n >\n \n \n{/if}\n","\n\n
\n {#each $visibleNodes as node (node.id)}\n
\n\n\n","\n\n\n\n\n\n{#if !hidden}\n \n {\n onMouseEvent(e, 'edgecontextmenu');\n }}\n on:mouseenter={(e) => {\n onMouseEvent(e, 'edgemouseenter');\n }}\n on:mouseleave={(e) => {\n onMouseEvent(e, 'edgemouseleave');\n }}\n aria-label={ariaLabel === null\n ? undefined\n : ariaLabel\n ? ariaLabel\n : `Edge from ${source} to ${target}`}\n role=\"img\"\n >\n \n \n \n{/if}\n","\n","\n\n\n {#each $markers as marker (marker.id)}\n \n {/each}\n\n","\n\n\n {#if type === MarkerType.Arrow}\n \n {:else if type === MarkerType.ArrowClosed}\n \n {/if}\n\n","\n\n
\n \n \n \n\n {#each $visibleEdges as edge (edge.id)}\n
\n","\n\n{#if isVisible}\n \n{/if}\n\n\n","\n\n\n","\n\n{#if $selectionRectMode === 'nodes' && bounds && isNumeric(bounds.x) && isNumeric(bounds.y)}\n {\n dispatch('nodedrag', { event, targetNode: null, nodes });\n },\n onDragStart: (event, _, __, nodes) => {\n dispatch('nodedragstart', { event, targetNode: null, nodes });\n },\n onDragStop: (event, _, __, nodes) => {\n dispatch('nodedragstop', { event, targetNode: null, nodes });\n }\n }}\n on:contextmenu={onContextMenu}\n on:click={onClick}\n role=\"button\"\n tabindex=\"-1\"\n on:keyup={() => {}}\n >\n \n \n{/if}\n\n\n","/**\n * Listen for keyboard event and trigger `shortcut` {@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent | CustomEvent }\n * @example Typical usage\n *\n * ```svelte\n * \n *\n * \n * ```\n *\n *\n *\n * As with any svelte action, `shortcut` should be use with element and not component.\n *\n * ```html\n * <-- correct usage-->\n *
\n *\n * <-- incorrect usage-->\n * \n * ```\n *\n * You can either:\n *\n * - pass multiple callbacks to their associated triggers, or\n *\n * - pass one single handler to the `on:shortcut` event, in which case you should\n * provide an ID to each trigger to be able to distinguish what trigger was activated\n * in the event handler.\n *\n * Either way, only use `callback` or `on:shortcut` and not both to\n * avoid handler duplication.\n * @param {HTMLElement} node - HTMLElement to add event listener to\n * @param {import('./public').ShortcutParameter} param - svelte action parameters\n * @returns {import('./public').ShortcutActionReturn}\n */\nexport function shortcut(node, param) {\n\tlet { enabled = true, trigger, type = 'keydown' } = param;\n\n\t/**\n\t * @param {KeyboardEvent} event\n\t */\n\tfunction handler(event) {\n\t\tconst normalizedTriggers = Array.isArray(trigger) ? trigger : [trigger];\n\t\t/** @type {Record} */\n\t\tconst modifiedMap = {\n\t\t\talt: event.altKey,\n\t\t\tctrl: event.ctrlKey,\n\t\t\tshift: event.shiftKey,\n\t\t\tmeta: event.metaKey,\n\t\t};\n\t\tfor (const trigger of normalizedTriggers) {\n\t\t\tconst mergedTrigger = {\n\t\t\t\tmodifier: [],\n\t\t\t\tpreventDefault: false,\n\t\t\t\tenabled: true,\n\t\t\t\t...trigger,\n\t\t\t};\n\t\t\tconst { modifier, key, callback, preventDefault, enabled: triggerEnabled } = mergedTrigger;\n\t\t\tif (triggerEnabled) {\n\t\t\t\tif (modifier.length) {\n\t\t\t\t\tconst modifierDefs = (Array.isArray(modifier) ? modifier : [modifier]).map((def) =>\n\t\t\t\t\t\ttypeof def === 'string' ? [def] : def,\n\t\t\t\t\t);\n\t\t\t\t\tconst modified = modifierDefs.some((def) =>\n\t\t\t\t\t\tdef.every((modifier) => modifiedMap[modifier]),\n\t\t\t\t\t);\n\t\t\t\t\tif (!modified) continue;\n\t\t\t\t}\n\t\t\t\tif (event.key === key) {\n\t\t\t\t\tif (preventDefault) event.preventDefault();\n\t\t\t\t\t/** @type {import('./public').ShortcutEventDetail} */\n\t\t\t\t\tconst detail = {\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\ttrigger: mergedTrigger,\n\t\t\t\t\t\toriginalEvent: event,\n\t\t\t\t\t};\n\t\t\t\t\tnode.dispatchEvent(new CustomEvent('shortcut', { detail }));\n\t\t\t\t\tcallback?.(detail);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (enabled) node.addEventListener(type, handler);\n\n\treturn {\n\t\tupdate: (update) => {\n\t\t\tconst { enabled: newEnabled = true, type: newType = 'keydown' } = update;\n\n\t\t\tif (enabled && (!newEnabled || type !== newType)) {\n\t\t\t\tnode.removeEventListener(type, handler);\n\t\t\t} else if (!enabled && newEnabled) {\n\t\t\t\tnode.addEventListener(newType, handler);\n\t\t\t}\n\n\t\t\tenabled = newEnabled;\n\t\t\ttype = newType;\n\t\t\ttrigger = update.trigger;\n\t\t},\n\t\tdestroy: () => {\n\t\t\tnode.removeEventListener(type, handler);\n\t\t},\n\t};\n}\n","\n\n selectionKeyPressed.set(true)),\n type: 'keydown'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(selectionKey, () => selectionKeyPressed.set(false)),\n type: 'keyup'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(multiSelectionKey, () => multiselectionKeyPressed.set(true)),\n type: 'keydown'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(multiSelectionKey, () => multiselectionKeyPressed.set(false)),\n type: 'keyup'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(deleteKey, (detail) => {\n const isModifierKey =\n detail.originalEvent.ctrlKey ||\n detail.originalEvent.metaKey ||\n detail.originalEvent.shiftKey;\n if (!isModifierKey && !isInputDOMNode(detail.originalEvent)) {\n deleteKeyPressed.set(true);\n }\n }),\n type: 'keydown'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(deleteKey, () => deleteKeyPressed.set(false)),\n type: 'keyup'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(panActivationKey, () => panActivationKeyPressed.set(true)),\n type: 'keydown'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(panActivationKey, () => panActivationKeyPressed.set(false)),\n type: 'keyup'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(zoomActivationKey, () => zoomActivationKeyPressed.set(true)),\n type: 'keydown'\n }}\n use:shortcut={{\n trigger: getShortcutTrigger(zoomActivationKey, () => zoomActivationKeyPressed.set(false)),\n type: 'keyup'\n }}\n/>\n","\n\n{#if $connection.inProgress}\n \n \n \n \n {#if !isCustomComponent}\n \n {/if}\n \n \n{/if}\n","\n\n\n \n
\n","\n\n{#if !proOptions?.hideAttribution}\n \n \n Svelte Flow\n \n \n{/if}\n","// this is helper function for updating the store\n// for props where we need to call a specific store action\nexport function updateStore(store, { nodeTypes, edgeTypes, minZoom, maxZoom, translateExtent, paneClickDistance }) {\n if (nodeTypes !== undefined) {\n store.setNodeTypes(nodeTypes);\n }\n if (edgeTypes !== undefined) {\n store.setEdgeTypes(edgeTypes);\n }\n if (minZoom !== undefined) {\n store.setMinZoom(minZoom);\n }\n if (maxZoom !== undefined) {\n store.setMaxZoom(maxZoom);\n }\n if (translateExtent !== undefined) {\n store.setTranslateExtent(translateExtent);\n }\n if (paneClickDistance !== undefined) {\n store.setPaneClickDistance(paneClickDistance);\n }\n}\nconst getKeys = (obj) => Object.keys(obj);\nexport function updateStoreByKeys(store, keys) {\n getKeys(keys).forEach((prop) => {\n const update = keys[prop];\n if (update !== undefined) {\n // @ts-expect-error @todo: how to fix this TS error?\n store[prop].set(update);\n }\n });\n}\n","import { readable } from 'svelte/store';\nfunction getMediaQuery() {\n if (typeof window === 'undefined' || !window.matchMedia) {\n return null;\n }\n return window.matchMedia('(prefers-color-scheme: dark)');\n}\n/**\n * Hook for receiving the current color mode class 'dark' or 'light'.\n *\n * @internal\n * @param colorMode - The color mode to use ('dark', 'light' or 'system')\n */\nexport function useColorModeClass(colorMode = 'light') {\n const colorModeClass = readable('light', (set) => {\n if (colorMode !== 'system') {\n set(colorMode);\n return;\n }\n const mediaQuery = getMediaQuery();\n const updateColorModeClass = () => set(mediaQuery?.matches ? 'dark' : 'light');\n set(mediaQuery?.matches ? 'dark' : 'light');\n mediaQuery?.addEventListener('change', updateColorModeClass);\n return () => {\n mediaQuery?.removeEventListener('change', updateColorModeClass);\n };\n });\n return colorModeClass;\n}\n","\n\n\n \n \n \n \n \n \n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n\n\n","\n\n\n","\n\n\n \n\n","\n \n\n","\n \n\n","\n \n\n","\n \n\n","\n \n\n","\n\n\n \n {#if showZoom}\n \n \n \n \n \n \n {/if}\n {#if showFitView}\n \n \n \n {/if}\n {#if showLock}\n \n {#if isInteractive}{:else}{/if}\n \n {/if}\n \n \n\n","export var BackgroundVariant;\n(function (BackgroundVariant) {\n BackgroundVariant[\"Lines\"] = \"lines\";\n BackgroundVariant[\"Dots\"] = \"dots\";\n BackgroundVariant[\"Cross\"] = \"cross\";\n})(BackgroundVariant || (BackgroundVariant = {}));\n","\n\n\n","\n\n\n","\n\n\n\n\n \n {#if isDots}\n \n {:else}\n \n {/if}\n \n \n\n\n\n","import { isNodeBase, isEdgeBase } from '@xyflow/system';\n/**\n * Test whether an object is useable as a Node\n * @public\n * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true\n * @param element - The element to test\n * @returns A boolean indicating whether the element is an Node\n */\nexport const isNode = (element) => isNodeBase(element);\n/**\n * Test whether an object is useable as an Edge\n * @public\n * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true\n * @param element - The element to test\n * @returns A boolean indicating whether the element is an Edge\n */\nexport const isEdge = (element) => isEdgeBase(element);\n","import { get } from 'svelte/store';\nimport { getOverlappingArea, isRectObject, nodeToRect, pointToRendererPoint, getViewportForBounds, getElementsToRemove, rendererPointToPoint, evaluateAbsolutePosition, getNodesBounds } from '@xyflow/system';\nimport { useStore } from '../store';\nimport { isNode } from '../utils';\n/**\n * Hook for accessing the ReactFlow instance.\n *\n * @public\n *\n * @returns helper functions\n */\nexport function useSvelteFlow() {\n const { zoomIn, zoomOut, fitView, onbeforedelete, snapGrid, viewport, width, height, minZoom, maxZoom, panZoom, nodes, edges, domNode, nodeLookup, nodeOrigin, edgeLookup, connectionLookup } = useStore();\n const getNodeRect = (node) => {\n const $nodeLookup = get(nodeLookup);\n const nodeToUse = isNode(node) ? node : $nodeLookup.get(node.id);\n const position = nodeToUse.parentId\n ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, $nodeLookup, get(nodeOrigin))\n : nodeToUse.position;\n const nodeWithPosition = {\n id: nodeToUse.id,\n position,\n width: nodeToUse.measured?.width ?? nodeToUse.width,\n height: nodeToUse.measured?.height ?? nodeToUse.height,\n data: nodeToUse.data\n };\n return nodeToRect(nodeWithPosition);\n };\n const updateNode = (id, nodeUpdate, options = { replace: false }) => {\n const node = get(nodeLookup).get(id)?.internals.userNode;\n if (!node) {\n return;\n }\n const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node) : nodeUpdate;\n if (options.replace) {\n nodes.update((nds) => nds.map((node) => {\n if (node.id === id) {\n return isNode(nextNode) ? nextNode : { ...node, ...nextNode };\n }\n return node;\n }));\n }\n else {\n Object.assign(node, nextNode);\n nodes.update((nds) => nds);\n }\n };\n const getInternalNode = (id) => get(nodeLookup).get(id);\n return {\n zoomIn,\n zoomOut,\n getInternalNode,\n getNode: (id) => getInternalNode(id)?.internals.userNode,\n getNodes: (ids) => (ids === undefined ? get(nodes) : getElements(get(nodeLookup), ids)),\n getEdge: (id) => get(edgeLookup).get(id),\n getEdges: (ids) => (ids === undefined ? get(edges) : getElements(get(edgeLookup), ids)),\n setZoom: (zoomLevel, options) => {\n const currentPanZoom = get(panZoom);\n return currentPanZoom\n ? currentPanZoom.scaleTo(zoomLevel, { duration: options?.duration })\n : Promise.resolve(false);\n },\n getZoom: () => get(viewport).zoom,\n setViewport: async (nextViewport, options) => {\n const currentViewport = get(viewport);\n const currentPanZoom = get(panZoom);\n if (!currentPanZoom) {\n return Promise.resolve(false);\n }\n await currentPanZoom.setViewport({\n x: nextViewport.x ?? currentViewport.x,\n y: nextViewport.y ?? currentViewport.y,\n zoom: nextViewport.zoom ?? currentViewport.zoom\n }, { duration: options?.duration });\n return Promise.resolve(true);\n },\n getViewport: () => get(viewport),\n setCenter: async (x, y, options) => {\n const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : get(maxZoom);\n const currentPanZoom = get(panZoom);\n if (!currentPanZoom) {\n return Promise.resolve(false);\n }\n await currentPanZoom.setViewport({\n x: get(width) / 2 - x * nextZoom,\n y: get(height) / 2 - y * nextZoom,\n zoom: nextZoom\n }, { duration: options?.duration });\n return Promise.resolve(true);\n },\n fitView,\n fitBounds: async (bounds, options) => {\n const currentPanZoom = get(panZoom);\n if (!currentPanZoom) {\n return Promise.resolve(false);\n }\n const viewport = getViewportForBounds(bounds, get(width), get(height), get(minZoom), get(maxZoom), options?.padding ?? 0.1);\n await currentPanZoom.setViewport(viewport, { duration: options?.duration });\n return Promise.resolve(true);\n },\n getIntersectingNodes: (nodeOrRect, partially = true, nodesToIntersect) => {\n const isRect = isRectObject(nodeOrRect);\n const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);\n if (!nodeRect) {\n return [];\n }\n return (nodesToIntersect || get(nodes)).filter((n) => {\n const internalNode = get(nodeLookup).get(n.id);\n if (!internalNode || (!isRect && n.id === nodeOrRect.id)) {\n return false;\n }\n const currNodeRect = nodeToRect(internalNode);\n const overlappingArea = getOverlappingArea(currNodeRect, nodeRect);\n const partiallyVisible = partially && overlappingArea > 0;\n return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;\n });\n },\n isNodeIntersecting: (nodeOrRect, area, partially = true) => {\n const isRect = isRectObject(nodeOrRect);\n const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);\n if (!nodeRect) {\n return false;\n }\n const overlappingArea = getOverlappingArea(nodeRect, area);\n const partiallyVisible = partially && overlappingArea > 0;\n return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;\n },\n deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {\n const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({\n nodesToRemove,\n edgesToRemove,\n nodes: get(nodes),\n edges: get(edges),\n onBeforeDelete: get(onbeforedelete)\n });\n if (matchingNodes) {\n nodes.update((nds) => nds.filter((node) => !matchingNodes.some(({ id }) => id === node.id)));\n }\n if (matchingEdges) {\n edges.update((eds) => eds.filter((edge) => !matchingEdges.some(({ id }) => id === edge.id)));\n }\n return {\n deletedNodes: matchingNodes,\n deletedEdges: matchingEdges\n };\n },\n screenToFlowPosition: (position, options = { snapToGrid: true }) => {\n const _domNode = get(domNode);\n if (!_domNode) {\n return position;\n }\n const _snapGrid = options.snapToGrid ? get(snapGrid) : false;\n const { x, y, zoom } = get(viewport);\n const { x: domX, y: domY } = _domNode.getBoundingClientRect();\n const correctedPosition = {\n x: position.x - domX,\n y: position.y - domY\n };\n return pointToRendererPoint(correctedPosition, [x, y, zoom], _snapGrid !== null, _snapGrid || [1, 1]);\n },\n /**\n *\n * @param position\n * @returns\n */\n flowToScreenPosition: (position) => {\n const _domNode = get(domNode);\n if (!_domNode) {\n return position;\n }\n const { x, y, zoom } = get(viewport);\n const { x: domX, y: domY } = _domNode.getBoundingClientRect();\n const rendererPosition = rendererPointToPoint(position, [x, y, zoom]);\n return {\n x: rendererPosition.x + domX,\n y: rendererPosition.y + domY\n };\n },\n toObject: () => {\n return {\n nodes: get(nodes).map((node) => ({\n ...node,\n // we want to make sure that changes to the nodes object that gets returned by toObject\n // do not affect the nodes object\n position: { ...node.position },\n data: { ...node.data }\n })),\n edges: get(edges).map((edge) => ({ ...edge })),\n viewport: { ...get(viewport) }\n };\n },\n updateNode,\n updateNodeData: (id, dataUpdate, options) => {\n const node = get(nodeLookup).get(id)?.internals.userNode;\n if (!node) {\n return;\n }\n const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;\n node.data = options?.replace ? nextData : { ...node.data, ...nextData };\n nodes.update((nds) => nds);\n },\n getNodesBounds: (nodes) => {\n const _nodeLookup = get(nodeLookup);\n const _nodeOrigin = get(nodeOrigin);\n return getNodesBounds(nodes, { nodeLookup: _nodeLookup, nodeOrigin: _nodeOrigin });\n },\n getHandleConnections: ({ type, id, nodeId }) => Array.from(get(connectionLookup)\n .get(`${nodeId}-${type}-${id ?? null}`)\n ?.values() ?? []),\n viewport\n };\n}\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getElements(lookup, ids) {\n const result = [];\n for (const id of ids) {\n const item = lookup.get(id);\n if (item) {\n const element = 'internals' in item ? item.internals?.userNode : item;\n result.push(element);\n }\n }\n return result;\n}\n","import { useStore } from '../store';\n/**\n * Hook for seeing if nodes are initialized\n * @returns - nodesInitialized Writable\n */\nexport function useNodesInitialized() {\n const { nodesInitialized } = useStore();\n return {\n subscribe: nodesInitialized.subscribe\n };\n}\n/**\n * Hook for seeing if the flow is initialized\n * @returns - initialized Writable\n */\nexport function useInitialized() {\n const { initialized } = useStore();\n return {\n subscribe: initialized.subscribe\n };\n}\n","\n\n {\n\t\tsubmitHandler();\n\t\tdispatch('save');\n\t}}\n>\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\n\t\t\t\t
\n\t\t\t\t\t {\n\t\t\t\t\t\t\tawait tick();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{#if tab === 'tools'}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{/each}\n\t\t\t\t\t\t{:else if tab === 'functions'}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{/each}\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\n\t\t{#if selectedId}\n\t\t\t
\n\n\t\t\t
\n\t\t\t\t{#if !loading}\n\t\t\t\t\t {\n\t\t\t\t\t\t\tdebounceSubmitHandler();\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t{:else}\n\t\t\t\t\t\n\t\t\t\t{/if}\n\t\t\t
\n\t\t{/if}\n\t
\n\n","\n\n
\n\t
\n\t\t
{$i18n.t('Chat Controls')}
\n\t\t {\n\t\t\t\tdispatch('close');\n\t\t\t}}\n\t\t>\n\t\t\t\n\t\t\n\t
\n\n\t
\n\t\t{#if chatFiles.length > 0}\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{#each chatFiles as file, fileIdx}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t// Remove the file from the chatFiles array\n\n\t\t\t\t\t\t\t\tchatFiles.splice(fileIdx, 1);\n\t\t\t\t\t\t\t\tchatFiles = chatFiles;\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t{/each}\n\t\t\t\t
\n\t\t\t
\n\n\t\t\t
\n\t\t{/if}\n\n\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t
\n\n\t\t
\n\n\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t
\n\n\t\t
\n\n\t\t\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t
\n
\n","\n\n {\n\t\tif (e.detail === false) {\n\t\t\tonClose();\n\t\t}\n\t}}\n>\n\t\n\n\t
\n\t\t\n\t\t\t{#each devices as device}\n\t\t\t\t {\n\t\t\t\t\t\tdispatch('change', device.deviceId);\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{device?.label ?? 'Camera'}\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\n\t\t\t{/each}\n\t\t\n\t
\n\n","\n\n{#if $showCallOverlay}\n\t
\n\t\t{#if camera}\n\t\t\t {\n\t\t\t\t\tif (assistantSpeaking) {\n\t\t\t\t\t\tstopAllAudio();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{#if emoji}\n\t\t\t\t\t 4\n\t\t\t\t\t\t\t? '4.5'\n\t\t\t\t\t\t\t: rmsLevel * 100 > 2\n\t\t\t\t\t\t\t\t? '4.25'\n\t\t\t\t\t\t\t\t: rmsLevel * 100 > 1\n\t\t\t\t\t\t\t\t\t? '3.75'\n\t\t\t\t\t\t\t\t\t: '3.5'}rem;width: 100%; text-align:center;\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{emoji}\n\t\t\t\t\t
\n\t\t\t\t{:else if loading || assistantSpeaking}\n\t\t\t\t\t\n\t\t\t\t{:else}\n\t\t\t\t\t 4\n\t\t\t\t\t\t\t? ' size-[4.5rem]'\n\t\t\t\t\t\t\t: rmsLevel * 100 > 2\n\t\t\t\t\t\t\t\t? ' size-16'\n\t\t\t\t\t\t\t\t: rmsLevel * 100 > 1\n\t\t\t\t\t\t\t\t\t? 'size-14'\n\t\t\t\t\t\t\t\t\t: 'size-12'} transition-all rounded-full {(model?.info?.meta\n\t\t\t\t\t\t\t?.profile_image_url ?? '/static/favicon.png') !== '/static/favicon.png'\n\t\t\t\t\t\t\t? ' bg-cover bg-center bg-no-repeat'\n\t\t\t\t\t\t\t: 'bg-black dark:bg-white'} bg-black dark:bg-white\"\n\t\t\t\t\t\tstyle={(model?.info?.meta?.profile_image_url ?? '/static/favicon.png') !==\n\t\t\t\t\t\t'/static/favicon.png'\n\t\t\t\t\t\t\t? `background-image: url('${model?.info?.meta?.profile_image_url}');`\n\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t/>\n\t\t\t\t{/if}\n\t\t\t\t\n\t\t\t\n\t\t{/if}\n\n\t\t
\n\t\t\t{#if !camera}\n\t\t\t\t {\n\t\t\t\t\t\tif (assistantSpeaking) {\n\t\t\t\t\t\t\tstopAllAudio();\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{#if emoji}\n\t\t\t\t\t\t 4\n\t\t\t\t\t\t\t\t? '13'\n\t\t\t\t\t\t\t\t: rmsLevel * 100 > 2\n\t\t\t\t\t\t\t\t\t? '12'\n\t\t\t\t\t\t\t\t\t: rmsLevel * 100 > 1\n\t\t\t\t\t\t\t\t\t\t? '11.5'\n\t\t\t\t\t\t\t\t\t\t: '11'}rem;width:100%;text-align:center;\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{emoji}\n\t\t\t\t\t\t
\n\t\t\t\t\t{:else if loading || assistantSpeaking}\n\t\t\t\t\t\t\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t 4\n\t\t\t\t\t\t\t\t? ' size-52'\n\t\t\t\t\t\t\t\t: rmsLevel * 100 > 2\n\t\t\t\t\t\t\t\t\t? 'size-48'\n\t\t\t\t\t\t\t\t\t: rmsLevel * 100 > 1\n\t\t\t\t\t\t\t\t\t\t? 'size-44'\n\t\t\t\t\t\t\t\t\t\t: 'size-40'} transition-all rounded-full {(model?.info?.meta\n\t\t\t\t\t\t\t\t?.profile_image_url ?? '/static/favicon.png') !== '/static/favicon.png'\n\t\t\t\t\t\t\t\t? ' bg-cover bg-center bg-no-repeat'\n\t\t\t\t\t\t\t\t: 'bg-black dark:bg-white'} \"\n\t\t\t\t\t\t\tstyle={(model?.info?.meta?.profile_image_url ?? '/static/favicon.png') !==\n\t\t\t\t\t\t\t'/static/favicon.png'\n\t\t\t\t\t\t\t\t? `background-image: url('${model?.info?.meta?.profile_image_url}');`\n\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t/>\n\t\t\t\t\t{/if}\n\t\t\t\t\n\t\t\t{:else}\n\t\t\t\t
\n\t\t\t\t\t\n\n\t\t\t\t\t\n\n\t\t\t\t\t
\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tstopCamera();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t{/if}\n\t\t
\n\n\t\t
\n\t\t\t
\n\t\t\t\t{#if camera}\n\t\t\t\t\t {\n\t\t\t\t\t\t\tconsole.log(e.detail);\n\t\t\t\t\t\t\tselectedVideoInputDeviceId = e.detail;\n\t\t\t\t\t\t\tawait stopVideoStream();\n\t\t\t\t\t\t\tawait startVideoStream();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t{:else}\n\t\t\t\t\t\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tawait navigator.mediaDevices.getUserMedia({ video: true });\n\t\t\t\t\t\t\t\tstartCamera();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t{/if}\n\t\t\t
\n\n\t\t\t
\n\t\t\t\t {\n\t\t\t\t\t\tif (assistantSpeaking) {\n\t\t\t\t\t\t\tstopAllAudio();\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t
\n\t\t\t\t\t\t{#if loading}\n\t\t\t\t\t\t\t{$i18n.t('Thinking...')}\n\t\t\t\t\t\t{:else if assistantSpeaking}\n\t\t\t\t\t\t\t{$i18n.t('Tap to interrupt')}\n\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t{$i18n.t('Listening...')}\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t
\n\t\t\t\t\n\t\t\t
\n\n\t\t\t
\n\t\t\t\t {\n\t\t\t\t\t\tawait stopAudioStream();\n\t\t\t\t\t\tawait stopVideoStream();\n\n\t\t\t\t\t\tconsole.log(audioStream);\n\t\t\t\t\t\tconsole.log(cameraStream);\n\n\t\t\t\t\t\tshowCallOverlay.set(false);\n\t\t\t\t\t\tdispatch('close');\n\t\t\t\t\t}}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\t\t
\n\t\n{/if}\n","\n\n\n\n\n {\n\t\tshow = false;\n\t}}\n>\n\t {\n\t\t\te.stopPropagation();\n\t\t}}\n\t>\n\t\t\n\t\n\n\n\n","\n\n\n\t\n\t\t{#if data.message.role === 'user'}\n\t\t\t
\n\t\t\t\t\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{data?.user?.name ?? 'User'}\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\n\t\t\t\t\t{#if data?.message?.error}\n\t\t\t\t\t\t
{data.message.error.content}
\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t
{data.message.content}
\n\t\t\t\t\t{/if}\n\t\t\t\t
\n\t\t\t
\n\t\t{:else}\n\t\t\t
\n\t\t\t\t\n\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{data?.model?.name ?? data?.message?.model ?? 'Assistant'}\n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tdata.message.favorite = !(data?.message?.favorite ?? false);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\n\t\t\t\t\t{#if data?.message?.error}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{data.message.error.content}\n\t\t\t\t\t\t
\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t
{data.message.content}
\n\t\t\t\t\t{/if}\n\t\t\t\t
\n\t\t\t
\n\t\t{/if}\n\t\n\t\n\t\n\n","\n\n dispatch('nodeclick', e.detail)}\n\toninit={() => {\n\t\tconsole.log('Flow initialized');\n\t}}\n>\n\t\n\t\n\n","\n\n
\n\t
\n\t\t
{$i18n.t('Chat Overview')}
\n\t\t {\n\t\t\t\tdispatch('close');\n\t\t\t\tshowOverview.set(false);\n\t\t\t}}\n\t\t>\n\t\t\t\n\t\t\n\t
\n\n\t{#if $nodes.length > 0}\n\t\t {\n\t\t\t\tconsole.log(e.detail.node.data);\n\t\t\t\tdispatch('nodeclick', e.detail);\n\t\t\t\tselectedMessageId = e.detail.node.data.message.id;\n\t\t\t\tfitView({ nodes: [{ id: selectedMessageId }] });\n\t\t\t}}\n\t\t/>\n\t{/if}\n
\n","\n\n\n\t\n\n","\n\n\n\t{#if !largeScreen}\n\t\t{#if $showControls}\n\t\t\t {\n\t\t\t\t\tshowControls.set(false);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t\t{#if $showCallOverlay}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\tshowControls.set(false);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\n\t\t\t\t\t{:else if $showOverview}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tshowMessage(e.detail.node.data.message);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ton:close={() => {\n\t\t\t\t\t\t\t\tshowControls.set(false);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tshowControls.set(false);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t{models}\n\t\t\t\t\t\t\tbind:chatFiles\n\t\t\t\t\t\t\tbind:params\n\t\t\t\t\t\t/>\n\t\t\t\t\t{/if}\n\t\t\t\t\n\t\t\t\n\t\t{/if}\n\t{:else}\n\t\t\n\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t
\n\t\t {\n\t\t\t\tif (size === 0) {\n\t\t\t\t\tshowControls.set(false);\n\t\t\t\t} else {\n\t\t\t\t\tif (!$showControls) {\n\t\t\t\t\t\tshowControls.set(true);\n\t\t\t\t\t}\n\t\t\t\t\tlocalStorage.chatControlsSize = size;\n\t\t\t\t}\n\t\t\t}}\n\t\t>\n\t\t\t{#if $showControls}\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\t{#if $showCallOverlay}\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\tshowControls.set(false);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t{:else if $showOverview}\n\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\tif (e.detail.node.data.message.favorite) {\n\t\t\t\t\t\t\t\t\t\thistory.messages[e.detail.node.data.message.id].favorite = true;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\thistory.messages[e.detail.node.data.message.id].favorite = null;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tshowMessage(e.detail.node.data.message);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ton:close={() => {\n\t\t\t\t\t\t\t\t\tshowControls.set(false);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\tshowControls.set(false);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t{models}\n\t\t\t\t\t\t\t\tbind:chatFiles\n\t\t\t\t\t\t\t\tbind:params\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t
\n\t\t\t\t\n\t\t\t{/if}\n\t\t\n\t{/if}\n
\n","\n\n\n\t\n\t\t{$chatTitle\n\t\t\t? `${$chatTitle.length > 30 ? `${$chatTitle.slice(0, 30)}...` : $chatTitle} | ${$WEBUI_NAME}`\n\t\t\t: `${$WEBUI_NAME}`}\n\t\n\n\n