`, so it can be styled via any CSS solution you prefer.\n * @see https://floating-ui.com/docs/FloatingOverlay\n */\nconst FloatingOverlay = /*#__PURE__*/React.forwardRef(function FloatingOverlay(props, ref) {\n const {\n lockScroll = false,\n ...rest\n } = props;\n const lockId = useId();\n index(() => {\n if (!lockScroll) return;\n activeLocks.add(lockId);\n const isIOS = /iP(hone|ad|od)|iOS/.test(getPlatform());\n const bodyStyle = document.body.style;\n // RTL scrollbar\n const scrollbarX = Math.round(document.documentElement.getBoundingClientRect().left) + document.documentElement.scrollLeft;\n const paddingProp = scrollbarX ? 'paddingLeft' : 'paddingRight';\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n const scrollX = bodyStyle.left ? parseFloat(bodyStyle.left) : window.scrollX;\n const scrollY = bodyStyle.top ? parseFloat(bodyStyle.top) : window.scrollY;\n bodyStyle.overflow = 'hidden';\n if (scrollbarWidth) {\n bodyStyle[paddingProp] = scrollbarWidth + \"px\";\n }\n\n // Only iOS doesn't respect `overflow: hidden` on document.body, and this\n // technique has fewer side effects.\n if (isIOS) {\n var _window$visualViewpor, _window$visualViewpor2;\n // iOS 12 does not support `visualViewport`.\n const offsetLeft = ((_window$visualViewpor = window.visualViewport) == null ? void 0 : _window$visualViewpor.offsetLeft) || 0;\n const offsetTop = ((_window$visualViewpor2 = window.visualViewport) == null ? void 0 : _window$visualViewpor2.offsetTop) || 0;\n Object.assign(bodyStyle, {\n position: 'fixed',\n top: -(scrollY - Math.floor(offsetTop)) + \"px\",\n left: -(scrollX - Math.floor(offsetLeft)) + \"px\",\n right: '0'\n });\n }\n return () => {\n activeLocks.delete(lockId);\n if (activeLocks.size === 0) {\n Object.assign(bodyStyle, {\n overflow: '',\n [paddingProp]: ''\n });\n if (isIOS) {\n Object.assign(bodyStyle, {\n position: '',\n top: '',\n left: '',\n right: ''\n });\n window.scrollTo(scrollX, scrollY);\n }\n }\n };\n }, [lockId, lockScroll]);\n return /*#__PURE__*/React.createElement(\"div\", _extends({\n ref: ref\n }, rest, {\n style: {\n position: 'fixed',\n overflow: 'auto',\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n ...rest.style\n }\n }));\n});\n\nfunction isButtonTarget(event) {\n return isHTMLElement(event.target) && event.target.tagName === 'BUTTON';\n}\nfunction isSpaceIgnored(element) {\n return isTypeableElement(element);\n}\n/**\n * Opens or closes the floating element when clicking the reference element.\n * @see https://floating-ui.com/docs/useClick\n */\nfunction useClick(context, props) {\n if (props === void 0) {\n props = {};\n }\n const {\n open,\n onOpenChange,\n dataRef,\n elements: {\n domReference\n }\n } = context;\n const {\n enabled = true,\n event: eventOption = 'click',\n toggle = true,\n ignoreMouse = false,\n keyboardHandlers = true\n } = props;\n const pointerTypeRef = React.useRef();\n const didKeyDownRef = React.useRef(false);\n const reference = React.useMemo(() => ({\n onPointerDown(event) {\n pointerTypeRef.current = event.pointerType;\n },\n onMouseDown(event) {\n const pointerType = pointerTypeRef.current;\n\n // Ignore all buttons except for the \"main\" button.\n // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button\n if (event.button !== 0) return;\n if (eventOption === 'click') return;\n if (isMouseLikePointerType(pointerType, true) && ignoreMouse) return;\n if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'mousedown' : true)) {\n onOpenChange(false, event.nativeEvent, 'click');\n } else {\n // Prevent stealing focus from the floating element\n event.preventDefault();\n onOpenChange(true, event.nativeEvent, 'click');\n }\n },\n onClick(event) {\n const pointerType = pointerTypeRef.current;\n if (eventOption === 'mousedown' && pointerTypeRef.current) {\n pointerTypeRef.current = undefined;\n return;\n }\n if (isMouseLikePointerType(pointerType, true) && ignoreMouse) return;\n if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'click' : true)) {\n onOpenChange(false, event.nativeEvent, 'click');\n } else {\n onOpenChange(true, event.nativeEvent, 'click');\n }\n },\n onKeyDown(event) {\n pointerTypeRef.current = undefined;\n if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event)) {\n return;\n }\n if (event.key === ' ' && !isSpaceIgnored(domReference)) {\n // Prevent scrolling\n event.preventDefault();\n didKeyDownRef.current = true;\n }\n if (event.key === 'Enter') {\n if (open && toggle) {\n onOpenChange(false, event.nativeEvent, 'click');\n } else {\n onOpenChange(true, event.nativeEvent, 'click');\n }\n }\n },\n onKeyUp(event) {\n if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event) || isSpaceIgnored(domReference)) {\n return;\n }\n if (event.key === ' ' && didKeyDownRef.current) {\n didKeyDownRef.current = false;\n if (open && toggle) {\n onOpenChange(false, event.nativeEvent, 'click');\n } else {\n onOpenChange(true, event.nativeEvent, 'click');\n }\n }\n }\n }), [dataRef, domReference, eventOption, ignoreMouse, keyboardHandlers, onOpenChange, open, toggle]);\n return React.useMemo(() => enabled ? {\n reference\n } : {}, [enabled, reference]);\n}\n\nfunction createVirtualElement(domElement, data) {\n let offsetX = null;\n let offsetY = null;\n let isAutoUpdateEvent = false;\n return {\n contextElement: domElement || undefined,\n getBoundingClientRect() {\n var _data$dataRef$current;\n const domRect = (domElement == null ? void 0 : domElement.getBoundingClientRect()) || {\n width: 0,\n height: 0,\n x: 0,\n y: 0\n };\n const isXAxis = data.axis === 'x' || data.axis === 'both';\n const isYAxis = data.axis === 'y' || data.axis === 'both';\n const canTrackCursorOnAutoUpdate = ['mouseenter', 'mousemove'].includes(((_data$dataRef$current = data.dataRef.current.openEvent) == null ? void 0 : _data$dataRef$current.type) || '') && data.pointerType !== 'touch';\n let width = domRect.width;\n let height = domRect.height;\n let x = domRect.x;\n let y = domRect.y;\n if (offsetX == null && data.x && isXAxis) {\n offsetX = domRect.x - data.x;\n }\n if (offsetY == null && data.y && isYAxis) {\n offsetY = domRect.y - data.y;\n }\n x -= offsetX || 0;\n y -= offsetY || 0;\n width = 0;\n height = 0;\n if (!isAutoUpdateEvent || canTrackCursorOnAutoUpdate) {\n width = data.axis === 'y' ? domRect.width : 0;\n height = data.axis === 'x' ? domRect.height : 0;\n x = isXAxis && data.x != null ? data.x : x;\n y = isYAxis && data.y != null ? data.y : y;\n } else if (isAutoUpdateEvent && !canTrackCursorOnAutoUpdate) {\n height = data.axis === 'x' ? domRect.height : height;\n width = data.axis === 'y' ? domRect.width : width;\n }\n isAutoUpdateEvent = true;\n return {\n width,\n height,\n x,\n y,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x\n };\n }\n };\n}\nfunction isMouseBasedEvent(event) {\n return event != null && event.clientX != null;\n}\n/**\n * Positions the floating element relative to a client point (in the viewport),\n * such as the mouse position. By default, it follows the mouse cursor.\n * @see https://floating-ui.com/docs/useClientPoint\n */\nfunction useClientPoint(context, props) {\n if (props === void 0) {\n props = {};\n }\n const {\n open,\n dataRef,\n elements: {\n floating,\n domReference\n },\n refs\n } = context;\n const {\n enabled = true,\n axis = 'both',\n x = null,\n y = null\n } = props;\n const initialRef = React.useRef(false);\n const cleanupListenerRef = React.useRef(null);\n const [pointerType, setPointerType] = React.useState();\n const [reactive, setReactive] = React.useState([]);\n const setReference = useEffectEvent((x, y) => {\n if (initialRef.current) return;\n\n // Prevent setting if the open event was not a mouse-like one\n // (e.g. focus to open, then hover over the reference element).\n // Only apply if the event exists.\n if (dataRef.current.openEvent && !isMouseBasedEvent(dataRef.current.openEvent)) {\n return;\n }\n refs.setPositionReference(createVirtualElement(domReference, {\n x,\n y,\n axis,\n dataRef,\n pointerType\n }));\n });\n const handleReferenceEnterOrMove = useEffectEvent(event => {\n if (x != null || y != null) return;\n if (!open) {\n setReference(event.clientX, event.clientY);\n } else if (!cleanupListenerRef.current) {\n // If there's no cleanup, there's no listener, but we want to ensure\n // we add the listener if the cursor landed on the floating element and\n // then back on the reference (i.e. it's interactive).\n setReactive([]);\n }\n });\n\n // If the pointer is a mouse-like pointer, we want to continue following the\n // mouse even if the floating element is transitioning out. On touch\n // devices, this is undesirable because the floating element will move to\n // the dismissal touch point.\n const openCheck = isMouseLikePointerType(pointerType) ? floating : open;\n const addListener = React.useCallback(() => {\n // Explicitly specified `x`/`y` coordinates shouldn't add a listener.\n if (!openCheck || !enabled || x != null || y != null) return;\n const win = getWindow(floating);\n function handleMouseMove(event) {\n const target = getTarget(event);\n if (!contains(floating, target)) {\n setReference(event.clientX, event.clientY);\n } else {\n win.removeEventListener('mousemove', handleMouseMove);\n cleanupListenerRef.current = null;\n }\n }\n if (!dataRef.current.openEvent || isMouseBasedEvent(dataRef.current.openEvent)) {\n win.addEventListener('mousemove', handleMouseMove);\n const cleanup = () => {\n win.removeEventListener('mousemove', handleMouseMove);\n cleanupListenerRef.current = null;\n };\n cleanupListenerRef.current = cleanup;\n return cleanup;\n }\n refs.setPositionReference(domReference);\n }, [openCheck, enabled, x, y, floating, dataRef, refs, domReference, setReference]);\n React.useEffect(() => {\n return addListener();\n }, [addListener, reactive]);\n React.useEffect(() => {\n if (enabled && !floating) {\n initialRef.current = false;\n }\n }, [enabled, floating]);\n React.useEffect(() => {\n if (!enabled && open) {\n initialRef.current = true;\n }\n }, [enabled, open]);\n index(() => {\n if (enabled && (x != null || y != null)) {\n initialRef.current = false;\n setReference(x, y);\n }\n }, [enabled, x, y, setReference]);\n const reference = React.useMemo(() => {\n function setPointerTypeRef(_ref) {\n let {\n pointerType\n } = _ref;\n setPointerType(pointerType);\n }\n return {\n onPointerDown: setPointerTypeRef,\n onPointerEnter: setPointerTypeRef,\n onMouseMove: handleReferenceEnterOrMove,\n onMouseEnter: handleReferenceEnterOrMove\n };\n }, [handleReferenceEnterOrMove]);\n return React.useMemo(() => enabled ? {\n reference\n } : {}, [enabled, reference]);\n}\n\nconst bubbleHandlerKeys = {\n pointerdown: 'onPointerDown',\n mousedown: 'onMouseDown',\n click: 'onClick'\n};\nconst captureHandlerKeys = {\n pointerdown: 'onPointerDownCapture',\n mousedown: 'onMouseDownCapture',\n click: 'onClickCapture'\n};\nconst normalizeProp = normalizable => {\n var _normalizable$escapeK, _normalizable$outside;\n return {\n escapeKey: typeof normalizable === 'boolean' ? normalizable : (_normalizable$escapeK = normalizable == null ? void 0 : normalizable.escapeKey) != null ? _normalizable$escapeK : false,\n outsidePress: typeof normalizable === 'boolean' ? normalizable : (_normalizable$outside = normalizable == null ? void 0 : normalizable.outsidePress) != null ? _normalizable$outside : true\n };\n};\n/**\n * Closes the floating element when a dismissal is requested — by default, when\n * the user presses the `escape` key or outside of the floating element.\n * @see https://floating-ui.com/docs/useDismiss\n */\nfunction useDismiss(context, props) {\n if (props === void 0) {\n props = {};\n }\n const {\n open,\n onOpenChange,\n elements,\n dataRef\n } = context;\n const {\n enabled = true,\n escapeKey = true,\n outsidePress: unstable_outsidePress = true,\n outsidePressEvent = 'pointerdown',\n referencePress = false,\n referencePressEvent = 'pointerdown',\n ancestorScroll = false,\n bubbles,\n capture\n } = props;\n const tree = useFloatingTree();\n const outsidePressFn = useEffectEvent(typeof unstable_outsidePress === 'function' ? unstable_outsidePress : () => false);\n const outsidePress = typeof unstable_outsidePress === 'function' ? outsidePressFn : unstable_outsidePress;\n const insideReactTreeRef = React.useRef(false);\n const endedOrStartedInsideRef = React.useRef(false);\n const {\n escapeKey: escapeKeyBubbles,\n outsidePress: outsidePressBubbles\n } = normalizeProp(bubbles);\n const {\n escapeKey: escapeKeyCapture,\n outsidePress: outsidePressCapture\n } = normalizeProp(capture);\n const closeOnEscapeKeyDown = useEffectEvent(event => {\n var _dataRef$current$floa;\n if (!open || !enabled || !escapeKey || event.key !== 'Escape') {\n return;\n }\n const nodeId = (_dataRef$current$floa = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa.nodeId;\n const children = tree ? getChildren(tree.nodesRef.current, nodeId) : [];\n if (!escapeKeyBubbles) {\n event.stopPropagation();\n if (children.length > 0) {\n let shouldDismiss = true;\n children.forEach(child => {\n var _child$context;\n if ((_child$context = child.context) != null && _child$context.open && !child.context.dataRef.current.__escapeKeyBubbles) {\n shouldDismiss = false;\n return;\n }\n });\n if (!shouldDismiss) {\n return;\n }\n }\n }\n onOpenChange(false, isReactEvent(event) ? event.nativeEvent : event, 'escape-key');\n });\n const closeOnEscapeKeyDownCapture = useEffectEvent(event => {\n var _getTarget2;\n const callback = () => {\n var _getTarget;\n closeOnEscapeKeyDown(event);\n (_getTarget = getTarget(event)) == null || _getTarget.removeEventListener('keydown', callback);\n };\n (_getTarget2 = getTarget(event)) == null || _getTarget2.addEventListener('keydown', callback);\n });\n const closeOnPressOutside = useEffectEvent(event => {\n var _dataRef$current$floa2;\n // Given developers can stop the propagation of the synthetic event,\n // we can only be confident with a positive value.\n const insideReactTree = insideReactTreeRef.current;\n insideReactTreeRef.current = false;\n\n // When click outside is lazy (`click` event), handle dragging.\n // Don't close if:\n // - The click started inside the floating element.\n // - The click ended inside the floating element.\n const endedOrStartedInside = endedOrStartedInsideRef.current;\n endedOrStartedInsideRef.current = false;\n if (outsidePressEvent === 'click' && endedOrStartedInside) {\n return;\n }\n if (insideReactTree) {\n return;\n }\n if (typeof outsidePress === 'function' && !outsidePress(event)) {\n return;\n }\n const target = getTarget(event);\n const inertSelector = \"[\" + createAttribute('inert') + \"]\";\n const markers = getDocument(elements.floating).querySelectorAll(inertSelector);\n let targetRootAncestor = isElement(target) ? target : null;\n while (targetRootAncestor && !isLastTraversableNode(targetRootAncestor)) {\n const nextParent = getParentNode(targetRootAncestor);\n if (isLastTraversableNode(nextParent) || !isElement(nextParent)) {\n break;\n }\n targetRootAncestor = nextParent;\n }\n\n // Check if the click occurred on a third-party element injected after the\n // floating element rendered.\n if (markers.length && isElement(target) && !isRootElement(target) &&\n // Clicked on a direct ancestor (e.g. FloatingOverlay).\n !contains(target, elements.floating) &&\n // If the target root element contains none of the markers, then the\n // element was injected after the floating element rendered.\n Array.from(markers).every(marker => !contains(targetRootAncestor, marker))) {\n return;\n }\n\n // Check if the click occurred on the scrollbar\n if (isHTMLElement(target) && floating) {\n // In Firefox, `target.scrollWidth > target.clientWidth` for inline\n // elements.\n const canScrollX = target.clientWidth > 0 && target.scrollWidth > target.clientWidth;\n const canScrollY = target.clientHeight > 0 && target.scrollHeight > target.clientHeight;\n let xCond = canScrollY && event.offsetX > target.clientWidth;\n\n // In some browsers it is possible to change the (or window)\n // scrollbar to the left side, but is very rare and is difficult to\n // check for. Plus, for modal dialogs with backdrops, it is more\n // important that the backdrop is checked but not so much the window.\n if (canScrollY) {\n const isRTL = getComputedStyle(target).direction === 'rtl';\n if (isRTL) {\n xCond = event.offsetX <= target.offsetWidth - target.clientWidth;\n }\n }\n if (xCond || canScrollX && event.offsetY > target.clientHeight) {\n return;\n }\n }\n const nodeId = (_dataRef$current$floa2 = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa2.nodeId;\n const targetIsInsideChildren = tree && getChildren(tree.nodesRef.current, nodeId).some(node => {\n var _node$context;\n return isEventTargetWithin(event, (_node$context = node.context) == null ? void 0 : _node$context.elements.floating);\n });\n if (isEventTargetWithin(event, elements.floating) || isEventTargetWithin(event, elements.domReference) || targetIsInsideChildren) {\n return;\n }\n const children = tree ? getChildren(tree.nodesRef.current, nodeId) : [];\n if (children.length > 0) {\n let shouldDismiss = true;\n children.forEach(child => {\n var _child$context2;\n if ((_child$context2 = child.context) != null && _child$context2.open && !child.context.dataRef.current.__outsidePressBubbles) {\n shouldDismiss = false;\n return;\n }\n });\n if (!shouldDismiss) {\n return;\n }\n }\n onOpenChange(false, event, 'outside-press');\n });\n const closeOnPressOutsideCapture = useEffectEvent(event => {\n var _getTarget4;\n const callback = () => {\n var _getTarget3;\n closeOnPressOutside(event);\n (_getTarget3 = getTarget(event)) == null || _getTarget3.removeEventListener(outsidePressEvent, callback);\n };\n (_getTarget4 = getTarget(event)) == null || _getTarget4.addEventListener(outsidePressEvent, callback);\n });\n React.useEffect(() => {\n if (!open || !enabled) {\n return;\n }\n dataRef.current.__escapeKeyBubbles = escapeKeyBubbles;\n dataRef.current.__outsidePressBubbles = outsidePressBubbles;\n function onScroll(event) {\n onOpenChange(false, event, 'ancestor-scroll');\n }\n const doc = getDocument(elements.floating);\n escapeKey && doc.addEventListener('keydown', escapeKeyCapture ? closeOnEscapeKeyDownCapture : closeOnEscapeKeyDown, escapeKeyCapture);\n outsidePress && doc.addEventListener(outsidePressEvent, outsidePressCapture ? closeOnPressOutsideCapture : closeOnPressOutside, outsidePressCapture);\n let ancestors = [];\n if (ancestorScroll) {\n if (isElement(elements.domReference)) {\n ancestors = getOverflowAncestors(elements.domReference);\n }\n if (isElement(elements.floating)) {\n ancestors = ancestors.concat(getOverflowAncestors(elements.floating));\n }\n if (!isElement(elements.reference) && elements.reference && elements.reference.contextElement) {\n ancestors = ancestors.concat(getOverflowAncestors(elements.reference.contextElement));\n }\n }\n\n // Ignore the visual viewport for scrolling dismissal (allow pinch-zoom)\n ancestors = ancestors.filter(ancestor => {\n var _doc$defaultView;\n return ancestor !== ((_doc$defaultView = doc.defaultView) == null ? void 0 : _doc$defaultView.visualViewport);\n });\n ancestors.forEach(ancestor => {\n ancestor.addEventListener('scroll', onScroll, {\n passive: true\n });\n });\n return () => {\n escapeKey && doc.removeEventListener('keydown', escapeKeyCapture ? closeOnEscapeKeyDownCapture : closeOnEscapeKeyDown, escapeKeyCapture);\n outsidePress && doc.removeEventListener(outsidePressEvent, outsidePressCapture ? closeOnPressOutsideCapture : closeOnPressOutside, outsidePressCapture);\n ancestors.forEach(ancestor => {\n ancestor.removeEventListener('scroll', onScroll);\n });\n };\n }, [dataRef, elements, escapeKey, outsidePress, outsidePressEvent, open, onOpenChange, ancestorScroll, enabled, escapeKeyBubbles, outsidePressBubbles, closeOnEscapeKeyDown, escapeKeyCapture, closeOnEscapeKeyDownCapture, closeOnPressOutside, outsidePressCapture, closeOnPressOutsideCapture]);\n React.useEffect(() => {\n insideReactTreeRef.current = false;\n }, [outsidePress, outsidePressEvent]);\n const reference = React.useMemo(() => ({\n onKeyDown: closeOnEscapeKeyDown,\n [bubbleHandlerKeys[referencePressEvent]]: event => {\n if (referencePress) {\n onOpenChange(false, event.nativeEvent, 'reference-press');\n }\n }\n }), [closeOnEscapeKeyDown, onOpenChange, referencePress, referencePressEvent]);\n const floating = React.useMemo(() => ({\n onKeyDown: closeOnEscapeKeyDown,\n onMouseDown() {\n endedOrStartedInsideRef.current = true;\n },\n onMouseUp() {\n endedOrStartedInsideRef.current = true;\n },\n [captureHandlerKeys[outsidePressEvent]]: () => {\n insideReactTreeRef.current = true;\n }\n }), [closeOnEscapeKeyDown, outsidePressEvent]);\n return React.useMemo(() => enabled ? {\n reference,\n floating\n } : {}, [enabled, reference, floating]);\n}\n\nfunction useFloatingRootContext(options) {\n const {\n open = false,\n onOpenChange: onOpenChangeProp,\n elements: elementsProp\n } = options;\n const floatingId = useId();\n const dataRef = React.useRef({});\n const [events] = React.useState(() => createPubSub());\n const nested = useFloatingParentNodeId() != null;\n if (process.env.NODE_ENV !== \"production\") {\n const optionDomReference = elementsProp.reference;\n if (optionDomReference && !isElement(optionDomReference)) {\n error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `refs.setPositionReference()`', 'instead.');\n }\n }\n const [positionReference, setPositionReference] = React.useState(elementsProp.reference);\n const onOpenChange = useEffectEvent((open, event, reason) => {\n dataRef.current.openEvent = open ? event : undefined;\n events.emit('openchange', {\n open,\n event,\n reason,\n nested\n });\n onOpenChangeProp == null || onOpenChangeProp(open, event, reason);\n });\n const refs = React.useMemo(() => ({\n setPositionReference\n }), []);\n const elements = React.useMemo(() => ({\n reference: positionReference || elementsProp.reference || null,\n floating: elementsProp.floating || null,\n domReference: elementsProp.reference\n }), [positionReference, elementsProp.reference, elementsProp.floating]);\n return React.useMemo(() => ({\n dataRef,\n open,\n onOpenChange,\n elements,\n events,\n floatingId,\n refs\n }), [open, onOpenChange, elements, events, floatingId, refs]);\n}\n\n/**\n * Provides data to position a floating element and context to add interactions.\n * @see https://floating-ui.com/docs/useFloating\n */\nfunction useFloating(options) {\n if (options === void 0) {\n options = {};\n }\n const {\n nodeId\n } = options;\n const internalRootContext = useFloatingRootContext({\n ...options,\n elements: {\n reference: null,\n floating: null,\n ...options.elements\n }\n });\n const rootContext = options.rootContext || internalRootContext;\n const computedElements = rootContext.elements;\n const [_domReference, setDomReference] = React.useState(null);\n const [positionReference, _setPositionReference] = React.useState(null);\n const optionDomReference = computedElements == null ? void 0 : computedElements.reference;\n const domReference = optionDomReference || _domReference;\n const domReferenceRef = React.useRef(null);\n const tree = useFloatingTree();\n index(() => {\n if (domReference) {\n domReferenceRef.current = domReference;\n }\n }, [domReference]);\n const position = useFloating$1({\n ...options,\n elements: {\n ...computedElements,\n ...(positionReference && {\n reference: positionReference\n })\n }\n });\n const setPositionReference = React.useCallback(node => {\n const computedPositionReference = isElement(node) ? {\n getBoundingClientRect: () => node.getBoundingClientRect(),\n contextElement: node\n } : node;\n // Store the positionReference in state if the DOM reference is specified externally via the\n // `elements.reference` option. This ensures that it won't be overridden on future renders.\n _setPositionReference(computedPositionReference);\n position.refs.setReference(computedPositionReference);\n }, [position.refs]);\n const setReference = React.useCallback(node => {\n if (isElement(node) || node === null) {\n domReferenceRef.current = node;\n setDomReference(node);\n }\n\n // Backwards-compatibility for passing a virtual element to `reference`\n // after it has set the DOM reference.\n if (isElement(position.refs.reference.current) || position.refs.reference.current === null ||\n // Don't allow setting virtual elements using the old technique back to\n // `null` to support `positionReference` + an unstable `reference`\n // callback ref.\n node !== null && !isElement(node)) {\n position.refs.setReference(node);\n }\n }, [position.refs]);\n const refs = React.useMemo(() => ({\n ...position.refs,\n setReference,\n setPositionReference,\n domReference: domReferenceRef\n }), [position.refs, setReference, setPositionReference]);\n const elements = React.useMemo(() => ({\n ...position.elements,\n domReference: domReference\n }), [position.elements, domReference]);\n const context = React.useMemo(() => ({\n ...position,\n ...rootContext,\n refs,\n elements,\n nodeId\n }), [position, refs, elements, nodeId, rootContext]);\n index(() => {\n rootContext.dataRef.current.floatingContext = context;\n const node = tree == null ? void 0 : tree.nodesRef.current.find(node => node.id === nodeId);\n if (node) {\n node.context = context;\n }\n });\n return React.useMemo(() => ({\n ...position,\n context,\n refs,\n elements\n }), [position, refs, elements, context]);\n}\n\n/**\n * Opens the floating element while the reference element has focus, like CSS\n * `:focus`.\n * @see https://floating-ui.com/docs/useFocus\n */\nfunction useFocus(context, props) {\n if (props === void 0) {\n props = {};\n }\n const {\n open,\n onOpenChange,\n events,\n dataRef,\n elements\n } = context;\n const {\n enabled = true,\n visibleOnly = true\n } = props;\n const blockFocusRef = React.useRef(false);\n const timeoutRef = React.useRef();\n const keyboardModalityRef = React.useRef(true);\n React.useEffect(() => {\n if (!enabled) return;\n const win = getWindow(elements.domReference);\n\n // If the reference was focused and the user left the tab/window, and the\n // floating element was not open, the focus should be blocked when they\n // return to the tab/window.\n function onBlur() {\n if (!open && isHTMLElement(elements.domReference) && elements.domReference === activeElement(getDocument(elements.domReference))) {\n blockFocusRef.current = true;\n }\n }\n function onKeyDown() {\n keyboardModalityRef.current = true;\n }\n win.addEventListener('blur', onBlur);\n win.addEventListener('keydown', onKeyDown, true);\n return () => {\n win.removeEventListener('blur', onBlur);\n win.removeEventListener('keydown', onKeyDown, true);\n };\n }, [elements.domReference, open, enabled]);\n React.useEffect(() => {\n if (!enabled) return;\n function onOpenChange(_ref) {\n let {\n reason\n } = _ref;\n if (reason === 'reference-press' || reason === 'escape-key') {\n blockFocusRef.current = true;\n }\n }\n events.on('openchange', onOpenChange);\n return () => {\n events.off('openchange', onOpenChange);\n };\n }, [events, enabled]);\n React.useEffect(() => {\n return () => {\n clearTimeout(timeoutRef.current);\n };\n }, []);\n const reference = React.useMemo(() => ({\n onPointerDown(event) {\n if (isVirtualPointerEvent(event.nativeEvent)) return;\n keyboardModalityRef.current = false;\n },\n onMouseLeave() {\n blockFocusRef.current = false;\n },\n onFocus(event) {\n if (blockFocusRef.current) return;\n const target = getTarget(event.nativeEvent);\n if (visibleOnly && isElement(target)) {\n try {\n // Mac Safari unreliably matches `:focus-visible` on the reference\n // if focus was outside the page initially - use the fallback\n // instead.\n if (isSafari() && isMac()) throw Error();\n if (!target.matches(':focus-visible')) return;\n } catch (e) {\n // Old browsers will throw an error when using `:focus-visible`.\n if (!keyboardModalityRef.current && !isTypeableElement(target)) {\n return;\n }\n }\n }\n onOpenChange(true, event.nativeEvent, 'focus');\n },\n onBlur(event) {\n blockFocusRef.current = false;\n const relatedTarget = event.relatedTarget;\n const nativeEvent = event.nativeEvent;\n\n // Hit the non-modal focus management portal guard. Focus will be\n // moved into the floating element immediately after.\n const movedToFocusGuard = isElement(relatedTarget) && relatedTarget.hasAttribute(createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';\n\n // Wait for the window blur listener to fire.\n timeoutRef.current = window.setTimeout(() => {\n var _dataRef$current$floa;\n const activeEl = activeElement(elements.domReference ? elements.domReference.ownerDocument : document);\n\n // Focus left the page, keep it open.\n if (!relatedTarget && activeEl === elements.domReference) return;\n\n // When focusing the reference element (e.g. regular click), then\n // clicking into the floating element, prevent it from hiding.\n // Note: it must be focusable, e.g. `tabindex=\"-1\"`.\n // We can not rely on relatedTarget to point to the correct element\n // as it will only point to the shadow host of the newly focused element\n // and not the element that actually has received focus if it is located\n // inside a shadow root.\n if (contains((_dataRef$current$floa = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa.refs.floating.current, activeEl) || contains(elements.domReference, activeEl) || movedToFocusGuard) {\n return;\n }\n onOpenChange(false, nativeEvent, 'focus');\n });\n }\n }), [dataRef, elements.domReference, onOpenChange, visibleOnly]);\n return React.useMemo(() => enabled ? {\n reference\n } : {}, [enabled, reference]);\n}\n\nconst ACTIVE_KEY = 'active';\nconst SELECTED_KEY = 'selected';\nfunction mergeProps(userProps, propsList, elementKey) {\n const map = new Map();\n const isItem = elementKey === 'item';\n let domUserProps = userProps;\n if (isItem && userProps) {\n const {\n [ACTIVE_KEY]: _,\n [SELECTED_KEY]: __,\n ...validProps\n } = userProps;\n domUserProps = validProps;\n }\n return {\n ...(elementKey === 'floating' && {\n tabIndex: -1,\n [FOCUSABLE_ATTRIBUTE]: ''\n }),\n ...domUserProps,\n ...propsList.map(value => {\n const propsOrGetProps = value ? value[elementKey] : null;\n if (typeof propsOrGetProps === 'function') {\n return userProps ? propsOrGetProps(userProps) : null;\n }\n return propsOrGetProps;\n }).concat(userProps).reduce((acc, props) => {\n if (!props) {\n return acc;\n }\n Object.entries(props).forEach(_ref => {\n let [key, value] = _ref;\n if (isItem && [ACTIVE_KEY, SELECTED_KEY].includes(key)) {\n return;\n }\n if (key.indexOf('on') === 0) {\n if (!map.has(key)) {\n map.set(key, []);\n }\n if (typeof value === 'function') {\n var _map$get;\n (_map$get = map.get(key)) == null || _map$get.push(value);\n acc[key] = function () {\n var _map$get2;\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n return (_map$get2 = map.get(key)) == null ? void 0 : _map$get2.map(fn => fn(...args)).find(val => val !== undefined);\n };\n }\n } else {\n acc[key] = value;\n }\n });\n return acc;\n }, {})\n };\n}\n/**\n * Merges an array of interaction hooks' props into prop getters, allowing\n * event handler functions to be composed together without overwriting one\n * another.\n * @see https://floating-ui.com/docs/useInteractions\n */\nfunction useInteractions(propsList) {\n if (propsList === void 0) {\n propsList = [];\n }\n const referenceDeps = propsList.map(key => key == null ? void 0 : key.reference);\n const floatingDeps = propsList.map(key => key == null ? void 0 : key.floating);\n const itemDeps = propsList.map(key => key == null ? void 0 : key.item);\n const getReferenceProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'reference'),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n referenceDeps);\n const getFloatingProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'floating'),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n floatingDeps);\n const getItemProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'item'),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n itemDeps);\n return React.useMemo(() => ({\n getReferenceProps,\n getFloatingProps,\n getItemProps\n }), [getReferenceProps, getFloatingProps, getItemProps]);\n}\n\nlet isPreventScrollSupported = false;\nfunction doSwitch(orientation, vertical, horizontal) {\n switch (orientation) {\n case 'vertical':\n return vertical;\n case 'horizontal':\n return horizontal;\n default:\n return vertical || horizontal;\n }\n}\nfunction isMainOrientationKey(key, orientation) {\n const vertical = key === ARROW_UP || key === ARROW_DOWN;\n const horizontal = key === ARROW_LEFT || key === ARROW_RIGHT;\n return doSwitch(orientation, vertical, horizontal);\n}\nfunction isMainOrientationToEndKey(key, orientation, rtl) {\n const vertical = key === ARROW_DOWN;\n const horizontal = rtl ? key === ARROW_LEFT : key === ARROW_RIGHT;\n return doSwitch(orientation, vertical, horizontal) || key === 'Enter' || key === ' ' || key === '';\n}\nfunction isCrossOrientationOpenKey(key, orientation, rtl) {\n const vertical = rtl ? key === ARROW_LEFT : key === ARROW_RIGHT;\n const horizontal = key === ARROW_DOWN;\n return doSwitch(orientation, vertical, horizontal);\n}\nfunction isCrossOrientationCloseKey(key, orientation, rtl) {\n const vertical = rtl ? key === ARROW_RIGHT : key === ARROW_LEFT;\n const horizontal = key === ARROW_UP;\n return doSwitch(orientation, vertical, horizontal);\n}\n/**\n * Adds arrow key-based navigation of a list of items, either using real DOM\n * focus or virtual focus.\n * @see https://floating-ui.com/docs/useListNavigation\n */\nfunction useListNavigation(context, props) {\n const {\n open,\n onOpenChange,\n elements\n } = context;\n const {\n listRef,\n activeIndex,\n onNavigate: unstable_onNavigate = () => {},\n enabled = true,\n selectedIndex = null,\n allowEscape = false,\n loop = false,\n nested = false,\n rtl = false,\n virtual = false,\n focusItemOnOpen = 'auto',\n focusItemOnHover = true,\n openOnArrowKeyDown = true,\n disabledIndices = undefined,\n orientation = 'vertical',\n cols = 1,\n scrollItemIntoView = true,\n virtualItemRef,\n itemSizes,\n dense = false\n } = props;\n if (process.env.NODE_ENV !== \"production\") {\n if (allowEscape) {\n if (!loop) {\n warn('`useListNavigation` looping must be enabled to allow escaping.');\n }\n if (!virtual) {\n warn('`useListNavigation` must be virtual to allow escaping.');\n }\n }\n if (orientation === 'vertical' && cols > 1) {\n warn('In grid list navigation mode (`cols` > 1), the `orientation` should', 'be either \"horizontal\" or \"both\".');\n }\n }\n const floatingFocusElement = getFloatingFocusElement(elements.floating);\n const floatingFocusElementRef = useLatestRef(floatingFocusElement);\n const parentId = useFloatingParentNodeId();\n const tree = useFloatingTree();\n const onNavigate = useEffectEvent(unstable_onNavigate);\n const focusItemOnOpenRef = React.useRef(focusItemOnOpen);\n const indexRef = React.useRef(selectedIndex != null ? selectedIndex : -1);\n const keyRef = React.useRef(null);\n const isPointerModalityRef = React.useRef(true);\n const previousOnNavigateRef = React.useRef(onNavigate);\n const previousMountedRef = React.useRef(!!elements.floating);\n const previousOpenRef = React.useRef(open);\n const forceSyncFocus = React.useRef(false);\n const forceScrollIntoViewRef = React.useRef(false);\n const disabledIndicesRef = useLatestRef(disabledIndices);\n const latestOpenRef = useLatestRef(open);\n const scrollItemIntoViewRef = useLatestRef(scrollItemIntoView);\n const selectedIndexRef = useLatestRef(selectedIndex);\n const [activeId, setActiveId] = React.useState();\n const [virtualId, setVirtualId] = React.useState();\n const focusItem = useEffectEvent(function (listRef, indexRef, forceScrollIntoView) {\n if (forceScrollIntoView === void 0) {\n forceScrollIntoView = false;\n }\n function runFocus(item) {\n if (virtual) {\n setActiveId(item.id);\n tree == null || tree.events.emit('virtualfocus', item);\n if (virtualItemRef) {\n virtualItemRef.current = item;\n }\n } else {\n enqueueFocus(item, {\n preventScroll: true,\n // Mac Safari does not move the virtual cursor unless the focus call\n // is sync. However, for the very first focus call, we need to wait\n // for the position to be ready in order to prevent unwanted\n // scrolling. This means the virtual cursor will not move to the first\n // item when first opening the floating element, but will on\n // subsequent calls. `preventScroll` is supported in modern Safari,\n // so we can use that instead.\n // iOS Safari must be async or the first item will not be focused.\n sync: isMac() && isSafari() ? isPreventScrollSupported || forceSyncFocus.current : false\n });\n }\n }\n const initialItem = listRef.current[indexRef.current];\n if (initialItem) {\n runFocus(initialItem);\n }\n requestAnimationFrame(() => {\n const waitedItem = listRef.current[indexRef.current] || initialItem;\n if (!waitedItem) return;\n if (!initialItem) {\n runFocus(waitedItem);\n }\n const scrollIntoViewOptions = scrollItemIntoViewRef.current;\n const shouldScrollIntoView = scrollIntoViewOptions && item && (forceScrollIntoView || !isPointerModalityRef.current);\n if (shouldScrollIntoView) {\n // JSDOM doesn't support `.scrollIntoView()` but it's widely supported\n // by all browsers.\n waitedItem.scrollIntoView == null || waitedItem.scrollIntoView(typeof scrollIntoViewOptions === 'boolean' ? {\n block: 'nearest',\n inline: 'nearest'\n } : scrollIntoViewOptions);\n }\n });\n });\n index(() => {\n document.createElement('div').focus({\n get preventScroll() {\n isPreventScrollSupported = true;\n return false;\n }\n });\n }, []);\n\n // Sync `selectedIndex` to be the `activeIndex` upon opening the floating\n // element. Also, reset `activeIndex` upon closing the floating element.\n index(() => {\n if (!enabled) return;\n if (open && elements.floating) {\n if (focusItemOnOpenRef.current && selectedIndex != null) {\n // Regardless of the pointer modality, we want to ensure the selected\n // item comes into view when the floating element is opened.\n forceScrollIntoViewRef.current = true;\n indexRef.current = selectedIndex;\n onNavigate(selectedIndex);\n }\n } else if (previousMountedRef.current) {\n // Since the user can specify `onNavigate` conditionally\n // (onNavigate: open ? setActiveIndex : setSelectedIndex),\n // we store and call the previous function.\n indexRef.current = -1;\n previousOnNavigateRef.current(null);\n }\n }, [enabled, open, elements.floating, selectedIndex, onNavigate]);\n\n // Sync `activeIndex` to be the focused item while the floating element is\n // open.\n index(() => {\n if (!enabled) return;\n if (open && elements.floating) {\n if (activeIndex == null) {\n forceSyncFocus.current = false;\n if (selectedIndexRef.current != null) {\n return;\n }\n\n // Reset while the floating element was open (e.g. the list changed).\n if (previousMountedRef.current) {\n indexRef.current = -1;\n focusItem(listRef, indexRef);\n }\n\n // Initial sync.\n if ((!previousOpenRef.current || !previousMountedRef.current) && focusItemOnOpenRef.current && (keyRef.current != null || focusItemOnOpenRef.current === true && keyRef.current == null)) {\n let runs = 0;\n const waitForListPopulated = () => {\n if (listRef.current[0] == null) {\n // Avoid letting the browser paint if possible on the first try,\n // otherwise use rAF. Don't try more than twice, since something\n // is wrong otherwise.\n if (runs < 2) {\n const scheduler = runs ? requestAnimationFrame : queueMicrotask;\n scheduler(waitForListPopulated);\n }\n runs++;\n } else {\n indexRef.current = keyRef.current == null || isMainOrientationToEndKey(keyRef.current, orientation, rtl) || nested ? getMinIndex(listRef, disabledIndicesRef.current) : getMaxIndex(listRef, disabledIndicesRef.current);\n keyRef.current = null;\n onNavigate(indexRef.current);\n }\n };\n waitForListPopulated();\n }\n } else if (!isIndexOutOfBounds(listRef, activeIndex)) {\n indexRef.current = activeIndex;\n focusItem(listRef, indexRef, forceScrollIntoViewRef.current);\n forceScrollIntoViewRef.current = false;\n }\n }\n }, [enabled, open, elements.floating, activeIndex, selectedIndexRef, nested, listRef, orientation, rtl, onNavigate, focusItem, disabledIndicesRef]);\n\n // Ensure the parent floating element has focus when a nested child closes\n // to allow arrow key navigation to work after the pointer leaves the child.\n index(() => {\n var _nodes$find;\n if (!enabled || elements.floating || !tree || virtual || !previousMountedRef.current) {\n return;\n }\n const nodes = tree.nodesRef.current;\n const parent = (_nodes$find = nodes.find(node => node.id === parentId)) == null || (_nodes$find = _nodes$find.context) == null ? void 0 : _nodes$find.elements.floating;\n const activeEl = activeElement(getDocument(elements.floating));\n const treeContainsActiveEl = nodes.some(node => node.context && contains(node.context.elements.floating, activeEl));\n if (parent && !treeContainsActiveEl && isPointerModalityRef.current) {\n parent.focus({\n preventScroll: true\n });\n }\n }, [enabled, elements.floating, tree, parentId, virtual]);\n index(() => {\n if (!enabled) return;\n if (!tree) return;\n if (!virtual) return;\n if (parentId) return;\n function handleVirtualFocus(item) {\n setVirtualId(item.id);\n if (virtualItemRef) {\n virtualItemRef.current = item;\n }\n }\n tree.events.on('virtualfocus', handleVirtualFocus);\n return () => {\n tree.events.off('virtualfocus', handleVirtualFocus);\n };\n }, [enabled, tree, virtual, parentId, virtualItemRef]);\n index(() => {\n previousOnNavigateRef.current = onNavigate;\n previousMountedRef.current = !!elements.floating;\n });\n index(() => {\n if (!open) {\n keyRef.current = null;\n }\n }, [open]);\n index(() => {\n previousOpenRef.current = open;\n }, [open]);\n const hasActiveIndex = activeIndex != null;\n const item = React.useMemo(() => {\n function syncCurrentTarget(currentTarget) {\n if (!open) return;\n const index = listRef.current.indexOf(currentTarget);\n if (index !== -1) {\n onNavigate(index);\n }\n }\n const props = {\n onFocus(_ref) {\n let {\n currentTarget\n } = _ref;\n syncCurrentTarget(currentTarget);\n },\n onClick: _ref2 => {\n let {\n currentTarget\n } = _ref2;\n return currentTarget.focus({\n preventScroll: true\n });\n },\n // Safari\n ...(focusItemOnHover && {\n onMouseMove(_ref3) {\n let {\n currentTarget\n } = _ref3;\n syncCurrentTarget(currentTarget);\n },\n onPointerLeave(_ref4) {\n let {\n pointerType\n } = _ref4;\n if (!isPointerModalityRef.current || pointerType === 'touch') {\n return;\n }\n indexRef.current = -1;\n focusItem(listRef, indexRef);\n onNavigate(null);\n if (!virtual) {\n enqueueFocus(floatingFocusElementRef.current, {\n preventScroll: true\n });\n }\n }\n })\n };\n return props;\n }, [open, floatingFocusElementRef, focusItem, focusItemOnHover, listRef, onNavigate, virtual]);\n const commonOnKeyDown = useEffectEvent(event => {\n isPointerModalityRef.current = false;\n forceSyncFocus.current = true;\n\n // If the floating element is animating out, ignore navigation. Otherwise,\n // the `activeIndex` gets set to 0 despite not being open so the next time\n // the user ArrowDowns, the first item won't be focused.\n if (!latestOpenRef.current && event.currentTarget === floatingFocusElementRef.current) {\n return;\n }\n if (nested && isCrossOrientationCloseKey(event.key, orientation, rtl)) {\n stopEvent(event);\n onOpenChange(false, event.nativeEvent, 'list-navigation');\n if (isHTMLElement(elements.domReference) && !virtual) {\n elements.domReference.focus();\n }\n return;\n }\n const currentIndex = indexRef.current;\n const minIndex = getMinIndex(listRef, disabledIndices);\n const maxIndex = getMaxIndex(listRef, disabledIndices);\n if (event.key === 'Home') {\n stopEvent(event);\n indexRef.current = minIndex;\n onNavigate(indexRef.current);\n }\n if (event.key === 'End') {\n stopEvent(event);\n indexRef.current = maxIndex;\n onNavigate(indexRef.current);\n }\n\n // Grid navigation.\n if (cols > 1) {\n const sizes = itemSizes || Array.from({\n length: listRef.current.length\n }, () => ({\n width: 1,\n height: 1\n }));\n // To calculate movements on the grid, we use hypothetical cell indices\n // as if every item was 1x1, then convert back to real indices.\n const cellMap = buildCellMap(sizes, cols, dense);\n const minGridIndex = cellMap.findIndex(index => index != null && !isDisabled(listRef.current, index, disabledIndices));\n // last enabled index\n const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !isDisabled(listRef.current, index, disabledIndices) ? cellIndex : foundIndex, -1);\n const index = cellMap[getGridNavigatedIndex({\n current: cellMap.map(itemIndex => itemIndex != null ? listRef.current[itemIndex] : null)\n }, {\n event,\n orientation,\n loop,\n cols,\n // treat undefined (empty grid spaces) as disabled indices so we\n // don't end up in them\n disabledIndices: getCellIndices([...(disabledIndices || listRef.current.map((_, index) => isDisabled(listRef.current, index) ? index : undefined)), undefined], cellMap),\n minIndex: minGridIndex,\n maxIndex: maxGridIndex,\n prevIndex: getCellIndexOfCorner(indexRef.current > maxIndex ? minIndex : indexRef.current, sizes, cellMap, cols,\n // use a corner matching the edge closest to the direction\n // we're moving in so we don't end up in the same item. Prefer\n // top/left over bottom/right.\n event.key === ARROW_DOWN ? 'bl' : event.key === ARROW_RIGHT ? 'tr' : 'tl'),\n stopEvent: true\n })];\n if (index != null) {\n indexRef.current = index;\n onNavigate(indexRef.current);\n }\n if (orientation === 'both') {\n return;\n }\n }\n if (isMainOrientationKey(event.key, orientation)) {\n stopEvent(event);\n\n // Reset the index if no item is focused.\n if (open && !virtual && activeElement(event.currentTarget.ownerDocument) === event.currentTarget) {\n indexRef.current = isMainOrientationToEndKey(event.key, orientation, rtl) ? minIndex : maxIndex;\n onNavigate(indexRef.current);\n return;\n }\n if (isMainOrientationToEndKey(event.key, orientation, rtl)) {\n if (loop) {\n indexRef.current = currentIndex >= maxIndex ? allowEscape && currentIndex !== listRef.current.length ? -1 : minIndex : findNonDisabledIndex(listRef, {\n startingIndex: currentIndex,\n disabledIndices\n });\n } else {\n indexRef.current = Math.min(maxIndex, findNonDisabledIndex(listRef, {\n startingIndex: currentIndex,\n disabledIndices\n }));\n }\n } else {\n if (loop) {\n indexRef.current = currentIndex <= minIndex ? allowEscape && currentIndex !== -1 ? listRef.current.length : maxIndex : findNonDisabledIndex(listRef, {\n startingIndex: currentIndex,\n decrement: true,\n disabledIndices\n });\n } else {\n indexRef.current = Math.max(minIndex, findNonDisabledIndex(listRef, {\n startingIndex: currentIndex,\n decrement: true,\n disabledIndices\n }));\n }\n }\n if (isIndexOutOfBounds(listRef, indexRef.current)) {\n onNavigate(null);\n } else {\n onNavigate(indexRef.current);\n }\n }\n });\n const ariaActiveDescendantProp = React.useMemo(() => {\n return virtual && open && hasActiveIndex && {\n 'aria-activedescendant': virtualId || activeId\n };\n }, [virtual, open, hasActiveIndex, virtualId, activeId]);\n const floating = React.useMemo(() => {\n return {\n 'aria-orientation': orientation === 'both' ? undefined : orientation,\n ...(!isTypeableCombobox(elements.domReference) && ariaActiveDescendantProp),\n onKeyDown: commonOnKeyDown,\n onPointerMove() {\n isPointerModalityRef.current = true;\n }\n };\n }, [ariaActiveDescendantProp, commonOnKeyDown, elements.domReference, orientation]);\n const reference = React.useMemo(() => {\n function checkVirtualMouse(event) {\n if (focusItemOnOpen === 'auto' && isVirtualClick(event.nativeEvent)) {\n focusItemOnOpenRef.current = true;\n }\n }\n function checkVirtualPointer(event) {\n // `pointerdown` fires first, reset the state then perform the checks.\n focusItemOnOpenRef.current = focusItemOnOpen;\n if (focusItemOnOpen === 'auto' && isVirtualPointerEvent(event.nativeEvent)) {\n focusItemOnOpenRef.current = true;\n }\n }\n return {\n ...ariaActiveDescendantProp,\n onKeyDown(event) {\n isPointerModalityRef.current = false;\n const isArrowKey = event.key.indexOf('Arrow') === 0;\n const isCrossOpenKey = isCrossOrientationOpenKey(event.key, orientation, rtl);\n const isCrossCloseKey = isCrossOrientationCloseKey(event.key, orientation, rtl);\n const isMainKey = isMainOrientationKey(event.key, orientation);\n const isNavigationKey = (nested ? isCrossOpenKey : isMainKey) || event.key === 'Enter' || event.key.trim() === '';\n if (virtual && open) {\n const rootNode = tree == null ? void 0 : tree.nodesRef.current.find(node => node.parentId == null);\n const deepestNode = tree && rootNode ? getDeepestNode(tree.nodesRef.current, rootNode.id) : null;\n if (isArrowKey && deepestNode && virtualItemRef) {\n const eventObject = new KeyboardEvent('keydown', {\n key: event.key,\n bubbles: true\n });\n if (isCrossOpenKey || isCrossCloseKey) {\n var _deepestNode$context, _deepestNode$context2;\n const isCurrentTarget = ((_deepestNode$context = deepestNode.context) == null ? void 0 : _deepestNode$context.elements.domReference) === event.currentTarget;\n const dispatchItem = isCrossCloseKey && !isCurrentTarget ? (_deepestNode$context2 = deepestNode.context) == null ? void 0 : _deepestNode$context2.elements.domReference : isCrossOpenKey ? listRef.current.find(item => (item == null ? void 0 : item.id) === activeId) : null;\n if (dispatchItem) {\n stopEvent(event);\n dispatchItem.dispatchEvent(eventObject);\n setVirtualId(undefined);\n }\n }\n if (isMainKey && deepestNode.context) {\n if (deepestNode.context.open && deepestNode.parentId && event.currentTarget !== deepestNode.context.elements.domReference) {\n var _deepestNode$context$;\n stopEvent(event);\n (_deepestNode$context$ = deepestNode.context.elements.domReference) == null || _deepestNode$context$.dispatchEvent(eventObject);\n return;\n }\n }\n }\n return commonOnKeyDown(event);\n }\n\n // If a floating element should not open on arrow key down, avoid\n // setting `activeIndex` while it's closed.\n if (!open && !openOnArrowKeyDown && isArrowKey) {\n return;\n }\n if (isNavigationKey) {\n keyRef.current = nested && isMainKey ? null : event.key;\n }\n if (nested) {\n if (isCrossOpenKey) {\n stopEvent(event);\n if (open) {\n indexRef.current = getMinIndex(listRef, disabledIndicesRef.current);\n onNavigate(indexRef.current);\n } else {\n onOpenChange(true, event.nativeEvent, 'list-navigation');\n }\n }\n return;\n }\n if (isMainKey) {\n if (selectedIndex != null) {\n indexRef.current = selectedIndex;\n }\n stopEvent(event);\n if (!open && openOnArrowKeyDown) {\n onOpenChange(true, event.nativeEvent, 'list-navigation');\n } else {\n commonOnKeyDown(event);\n }\n if (open) {\n onNavigate(indexRef.current);\n }\n }\n },\n onFocus() {\n if (open && !virtual) {\n onNavigate(null);\n }\n },\n onPointerDown: checkVirtualPointer,\n onMouseDown: checkVirtualMouse,\n onClick: checkVirtualMouse\n };\n }, [activeId, ariaActiveDescendantProp, commonOnKeyDown, disabledIndicesRef, focusItemOnOpen, listRef, nested, onNavigate, onOpenChange, open, openOnArrowKeyDown, orientation, rtl, selectedIndex, tree, virtual, virtualItemRef]);\n return React.useMemo(() => enabled ? {\n reference,\n floating,\n item\n } : {}, [enabled, reference, floating, item]);\n}\n\nconst componentRoleToAriaRoleMap = /*#__PURE__*/new Map([['select', 'listbox'], ['combobox', 'listbox'], ['label', false]]);\n\n/**\n * Adds base screen reader props to the reference and floating elements for a\n * given floating element `role`.\n * @see https://floating-ui.com/docs/useRole\n */\nfunction useRole(context, props) {\n var _componentRoleToAriaR;\n if (props === void 0) {\n props = {};\n }\n const {\n open,\n floatingId\n } = context;\n const {\n enabled = true,\n role = 'dialog'\n } = props;\n const ariaRole = (_componentRoleToAriaR = componentRoleToAriaRoleMap.get(role)) != null ? _componentRoleToAriaR : role;\n const referenceId = useId();\n const parentId = useFloatingParentNodeId();\n const isNested = parentId != null;\n const reference = React.useMemo(() => {\n if (ariaRole === 'tooltip' || role === 'label') {\n return {\n [\"aria-\" + (role === 'label' ? 'labelledby' : 'describedby')]: open ? floatingId : undefined\n };\n }\n return {\n 'aria-expanded': open ? 'true' : 'false',\n 'aria-haspopup': ariaRole === 'alertdialog' ? 'dialog' : ariaRole,\n 'aria-controls': open ? floatingId : undefined,\n ...(ariaRole === 'listbox' && {\n role: 'combobox'\n }),\n ...(ariaRole === 'menu' && {\n id: referenceId\n }),\n ...(ariaRole === 'menu' && isNested && {\n role: 'menuitem'\n }),\n ...(role === 'select' && {\n 'aria-autocomplete': 'none'\n }),\n ...(role === 'combobox' && {\n 'aria-autocomplete': 'list'\n })\n };\n }, [ariaRole, floatingId, isNested, open, referenceId, role]);\n const floating = React.useMemo(() => {\n const floatingProps = {\n id: floatingId,\n ...(ariaRole && {\n role: ariaRole\n })\n };\n if (ariaRole === 'tooltip' || role === 'label') {\n return floatingProps;\n }\n return {\n ...floatingProps,\n ...(ariaRole === 'menu' && {\n 'aria-labelledby': referenceId\n })\n };\n }, [ariaRole, floatingId, referenceId, role]);\n const item = React.useCallback(_ref => {\n let {\n active,\n selected\n } = _ref;\n const commonProps = {\n role: 'option',\n ...(active && {\n id: floatingId + \"-option\"\n })\n };\n\n // For `menu`, we are unable to tell if the item is a `menuitemradio`\n // or `menuitemcheckbox`. For backwards-compatibility reasons, also\n // avoid defaulting to `menuitem` as it may overwrite custom role props.\n switch (role) {\n case 'select':\n return {\n ...commonProps,\n 'aria-selected': active && selected\n };\n case 'combobox':\n {\n return {\n ...commonProps,\n ...(active && {\n 'aria-selected': true\n })\n };\n }\n }\n return {};\n }, [floatingId, role]);\n return React.useMemo(() => enabled ? {\n reference,\n floating,\n item\n } : {}, [enabled, reference, floating, item]);\n}\n\n// Converts a JS style key like `backgroundColor` to a CSS transition-property\n// like `background-color`.\nconst camelCaseToKebabCase = str => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase());\nfunction execWithArgsOrReturn(valueOrFn, args) {\n return typeof valueOrFn === 'function' ? valueOrFn(args) : valueOrFn;\n}\nfunction useDelayUnmount(open, durationMs) {\n const [isMounted, setIsMounted] = React.useState(open);\n if (open && !isMounted) {\n setIsMounted(true);\n }\n React.useEffect(() => {\n if (!open && isMounted) {\n const timeout = setTimeout(() => setIsMounted(false), durationMs);\n return () => clearTimeout(timeout);\n }\n }, [open, isMounted, durationMs]);\n return isMounted;\n}\n/**\n * Provides a status string to apply CSS transitions to a floating element,\n * correctly handling placement-aware transitions.\n * @see https://floating-ui.com/docs/useTransition#usetransitionstatus\n */\nfunction useTransitionStatus(context, props) {\n if (props === void 0) {\n props = {};\n }\n const {\n open,\n elements: {\n floating\n }\n } = context;\n const {\n duration = 250\n } = props;\n const isNumberDuration = typeof duration === 'number';\n const closeDuration = (isNumberDuration ? duration : duration.close) || 0;\n const [status, setStatus] = React.useState('unmounted');\n const isMounted = useDelayUnmount(open, closeDuration);\n if (!isMounted && status === 'close') {\n setStatus('unmounted');\n }\n index(() => {\n if (!floating) return;\n if (open) {\n setStatus('initial');\n const frame = requestAnimationFrame(() => {\n setStatus('open');\n });\n return () => {\n cancelAnimationFrame(frame);\n };\n }\n setStatus('close');\n }, [open, floating]);\n return {\n isMounted,\n status\n };\n}\n/**\n * Provides styles to apply CSS transitions to a floating element, correctly\n * handling placement-aware transitions. Wrapper around `useTransitionStatus`.\n * @see https://floating-ui.com/docs/useTransition#usetransitionstyles\n */\nfunction useTransitionStyles(context, props) {\n if (props === void 0) {\n props = {};\n }\n const {\n initial: unstable_initial = {\n opacity: 0\n },\n open: unstable_open,\n close: unstable_close,\n common: unstable_common,\n duration = 250\n } = props;\n const placement = context.placement;\n const side = placement.split('-')[0];\n const fnArgs = React.useMemo(() => ({\n side,\n placement\n }), [side, placement]);\n const isNumberDuration = typeof duration === 'number';\n const openDuration = (isNumberDuration ? duration : duration.open) || 0;\n const closeDuration = (isNumberDuration ? duration : duration.close) || 0;\n const [styles, setStyles] = React.useState(() => ({\n ...execWithArgsOrReturn(unstable_common, fnArgs),\n ...execWithArgsOrReturn(unstable_initial, fnArgs)\n }));\n const {\n isMounted,\n status\n } = useTransitionStatus(context, {\n duration\n });\n const initialRef = useLatestRef(unstable_initial);\n const openRef = useLatestRef(unstable_open);\n const closeRef = useLatestRef(unstable_close);\n const commonRef = useLatestRef(unstable_common);\n index(() => {\n const initialStyles = execWithArgsOrReturn(initialRef.current, fnArgs);\n const closeStyles = execWithArgsOrReturn(closeRef.current, fnArgs);\n const commonStyles = execWithArgsOrReturn(commonRef.current, fnArgs);\n const openStyles = execWithArgsOrReturn(openRef.current, fnArgs) || Object.keys(initialStyles).reduce((acc, key) => {\n acc[key] = '';\n return acc;\n }, {});\n if (status === 'initial') {\n setStyles(styles => ({\n transitionProperty: styles.transitionProperty,\n ...commonStyles,\n ...initialStyles\n }));\n }\n if (status === 'open') {\n setStyles({\n transitionProperty: Object.keys(openStyles).map(camelCaseToKebabCase).join(','),\n transitionDuration: openDuration + \"ms\",\n ...commonStyles,\n ...openStyles\n });\n }\n if (status === 'close') {\n const styles = closeStyles || initialStyles;\n setStyles({\n transitionProperty: Object.keys(styles).map(camelCaseToKebabCase).join(','),\n transitionDuration: closeDuration + \"ms\",\n ...commonStyles,\n ...styles\n });\n }\n }, [closeDuration, closeRef, initialRef, openRef, commonRef, openDuration, status, fnArgs]);\n return {\n isMounted,\n styles\n };\n}\n\n/**\n * Provides a matching callback that can be used to focus an item as the user\n * types, often used in tandem with `useListNavigation()`.\n * @see https://floating-ui.com/docs/useTypeahead\n */\nfunction useTypeahead(context, props) {\n var _ref;\n const {\n open,\n dataRef\n } = context;\n const {\n listRef,\n activeIndex,\n onMatch: unstable_onMatch,\n onTypingChange: unstable_onTypingChange,\n enabled = true,\n findMatch = null,\n resetMs = 750,\n ignoreKeys = [],\n selectedIndex = null\n } = props;\n const timeoutIdRef = React.useRef();\n const stringRef = React.useRef('');\n const prevIndexRef = React.useRef((_ref = selectedIndex != null ? selectedIndex : activeIndex) != null ? _ref : -1);\n const matchIndexRef = React.useRef(null);\n const onMatch = useEffectEvent(unstable_onMatch);\n const onTypingChange = useEffectEvent(unstable_onTypingChange);\n const findMatchRef = useLatestRef(findMatch);\n const ignoreKeysRef = useLatestRef(ignoreKeys);\n index(() => {\n if (open) {\n clearTimeout(timeoutIdRef.current);\n matchIndexRef.current = null;\n stringRef.current = '';\n }\n }, [open]);\n index(() => {\n // Sync arrow key navigation but not typeahead navigation.\n if (open && stringRef.current === '') {\n var _ref2;\n prevIndexRef.current = (_ref2 = selectedIndex != null ? selectedIndex : activeIndex) != null ? _ref2 : -1;\n }\n }, [open, selectedIndex, activeIndex]);\n const setTypingChange = useEffectEvent(value => {\n if (value) {\n if (!dataRef.current.typing) {\n dataRef.current.typing = value;\n onTypingChange(value);\n }\n } else {\n if (dataRef.current.typing) {\n dataRef.current.typing = value;\n onTypingChange(value);\n }\n }\n });\n const onKeyDown = useEffectEvent(event => {\n function getMatchingIndex(list, orderedList, string) {\n const str = findMatchRef.current ? findMatchRef.current(orderedList, string) : orderedList.find(text => (text == null ? void 0 : text.toLocaleLowerCase().indexOf(string.toLocaleLowerCase())) === 0);\n return str ? list.indexOf(str) : -1;\n }\n const listContent = listRef.current;\n if (stringRef.current.length > 0 && stringRef.current[0] !== ' ') {\n if (getMatchingIndex(listContent, listContent, stringRef.current) === -1) {\n setTypingChange(false);\n } else if (event.key === ' ') {\n stopEvent(event);\n }\n }\n if (listContent == null || ignoreKeysRef.current.includes(event.key) ||\n // Character key.\n event.key.length !== 1 ||\n // Modifier key.\n event.ctrlKey || event.metaKey || event.altKey) {\n return;\n }\n if (open && event.key !== ' ') {\n stopEvent(event);\n setTypingChange(true);\n }\n\n // Bail out if the list contains a word like \"llama\" or \"aaron\". TODO:\n // allow it in this case, too.\n const allowRapidSuccessionOfFirstLetter = listContent.every(text => {\n var _text$, _text$2;\n return text ? ((_text$ = text[0]) == null ? void 0 : _text$.toLocaleLowerCase()) !== ((_text$2 = text[1]) == null ? void 0 : _text$2.toLocaleLowerCase()) : true;\n });\n\n // Allows the user to cycle through items that start with the same letter\n // in rapid succession.\n if (allowRapidSuccessionOfFirstLetter && stringRef.current === event.key) {\n stringRef.current = '';\n prevIndexRef.current = matchIndexRef.current;\n }\n stringRef.current += event.key;\n clearTimeout(timeoutIdRef.current);\n timeoutIdRef.current = setTimeout(() => {\n stringRef.current = '';\n prevIndexRef.current = matchIndexRef.current;\n setTypingChange(false);\n }, resetMs);\n const prevIndex = prevIndexRef.current;\n const index = getMatchingIndex(listContent, [...listContent.slice((prevIndex || 0) + 1), ...listContent.slice(0, (prevIndex || 0) + 1)], stringRef.current);\n if (index !== -1) {\n onMatch(index);\n matchIndexRef.current = index;\n } else if (event.key !== ' ') {\n stringRef.current = '';\n setTypingChange(false);\n }\n });\n const reference = React.useMemo(() => ({\n onKeyDown\n }), [onKeyDown]);\n const floating = React.useMemo(() => {\n return {\n onKeyDown,\n onKeyUp(event) {\n if (event.key === ' ') {\n setTypingChange(false);\n }\n }\n };\n }, [onKeyDown, setTypingChange]);\n return React.useMemo(() => enabled ? {\n reference,\n floating\n } : {}, [enabled, reference, floating]);\n}\n\nfunction getArgsWithCustomFloatingHeight(state, height) {\n return {\n ...state,\n rects: {\n ...state.rects,\n floating: {\n ...state.rects.floating,\n height\n }\n }\n };\n}\n/**\n * Positions the floating element such that an inner element inside of it is\n * anchored to the reference element.\n * @see https://floating-ui.com/docs/inner\n */\nconst inner = props => ({\n name: 'inner',\n options: props,\n async fn(state) {\n const {\n listRef,\n overflowRef,\n onFallbackChange,\n offset: innerOffset = 0,\n index = 0,\n minItemsVisible = 4,\n referenceOverflowThreshold = 0,\n scrollRef,\n ...detectOverflowOptions\n } = evaluate(props, state);\n const {\n rects,\n elements: {\n floating\n }\n } = state;\n const item = listRef.current[index];\n const scrollEl = (scrollRef == null ? void 0 : scrollRef.current) || floating;\n\n // Valid combinations:\n // 1. Floating element is the scrollRef and has a border (default)\n // 2. Floating element is not the scrollRef, floating element has a border\n // 3. Floating element is not the scrollRef, scrollRef has a border\n // Floating > {...getFloatingProps()} wrapper > scrollRef > items is not\n // allowed as VoiceOver doesn't work.\n const clientTop = floating.clientTop || scrollEl.clientTop;\n const floatingIsBordered = floating.clientTop !== 0;\n const scrollElIsBordered = scrollEl.clientTop !== 0;\n const floatingIsScrollEl = floating === scrollEl;\n if (process.env.NODE_ENV !== \"production\") {\n if (!state.placement.startsWith('bottom')) {\n warn('`placement` side must be \"bottom\" when using the `inner`', 'middleware.');\n }\n }\n if (!item) {\n return {};\n }\n const nextArgs = {\n ...state,\n ...(await offset(-item.offsetTop - floating.clientTop - rects.reference.height / 2 - item.offsetHeight / 2 - innerOffset).fn(state))\n };\n const overflow = await detectOverflow(getArgsWithCustomFloatingHeight(nextArgs, scrollEl.scrollHeight + clientTop + floating.clientTop), detectOverflowOptions);\n const refOverflow = await detectOverflow(nextArgs, {\n ...detectOverflowOptions,\n elementContext: 'reference'\n });\n const diffY = Math.max(0, overflow.top);\n const nextY = nextArgs.y + diffY;\n const maxHeight = Math.max(0, scrollEl.scrollHeight + (floatingIsBordered && floatingIsScrollEl || scrollElIsBordered ? clientTop * 2 : 0) - diffY - Math.max(0, overflow.bottom));\n scrollEl.style.maxHeight = maxHeight + \"px\";\n scrollEl.scrollTop = diffY;\n\n // There is not enough space, fallback to standard anchored positioning\n if (onFallbackChange) {\n if (scrollEl.offsetHeight < item.offsetHeight * Math.min(minItemsVisible, listRef.current.length - 1) - 1 || refOverflow.top >= -referenceOverflowThreshold || refOverflow.bottom >= -referenceOverflowThreshold) {\n ReactDOM.flushSync(() => onFallbackChange(true));\n } else {\n ReactDOM.flushSync(() => onFallbackChange(false));\n }\n }\n if (overflowRef) {\n overflowRef.current = await detectOverflow(getArgsWithCustomFloatingHeight({\n ...nextArgs,\n y: nextY\n }, scrollEl.offsetHeight + clientTop + floating.clientTop), detectOverflowOptions);\n }\n return {\n y: nextY\n };\n }\n});\n/**\n * Changes the `inner` middleware's `offset` upon a `wheel` event to\n * expand the floating element's height, revealing more list items.\n * @see https://floating-ui.com/docs/inner\n */\nfunction useInnerOffset(context, props) {\n const {\n open,\n elements\n } = context;\n const {\n enabled = true,\n overflowRef,\n scrollRef,\n onChange: unstable_onChange\n } = props;\n const onChange = useEffectEvent(unstable_onChange);\n const controlledScrollingRef = React.useRef(false);\n const prevScrollTopRef = React.useRef(null);\n const initialOverflowRef = React.useRef(null);\n React.useEffect(() => {\n if (!enabled) return;\n function onWheel(e) {\n if (e.ctrlKey || !el || overflowRef.current == null) {\n return;\n }\n const dY = e.deltaY;\n const isAtTop = overflowRef.current.top >= -0.5;\n const isAtBottom = overflowRef.current.bottom >= -0.5;\n const remainingScroll = el.scrollHeight - el.clientHeight;\n const sign = dY < 0 ? -1 : 1;\n const method = dY < 0 ? 'max' : 'min';\n if (el.scrollHeight <= el.clientHeight) {\n return;\n }\n if (!isAtTop && dY > 0 || !isAtBottom && dY < 0) {\n e.preventDefault();\n ReactDOM.flushSync(() => {\n onChange(d => d + Math[method](dY, remainingScroll * sign));\n });\n } else if (/firefox/i.test(getUserAgent())) {\n // Needed to propagate scrolling during momentum scrolling phase once\n // it gets limited by the boundary. UX improvement, not critical.\n el.scrollTop += dY;\n }\n }\n const el = (scrollRef == null ? void 0 : scrollRef.current) || elements.floating;\n if (open && el) {\n el.addEventListener('wheel', onWheel);\n\n // Wait for the position to be ready.\n requestAnimationFrame(() => {\n prevScrollTopRef.current = el.scrollTop;\n if (overflowRef.current != null) {\n initialOverflowRef.current = {\n ...overflowRef.current\n };\n }\n });\n return () => {\n prevScrollTopRef.current = null;\n initialOverflowRef.current = null;\n el.removeEventListener('wheel', onWheel);\n };\n }\n }, [enabled, open, elements.floating, overflowRef, scrollRef, onChange]);\n const floating = React.useMemo(() => ({\n onKeyDown() {\n controlledScrollingRef.current = true;\n },\n onWheel() {\n controlledScrollingRef.current = false;\n },\n onPointerMove() {\n controlledScrollingRef.current = false;\n },\n onScroll() {\n const el = (scrollRef == null ? void 0 : scrollRef.current) || elements.floating;\n if (!overflowRef.current || !el || !controlledScrollingRef.current) {\n return;\n }\n if (prevScrollTopRef.current !== null) {\n const scrollDiff = el.scrollTop - prevScrollTopRef.current;\n if (overflowRef.current.bottom < -0.5 && scrollDiff < -1 || overflowRef.current.top < -0.5 && scrollDiff > 1) {\n ReactDOM.flushSync(() => onChange(d => d + scrollDiff));\n }\n }\n\n // [Firefox] Wait for the height change to have been applied.\n requestAnimationFrame(() => {\n prevScrollTopRef.current = el.scrollTop;\n });\n }\n }), [elements.floating, onChange, overflowRef, scrollRef]);\n return React.useMemo(() => enabled ? {\n floating\n } : {}, [enabled, floating]);\n}\n\nfunction isPointInPolygon(point, polygon) {\n const [x, y] = point;\n let isInside = false;\n const length = polygon.length;\n for (let i = 0, j = length - 1; i < length; j = i++) {\n const [xi, yi] = polygon[i] || [0, 0];\n const [xj, yj] = polygon[j] || [0, 0];\n const intersect = yi >= y !== yj >= y && x <= (xj - xi) * (y - yi) / (yj - yi) + xi;\n if (intersect) {\n isInside = !isInside;\n }\n }\n return isInside;\n}\nfunction isInside(point, rect) {\n return point[0] >= rect.x && point[0] <= rect.x + rect.width && point[1] >= rect.y && point[1] <= rect.y + rect.height;\n}\n/**\n * Generates a safe polygon area that the user can traverse without closing the\n * floating element once leaving the reference element.\n * @see https://floating-ui.com/docs/useHover#safepolygon\n */\nfunction safePolygon(options) {\n if (options === void 0) {\n options = {};\n }\n const {\n buffer = 0.5,\n blockPointerEvents = false,\n requireIntent = true\n } = options;\n let timeoutId;\n let hasLanded = false;\n let lastX = null;\n let lastY = null;\n let lastCursorTime = performance.now();\n function getCursorSpeed(x, y) {\n const currentTime = performance.now();\n const elapsedTime = currentTime - lastCursorTime;\n if (lastX === null || lastY === null || elapsedTime === 0) {\n lastX = x;\n lastY = y;\n lastCursorTime = currentTime;\n return null;\n }\n const deltaX = x - lastX;\n const deltaY = y - lastY;\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const speed = distance / elapsedTime; // px / ms\n\n lastX = x;\n lastY = y;\n lastCursorTime = currentTime;\n return speed;\n }\n const fn = _ref => {\n let {\n x,\n y,\n placement,\n elements,\n onClose,\n nodeId,\n tree\n } = _ref;\n return function onMouseMove(event) {\n function close() {\n clearTimeout(timeoutId);\n onClose();\n }\n clearTimeout(timeoutId);\n if (!elements.domReference || !elements.floating || placement == null || x == null || y == null) {\n return;\n }\n const {\n clientX,\n clientY\n } = event;\n const clientPoint = [clientX, clientY];\n const target = getTarget(event);\n const isLeave = event.type === 'mouseleave';\n const isOverFloatingEl = contains(elements.floating, target);\n const isOverReferenceEl = contains(elements.domReference, target);\n const refRect = elements.domReference.getBoundingClientRect();\n const rect = elements.floating.getBoundingClientRect();\n const side = placement.split('-')[0];\n const cursorLeaveFromRight = x > rect.right - rect.width / 2;\n const cursorLeaveFromBottom = y > rect.bottom - rect.height / 2;\n const isOverReferenceRect = isInside(clientPoint, refRect);\n const isFloatingWider = rect.width > refRect.width;\n const isFloatingTaller = rect.height > refRect.height;\n const left = (isFloatingWider ? refRect : rect).left;\n const right = (isFloatingWider ? refRect : rect).right;\n const top = (isFloatingTaller ? refRect : rect).top;\n const bottom = (isFloatingTaller ? refRect : rect).bottom;\n if (isOverFloatingEl) {\n hasLanded = true;\n if (!isLeave) {\n return;\n }\n }\n if (isOverReferenceEl) {\n hasLanded = false;\n }\n if (isOverReferenceEl && !isLeave) {\n hasLanded = true;\n return;\n }\n\n // Prevent overlapping floating element from being stuck in an open-close\n // loop: https://github.com/floating-ui/floating-ui/issues/1910\n if (isLeave && isElement(event.relatedTarget) && contains(elements.floating, event.relatedTarget)) {\n return;\n }\n\n // If any nested child is open, abort.\n if (tree && getChildren(tree.nodesRef.current, nodeId).some(_ref2 => {\n let {\n context\n } = _ref2;\n return context == null ? void 0 : context.open;\n })) {\n return;\n }\n\n // If the pointer is leaving from the opposite side, the \"buffer\" logic\n // creates a point where the floating element remains open, but should be\n // ignored.\n // A constant of 1 handles floating point rounding errors.\n if (side === 'top' && y >= refRect.bottom - 1 || side === 'bottom' && y <= refRect.top + 1 || side === 'left' && x >= refRect.right - 1 || side === 'right' && x <= refRect.left + 1) {\n return close();\n }\n\n // Ignore when the cursor is within the rectangular trough between the\n // two elements. Since the triangle is created from the cursor point,\n // which can start beyond the ref element's edge, traversing back and\n // forth from the ref to the floating element can cause it to close. This\n // ensures it always remains open in that case.\n let rectPoly = [];\n switch (side) {\n case 'top':\n rectPoly = [[left, refRect.top + 1], [left, rect.bottom - 1], [right, rect.bottom - 1], [right, refRect.top + 1]];\n break;\n case 'bottom':\n rectPoly = [[left, rect.top + 1], [left, refRect.bottom - 1], [right, refRect.bottom - 1], [right, rect.top + 1]];\n break;\n case 'left':\n rectPoly = [[rect.right - 1, bottom], [rect.right - 1, top], [refRect.left + 1, top], [refRect.left + 1, bottom]];\n break;\n case 'right':\n rectPoly = [[refRect.right - 1, bottom], [refRect.right - 1, top], [rect.left + 1, top], [rect.left + 1, bottom]];\n break;\n }\n function getPolygon(_ref3) {\n let [x, y] = _ref3;\n switch (side) {\n case 'top':\n {\n const cursorPointOne = [isFloatingWider ? x + buffer / 2 : cursorLeaveFromRight ? x + buffer * 4 : x - buffer * 4, y + buffer + 1];\n const cursorPointTwo = [isFloatingWider ? x - buffer / 2 : cursorLeaveFromRight ? x + buffer * 4 : x - buffer * 4, y + buffer + 1];\n const commonPoints = [[rect.left, cursorLeaveFromRight ? rect.bottom - buffer : isFloatingWider ? rect.bottom - buffer : rect.top], [rect.right, cursorLeaveFromRight ? isFloatingWider ? rect.bottom - buffer : rect.top : rect.bottom - buffer]];\n return [cursorPointOne, cursorPointTwo, ...commonPoints];\n }\n case 'bottom':\n {\n const cursorPointOne = [isFloatingWider ? x + buffer / 2 : cursorLeaveFromRight ? x + buffer * 4 : x - buffer * 4, y - buffer];\n const cursorPointTwo = [isFloatingWider ? x - buffer / 2 : cursorLeaveFromRight ? x + buffer * 4 : x - buffer * 4, y - buffer];\n const commonPoints = [[rect.left, cursorLeaveFromRight ? rect.top + buffer : isFloatingWider ? rect.top + buffer : rect.bottom], [rect.right, cursorLeaveFromRight ? isFloatingWider ? rect.top + buffer : rect.bottom : rect.top + buffer]];\n return [cursorPointOne, cursorPointTwo, ...commonPoints];\n }\n case 'left':\n {\n const cursorPointOne = [x + buffer + 1, isFloatingTaller ? y + buffer / 2 : cursorLeaveFromBottom ? y + buffer * 4 : y - buffer * 4];\n const cursorPointTwo = [x + buffer + 1, isFloatingTaller ? y - buffer / 2 : cursorLeaveFromBottom ? y + buffer * 4 : y - buffer * 4];\n const commonPoints = [[cursorLeaveFromBottom ? rect.right - buffer : isFloatingTaller ? rect.right - buffer : rect.left, rect.top], [cursorLeaveFromBottom ? isFloatingTaller ? rect.right - buffer : rect.left : rect.right - buffer, rect.bottom]];\n return [...commonPoints, cursorPointOne, cursorPointTwo];\n }\n case 'right':\n {\n const cursorPointOne = [x - buffer, isFloatingTaller ? y + buffer / 2 : cursorLeaveFromBottom ? y + buffer * 4 : y - buffer * 4];\n const cursorPointTwo = [x - buffer, isFloatingTaller ? y - buffer / 2 : cursorLeaveFromBottom ? y + buffer * 4 : y - buffer * 4];\n const commonPoints = [[cursorLeaveFromBottom ? rect.left + buffer : isFloatingTaller ? rect.left + buffer : rect.right, rect.top], [cursorLeaveFromBottom ? isFloatingTaller ? rect.left + buffer : rect.right : rect.left + buffer, rect.bottom]];\n return [cursorPointOne, cursorPointTwo, ...commonPoints];\n }\n }\n }\n if (isPointInPolygon([clientX, clientY], rectPoly)) {\n return;\n }\n if (hasLanded && !isOverReferenceRect) {\n return close();\n }\n if (!isLeave && requireIntent) {\n const cursorSpeed = getCursorSpeed(event.clientX, event.clientY);\n const cursorSpeedThreshold = 0.1;\n if (cursorSpeed !== null && cursorSpeed < cursorSpeedThreshold) {\n return close();\n }\n }\n if (!isPointInPolygon([clientX, clientY], getPolygon([x, y]))) {\n close();\n } else if (!hasLanded && requireIntent) {\n timeoutId = window.setTimeout(close, 40);\n }\n };\n };\n fn.__options = {\n blockPointerEvents\n };\n return fn;\n}\n\nexport { Composite, CompositeItem, FloatingArrow, FloatingDelayGroup, FloatingFocusManager, FloatingList, FloatingNode, FloatingOverlay, FloatingPortal, FloatingTree, inner, safePolygon, useClick, useClientPoint, useDelayGroup, useDelayGroupContext, useDismiss, useFloating, useFloatingNodeId, useFloatingParentNodeId, useFloatingPortalNode, useFloatingRootContext, useFloatingTree, useFocus, useHover, useId, useInnerOffset, useInteractions, useListItem, useListNavigation, useMergeRefs, useRole, useTransitionStatus, useTransitionStyles, useTypeahead };\n","import { isShadowRoot, isHTMLElement } from '@floating-ui/utils/dom';\n\nfunction activeElement(doc) {\n let activeElement = doc.activeElement;\n while (((_activeElement = activeElement) == null || (_activeElement = _activeElement.shadowRoot) == null ? void 0 : _activeElement.activeElement) != null) {\n var _activeElement;\n activeElement = activeElement.shadowRoot.activeElement;\n }\n return activeElement;\n}\nfunction contains(parent, child) {\n if (!parent || !child) {\n return false;\n }\n const rootNode = child.getRootNode == null ? void 0 : child.getRootNode();\n\n // First, attempt with faster native method\n if (parent.contains(child)) {\n return true;\n }\n\n // then fallback to custom implementation with Shadow DOM support\n if (rootNode && isShadowRoot(rootNode)) {\n let next = child;\n while (next) {\n if (parent === next) {\n return true;\n }\n // @ts-ignore\n next = next.parentNode || next.host;\n }\n }\n\n // Give up, the result is false\n return false;\n}\n// Avoid Chrome DevTools blue warning.\nfunction getPlatform() {\n const uaData = navigator.userAgentData;\n if (uaData != null && uaData.platform) {\n return uaData.platform;\n }\n return navigator.platform;\n}\nfunction getUserAgent() {\n const uaData = navigator.userAgentData;\n if (uaData && Array.isArray(uaData.brands)) {\n return uaData.brands.map(_ref => {\n let {\n brand,\n version\n } = _ref;\n return brand + \"/\" + version;\n }).join(' ');\n }\n return navigator.userAgent;\n}\n\n// License: https://github.com/adobe/react-spectrum/blob/b35d5c02fe900badccd0cf1a8f23bb593419f238/packages/@react-aria/utils/src/isVirtualEvent.ts\nfunction isVirtualClick(event) {\n // FIXME: Firefox is now emitting a deprecation warning for `mozInputSource`.\n // Try to find a workaround for this. `react-aria` source still has the check.\n if (event.mozInputSource === 0 && event.isTrusted) {\n return true;\n }\n if (isAndroid() && event.pointerType) {\n return event.type === 'click' && event.buttons === 1;\n }\n return event.detail === 0 && !event.pointerType;\n}\nfunction isVirtualPointerEvent(event) {\n if (isJSDOM()) return false;\n return !isAndroid() && event.width === 0 && event.height === 0 || isAndroid() && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||\n // iOS VoiceOver returns 0.333• for width/height.\n event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';\n}\nfunction isSafari() {\n // Chrome DevTools does not complain about navigator.vendor\n return /apple/i.test(navigator.vendor);\n}\nfunction isAndroid() {\n const re = /android/i;\n return re.test(getPlatform()) || re.test(getUserAgent());\n}\nfunction isMac() {\n return getPlatform().toLowerCase().startsWith('mac') && !navigator.maxTouchPoints;\n}\nfunction isJSDOM() {\n return getUserAgent().includes('jsdom/');\n}\nfunction isMouseLikePointerType(pointerType, strict) {\n // On some Linux machines with Chromium, mouse inputs return a `pointerType`\n // of \"pen\": https://github.com/floating-ui/floating-ui/issues/2015\n const values = ['mouse', 'pen'];\n if (!strict) {\n values.push('', undefined);\n }\n return values.includes(pointerType);\n}\nfunction isReactEvent(event) {\n return 'nativeEvent' in event;\n}\nfunction isRootElement(element) {\n return element.matches('html,body');\n}\nfunction getDocument(node) {\n return (node == null ? void 0 : node.ownerDocument) || document;\n}\nfunction isEventTargetWithin(event, node) {\n if (node == null) {\n return false;\n }\n if ('composedPath' in event) {\n return event.composedPath().includes(node);\n }\n\n // TS thinks `event` is of type never as it assumes all browsers support composedPath, but browsers without shadow dom don't\n const e = event;\n return e.target != null && node.contains(e.target);\n}\nfunction getTarget(event) {\n if ('composedPath' in event) {\n return event.composedPath()[0];\n }\n\n // TS thinks `event` is of type never as it assumes all browsers support\n // `composedPath()`, but browsers without shadow DOM don't.\n return event.target;\n}\nconst TYPEABLE_SELECTOR = \"input:not([type='hidden']):not([disabled]),\" + \"[contenteditable]:not([contenteditable='false']),textarea:not([disabled])\";\nfunction isTypeableElement(element) {\n return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);\n}\nfunction stopEvent(event) {\n event.preventDefault();\n event.stopPropagation();\n}\nfunction isTypeableCombobox(element) {\n if (!element) return false;\n return element.getAttribute('role') === 'combobox' && isTypeableElement(element);\n}\n\nexport { TYPEABLE_SELECTOR, activeElement, contains, getDocument, getPlatform, getTarget, getUserAgent, isAndroid, isEventTargetWithin, isJSDOM, isMac, isMouseLikePointerType, isReactEvent, isRootElement, isSafari, isTypeableCombobox, isTypeableElement, isVirtualClick, isVirtualPointerEvent, stopEvent };\n","function getNodeName(node) {\n if (isNode(node)) {\n return (node.nodeName || '').toLowerCase();\n }\n // Mocked nodes in testing environments may not be instances of Node. By\n // returning `#document` an infinite loop won't occur.\n // https://github.com/floating-ui/floating-ui/issues/2317\n return '#document';\n}\nfunction getWindow(node) {\n var _node$ownerDocument;\n return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;\n}\nfunction getDocumentElement(node) {\n var _ref;\n return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;\n}\nfunction isNode(value) {\n return value instanceof Node || value instanceof getWindow(value).Node;\n}\nfunction isElement(value) {\n return value instanceof Element || value instanceof getWindow(value).Element;\n}\nfunction isHTMLElement(value) {\n return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;\n}\nfunction isShadowRoot(value) {\n // Browsers without `ShadowRoot` support.\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;\n}\nfunction isOverflowElement(element) {\n const {\n overflow,\n overflowX,\n overflowY,\n display\n } = getComputedStyle(element);\n return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !['inline', 'contents'].includes(display);\n}\nfunction isTableElement(element) {\n return ['table', 'td', 'th'].includes(getNodeName(element));\n}\nfunction isTopLayer(element) {\n return [':popover-open', ':modal'].some(selector => {\n try {\n return element.matches(selector);\n } catch (e) {\n return false;\n }\n });\n}\nfunction isContainingBlock(elementOrCss) {\n const webkit = isWebKit();\n const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n return css.transform !== 'none' || css.perspective !== 'none' || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || ['transform', 'perspective', 'filter'].some(value => (css.willChange || '').includes(value)) || ['paint', 'layout', 'strict', 'content'].some(value => (css.contain || '').includes(value));\n}\nfunction getContainingBlock(element) {\n let currentNode = getParentNode(element);\n while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {\n if (isContainingBlock(currentNode)) {\n return currentNode;\n } else if (isTopLayer(currentNode)) {\n return null;\n }\n currentNode = getParentNode(currentNode);\n }\n return null;\n}\nfunction isWebKit() {\n if (typeof CSS === 'undefined' || !CSS.supports) return false;\n return CSS.supports('-webkit-backdrop-filter', 'none');\n}\nfunction isLastTraversableNode(node) {\n return ['html', 'body', '#document'].includes(getNodeName(node));\n}\nfunction getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}\nfunction getNodeScroll(element) {\n if (isElement(element)) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n }\n return {\n scrollLeft: element.scrollX,\n scrollTop: element.scrollY\n };\n}\nfunction getParentNode(node) {\n if (getNodeName(node) === 'html') {\n return node;\n }\n const result =\n // Step into the shadow DOM of the parent of a slotted node.\n node.assignedSlot ||\n // DOM Element detected.\n node.parentNode ||\n // ShadowRoot detected.\n isShadowRoot(node) && node.host ||\n // Fallback.\n getDocumentElement(node);\n return isShadowRoot(result) ? result.host : result;\n}\nfunction getNearestOverflowAncestor(node) {\n const parentNode = getParentNode(node);\n if (isLastTraversableNode(parentNode)) {\n return node.ownerDocument ? node.ownerDocument.body : node.body;\n }\n if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {\n return parentNode;\n }\n return getNearestOverflowAncestor(parentNode);\n}\nfunction getOverflowAncestors(node, list, traverseIframes) {\n var _node$ownerDocument2;\n if (list === void 0) {\n list = [];\n }\n if (traverseIframes === void 0) {\n traverseIframes = true;\n }\n const scrollableAncestor = getNearestOverflowAncestor(node);\n const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);\n const win = getWindow(scrollableAncestor);\n if (isBody) {\n const frameElement = getFrameElement(win);\n return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);\n }\n return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));\n}\nfunction getFrameElement(win) {\n return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;\n}\n\nexport { getComputedStyle, getContainingBlock, getDocumentElement, getFrameElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isTopLayer, isWebKit };\n","/**\n * Custom positioning reference element.\n * @see https://floating-ui.com/docs/virtual-elements\n */\n\nconst sides = ['top', 'right', 'bottom', 'left'];\nconst alignments = ['start', 'end'];\nconst placements = /*#__PURE__*/sides.reduce((acc, side) => acc.concat(side, side + \"-\" + alignments[0], side + \"-\" + alignments[1]), []);\nconst min = Math.min;\nconst max = Math.max;\nconst round = Math.round;\nconst floor = Math.floor;\nconst createCoords = v => ({\n x: v,\n y: v\n});\nconst oppositeSideMap = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nconst oppositeAlignmentMap = {\n start: 'end',\n end: 'start'\n};\nfunction clamp(start, value, end) {\n return max(start, min(value, end));\n}\nfunction evaluate(value, param) {\n return typeof value === 'function' ? value(param) : value;\n}\nfunction getSide(placement) {\n return placement.split('-')[0];\n}\nfunction getAlignment(placement) {\n return placement.split('-')[1];\n}\nfunction getOppositeAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}\nfunction getAxisLength(axis) {\n return axis === 'y' ? 'height' : 'width';\n}\nfunction getSideAxis(placement) {\n return ['top', 'bottom'].includes(getSide(placement)) ? 'y' : 'x';\n}\nfunction getAlignmentAxis(placement) {\n return getOppositeAxis(getSideAxis(placement));\n}\nfunction getAlignmentSides(placement, rects, rtl) {\n if (rtl === void 0) {\n rtl = false;\n }\n const alignment = getAlignment(placement);\n const alignmentAxis = getAlignmentAxis(placement);\n const length = getAxisLength(alignmentAxis);\n let mainAlignmentSide = alignmentAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';\n if (rects.reference[length] > rects.floating[length]) {\n mainAlignmentSide = getOppositePlacement(mainAlignmentSide);\n }\n return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];\n}\nfunction getExpandedPlacements(placement) {\n const oppositePlacement = getOppositePlacement(placement);\n return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];\n}\nfunction getOppositeAlignmentPlacement(placement) {\n return placement.replace(/start|end/g, alignment => oppositeAlignmentMap[alignment]);\n}\nfunction getSideList(side, isStart, rtl) {\n const lr = ['left', 'right'];\n const rl = ['right', 'left'];\n const tb = ['top', 'bottom'];\n const bt = ['bottom', 'top'];\n switch (side) {\n case 'top':\n case 'bottom':\n if (rtl) return isStart ? rl : lr;\n return isStart ? lr : rl;\n case 'left':\n case 'right':\n return isStart ? tb : bt;\n default:\n return [];\n }\n}\nfunction getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {\n const alignment = getAlignment(placement);\n let list = getSideList(getSide(placement), direction === 'start', rtl);\n if (alignment) {\n list = list.map(side => side + \"-\" + alignment);\n if (flipAlignment) {\n list = list.concat(list.map(getOppositeAlignmentPlacement));\n }\n }\n return list;\n}\nfunction getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, side => oppositeSideMap[side]);\n}\nfunction expandPaddingObject(padding) {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n ...padding\n };\n}\nfunction getPaddingObject(padding) {\n return typeof padding !== 'number' ? expandPaddingObject(padding) : {\n top: padding,\n right: padding,\n bottom: padding,\n left: padding\n };\n}\nfunction rectToClientRect(rect) {\n const {\n x,\n y,\n width,\n height\n } = rect;\n return {\n width,\n height,\n top: y,\n left: x,\n right: x + width,\n bottom: y + height,\n x,\n y\n };\n}\n\nexport { alignments, clamp, createCoords, evaluate, expandPaddingObject, floor, getAlignment, getAlignmentAxis, getAlignmentSides, getAxisLength, getExpandedPlacements, getOppositeAlignmentPlacement, getOppositeAxis, getOppositeAxisPlacements, getOppositePlacement, getPaddingObject, getSide, getSideAxis, max, min, placements, rectToClientRect, round, sides };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html';\nimport { $addNodeStyle, $sliceSelectedTextNodeContent } from '@lexical/selection';\nimport { objectKlassEquals } from '@lexical/utils';\nimport { $isRangeSelection, $getSelection, $createTabNode, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, $getRoot, $parseSerializedNode, $isTextNode, COPY_COMMAND, COMMAND_PRIORITY_CRITICAL, isSelectionWithinEditor, $getEditor, $isElementNode, $cloneWithProperties } from 'lexical';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;\n/**\n * Returns the *currently selected* Lexical content as an HTML string, relying on the\n * logic defined in the exportDOM methods on the LexicalNode classes. Note that\n * this will not return the HTML content of the entire editor (unless all the content is included\n * in the current selection).\n *\n * @param editor - LexicalEditor instance to get HTML content from\n * @param selection - The selection to use (default is $getSelection())\n * @returns a string of HTML content\n */\nfunction $getHtmlContent(editor, selection = $getSelection()) {\n if (selection == null) {\n {\n throw Error(`Expected valid LexicalSelection`);\n }\n }\n\n // If we haven't selected anything\n if ($isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) {\n return '';\n }\n return $generateHtmlFromNodes(editor, selection);\n}\n\n/**\n * Returns the *currently selected* Lexical content as a JSON string, relying on the\n * logic defined in the exportJSON methods on the LexicalNode classes. Note that\n * this will not return the JSON content of the entire editor (unless all the content is included\n * in the current selection).\n *\n * @param editor - LexicalEditor instance to get the JSON content from\n * @param selection - The selection to use (default is $getSelection())\n * @returns\n */\nfunction $getLexicalContent(editor, selection = $getSelection()) {\n if (selection == null) {\n {\n throw Error(`Expected valid LexicalSelection`);\n }\n }\n\n // If we haven't selected anything\n if ($isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) {\n return null;\n }\n return JSON.stringify($generateJSONFromSelectedNodes(editor, selection));\n}\n\n/**\n * Attempts to insert content of the mime-types text/plain or text/uri-list from\n * the provided DataTransfer object into the editor at the provided selection.\n * text/uri-list is only used if text/plain is not also provided.\n *\n * @param dataTransfer an object conforming to the [DataTransfer interface] (https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface)\n * @param selection the selection to use as the insertion point for the content in the DataTransfer object\n */\nfunction $insertDataTransferForPlainText(dataTransfer, selection) {\n const text = dataTransfer.getData('text/plain') || dataTransfer.getData('text/uri-list');\n if (text != null) {\n selection.insertRawText(text);\n }\n}\n\n/**\n * Attempts to insert content of the mime-types application/x-lexical-editor, text/html,\n * text/plain, or text/uri-list (in descending order of priority) from the provided DataTransfer\n * object into the editor at the provided selection.\n *\n * @param dataTransfer an object conforming to the [DataTransfer interface] (https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface)\n * @param selection the selection to use as the insertion point for the content in the DataTransfer object\n * @param editor the LexicalEditor the content is being inserted into.\n */\nfunction $insertDataTransferForRichText(dataTransfer, selection, editor) {\n const lexicalString = dataTransfer.getData('application/x-lexical-editor');\n if (lexicalString) {\n try {\n const payload = JSON.parse(lexicalString);\n if (payload.namespace === editor._config.namespace && Array.isArray(payload.nodes)) {\n const nodes = $generateNodesFromSerializedNodes(payload.nodes);\n return $insertGeneratedNodes(editor, nodes, selection);\n }\n } catch (_unused) {\n // Fail silently.\n }\n }\n const htmlString = dataTransfer.getData('text/html');\n if (htmlString) {\n try {\n const parser = new DOMParser();\n const dom = parser.parseFromString(htmlString, 'text/html');\n const nodes = $generateNodesFromDOM(editor, dom);\n return $insertGeneratedNodes(editor, nodes, selection);\n } catch (_unused2) {\n // Fail silently.\n }\n }\n\n // Multi-line plain text in rich text mode pasted as separate paragraphs\n // instead of single paragraph with linebreaks.\n // Webkit-specific: Supports read 'text/uri-list' in clipboard.\n const text = dataTransfer.getData('text/plain') || dataTransfer.getData('text/uri-list');\n if (text != null) {\n if ($isRangeSelection(selection)) {\n const parts = text.split(/(\\r?\\n|\\t)/);\n if (parts[parts.length - 1] === '') {\n parts.pop();\n }\n for (let i = 0; i < parts.length; i++) {\n const currentSelection = $getSelection();\n if ($isRangeSelection(currentSelection)) {\n const part = parts[i];\n if (part === '\\n' || part === '\\r\\n') {\n currentSelection.insertParagraph();\n } else if (part === '\\t') {\n currentSelection.insertNodes([$createTabNode()]);\n } else {\n currentSelection.insertText(part);\n }\n }\n }\n } else {\n selection.insertRawText(text);\n }\n }\n}\n\n/**\n * Inserts Lexical nodes into the editor using different strategies depending on\n * some simple selection-based heuristics. If you're looking for a generic way to\n * to insert nodes into the editor at a specific selection point, you probably want\n * {@link lexical.$insertNodes}\n *\n * @param editor LexicalEditor instance to insert the nodes into.\n * @param nodes The nodes to insert.\n * @param selection The selection to insert the nodes into.\n */\nfunction $insertGeneratedNodes(editor, nodes, selection) {\n if (!editor.dispatchCommand(SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, {\n nodes,\n selection\n })) {\n selection.insertNodes(nodes);\n }\n return;\n}\nfunction exportNodeToJSON(node) {\n const serializedNode = node.exportJSON();\n const nodeClass = node.constructor;\n if (serializedNode.type !== nodeClass.getType()) {\n {\n throw Error(`LexicalNode: Node ${nodeClass.name} does not implement .exportJSON().`);\n }\n }\n if ($isElementNode(node)) {\n const serializedChildren = serializedNode.children;\n if (!Array.isArray(serializedChildren)) {\n {\n throw Error(`LexicalNode: Node ${nodeClass.name} is an element but .exportJSON() does not have a children array.`);\n }\n }\n }\n return serializedNode;\n}\nfunction $appendNodesToJSON(editor, selection, currentNode, targetArray = []) {\n let shouldInclude = selection !== null ? currentNode.isSelected(selection) : true;\n const shouldExclude = $isElementNode(currentNode) && currentNode.excludeFromCopy('html');\n let target = currentNode;\n if (selection !== null) {\n let clone = $cloneWithProperties(currentNode);\n clone = $isTextNode(clone) && selection !== null ? $sliceSelectedTextNodeContent(selection, clone) : clone;\n target = clone;\n }\n const children = $isElementNode(target) ? target.getChildren() : [];\n const serializedNode = exportNodeToJSON(target);\n\n // TODO: TextNode calls getTextContent() (NOT node.__text) within its exportJSON method\n // which uses getLatest() to get the text from the original node with the same key.\n // This is a deeper issue with the word \"clone\" here, it's still a reference to the\n // same node as far as the LexicalEditor is concerned since it shares a key.\n // We need a way to create a clone of a Node in memory with its own key, but\n // until then this hack will work for the selected text extract use case.\n if ($isTextNode(target)) {\n const text = target.__text;\n // If an uncollapsed selection ends or starts at the end of a line of specialized,\n // TextNodes, such as code tokens, we will get a 'blank' TextNode here, i.e., one\n // with text of length 0. We don't want this, it makes a confusing mess. Reset!\n if (text.length > 0) {\n serializedNode.text = text;\n } else {\n shouldInclude = false;\n }\n }\n for (let i = 0; i < children.length; i++) {\n const childNode = children[i];\n const shouldIncludeChild = $appendNodesToJSON(editor, selection, childNode, serializedNode.children);\n if (!shouldInclude && $isElementNode(currentNode) && shouldIncludeChild && currentNode.extractWithChild(childNode, selection, 'clone')) {\n shouldInclude = true;\n }\n }\n if (shouldInclude && !shouldExclude) {\n targetArray.push(serializedNode);\n } else if (Array.isArray(serializedNode.children)) {\n for (let i = 0; i < serializedNode.children.length; i++) {\n const serializedChildNode = serializedNode.children[i];\n targetArray.push(serializedChildNode);\n }\n }\n return shouldInclude;\n}\n\n// TODO why $ function with Editor instance?\n/**\n * Gets the Lexical JSON of the nodes inside the provided Selection.\n *\n * @param editor LexicalEditor to get the JSON content from.\n * @param selection Selection to get the JSON content from.\n * @returns an object with the editor namespace and a list of serializable nodes as JavaScript objects.\n */\nfunction $generateJSONFromSelectedNodes(editor, selection) {\n const nodes = [];\n const root = $getRoot();\n const topLevelChildren = root.getChildren();\n for (let i = 0; i < topLevelChildren.length; i++) {\n const topLevelNode = topLevelChildren[i];\n $appendNodesToJSON(editor, selection, topLevelNode, nodes);\n }\n return {\n namespace: editor._config.namespace,\n nodes\n };\n}\n\n/**\n * This method takes an array of objects conforming to the BaseSeralizedNode interface and returns\n * an Array containing instances of the corresponding LexicalNode classes registered on the editor.\n * Normally, you'd get an Array of BaseSerialized nodes from {@link $generateJSONFromSelectedNodes}\n *\n * @param serializedNodes an Array of objects conforming to the BaseSerializedNode interface.\n * @returns an Array of Lexical Node objects.\n */\nfunction $generateNodesFromSerializedNodes(serializedNodes) {\n const nodes = [];\n for (let i = 0; i < serializedNodes.length; i++) {\n const serializedNode = serializedNodes[i];\n const node = $parseSerializedNode(serializedNode);\n if ($isTextNode(node)) {\n $addNodeStyle(node);\n }\n nodes.push(node);\n }\n return nodes;\n}\nconst EVENT_LATENCY = 50;\nlet clipboardEventTimeout = null;\n\n// TODO custom selection\n// TODO potentially have a node customizable version for plain text\n/**\n * Copies the content of the current selection to the clipboard in\n * text/plain, text/html, and application/x-lexical-editor (Lexical JSON)\n * formats.\n *\n * @param editor the LexicalEditor instance to copy content from\n * @param event the native browser ClipboardEvent to add the content to.\n * @returns\n */\nasync function copyToClipboard(editor, event, data) {\n if (clipboardEventTimeout !== null) {\n // Prevent weird race conditions that can happen when this function is run multiple times\n // synchronously. In the future, we can do better, we can cancel/override the previously running job.\n return false;\n }\n if (event !== null) {\n return new Promise((resolve, reject) => {\n editor.update(() => {\n resolve($copyToClipboardEvent(editor, event, data));\n });\n });\n }\n const rootElement = editor.getRootElement();\n const windowDocument = editor._window == null ? window.document : editor._window.document;\n const domSelection = getDOMSelection(editor._window);\n if (rootElement === null || domSelection === null) {\n return false;\n }\n const element = windowDocument.createElement('span');\n element.style.cssText = 'position: fixed; top: -1000px;';\n element.append(windowDocument.createTextNode('#'));\n rootElement.append(element);\n const range = new Range();\n range.setStart(element, 0);\n range.setEnd(element, 1);\n domSelection.removeAllRanges();\n domSelection.addRange(range);\n return new Promise((resolve, reject) => {\n const removeListener = editor.registerCommand(COPY_COMMAND, secondEvent => {\n if (objectKlassEquals(secondEvent, ClipboardEvent)) {\n removeListener();\n if (clipboardEventTimeout !== null) {\n window.clearTimeout(clipboardEventTimeout);\n clipboardEventTimeout = null;\n }\n resolve($copyToClipboardEvent(editor, secondEvent, data));\n }\n // Block the entire copy flow while we wait for the next ClipboardEvent\n return true;\n }, COMMAND_PRIORITY_CRITICAL);\n // If the above hack execCommand hack works, this timeout code should never fire. Otherwise,\n // the listener will be quickly freed so that the user can reuse it again\n clipboardEventTimeout = window.setTimeout(() => {\n removeListener();\n clipboardEventTimeout = null;\n resolve(false);\n }, EVENT_LATENCY);\n windowDocument.execCommand('copy');\n element.remove();\n });\n}\n\n// TODO shouldn't pass editor (pass namespace directly)\nfunction $copyToClipboardEvent(editor, event, data) {\n if (data === undefined) {\n const domSelection = getDOMSelection(editor._window);\n if (!domSelection) {\n return false;\n }\n const anchorDOM = domSelection.anchorNode;\n const focusDOM = domSelection.focusNode;\n if (anchorDOM !== null && focusDOM !== null && !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {\n return false;\n }\n const selection = $getSelection();\n if (selection === null) {\n return false;\n }\n data = $getClipboardDataFromSelection(selection);\n }\n event.preventDefault();\n const clipboardData = event.clipboardData;\n if (clipboardData === null) {\n return false;\n }\n setLexicalClipboardDataTransfer(clipboardData, data);\n return true;\n}\nconst clipboardDataFunctions = [['text/html', $getHtmlContent], ['application/x-lexical-editor', $getLexicalContent]];\n\n/**\n * Serialize the content of the current selection to strings in\n * text/plain, text/html, and application/x-lexical-editor (Lexical JSON)\n * formats (as available).\n *\n * @param selection the selection to serialize (defaults to $getSelection())\n * @returns LexicalClipboardData\n */\nfunction $getClipboardDataFromSelection(selection = $getSelection()) {\n const clipboardData = {\n 'text/plain': selection ? selection.getTextContent() : ''\n };\n if (selection) {\n const editor = $getEditor();\n for (const [mimeType, $editorFn] of clipboardDataFunctions) {\n const v = $editorFn(editor, selection);\n if (v !== null) {\n clipboardData[mimeType] = v;\n }\n }\n }\n return clipboardData;\n}\n\n/**\n * Call setData on the given clipboardData for each MIME type present\n * in the given data (from {@link $getClipboardDataFromSelection})\n *\n * @param clipboardData the event.clipboardData to populate from data\n * @param data The lexical data\n */\nfunction setLexicalClipboardDataTransfer(clipboardData, data) {\n for (const k in data) {\n const v = data[k];\n if (v !== undefined) {\n clipboardData.setData(k, v);\n }\n }\n}\n\nexport { $generateJSONFromSelectedNodes, $generateNodesFromSerializedNodes, $getClipboardDataFromSelection, $getHtmlContent, $getLexicalContent, $insertDataTransferForPlainText, $insertDataTransferForRichText, $insertGeneratedNodes, copyToClipboard, setLexicalClipboardDataTransfer };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { $getSelection, $isRangeSelection, $isTextNode } from 'lexical';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction registerDragonSupport(editor) {\n const origin = window.location.origin;\n const handler = event => {\n if (event.origin !== origin) {\n return;\n }\n const rootElement = editor.getRootElement();\n if (document.activeElement !== rootElement) {\n return;\n }\n const data = event.data;\n if (typeof data === 'string') {\n let parsedData;\n try {\n parsedData = JSON.parse(data);\n } catch (e) {\n return;\n }\n if (parsedData && parsedData.protocol === 'nuanria_messaging' && parsedData.type === 'request') {\n const payload = parsedData.payload;\n if (payload && payload.functionId === 'makeChanges') {\n const args = payload.args;\n if (args) {\n const [elementStart, elementLength, text, selStart, selLength, formatCommand] = args;\n editor.update(() => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const anchor = selection.anchor;\n let anchorNode = anchor.getNode();\n let setSelStart = 0;\n let setSelEnd = 0;\n if ($isTextNode(anchorNode)) {\n // set initial selection\n if (elementStart >= 0 && elementLength >= 0) {\n setSelStart = elementStart;\n setSelEnd = elementStart + elementLength;\n // If the offset is more than the end, make it the end\n selection.setTextNodeRange(anchorNode, setSelStart, anchorNode, setSelEnd);\n }\n }\n if (setSelStart !== setSelEnd || text !== '') {\n selection.insertRawText(text);\n anchorNode = anchor.getNode();\n }\n if ($isTextNode(anchorNode)) {\n // set final selection\n setSelStart = selStart;\n setSelEnd = selStart + selLength;\n const anchorNodeTextLength = anchorNode.getTextContentSize();\n // If the offset is more than the end, make it the end\n setSelStart = setSelStart > anchorNodeTextLength ? anchorNodeTextLength : setSelStart;\n setSelEnd = setSelEnd > anchorNodeTextLength ? anchorNodeTextLength : setSelEnd;\n selection.setTextNodeRange(anchorNode, setSelStart, anchorNode, setSelEnd);\n }\n\n // block the chrome extension from handling this event\n event.stopImmediatePropagation();\n }\n });\n }\n }\n }\n }\n };\n window.addEventListener('message', handler, true);\n return () => {\n window.removeEventListener('message', handler, true);\n };\n}\n\nexport { registerDragonSupport };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { mergeRegister } from '@lexical/utils';\nimport { UNDO_COMMAND, COMMAND_PRIORITY_EDITOR, REDO_COMMAND, CLEAR_EDITOR_COMMAND, CLEAR_HISTORY_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, $isRangeSelection, $isTextNode, $isRootNode } from 'lexical';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst HISTORY_MERGE = 0;\nconst HISTORY_PUSH = 1;\nconst DISCARD_HISTORY_CANDIDATE = 2;\nconst OTHER = 0;\nconst COMPOSING_CHARACTER = 1;\nconst INSERT_CHARACTER_AFTER_SELECTION = 2;\nconst DELETE_CHARACTER_BEFORE_SELECTION = 3;\nconst DELETE_CHARACTER_AFTER_SELECTION = 4;\nfunction getDirtyNodes(editorState, dirtyLeaves, dirtyElements) {\n const nodeMap = editorState._nodeMap;\n const nodes = [];\n for (const dirtyLeafKey of dirtyLeaves) {\n const dirtyLeaf = nodeMap.get(dirtyLeafKey);\n if (dirtyLeaf !== undefined) {\n nodes.push(dirtyLeaf);\n }\n }\n for (const [dirtyElementKey, intentionallyMarkedAsDirty] of dirtyElements) {\n if (!intentionallyMarkedAsDirty) {\n continue;\n }\n const dirtyElement = nodeMap.get(dirtyElementKey);\n if (dirtyElement !== undefined && !$isRootNode(dirtyElement)) {\n nodes.push(dirtyElement);\n }\n }\n return nodes;\n}\nfunction getChangeType(prevEditorState, nextEditorState, dirtyLeavesSet, dirtyElementsSet, isComposing) {\n if (prevEditorState === null || dirtyLeavesSet.size === 0 && dirtyElementsSet.size === 0 && !isComposing) {\n return OTHER;\n }\n const nextSelection = nextEditorState._selection;\n const prevSelection = prevEditorState._selection;\n if (isComposing) {\n return COMPOSING_CHARACTER;\n }\n if (!$isRangeSelection(nextSelection) || !$isRangeSelection(prevSelection) || !prevSelection.isCollapsed() || !nextSelection.isCollapsed()) {\n return OTHER;\n }\n const dirtyNodes = getDirtyNodes(nextEditorState, dirtyLeavesSet, dirtyElementsSet);\n if (dirtyNodes.length === 0) {\n return OTHER;\n }\n\n // Catching the case when inserting new text node into an element (e.g. first char in paragraph/list),\n // or after existing node.\n if (dirtyNodes.length > 1) {\n const nextNodeMap = nextEditorState._nodeMap;\n const nextAnchorNode = nextNodeMap.get(nextSelection.anchor.key);\n const prevAnchorNode = nextNodeMap.get(prevSelection.anchor.key);\n if (nextAnchorNode && prevAnchorNode && !prevEditorState._nodeMap.has(nextAnchorNode.__key) && $isTextNode(nextAnchorNode) && nextAnchorNode.__text.length === 1 && nextSelection.anchor.offset === 1) {\n return INSERT_CHARACTER_AFTER_SELECTION;\n }\n return OTHER;\n }\n const nextDirtyNode = dirtyNodes[0];\n const prevDirtyNode = prevEditorState._nodeMap.get(nextDirtyNode.__key);\n if (!$isTextNode(prevDirtyNode) || !$isTextNode(nextDirtyNode) || prevDirtyNode.__mode !== nextDirtyNode.__mode) {\n return OTHER;\n }\n const prevText = prevDirtyNode.__text;\n const nextText = nextDirtyNode.__text;\n if (prevText === nextText) {\n return OTHER;\n }\n const nextAnchor = nextSelection.anchor;\n const prevAnchor = prevSelection.anchor;\n if (nextAnchor.key !== prevAnchor.key || nextAnchor.type !== 'text') {\n return OTHER;\n }\n const nextAnchorOffset = nextAnchor.offset;\n const prevAnchorOffset = prevAnchor.offset;\n const textDiff = nextText.length - prevText.length;\n if (textDiff === 1 && prevAnchorOffset === nextAnchorOffset - 1) {\n return INSERT_CHARACTER_AFTER_SELECTION;\n }\n if (textDiff === -1 && prevAnchorOffset === nextAnchorOffset + 1) {\n return DELETE_CHARACTER_BEFORE_SELECTION;\n }\n if (textDiff === -1 && prevAnchorOffset === nextAnchorOffset) {\n return DELETE_CHARACTER_AFTER_SELECTION;\n }\n return OTHER;\n}\nfunction isTextNodeUnchanged(key, prevEditorState, nextEditorState) {\n const prevNode = prevEditorState._nodeMap.get(key);\n const nextNode = nextEditorState._nodeMap.get(key);\n const prevSelection = prevEditorState._selection;\n const nextSelection = nextEditorState._selection;\n const isDeletingLine = $isRangeSelection(prevSelection) && $isRangeSelection(nextSelection) && prevSelection.anchor.type === 'element' && prevSelection.focus.type === 'element' && nextSelection.anchor.type === 'text' && nextSelection.focus.type === 'text';\n if (!isDeletingLine && $isTextNode(prevNode) && $isTextNode(nextNode) && prevNode.__parent === nextNode.__parent) {\n // This has the assumption that object key order won't change if the\n // content did not change, which should normally be safe given\n // the manner in which nodes and exportJSON are typically implemented.\n return JSON.stringify(prevEditorState.read(() => prevNode.exportJSON())) === JSON.stringify(nextEditorState.read(() => nextNode.exportJSON()));\n }\n return false;\n}\nfunction createMergeActionGetter(editor, delay) {\n let prevChangeTime = Date.now();\n let prevChangeType = OTHER;\n return (prevEditorState, nextEditorState, currentHistoryEntry, dirtyLeaves, dirtyElements, tags) => {\n const changeTime = Date.now();\n\n // If applying changes from history stack there's no need\n // to run history logic again, as history entries already calculated\n if (tags.has('historic')) {\n prevChangeType = OTHER;\n prevChangeTime = changeTime;\n return DISCARD_HISTORY_CANDIDATE;\n }\n const changeType = getChangeType(prevEditorState, nextEditorState, dirtyLeaves, dirtyElements, editor.isComposing());\n const mergeAction = (() => {\n const isSameEditor = currentHistoryEntry === null || currentHistoryEntry.editor === editor;\n const shouldPushHistory = tags.has('history-push');\n const shouldMergeHistory = !shouldPushHistory && isSameEditor && tags.has('history-merge');\n if (shouldMergeHistory) {\n return HISTORY_MERGE;\n }\n if (prevEditorState === null) {\n return HISTORY_PUSH;\n }\n const selection = nextEditorState._selection;\n const hasDirtyNodes = dirtyLeaves.size > 0 || dirtyElements.size > 0;\n if (!hasDirtyNodes) {\n if (selection !== null) {\n return HISTORY_MERGE;\n }\n return DISCARD_HISTORY_CANDIDATE;\n }\n if (shouldPushHistory === false && changeType !== OTHER && changeType === prevChangeType && changeTime < prevChangeTime + delay && isSameEditor) {\n return HISTORY_MERGE;\n }\n\n // A single node might have been marked as dirty, but not have changed\n // due to some node transform reverting the change.\n if (dirtyLeaves.size === 1) {\n const dirtyLeafKey = Array.from(dirtyLeaves)[0];\n if (isTextNodeUnchanged(dirtyLeafKey, prevEditorState, nextEditorState)) {\n return HISTORY_MERGE;\n }\n }\n return HISTORY_PUSH;\n })();\n prevChangeTime = changeTime;\n prevChangeType = changeType;\n return mergeAction;\n };\n}\nfunction redo(editor, historyState) {\n const redoStack = historyState.redoStack;\n const undoStack = historyState.undoStack;\n if (redoStack.length !== 0) {\n const current = historyState.current;\n if (current !== null) {\n undoStack.push(current);\n editor.dispatchCommand(CAN_UNDO_COMMAND, true);\n }\n const historyStateEntry = redoStack.pop();\n if (redoStack.length === 0) {\n editor.dispatchCommand(CAN_REDO_COMMAND, false);\n }\n historyState.current = historyStateEntry || null;\n if (historyStateEntry) {\n historyStateEntry.editor.setEditorState(historyStateEntry.editorState, {\n tag: 'historic'\n });\n }\n }\n}\nfunction undo(editor, historyState) {\n const redoStack = historyState.redoStack;\n const undoStack = historyState.undoStack;\n const undoStackLength = undoStack.length;\n if (undoStackLength !== 0) {\n const current = historyState.current;\n const historyStateEntry = undoStack.pop();\n if (current !== null) {\n redoStack.push(current);\n editor.dispatchCommand(CAN_REDO_COMMAND, true);\n }\n if (undoStack.length === 0) {\n editor.dispatchCommand(CAN_UNDO_COMMAND, false);\n }\n historyState.current = historyStateEntry || null;\n if (historyStateEntry) {\n historyStateEntry.editor.setEditorState(historyStateEntry.editorState, {\n tag: 'historic'\n });\n }\n }\n}\nfunction clearHistory(historyState) {\n historyState.undoStack = [];\n historyState.redoStack = [];\n historyState.current = null;\n}\n\n/**\n * Registers necessary listeners to manage undo/redo history stack and related editor commands.\n * It returns `unregister` callback that cleans up all listeners and should be called on editor unmount.\n * @param editor - The lexical editor.\n * @param historyState - The history state, containing the current state and the undo/redo stack.\n * @param delay - The time (in milliseconds) the editor should delay generating a new history stack,\n * instead of merging the current changes with the current stack.\n * @returns The listeners cleanup callback function.\n */\nfunction registerHistory(editor, historyState, delay) {\n const getMergeAction = createMergeActionGetter(editor, delay);\n const applyChange = ({\n editorState,\n prevEditorState,\n dirtyLeaves,\n dirtyElements,\n tags\n }) => {\n const current = historyState.current;\n const redoStack = historyState.redoStack;\n const undoStack = historyState.undoStack;\n const currentEditorState = current === null ? null : current.editorState;\n if (current !== null && editorState === currentEditorState) {\n return;\n }\n const mergeAction = getMergeAction(prevEditorState, editorState, current, dirtyLeaves, dirtyElements, tags);\n if (mergeAction === HISTORY_PUSH) {\n if (redoStack.length !== 0) {\n historyState.redoStack = [];\n editor.dispatchCommand(CAN_REDO_COMMAND, false);\n }\n if (current !== null) {\n undoStack.push({\n ...current\n });\n editor.dispatchCommand(CAN_UNDO_COMMAND, true);\n }\n } else if (mergeAction === DISCARD_HISTORY_CANDIDATE) {\n return;\n }\n\n // Else we merge\n historyState.current = {\n editor,\n editorState\n };\n };\n const unregister = mergeRegister(editor.registerCommand(UNDO_COMMAND, () => {\n undo(editor, historyState);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(REDO_COMMAND, () => {\n redo(editor, historyState);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(CLEAR_EDITOR_COMMAND, () => {\n clearHistory(historyState);\n return false;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(CLEAR_HISTORY_COMMAND, () => {\n clearHistory(historyState);\n editor.dispatchCommand(CAN_REDO_COMMAND, false);\n editor.dispatchCommand(CAN_UNDO_COMMAND, false);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerUpdateListener(applyChange));\n return unregister;\n}\n\n/**\n * Creates an empty history state.\n * @returns - The empty history state, as an object.\n */\nfunction createEmptyHistoryState() {\n return {\n current: null,\n redoStack: [],\n undoStack: []\n };\n}\n\nexport { createEmptyHistoryState, registerHistory };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { $sliceSelectedTextNodeContent } from '@lexical/selection';\nimport { isHTMLElement, isBlockDomNode } from '@lexical/utils';\nimport { $getRoot, $isElementNode, $cloneWithProperties, $isTextNode, $isRootOrShadowRoot, $isBlockElementNode, $createLineBreakNode, ArtificialNode__DO_NOT_USE, isInlineDomNode, $createParagraphNode } from 'lexical';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n/**\n * How you parse your html string to get a document is left up to you. In the browser you can use the native\n * DOMParser API to generate a document (see clipboard.ts), but to use in a headless environment you can use JSDom\n * or an equivalent library and pass in the document here.\n */\nfunction $generateNodesFromDOM(editor, dom) {\n const elements = dom.body ? dom.body.childNodes : [];\n let lexicalNodes = [];\n const allArtificialNodes = [];\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n if (!IGNORE_TAGS.has(element.nodeName)) {\n const lexicalNode = $createNodesFromDOM(element, editor, allArtificialNodes, false);\n if (lexicalNode !== null) {\n lexicalNodes = lexicalNodes.concat(lexicalNode);\n }\n }\n }\n $unwrapArtificalNodes(allArtificialNodes);\n return lexicalNodes;\n}\nfunction $generateHtmlFromNodes(editor, selection) {\n if (typeof document === 'undefined' || typeof window === 'undefined' && typeof global.window === 'undefined') {\n throw new Error('To use $generateHtmlFromNodes in headless mode please initialize a headless browser implementation such as JSDom before calling this function.');\n }\n const container = document.createElement('div');\n const root = $getRoot();\n const topLevelChildren = root.getChildren();\n for (let i = 0; i < topLevelChildren.length; i++) {\n const topLevelNode = topLevelChildren[i];\n $appendNodesToHTML(editor, topLevelNode, container, selection);\n }\n return container.innerHTML;\n}\nfunction $appendNodesToHTML(editor, currentNode, parentElement, selection = null) {\n let shouldInclude = selection !== null ? currentNode.isSelected(selection) : true;\n const shouldExclude = $isElementNode(currentNode) && currentNode.excludeFromCopy('html');\n let target = currentNode;\n if (selection !== null) {\n let clone = $cloneWithProperties(currentNode);\n clone = $isTextNode(clone) && selection !== null ? $sliceSelectedTextNodeContent(selection, clone) : clone;\n target = clone;\n }\n const children = $isElementNode(target) ? target.getChildren() : [];\n const registeredNode = editor._nodes.get(target.getType());\n let exportOutput;\n\n // Use HTMLConfig overrides, if available.\n if (registeredNode && registeredNode.exportDOM !== undefined) {\n exportOutput = registeredNode.exportDOM(editor, target);\n } else {\n exportOutput = target.exportDOM(editor);\n }\n const {\n element,\n after\n } = exportOutput;\n if (!element) {\n return false;\n }\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < children.length; i++) {\n const childNode = children[i];\n const shouldIncludeChild = $appendNodesToHTML(editor, childNode, fragment, selection);\n if (!shouldInclude && $isElementNode(currentNode) && shouldIncludeChild && currentNode.extractWithChild(childNode, selection, 'html')) {\n shouldInclude = true;\n }\n }\n if (shouldInclude && !shouldExclude) {\n if (isHTMLElement(element)) {\n element.append(fragment);\n }\n parentElement.append(element);\n if (after) {\n const newElement = after.call(target, element);\n if (newElement) {\n element.replaceWith(newElement);\n }\n }\n } else {\n parentElement.append(fragment);\n }\n return shouldInclude;\n}\nfunction getConversionFunction(domNode, editor) {\n const {\n nodeName\n } = domNode;\n const cachedConversions = editor._htmlConversions.get(nodeName.toLowerCase());\n let currentConversion = null;\n if (cachedConversions !== undefined) {\n for (const cachedConversion of cachedConversions) {\n const domConversion = cachedConversion(domNode);\n if (domConversion !== null && (currentConversion === null || (currentConversion.priority || 0) < (domConversion.priority || 0))) {\n currentConversion = domConversion;\n }\n }\n }\n return currentConversion !== null ? currentConversion.conversion : null;\n}\nconst IGNORE_TAGS = new Set(['STYLE', 'SCRIPT']);\nfunction $createNodesFromDOM(node, editor, allArtificialNodes, hasBlockAncestorLexicalNode, forChildMap = new Map(), parentLexicalNode) {\n let lexicalNodes = [];\n if (IGNORE_TAGS.has(node.nodeName)) {\n return lexicalNodes;\n }\n let currentLexicalNode = null;\n const transformFunction = getConversionFunction(node, editor);\n const transformOutput = transformFunction ? transformFunction(node) : null;\n let postTransform = null;\n if (transformOutput !== null) {\n postTransform = transformOutput.after;\n const transformNodes = transformOutput.node;\n currentLexicalNode = Array.isArray(transformNodes) ? transformNodes[transformNodes.length - 1] : transformNodes;\n if (currentLexicalNode !== null) {\n for (const [, forChildFunction] of forChildMap) {\n currentLexicalNode = forChildFunction(currentLexicalNode, parentLexicalNode);\n if (!currentLexicalNode) {\n break;\n }\n }\n if (currentLexicalNode) {\n lexicalNodes.push(...(Array.isArray(transformNodes) ? transformNodes : [currentLexicalNode]));\n }\n }\n if (transformOutput.forChild != null) {\n forChildMap.set(node.nodeName, transformOutput.forChild);\n }\n }\n\n // If the DOM node doesn't have a transformer, we don't know what\n // to do with it but we still need to process any childNodes.\n const children = node.childNodes;\n let childLexicalNodes = [];\n const hasBlockAncestorLexicalNodeForChildren = currentLexicalNode != null && $isRootOrShadowRoot(currentLexicalNode) ? false : currentLexicalNode != null && $isBlockElementNode(currentLexicalNode) || hasBlockAncestorLexicalNode;\n for (let i = 0; i < children.length; i++) {\n childLexicalNodes.push(...$createNodesFromDOM(children[i], editor, allArtificialNodes, hasBlockAncestorLexicalNodeForChildren, new Map(forChildMap), currentLexicalNode));\n }\n if (postTransform != null) {\n childLexicalNodes = postTransform(childLexicalNodes);\n }\n if (isBlockDomNode(node)) {\n if (!hasBlockAncestorLexicalNodeForChildren) {\n childLexicalNodes = wrapContinuousInlines(node, childLexicalNodes, $createParagraphNode);\n } else {\n childLexicalNodes = wrapContinuousInlines(node, childLexicalNodes, () => {\n const artificialNode = new ArtificialNode__DO_NOT_USE();\n allArtificialNodes.push(artificialNode);\n return artificialNode;\n });\n }\n }\n if (currentLexicalNode == null) {\n if (childLexicalNodes.length > 0) {\n // If it hasn't been converted to a LexicalNode, we hoist its children\n // up to the same level as it.\n lexicalNodes = lexicalNodes.concat(childLexicalNodes);\n } else {\n if (isBlockDomNode(node) && isDomNodeBetweenTwoInlineNodes(node)) {\n // Empty block dom node that hasnt been converted, we replace it with a linebreak if its between inline nodes\n lexicalNodes = lexicalNodes.concat($createLineBreakNode());\n }\n }\n } else {\n if ($isElementNode(currentLexicalNode)) {\n // If the current node is a ElementNode after conversion,\n // we can append all the children to it.\n currentLexicalNode.append(...childLexicalNodes);\n }\n }\n return lexicalNodes;\n}\nfunction wrapContinuousInlines(domNode, nodes, createWrapperFn) {\n const textAlign = domNode.style.textAlign;\n const out = [];\n let continuousInlines = [];\n // wrap contiguous inline child nodes in para\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n if ($isBlockElementNode(node)) {\n if (textAlign && !node.getFormat()) {\n node.setFormat(textAlign);\n }\n out.push(node);\n } else {\n continuousInlines.push(node);\n if (i === nodes.length - 1 || i < nodes.length - 1 && $isBlockElementNode(nodes[i + 1])) {\n const wrapper = createWrapperFn();\n wrapper.setFormat(textAlign);\n wrapper.append(...continuousInlines);\n out.push(wrapper);\n continuousInlines = [];\n }\n }\n }\n return out;\n}\nfunction $unwrapArtificalNodes(allArtificialNodes) {\n for (const node of allArtificialNodes) {\n if (node.getNextSibling() instanceof ArtificialNode__DO_NOT_USE) {\n node.insertAfter($createLineBreakNode());\n }\n }\n // Replace artificial node with it's children\n for (const node of allArtificialNodes) {\n const children = node.getChildren();\n for (const child of children) {\n node.insertBefore(child);\n }\n node.remove();\n }\n}\nfunction isDomNodeBetweenTwoInlineNodes(node) {\n if (node.nextSibling == null || node.previousSibling == null) {\n return false;\n }\n return isInlineDomNode(node.nextSibling) && isInlineDomNode(node.previousSibling);\n}\n\nexport { $generateHtmlFromNodes, $generateNodesFromDOM };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { $insertDataTransferForPlainText, $getHtmlContent } from '@lexical/clipboard';\nimport { $shouldOverrideDefaultCharacterSelection, $moveCharacter } from '@lexical/selection';\nimport { mergeRegister, objectKlassEquals } from '@lexical/utils';\nimport { DELETE_CHARACTER_COMMAND, $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, DELETE_WORD_COMMAND, DELETE_LINE_COMMAND, CONTROLLED_TEXT_INSERTION_COMMAND, REMOVE_TEXT_COMMAND, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, SELECT_ALL_COMMAND, $selectAll, COPY_COMMAND, CUT_COMMAND, PASTE_COMMAND, DROP_COMMAND, DRAGSTART_COMMAND } from 'lexical';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst documentMode = CAN_USE_DOM && 'documentMode' in document ? document.documentMode : null;\nconst CAN_USE_BEFORE_INPUT = CAN_USE_DOM && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;\nconst IS_SAFARI = CAN_USE_DOM && /Version\\/[\\d.]+.*Safari/.test(navigator.userAgent);\nconst IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n\n// Keep these in case we need to use them in the future.\n// export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);\nconst IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent);\nconst IS_APPLE_WEBKIT = CAN_USE_DOM && /AppleWebKit\\/[\\d.]+/.test(navigator.userAgent) && !IS_CHROME;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction onCopyForPlainText(event, editor) {\n editor.update(() => {\n if (event !== null) {\n const clipboardData = objectKlassEquals(event, KeyboardEvent) ? null : event.clipboardData;\n const selection = $getSelection();\n if (selection !== null && clipboardData != null) {\n event.preventDefault();\n const htmlString = $getHtmlContent(editor);\n if (htmlString !== null) {\n clipboardData.setData('text/html', htmlString);\n }\n clipboardData.setData('text/plain', selection.getTextContent());\n }\n }\n });\n}\nfunction onPasteForPlainText(event, editor) {\n event.preventDefault();\n editor.update(() => {\n const selection = $getSelection();\n const {\n clipboardData\n } = event;\n if (clipboardData != null && $isRangeSelection(selection)) {\n $insertDataTransferForPlainText(clipboardData, selection);\n }\n }, {\n tag: 'paste'\n });\n}\nfunction onCutForPlainText(event, editor) {\n onCopyForPlainText(event, editor);\n editor.update(() => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n selection.removeText();\n }\n });\n}\nfunction registerPlainText(editor) {\n const removeListener = mergeRegister(editor.registerCommand(DELETE_CHARACTER_COMMAND, isBackward => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n selection.deleteCharacter(isBackward);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(DELETE_WORD_COMMAND, isBackward => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n selection.deleteWord(isBackward);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(DELETE_LINE_COMMAND, isBackward => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n selection.deleteLine(isBackward);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(CONTROLLED_TEXT_INSERTION_COMMAND, eventOrText => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n if (typeof eventOrText === 'string') {\n selection.insertText(eventOrText);\n } else {\n const dataTransfer = eventOrText.dataTransfer;\n if (dataTransfer != null) {\n $insertDataTransferForPlainText(dataTransfer, selection);\n } else {\n const data = eventOrText.data;\n if (data) {\n selection.insertText(data);\n }\n }\n }\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(REMOVE_TEXT_COMMAND, () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n selection.removeText();\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(INSERT_LINE_BREAK_COMMAND, selectStart => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n selection.insertLineBreak(selectStart);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(INSERT_PARAGRAPH_COMMAND, () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n selection.insertLineBreak();\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(KEY_ARROW_LEFT_COMMAND, payload => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n const event = payload;\n const isHoldingShift = event.shiftKey;\n if ($shouldOverrideDefaultCharacterSelection(selection, true)) {\n event.preventDefault();\n $moveCharacter(selection, isHoldingShift, true);\n return true;\n }\n return false;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(KEY_ARROW_RIGHT_COMMAND, payload => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n const event = payload;\n const isHoldingShift = event.shiftKey;\n if ($shouldOverrideDefaultCharacterSelection(selection, false)) {\n event.preventDefault();\n $moveCharacter(selection, isHoldingShift, false);\n return true;\n }\n return false;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(KEY_BACKSPACE_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n event.preventDefault();\n return editor.dispatchCommand(DELETE_CHARACTER_COMMAND, true);\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(KEY_DELETE_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n event.preventDefault();\n return editor.dispatchCommand(DELETE_CHARACTER_COMMAND, false);\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(KEY_ENTER_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n if (event !== null) {\n // If we have beforeinput, then we can avoid blocking\n // the default behavior. This ensures that the iOS can\n // intercept that we're actually inserting a paragraph,\n // and autocomplete, autocapitalize etc work as intended.\n // This can also cause a strange performance issue in\n // Safari, where there is a noticeable pause due to\n // preventing the key down of enter.\n if ((IS_IOS || IS_SAFARI || IS_APPLE_WEBKIT) && CAN_USE_BEFORE_INPUT) {\n return false;\n }\n event.preventDefault();\n }\n return editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND, false);\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SELECT_ALL_COMMAND, () => {\n $selectAll();\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(COPY_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n onCopyForPlainText(event, editor);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(CUT_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n onCutForPlainText(event, editor);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(PASTE_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n onPasteForPlainText(event, editor);\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(DROP_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n\n // TODO: Make drag and drop work at some point.\n event.preventDefault();\n return true;\n }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(DRAGSTART_COMMAND, event => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n\n // TODO: Make drag and drop work at some point.\n event.preventDefault();\n return true;\n }, COMMAND_PRIORITY_EDITOR));\n return removeListener;\n}\n\nexport { registerPlainText };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { useEffect } from 'react';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction AutoFocusPlugin({\n defaultSelection\n}) {\n const [editor] = useLexicalComposerContext();\n useEffect(() => {\n editor.focus(() => {\n // If we try and move selection to the same point with setBaseAndExtent, it won't\n // trigger a re-focus on the element. So in the case this occurs, we'll need to correct it.\n // Normally this is fine, Selection API !== Focus API, but fore the intents of the naming\n // of this plugin, which should preserve focus too.\n const activeElement = document.activeElement;\n const rootElement = editor.getRootElement();\n if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {\n // Note: preventScroll won't work in Webkit.\n rootElement.focus({\n preventScroll: true\n });\n }\n }, {\n defaultSelection\n });\n }, [defaultSelection, editor]);\n return null;\n}\n\nexport { AutoFocusPlugin };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { createLexicalComposerContext, LexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { createEditor, $getRoot, $createParagraphNode, $getSelection } from 'lexical';\nimport { useLayoutEffect, useEffect, useMemo } from 'react';\nimport { jsx } from 'react/jsx-runtime';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// This workaround is no longer necessary in React 19,\n// but we currently support React >=17.x\n// https://github.com/facebook/react/pull/26395\nconst useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect : useEffect;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst HISTORY_MERGE_OPTIONS = {\n tag: 'history-merge'\n};\nfunction LexicalComposer({\n initialConfig,\n children\n}) {\n const composerContext = useMemo(() => {\n const {\n theme,\n namespace,\n nodes,\n onError,\n editorState: initialEditorState,\n html\n } = initialConfig;\n const context = createLexicalComposerContext(null, theme);\n const editor = createEditor({\n editable: initialConfig.editable,\n html,\n namespace,\n nodes,\n onError: error => onError(error, editor),\n theme\n });\n initializeEditor(editor, initialEditorState);\n return [editor, context];\n },\n // We only do this for init\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []);\n useLayoutEffectImpl(() => {\n const isEditable = initialConfig.editable;\n const [editor] = composerContext;\n editor.setEditable(isEditable !== undefined ? isEditable : true);\n\n // We only do this for init\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n return /*#__PURE__*/jsx(LexicalComposerContext.Provider, {\n value: composerContext,\n children: children\n });\n}\nfunction initializeEditor(editor, initialEditorState) {\n if (initialEditorState === null) {\n return;\n } else if (initialEditorState === undefined) {\n editor.update(() => {\n const root = $getRoot();\n if (root.isEmpty()) {\n const paragraph = $createParagraphNode();\n root.append(paragraph);\n const activeElement = CAN_USE_DOM ? document.activeElement : null;\n if ($getSelection() !== null || activeElement !== null && activeElement === editor.getRootElement()) {\n paragraph.select();\n }\n }\n }, HISTORY_MERGE_OPTIONS);\n } else if (initialEditorState !== null) {\n switch (typeof initialEditorState) {\n case 'string':\n {\n const parsedEditorState = editor.parseEditorState(initialEditorState);\n editor.setEditorState(parsedEditorState, HISTORY_MERGE_OPTIONS);\n break;\n }\n case 'object':\n {\n editor.setEditorState(initialEditorState, HISTORY_MERGE_OPTIONS);\n break;\n }\n case 'function':\n {\n editor.update(() => {\n const root = $getRoot();\n if (root.isEmpty()) {\n initialEditorState(editor);\n }\n }, HISTORY_MERGE_OPTIONS);\n break;\n }\n }\n }\n}\n\nexport { LexicalComposer };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { createContext, useContext } from 'react';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst LexicalComposerContext = /*#__PURE__*/createContext(null);\nfunction createLexicalComposerContext(parent, theme) {\n let parentContext = null;\n if (parent != null) {\n parentContext = parent[1];\n }\n function getTheme() {\n if (theme != null) {\n return theme;\n }\n return parentContext != null ? parentContext.getTheme() : null;\n }\n return {\n getTheme\n };\n}\nfunction useLexicalComposerContext() {\n const composerContext = useContext(LexicalComposerContext);\n if (composerContext == null) {\n {\n throw Error(`LexicalComposerContext.useLexicalComposerContext: cannot find a LexicalComposerContext`);\n }\n }\n return composerContext;\n}\n\nexport { LexicalComposerContext, createLexicalComposerContext, useLexicalComposerContext };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { useLayoutEffect, useEffect, forwardRef, useState, useCallback, useMemo } from 'react';\nimport { jsx, jsxs, Fragment } from 'react/jsx-runtime';\nimport { $canShowPlaceholderCurry } from '@lexical/text';\nimport { mergeRegister } from '@lexical/utils';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// This workaround is no longer necessary in React 19,\n// but we currently support React >=17.x\n// https://github.com/facebook/react/pull/26395\nconst useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect : useEffect;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n// Source: https://github.com/gregberge/react-merge-refs/blob/main/src/index.tsx\n\nfunction mergeRefs(...refs) {\n return value => {\n refs.forEach(ref => {\n if (typeof ref === 'function') {\n ref(value);\n } else if (ref != null) {\n ref.current = value;\n }\n });\n };\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction ContentEditableElementImpl({\n editor,\n ariaActiveDescendant,\n ariaAutoComplete,\n ariaControls,\n ariaDescribedBy,\n ariaExpanded,\n ariaLabel,\n ariaLabelledBy,\n ariaMultiline,\n ariaOwns,\n ariaRequired,\n autoCapitalize,\n className,\n id,\n role = 'textbox',\n spellCheck = true,\n style,\n tabIndex,\n 'data-testid': testid,\n ...rest\n}, ref) {\n const [isEditable, setEditable] = useState(editor.isEditable());\n const handleRef = useCallback(rootElement => {\n // defaultView is required for a root element.\n // In multi-window setups, the defaultView may not exist at certain points.\n if (rootElement && rootElement.ownerDocument && rootElement.ownerDocument.defaultView) {\n editor.setRootElement(rootElement);\n } else {\n editor.setRootElement(null);\n }\n }, [editor]);\n const mergedRefs = useMemo(() => mergeRefs(ref, handleRef), [handleRef, ref]);\n useLayoutEffectImpl(() => {\n setEditable(editor.isEditable());\n return editor.registerEditableListener(currentIsEditable => {\n setEditable(currentIsEditable);\n });\n }, [editor]);\n return /*#__PURE__*/jsx(\"div\", {\n ...rest,\n \"aria-activedescendant\": isEditable ? ariaActiveDescendant : undefined,\n \"aria-autocomplete\": isEditable ? ariaAutoComplete : 'none',\n \"aria-controls\": isEditable ? ariaControls : undefined,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-expanded\": isEditable && role === 'combobox' ? !!ariaExpanded : undefined,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-multiline\": ariaMultiline,\n \"aria-owns\": isEditable ? ariaOwns : undefined,\n \"aria-readonly\": isEditable ? undefined : true,\n \"aria-required\": ariaRequired,\n autoCapitalize: autoCapitalize,\n className: className,\n contentEditable: isEditable,\n \"data-testid\": testid,\n id: id,\n ref: mergedRefs,\n role: isEditable ? role : undefined,\n spellCheck: spellCheck,\n style: style,\n tabIndex: tabIndex\n });\n}\nconst ContentEditableElement = /*#__PURE__*/forwardRef(ContentEditableElementImpl);\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction canShowPlaceholderFromCurrentEditorState(editor) {\n const currentCanShowPlaceholder = editor.getEditorState().read($canShowPlaceholderCurry(editor.isComposing()));\n return currentCanShowPlaceholder;\n}\nfunction useCanShowPlaceholder(editor) {\n const [canShowPlaceholder, setCanShowPlaceholder] = useState(() => canShowPlaceholderFromCurrentEditorState(editor));\n useLayoutEffectImpl(() => {\n function resetCanShowPlaceholder() {\n const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);\n setCanShowPlaceholder(currentCanShowPlaceholder);\n }\n resetCanShowPlaceholder();\n return mergeRegister(editor.registerUpdateListener(() => {\n resetCanShowPlaceholder();\n }), editor.registerEditableListener(() => {\n resetCanShowPlaceholder();\n }));\n }, [editor]);\n return canShowPlaceholder;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst ContentEditable = /*#__PURE__*/forwardRef(ContentEditableImpl);\nfunction ContentEditableImpl(props, ref) {\n const {\n placeholder,\n ...rest\n } = props;\n const [editor] = useLexicalComposerContext();\n return /*#__PURE__*/jsxs(Fragment, {\n children: [/*#__PURE__*/jsx(ContentEditableElement, {\n editor: editor,\n ...rest,\n ref: ref\n }), placeholder != null && /*#__PURE__*/jsx(Placeholder, {\n editor: editor,\n content: placeholder\n })]\n });\n}\nfunction Placeholder({\n content,\n editor\n}) {\n const showPlaceholder = useCanShowPlaceholder(editor);\n const [isEditable, setEditable] = useState(editor.isEditable());\n useLayoutEffect(() => {\n setEditable(editor.isEditable());\n return editor.registerEditableListener(currentIsEditable => {\n setEditable(currentIsEditable);\n });\n }, [editor]);\n if (!showPlaceholder) {\n return null;\n }\n let placeholder = null;\n if (typeof content === 'function') {\n placeholder = content(isEditable);\n } else if (content !== null) {\n placeholder = content;\n }\n if (placeholder === null) {\n return null;\n }\n return /*#__PURE__*/jsx(\"div\", {\n \"aria-hidden\": true,\n children: placeholder\n });\n}\n\nexport { ContentEditable };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport * as React from 'react';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n/**\n *\n * Use this plugin to access the editor instance outside of the\n * LexicalComposer. This can help with things like buttons or other\n * UI components that need to update or read EditorState but need to\n * be positioned outside the LexicalComposer in the React tree.\n */\nfunction EditorRefPlugin({\n editorRef\n}) {\n const [editor] = useLexicalComposerContext();\n React.useEffect(() => {\n if (typeof editorRef === 'function') {\n editorRef(editor);\n } else if (typeof editorRef === 'object') {\n editorRef.current = editor;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editor]);\n return null;\n}\n\nexport { EditorRefPlugin };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport * as React from 'react';\nimport { jsx } from 'react/jsx-runtime';\n\nfunction _setPrototypeOf(o, p) {\n _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n return _setPrototypeOf(o, p);\n}\n\nfunction _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n _setPrototypeOf(subClass, superClass);\n}\n\nvar changedArray = function changedArray(a, b) {\n if (a === void 0) {\n a = [];\n }\n\n if (b === void 0) {\n b = [];\n }\n\n return a.length !== b.length || a.some(function (item, index) {\n return !Object.is(item, b[index]);\n });\n};\n\nvar initialState = {\n error: null\n};\n\nvar ErrorBoundary = /*#__PURE__*/function (_React$Component) {\n _inheritsLoose(ErrorBoundary, _React$Component);\n\n function ErrorBoundary() {\n var _this;\n\n for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {\n _args[_key] = arguments[_key];\n }\n\n _this = _React$Component.call.apply(_React$Component, [this].concat(_args)) || this;\n _this.state = initialState;\n\n _this.resetErrorBoundary = function () {\n var _this$props;\n\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n _this.props.onReset == null ? void 0 : (_this$props = _this.props).onReset.apply(_this$props, args);\n\n _this.reset();\n };\n\n return _this;\n }\n\n ErrorBoundary.getDerivedStateFromError = function getDerivedStateFromError(error) {\n return {\n error: error\n };\n };\n\n var _proto = ErrorBoundary.prototype;\n\n _proto.reset = function reset() {\n this.setState(initialState);\n };\n\n _proto.componentDidCatch = function componentDidCatch(error, info) {\n var _this$props$onError, _this$props2;\n\n (_this$props$onError = (_this$props2 = this.props).onError) == null ? void 0 : _this$props$onError.call(_this$props2, error, info);\n };\n\n _proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {\n var error = this.state.error;\n var resetKeys = this.props.resetKeys; // There's an edge case where if the thing that triggered the error\n // happens to *also* be in the resetKeys array, we'd end up resetting\n // the error boundary immediately. This would likely trigger a second\n // error to be thrown.\n // So we make sure that we don't check the resetKeys on the first call\n // of cDU after the error is set\n\n if (error !== null && prevState.error !== null && changedArray(prevProps.resetKeys, resetKeys)) {\n var _this$props$onResetKe, _this$props3;\n\n (_this$props$onResetKe = (_this$props3 = this.props).onResetKeysChange) == null ? void 0 : _this$props$onResetKe.call(_this$props3, prevProps.resetKeys, resetKeys);\n this.reset();\n }\n };\n\n _proto.render = function render() {\n var error = this.state.error;\n var _this$props4 = this.props,\n fallbackRender = _this$props4.fallbackRender,\n FallbackComponent = _this$props4.FallbackComponent,\n fallback = _this$props4.fallback;\n\n if (error !== null) {\n var _props = {\n error: error,\n resetErrorBoundary: this.resetErrorBoundary\n };\n\n if ( /*#__PURE__*/React.isValidElement(fallback)) {\n return fallback;\n } else if (typeof fallbackRender === 'function') {\n return fallbackRender(_props);\n } else if (FallbackComponent) {\n return /*#__PURE__*/React.createElement(FallbackComponent, _props);\n } else {\n throw new Error('react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop');\n }\n }\n\n return this.props.children;\n };\n\n return ErrorBoundary;\n}(React.Component);\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction LexicalErrorBoundary({\n children,\n onError\n}) {\n return /*#__PURE__*/jsx(ErrorBoundary, {\n fallback: /*#__PURE__*/jsx(\"div\", {\n style: {\n border: '1px solid #f00',\n color: '#f00',\n padding: '8px'\n },\n children: \"An error was thrown.\"\n }),\n onError: onError,\n children: children\n });\n}\n\nexport { LexicalErrorBoundary, LexicalErrorBoundary as default };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { createEmptyHistoryState, registerHistory } from '@lexical/history';\nexport { createEmptyHistoryState } from '@lexical/history';\nimport { useMemo, useEffect } from 'react';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction useHistory(editor, externalHistoryState, delay = 1000) {\n const historyState = useMemo(() => externalHistoryState || createEmptyHistoryState(), [externalHistoryState]);\n useEffect(() => {\n return registerHistory(editor, historyState, delay);\n }, [delay, editor, historyState]);\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction HistoryPlugin({\n delay,\n externalHistoryState\n}) {\n const [editor] = useLexicalComposerContext();\n useHistory(editor, externalHistoryState, delay);\n return null;\n}\n\nexport { HistoryPlugin };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { useLayoutEffect, useEffect } from 'react';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// This workaround is no longer necessary in React 19,\n// but we currently support React >=17.x\n// https://github.com/facebook/react/pull/26395\nconst useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect : useEffect;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction OnChangePlugin({\n ignoreHistoryMergeTagChange = true,\n ignoreSelectionChange = false,\n onChange\n}) {\n const [editor] = useLexicalComposerContext();\n useLayoutEffectImpl(() => {\n if (onChange) {\n return editor.registerUpdateListener(({\n editorState,\n dirtyElements,\n dirtyLeaves,\n prevEditorState,\n tags\n }) => {\n if (ignoreSelectionChange && dirtyElements.size === 0 && dirtyLeaves.size === 0 || ignoreHistoryMergeTagChange && tags.has('history-merge') || prevEditorState.isEmpty()) {\n return;\n }\n onChange(editorState, editor, tags);\n });\n }\n }, [editor, ignoreHistoryMergeTagChange, ignoreSelectionChange, onChange]);\n return null;\n}\n\nexport { OnChangePlugin };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { useLexicalEditable } from '@lexical/react/useLexicalEditable';\nimport { $canShowPlaceholderCurry } from '@lexical/text';\nimport { mergeRegister } from '@lexical/utils';\nimport { useLayoutEffect, useEffect, useState, useMemo, Suspense } from 'react';\nimport { flushSync, createPortal } from 'react-dom';\nimport { jsx, jsxs, Fragment } from 'react/jsx-runtime';\nimport { registerDragonSupport } from '@lexical/dragon';\nimport { registerPlainText } from '@lexical/plain-text';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// This workaround is no longer necessary in React 19,\n// but we currently support React >=17.x\n// https://github.com/facebook/react/pull/26395\nconst useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect : useEffect;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction canShowPlaceholderFromCurrentEditorState(editor) {\n const currentCanShowPlaceholder = editor.getEditorState().read($canShowPlaceholderCurry(editor.isComposing()));\n return currentCanShowPlaceholder;\n}\nfunction useCanShowPlaceholder(editor) {\n const [canShowPlaceholder, setCanShowPlaceholder] = useState(() => canShowPlaceholderFromCurrentEditorState(editor));\n useLayoutEffectImpl(() => {\n function resetCanShowPlaceholder() {\n const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);\n setCanShowPlaceholder(currentCanShowPlaceholder);\n }\n resetCanShowPlaceholder();\n return mergeRegister(editor.registerUpdateListener(() => {\n resetCanShowPlaceholder();\n }), editor.registerEditableListener(() => {\n resetCanShowPlaceholder();\n }));\n }, [editor]);\n return canShowPlaceholder;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction useDecorators(editor, ErrorBoundary) {\n const [decorators, setDecorators] = useState(() => editor.getDecorators());\n\n // Subscribe to changes\n useLayoutEffectImpl(() => {\n return editor.registerDecoratorListener(nextDecorators => {\n flushSync(() => {\n setDecorators(nextDecorators);\n });\n });\n }, [editor]);\n useEffect(() => {\n // If the content editable mounts before the subscription is added, then\n // nothing will be rendered on initial pass. We can get around that by\n // ensuring that we set the value.\n setDecorators(editor.getDecorators());\n }, [editor]);\n\n // Return decorators defined as React Portals\n return useMemo(() => {\n const decoratedPortals = [];\n const decoratorKeys = Object.keys(decorators);\n for (let i = 0; i < decoratorKeys.length; i++) {\n const nodeKey = decoratorKeys[i];\n const reactDecorator = /*#__PURE__*/jsx(ErrorBoundary, {\n onError: e => editor._onError(e),\n children: /*#__PURE__*/jsx(Suspense, {\n fallback: null,\n children: decorators[nodeKey]\n })\n });\n const element = editor.getElementByKey(nodeKey);\n if (element !== null) {\n decoratedPortals.push( /*#__PURE__*/createPortal(reactDecorator, element, nodeKey));\n }\n }\n return decoratedPortals;\n }, [ErrorBoundary, decorators, editor]);\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction usePlainTextSetup(editor) {\n useLayoutEffectImpl(() => {\n return mergeRegister(registerPlainText(editor), registerDragonSupport(editor));\n\n // We only do this for init\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editor]);\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction PlainTextPlugin({\n contentEditable,\n // TODO Remove. This property is now part of ContentEditable\n placeholder = null,\n ErrorBoundary\n}) {\n const [editor] = useLexicalComposerContext();\n const decorators = useDecorators(editor, ErrorBoundary);\n usePlainTextSetup(editor);\n return /*#__PURE__*/jsxs(Fragment, {\n children: [contentEditable, /*#__PURE__*/jsx(Placeholder, {\n content: placeholder\n }), decorators]\n });\n}\n\n// TODO Remove\nfunction Placeholder({\n content\n}) {\n const [editor] = useLexicalComposerContext();\n const showPlaceholder = useCanShowPlaceholder(editor);\n const editable = useLexicalEditable();\n if (!showPlaceholder) {\n return null;\n }\n if (typeof content === 'function') {\n return content(editable);\n } else {\n return content;\n }\n}\n\nexport { PlainTextPlugin };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { createCommand, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $isTextNode } from 'lexical';\nimport React, { useLayoutEffect, useEffect, useState, useCallback, useMemo, useRef } from 'react';\nimport { mergeRegister } from '@lexical/utils';\nimport { jsx } from 'react/jsx-runtime';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// Webpack + React 17 fails to compile on the usage of `React.startTransition` or\n// `React[\"startTransition\"]` even if it's behind a feature detection of\n// `\"startTransition\" in React`. Moving this to a constant avoids the issue :/\nconst START_TRANSITION = 'startTransition';\nfunction startTransition(callback) {\n if (START_TRANSITION in React) {\n React[START_TRANSITION](callback);\n } else {\n callback();\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// This workaround is no longer necessary in React 19,\n// but we currently support React >=17.x\n// https://github.com/facebook/react/pull/26395\nconst useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect : useEffect;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nclass MenuOption {\n constructor(key) {\n this.key = key;\n this.ref = {\n current: null\n };\n this.setRefElement = this.setRefElement.bind(this);\n }\n setRefElement(element) {\n this.ref = {\n current: element\n };\n }\n}\nconst scrollIntoViewIfNeeded = target => {\n const typeaheadContainerNode = document.getElementById('typeahead-menu');\n if (!typeaheadContainerNode) {\n return;\n }\n const typeaheadRect = typeaheadContainerNode.getBoundingClientRect();\n if (typeaheadRect.top + typeaheadRect.height > window.innerHeight) {\n typeaheadContainerNode.scrollIntoView({\n block: 'center'\n });\n }\n if (typeaheadRect.top < 0) {\n typeaheadContainerNode.scrollIntoView({\n block: 'center'\n });\n }\n target.scrollIntoView({\n block: 'nearest'\n });\n};\n\n/**\n * Walk backwards along user input and forward through entity title to try\n * and replace more of the user's text with entity.\n */\nfunction getFullMatchOffset(documentText, entryText, offset) {\n let triggerOffset = offset;\n for (let i = triggerOffset; i <= entryText.length; i++) {\n if (documentText.substr(-i) === entryText.substr(0, i)) {\n triggerOffset = i;\n }\n }\n return triggerOffset;\n}\n\n/**\n * Split Lexical TextNode and return a new TextNode only containing matched text.\n * Common use cases include: removing the node, replacing with a new node.\n */\nfunction $splitNodeContainingQuery(match) {\n const selection = $getSelection();\n if (!$isRangeSelection(selection) || !selection.isCollapsed()) {\n return null;\n }\n const anchor = selection.anchor;\n if (anchor.type !== 'text') {\n return null;\n }\n const anchorNode = anchor.getNode();\n if (!anchorNode.isSimpleText()) {\n return null;\n }\n const selectionOffset = anchor.offset;\n const textContent = anchorNode.getTextContent().slice(0, selectionOffset);\n const characterOffset = match.replaceableString.length;\n const queryOffset = getFullMatchOffset(textContent, match.matchingString, characterOffset);\n const startOffset = selectionOffset - queryOffset;\n if (startOffset < 0) {\n return null;\n }\n let newNode;\n if (startOffset === 0) {\n [newNode] = anchorNode.splitText(selectionOffset);\n } else {\n [, newNode] = anchorNode.splitText(startOffset, selectionOffset);\n }\n return newNode;\n}\n\n// Got from https://stackoverflow.com/a/42543908/2013580\nfunction getScrollParent$1(element, includeHidden) {\n let style = getComputedStyle(element);\n const excludeStaticParent = style.position === 'absolute';\n const overflowRegex = /(auto|scroll)/;\n if (style.position === 'fixed') {\n return document.body;\n }\n for (let parent = element; parent = parent.parentElement;) {\n style = getComputedStyle(parent);\n if (excludeStaticParent && style.position === 'static') {\n continue;\n }\n if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {\n return parent;\n }\n }\n return document.body;\n}\nfunction isTriggerVisibleInNearestScrollContainer(targetElement, containerElement) {\n const tRect = targetElement.getBoundingClientRect();\n const cRect = containerElement.getBoundingClientRect();\n return tRect.top > cRect.top && tRect.top < cRect.bottom;\n}\n\n// Reposition the menu on scroll, window resize, and element resize.\nfunction useDynamicPositioning(resolution, targetElement, onReposition, onVisibilityChange) {\n const [editor] = useLexicalComposerContext();\n useEffect(() => {\n if (targetElement != null && resolution != null) {\n const rootElement = editor.getRootElement();\n const rootScrollParent = rootElement != null ? getScrollParent$1(rootElement) : document.body;\n let ticking = false;\n let previousIsInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);\n const handleScroll = function () {\n if (!ticking) {\n window.requestAnimationFrame(function () {\n onReposition();\n ticking = false;\n });\n ticking = true;\n }\n const isInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);\n if (isInView !== previousIsInView) {\n previousIsInView = isInView;\n if (onVisibilityChange != null) {\n onVisibilityChange(isInView);\n }\n }\n };\n const resizeObserver = new ResizeObserver(onReposition);\n window.addEventListener('resize', onReposition);\n document.addEventListener('scroll', handleScroll, {\n capture: true,\n passive: true\n });\n resizeObserver.observe(targetElement);\n return () => {\n resizeObserver.unobserve(targetElement);\n window.removeEventListener('resize', onReposition);\n document.removeEventListener('scroll', handleScroll, true);\n };\n }\n }, [targetElement, editor, onVisibilityChange, onReposition, resolution]);\n}\nconst SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND$1 = createCommand('SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND');\nfunction LexicalMenu({\n close,\n editor,\n anchorElementRef,\n resolution,\n options,\n menuRenderFn,\n onSelectOption,\n shouldSplitNodeWithQuery = false,\n commandPriority = COMMAND_PRIORITY_LOW\n}) {\n const [selectedIndex, setHighlightedIndex] = useState(null);\n const matchingString = resolution.match && resolution.match.matchingString;\n useEffect(() => {\n setHighlightedIndex(0);\n }, [matchingString]);\n const selectOptionAndCleanUp = useCallback(selectedEntry => {\n editor.update(() => {\n const textNodeContainingQuery = resolution.match != null && shouldSplitNodeWithQuery ? $splitNodeContainingQuery(resolution.match) : null;\n onSelectOption(selectedEntry, textNodeContainingQuery, close, resolution.match ? resolution.match.matchingString : '');\n });\n }, [editor, shouldSplitNodeWithQuery, resolution.match, onSelectOption, close]);\n const updateSelectedIndex = useCallback(index => {\n const rootElem = editor.getRootElement();\n if (rootElem !== null) {\n rootElem.setAttribute('aria-activedescendant', 'typeahead-item-' + index);\n setHighlightedIndex(index);\n }\n }, [editor]);\n useEffect(() => {\n return () => {\n const rootElem = editor.getRootElement();\n if (rootElem !== null) {\n rootElem.removeAttribute('aria-activedescendant');\n }\n };\n }, [editor]);\n useLayoutEffectImpl(() => {\n if (options === null) {\n setHighlightedIndex(null);\n } else if (selectedIndex === null) {\n updateSelectedIndex(0);\n }\n }, [options, selectedIndex, updateSelectedIndex]);\n useEffect(() => {\n return mergeRegister(editor.registerCommand(SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND$1, ({\n option\n }) => {\n if (option.ref && option.ref.current != null) {\n scrollIntoViewIfNeeded(option.ref.current);\n return true;\n }\n return false;\n }, commandPriority));\n }, [editor, updateSelectedIndex, commandPriority]);\n useEffect(() => {\n return mergeRegister(editor.registerCommand(KEY_ARROW_DOWN_COMMAND, payload => {\n const event = payload;\n if (options !== null && options.length && selectedIndex !== null) {\n const newSelectedIndex = selectedIndex !== options.length - 1 ? selectedIndex + 1 : 0;\n updateSelectedIndex(newSelectedIndex);\n const option = options[newSelectedIndex];\n if (option.ref != null && option.ref.current) {\n editor.dispatchCommand(SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND$1, {\n index: newSelectedIndex,\n option\n });\n }\n event.preventDefault();\n event.stopImmediatePropagation();\n }\n return true;\n }, commandPriority), editor.registerCommand(KEY_ARROW_UP_COMMAND, payload => {\n const event = payload;\n if (options !== null && options.length && selectedIndex !== null) {\n const newSelectedIndex = selectedIndex !== 0 ? selectedIndex - 1 : options.length - 1;\n updateSelectedIndex(newSelectedIndex);\n const option = options[newSelectedIndex];\n if (option.ref != null && option.ref.current) {\n scrollIntoViewIfNeeded(option.ref.current);\n }\n event.preventDefault();\n event.stopImmediatePropagation();\n }\n return true;\n }, commandPriority), editor.registerCommand(KEY_ESCAPE_COMMAND, payload => {\n const event = payload;\n event.preventDefault();\n event.stopImmediatePropagation();\n close();\n return true;\n }, commandPriority), editor.registerCommand(KEY_TAB_COMMAND, payload => {\n const event = payload;\n if (options === null || selectedIndex === null || options[selectedIndex] == null) {\n return false;\n }\n event.preventDefault();\n event.stopImmediatePropagation();\n selectOptionAndCleanUp(options[selectedIndex]);\n return true;\n }, commandPriority), editor.registerCommand(KEY_ENTER_COMMAND, event => {\n if (options === null || selectedIndex === null || options[selectedIndex] == null) {\n return false;\n }\n if (event !== null) {\n event.preventDefault();\n event.stopImmediatePropagation();\n }\n selectOptionAndCleanUp(options[selectedIndex]);\n return true;\n }, commandPriority));\n }, [selectOptionAndCleanUp, close, editor, options, selectedIndex, updateSelectedIndex, commandPriority]);\n const listItemProps = useMemo(() => ({\n options,\n selectOptionAndCleanUp,\n selectedIndex,\n setHighlightedIndex\n }), [selectOptionAndCleanUp, selectedIndex, options]);\n return menuRenderFn(anchorElementRef, listItemProps, resolution.match ? resolution.match.matchingString : '');\n}\nfunction useMenuAnchorRef(resolution, setResolution, className, parent = document.body) {\n const [editor] = useLexicalComposerContext();\n const anchorElementRef = useRef(document.createElement('div'));\n const positionMenu = useCallback(() => {\n anchorElementRef.current.style.top = anchorElementRef.current.style.bottom;\n const rootElement = editor.getRootElement();\n const containerDiv = anchorElementRef.current;\n const menuEle = containerDiv.firstChild;\n if (rootElement !== null && resolution !== null) {\n const {\n left,\n top,\n width,\n height\n } = resolution.getRect();\n const anchorHeight = anchorElementRef.current.offsetHeight; // use to position under anchor\n containerDiv.style.top = `${top + window.pageYOffset + anchorHeight + 3}px`;\n containerDiv.style.left = `${left + window.pageXOffset}px`;\n containerDiv.style.height = `${height}px`;\n containerDiv.style.width = `${width}px`;\n if (menuEle !== null) {\n menuEle.style.top = `${top}`;\n const menuRect = menuEle.getBoundingClientRect();\n const menuHeight = menuRect.height;\n const menuWidth = menuRect.width;\n const rootElementRect = rootElement.getBoundingClientRect();\n if (left + menuWidth > rootElementRect.right) {\n containerDiv.style.left = `${rootElementRect.right - menuWidth + window.pageXOffset}px`;\n }\n if ((top + menuHeight > window.innerHeight || top + menuHeight > rootElementRect.bottom) && top - rootElementRect.top > menuHeight + height) {\n containerDiv.style.top = `${top - menuHeight + window.pageYOffset - height}px`;\n }\n }\n if (!containerDiv.isConnected) {\n if (className != null) {\n containerDiv.className = className;\n }\n containerDiv.setAttribute('aria-label', 'Typeahead menu');\n containerDiv.setAttribute('id', 'typeahead-menu');\n containerDiv.setAttribute('role', 'listbox');\n containerDiv.style.display = 'block';\n containerDiv.style.position = 'absolute';\n parent.append(containerDiv);\n }\n anchorElementRef.current = containerDiv;\n rootElement.setAttribute('aria-controls', 'typeahead-menu');\n }\n }, [editor, resolution, className, parent]);\n useEffect(() => {\n const rootElement = editor.getRootElement();\n if (resolution !== null) {\n positionMenu();\n return () => {\n if (rootElement !== null) {\n rootElement.removeAttribute('aria-controls');\n }\n const containerDiv = anchorElementRef.current;\n if (containerDiv !== null && containerDiv.isConnected) {\n containerDiv.remove();\n }\n };\n }\n }, [editor, positionMenu, resolution]);\n const onVisibilityChange = useCallback(isInView => {\n if (resolution !== null) {\n if (!isInView) {\n setResolution(null);\n }\n }\n }, [resolution, setResolution]);\n useDynamicPositioning(resolution, anchorElementRef.current, positionMenu, onVisibilityChange);\n return anchorElementRef;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst PUNCTUATION = '\\\\.,\\\\+\\\\*\\\\?\\\\$\\\\@\\\\|#{}\\\\(\\\\)\\\\^\\\\-\\\\[\\\\]\\\\\\\\/!%\\'\"~=<>_:;';\nfunction getTextUpToAnchor(selection) {\n const anchor = selection.anchor;\n if (anchor.type !== 'text') {\n return null;\n }\n const anchorNode = anchor.getNode();\n if (!anchorNode.isSimpleText()) {\n return null;\n }\n const anchorOffset = anchor.offset;\n return anchorNode.getTextContent().slice(0, anchorOffset);\n}\nfunction tryToPositionRange(leadOffset, range, editorWindow) {\n const domSelection = editorWindow.getSelection();\n if (domSelection === null || !domSelection.isCollapsed) {\n return false;\n }\n const anchorNode = domSelection.anchorNode;\n const startOffset = leadOffset;\n const endOffset = domSelection.anchorOffset;\n if (anchorNode == null || endOffset == null) {\n return false;\n }\n try {\n range.setStart(anchorNode, startOffset);\n range.setEnd(anchorNode, endOffset);\n } catch (error) {\n return false;\n }\n return true;\n}\nfunction getQueryTextForSearch(editor) {\n let text = null;\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return;\n }\n text = getTextUpToAnchor(selection);\n });\n return text;\n}\nfunction isSelectionOnEntityBoundary(editor, offset) {\n if (offset !== 0) {\n return false;\n }\n return editor.getEditorState().read(() => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const anchor = selection.anchor;\n const anchorNode = anchor.getNode();\n const prevSibling = anchorNode.getPreviousSibling();\n return $isTextNode(prevSibling) && prevSibling.isTextEntity();\n }\n return false;\n });\n}\n\n// Got from https://stackoverflow.com/a/42543908/2013580\nfunction getScrollParent(element, includeHidden) {\n let style = getComputedStyle(element);\n const excludeStaticParent = style.position === 'absolute';\n const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;\n if (style.position === 'fixed') {\n return document.body;\n }\n for (let parent = element; parent = parent.parentElement;) {\n style = getComputedStyle(parent);\n if (excludeStaticParent && style.position === 'static') {\n continue;\n }\n if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {\n return parent;\n }\n }\n return document.body;\n}\nconst SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND = createCommand('SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND');\nfunction useBasicTypeaheadTriggerMatch(trigger, {\n minLength = 1,\n maxLength = 75\n}) {\n return useCallback(text => {\n const validChars = '[^' + trigger + PUNCTUATION + '\\\\s]';\n const TypeaheadTriggerRegex = new RegExp('(^|\\\\s|\\\\()(' + '[' + trigger + ']' + '((?:' + validChars + '){0,' + maxLength + '})' + ')$');\n const match = TypeaheadTriggerRegex.exec(text);\n if (match !== null) {\n const maybeLeadingWhitespace = match[1];\n const matchingString = match[3];\n if (matchingString.length >= minLength) {\n return {\n leadOffset: match.index + maybeLeadingWhitespace.length,\n matchingString,\n replaceableString: match[2]\n };\n }\n }\n return null;\n }, [maxLength, minLength, trigger]);\n}\nfunction LexicalTypeaheadMenuPlugin({\n options,\n onQueryChange,\n onSelectOption,\n onOpen,\n onClose,\n menuRenderFn,\n triggerFn,\n anchorClassName,\n commandPriority = COMMAND_PRIORITY_LOW,\n parent\n}) {\n const [editor] = useLexicalComposerContext();\n const [resolution, setResolution] = useState(null);\n const anchorElementRef = useMenuAnchorRef(resolution, setResolution, anchorClassName, parent);\n const closeTypeahead = useCallback(() => {\n setResolution(null);\n if (onClose != null && resolution !== null) {\n onClose();\n }\n }, [onClose, resolution]);\n const openTypeahead = useCallback(res => {\n setResolution(res);\n if (onOpen != null && resolution === null) {\n onOpen(res);\n }\n }, [onOpen, resolution]);\n useEffect(() => {\n const updateListener = () => {\n editor.getEditorState().read(() => {\n const editorWindow = editor._window || window;\n const range = editorWindow.document.createRange();\n const selection = $getSelection();\n const text = getQueryTextForSearch(editor);\n if (!$isRangeSelection(selection) || !selection.isCollapsed() || text === null || range === null) {\n closeTypeahead();\n return;\n }\n const match = triggerFn(text, editor);\n onQueryChange(match ? match.matchingString : null);\n if (match !== null && !isSelectionOnEntityBoundary(editor, match.leadOffset)) {\n const isRangePositioned = tryToPositionRange(match.leadOffset, range, editorWindow);\n if (isRangePositioned !== null) {\n startTransition(() => openTypeahead({\n getRect: () => range.getBoundingClientRect(),\n match\n }));\n return;\n }\n }\n closeTypeahead();\n });\n };\n const removeUpdateListener = editor.registerUpdateListener(updateListener);\n return () => {\n removeUpdateListener();\n };\n }, [editor, triggerFn, onQueryChange, resolution, closeTypeahead, openTypeahead]);\n return resolution === null || editor === null ? null : /*#__PURE__*/jsx(LexicalMenu, {\n close: closeTypeahead,\n resolution: resolution,\n editor: editor,\n anchorElementRef: anchorElementRef,\n options: options,\n menuRenderFn: menuRenderFn,\n shouldSplitNodeWithQuery: true,\n onSelectOption: onSelectOption,\n commandPriority: commandPriority\n });\n}\n\nexport { LexicalTypeaheadMenuPlugin, MenuOption, PUNCTUATION, SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND, getScrollParent, useBasicTypeaheadTriggerMatch, useDynamicPositioning };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { useLayoutEffect, useEffect, useMemo, useRef, useState } from 'react';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// This workaround is no longer necessary in React 19,\n// but we currently support React >=17.x\n// https://github.com/facebook/react/pull/26395\nconst useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect : useEffect;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Shortcut to Lexical subscriptions when values are used for render.\n * @param subscription - The function to create the {@link LexicalSubscription}. This function's identity must be stable (e.g. defined at module scope or with useCallback).\n */\nfunction useLexicalSubscription(subscription) {\n const [editor] = useLexicalComposerContext();\n const initializedSubscription = useMemo(() => subscription(editor), [editor, subscription]);\n const valueRef = useRef(initializedSubscription.initialValueFn());\n const [value, setValue] = useState(valueRef.current);\n useLayoutEffectImpl(() => {\n const {\n initialValueFn,\n subscribe\n } = initializedSubscription;\n const currentValue = initialValueFn();\n if (valueRef.current !== currentValue) {\n valueRef.current = currentValue;\n setValue(currentValue);\n }\n return subscribe(newValue => {\n valueRef.current = newValue;\n setValue(newValue);\n });\n }, [initializedSubscription, subscription]);\n return value;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction subscription(editor) {\n return {\n initialValueFn: () => editor.isEditable(),\n subscribe: callback => {\n return editor.registerEditableListener(callback);\n }\n };\n}\n\n/**\n * Get the current value for {@link LexicalEditor.isEditable}\n * using {@link useLexicalSubscription}.\n * You should prefer this over manually observing the value with\n * {@link LexicalEditor.registerEditableListener},\n * which is a bit tricky to do correctly, particularly when using\n * React StrictMode (the default for development) or concurrency.\n */\nfunction useLexicalEditable() {\n return useLexicalSubscription(subscription);\n}\n\nexport { useLexicalEditable as default, useLexicalEditable };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { $isTextNode, $getCharacterOffsets, $isElementNode, $isRootNode, $getNodeByKey, $getPreviousSelection, $createTextNode, $isRangeSelection, $isTokenOrSegmented, $getRoot, $isRootOrShadowRoot, $hasAncestor, $isLeafNode, $setSelection, $getAdjacentNode, $isDecoratorNode, $isLineBreakNode } from 'lexical';\nexport { $cloneWithProperties } from 'lexical';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\nconst CSS_TO_STYLES = new Map();\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction getDOMTextNode(element) {\n let node = element;\n while (node != null) {\n if (node.nodeType === Node.TEXT_NODE) {\n return node;\n }\n node = node.firstChild;\n }\n return null;\n}\nfunction getDOMIndexWithinParent(node) {\n const parent = node.parentNode;\n if (parent == null) {\n throw new Error('Should never happen');\n }\n return [parent, Array.from(parent.childNodes).indexOf(node)];\n}\n\n/**\n * Creates a selection range for the DOM.\n * @param editor - The lexical editor.\n * @param anchorNode - The anchor node of a selection.\n * @param _anchorOffset - The amount of space offset from the anchor to the focus.\n * @param focusNode - The current focus.\n * @param _focusOffset - The amount of space offset from the focus to the anchor.\n * @returns The range of selection for the DOM that was created.\n */\nfunction createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffset) {\n const anchorKey = anchorNode.getKey();\n const focusKey = focusNode.getKey();\n const range = document.createRange();\n let anchorDOM = editor.getElementByKey(anchorKey);\n let focusDOM = editor.getElementByKey(focusKey);\n let anchorOffset = _anchorOffset;\n let focusOffset = _focusOffset;\n if ($isTextNode(anchorNode)) {\n anchorDOM = getDOMTextNode(anchorDOM);\n }\n if ($isTextNode(focusNode)) {\n focusDOM = getDOMTextNode(focusDOM);\n }\n if (anchorNode === undefined || focusNode === undefined || anchorDOM === null || focusDOM === null) {\n return null;\n }\n if (anchorDOM.nodeName === 'BR') {\n [anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM);\n }\n if (focusDOM.nodeName === 'BR') {\n [focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM);\n }\n const firstChild = anchorDOM.firstChild;\n if (anchorDOM === focusDOM && firstChild != null && firstChild.nodeName === 'BR' && anchorOffset === 0 && focusOffset === 0) {\n focusOffset = 1;\n }\n try {\n range.setStart(anchorDOM, anchorOffset);\n range.setEnd(focusDOM, focusOffset);\n } catch (e) {\n return null;\n }\n if (range.collapsed && (anchorOffset !== focusOffset || anchorKey !== focusKey)) {\n // Range is backwards, we need to reverse it\n range.setStart(focusDOM, focusOffset);\n range.setEnd(anchorDOM, anchorOffset);\n }\n return range;\n}\n\n/**\n * Creates DOMRects, generally used to help the editor find a specific location on the screen.\n * @param editor - The lexical editor\n * @param range - A fragment of a document that can contain nodes and parts of text nodes.\n * @returns The selectionRects as an array.\n */\nfunction createRectsFromDOMRange(editor, range) {\n const rootElement = editor.getRootElement();\n if (rootElement === null) {\n return [];\n }\n const rootRect = rootElement.getBoundingClientRect();\n const computedStyle = getComputedStyle(rootElement);\n const rootPadding = parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight);\n const selectionRects = Array.from(range.getClientRects());\n let selectionRectsLength = selectionRects.length;\n //sort rects from top left to bottom right.\n selectionRects.sort((a, b) => {\n const top = a.top - b.top;\n // Some rects match position closely, but not perfectly,\n // so we give a 3px tolerance.\n if (Math.abs(top) <= 3) {\n return a.left - b.left;\n }\n return top;\n });\n let prevRect;\n for (let i = 0; i < selectionRectsLength; i++) {\n const selectionRect = selectionRects[i];\n // Exclude rects that overlap preceding Rects in the sorted list.\n const isOverlappingRect = prevRect && prevRect.top <= selectionRect.top && prevRect.top + prevRect.height > selectionRect.top && prevRect.left + prevRect.width > selectionRect.left;\n // Exclude selections that span the entire element\n const selectionSpansElement = selectionRect.width + rootPadding === rootRect.width;\n if (isOverlappingRect || selectionSpansElement) {\n selectionRects.splice(i--, 1);\n selectionRectsLength--;\n continue;\n }\n prevRect = selectionRect;\n }\n return selectionRects;\n}\n\n/**\n * Creates an object containing all the styles and their values provided in the CSS string.\n * @param css - The CSS string of styles and their values.\n * @returns The styleObject containing all the styles and their values.\n */\nfunction getStyleObjectFromRawCSS(css) {\n const styleObject = {};\n const styles = css.split(';');\n for (const style of styles) {\n if (style !== '') {\n const [key, value] = style.split(/:([^]+)/); // split on first colon\n if (key && value) {\n styleObject[key.trim()] = value.trim();\n }\n }\n }\n return styleObject;\n}\n\n/**\n * Given a CSS string, returns an object from the style cache.\n * @param css - The CSS property as a string.\n * @returns The value of the given CSS property.\n */\nfunction getStyleObjectFromCSS(css) {\n let value = CSS_TO_STYLES.get(css);\n if (value === undefined) {\n value = getStyleObjectFromRawCSS(css);\n CSS_TO_STYLES.set(css, value);\n }\n {\n // Freeze the value in DEV to prevent accidental mutations\n Object.freeze(value);\n }\n return value;\n}\n\n/**\n * Gets the CSS styles from the style object.\n * @param styles - The style object containing the styles to get.\n * @returns A string containing the CSS styles and their values.\n */\nfunction getCSSFromStyleObject(styles) {\n let css = '';\n for (const style in styles) {\n if (style) {\n css += `${style}: ${styles[style]};`;\n }\n }\n return css;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Generally used to append text content to HTML and JSON. Grabs the text content and \"slices\"\n * it to be generated into the new TextNode.\n * @param selection - The selection containing the node whose TextNode is to be edited.\n * @param textNode - The TextNode to be edited.\n * @returns The updated TextNode.\n */\nfunction $sliceSelectedTextNodeContent(selection, textNode) {\n const anchorAndFocus = selection.getStartEndPoints();\n if (textNode.isSelected(selection) && !textNode.isSegmented() && !textNode.isToken() && anchorAndFocus !== null) {\n const [anchor, focus] = anchorAndFocus;\n const isBackward = selection.isBackward();\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n const isAnchor = textNode.is(anchorNode);\n const isFocus = textNode.is(focusNode);\n if (isAnchor || isFocus) {\n const [anchorOffset, focusOffset] = $getCharacterOffsets(selection);\n const isSame = anchorNode.is(focusNode);\n const isFirst = textNode.is(isBackward ? focusNode : anchorNode);\n const isLast = textNode.is(isBackward ? anchorNode : focusNode);\n let startOffset = 0;\n let endOffset = undefined;\n if (isSame) {\n startOffset = anchorOffset > focusOffset ? focusOffset : anchorOffset;\n endOffset = anchorOffset > focusOffset ? anchorOffset : focusOffset;\n } else if (isFirst) {\n const offset = isBackward ? focusOffset : anchorOffset;\n startOffset = offset;\n endOffset = undefined;\n } else if (isLast) {\n const offset = isBackward ? anchorOffset : focusOffset;\n startOffset = 0;\n endOffset = offset;\n }\n textNode.__text = textNode.__text.slice(startOffset, endOffset);\n return textNode;\n }\n }\n return textNode;\n}\n\n/**\n * Determines if the current selection is at the end of the node.\n * @param point - The point of the selection to test.\n * @returns true if the provided point offset is in the last possible position, false otherwise.\n */\nfunction $isAtNodeEnd(point) {\n if (point.type === 'text') {\n return point.offset === point.getNode().getTextContentSize();\n }\n const node = point.getNode();\n if (!$isElementNode(node)) {\n throw Error(`isAtNodeEnd: node must be a TextNode or ElementNode`);\n }\n return point.offset === node.getChildrenSize();\n}\n\n/**\n * Trims text from a node in order to shorten it, eg. to enforce a text's max length. If it deletes text\n * that is an ancestor of the anchor then it will leave 2 indents, otherwise, if no text content exists, it deletes\n * the TextNode. It will move the focus to either the end of any left over text or beginning of a new TextNode.\n * @param editor - The lexical editor.\n * @param anchor - The anchor of the current selection, where the selection should be pointing.\n * @param delCount - The amount of characters to delete. Useful as a dynamic variable eg. textContentSize - maxLength;\n */\nfunction $trimTextContentFromAnchor(editor, anchor, delCount) {\n // Work from the current selection anchor point\n let currentNode = anchor.getNode();\n let remaining = delCount;\n if ($isElementNode(currentNode)) {\n const descendantNode = currentNode.getDescendantByIndex(anchor.offset);\n if (descendantNode !== null) {\n currentNode = descendantNode;\n }\n }\n while (remaining > 0 && currentNode !== null) {\n if ($isElementNode(currentNode)) {\n const lastDescendant = currentNode.getLastDescendant();\n if (lastDescendant !== null) {\n currentNode = lastDescendant;\n }\n }\n let nextNode = currentNode.getPreviousSibling();\n let additionalElementWhitespace = 0;\n if (nextNode === null) {\n let parent = currentNode.getParentOrThrow();\n let parentSibling = parent.getPreviousSibling();\n while (parentSibling === null) {\n parent = parent.getParent();\n if (parent === null) {\n nextNode = null;\n break;\n }\n parentSibling = parent.getPreviousSibling();\n }\n if (parent !== null) {\n additionalElementWhitespace = parent.isInline() ? 0 : 2;\n nextNode = parentSibling;\n }\n }\n let text = currentNode.getTextContent();\n // If the text is empty, we need to consider adding in two line breaks to match\n // the content if we were to get it from its parent.\n if (text === '' && $isElementNode(currentNode) && !currentNode.isInline()) {\n // TODO: should this be handled in core?\n text = '\\n\\n';\n }\n const currentNodeSize = text.length;\n if (!$isTextNode(currentNode) || remaining >= currentNodeSize) {\n const parent = currentNode.getParent();\n currentNode.remove();\n if (parent != null && parent.getChildrenSize() === 0 && !$isRootNode(parent)) {\n parent.remove();\n }\n remaining -= currentNodeSize + additionalElementWhitespace;\n currentNode = nextNode;\n } else {\n const key = currentNode.getKey();\n // See if we can just revert it to what was in the last editor state\n const prevTextContent = editor.getEditorState().read(() => {\n const prevNode = $getNodeByKey(key);\n if ($isTextNode(prevNode) && prevNode.isSimpleText()) {\n return prevNode.getTextContent();\n }\n return null;\n });\n const offset = currentNodeSize - remaining;\n const slicedText = text.slice(0, offset);\n if (prevTextContent !== null && prevTextContent !== text) {\n const prevSelection = $getPreviousSelection();\n let target = currentNode;\n if (!currentNode.isSimpleText()) {\n const textNode = $createTextNode(prevTextContent);\n currentNode.replace(textNode);\n target = textNode;\n } else {\n currentNode.setTextContent(prevTextContent);\n }\n if ($isRangeSelection(prevSelection) && prevSelection.isCollapsed()) {\n const prevOffset = prevSelection.anchor.offset;\n target.select(prevOffset, prevOffset);\n }\n } else if (currentNode.isSimpleText()) {\n // Split text\n const isSelected = anchor.key === key;\n let anchorOffset = anchor.offset;\n // Move offset to end if it's less than the remaining number, otherwise\n // we'll have a negative splitStart.\n if (anchorOffset < remaining) {\n anchorOffset = currentNodeSize;\n }\n const splitStart = isSelected ? anchorOffset - remaining : 0;\n const splitEnd = isSelected ? anchorOffset : offset;\n if (isSelected && splitStart === 0) {\n const [excessNode] = currentNode.splitText(splitStart, splitEnd);\n excessNode.remove();\n } else {\n const [, excessNode] = currentNode.splitText(splitStart, splitEnd);\n excessNode.remove();\n }\n } else {\n const textNode = $createTextNode(slicedText);\n currentNode.replace(textNode);\n }\n remaining = 0;\n }\n }\n}\n\n/**\n * Gets the TextNode's style object and adds the styles to the CSS.\n * @param node - The TextNode to add styles to.\n */\nfunction $addNodeStyle(node) {\n const CSSText = node.getStyle();\n const styles = getStyleObjectFromRawCSS(CSSText);\n CSS_TO_STYLES.set(CSSText, styles);\n}\nfunction $patchStyle(target, patch) {\n const prevStyles = getStyleObjectFromCSS('getStyle' in target ? target.getStyle() : target.style);\n const newStyles = Object.entries(patch).reduce((styles, [key, value]) => {\n if (typeof value === 'function') {\n styles[key] = value(prevStyles[key], target);\n } else if (value === null) {\n delete styles[key];\n } else {\n styles[key] = value;\n }\n return styles;\n }, {\n ...prevStyles\n } || {});\n const newCSSText = getCSSFromStyleObject(newStyles);\n target.setStyle(newCSSText);\n CSS_TO_STYLES.set(newCSSText, newStyles);\n}\n\n/**\n * Applies the provided styles to the TextNodes in the provided Selection.\n * Will update partially selected TextNodes by splitting the TextNode and applying\n * the styles to the appropriate one.\n * @param selection - The selected node(s) to update.\n * @param patch - The patch to apply, which can include multiple styles. \\\\{CSSProperty: value\\\\} . Can also accept a function that returns the new property value.\n */\nfunction $patchStyleText(selection, patch) {\n const selectedNodes = selection.getNodes();\n const selectedNodesLength = selectedNodes.length;\n const anchorAndFocus = selection.getStartEndPoints();\n if (anchorAndFocus === null) {\n return;\n }\n const [anchor, focus] = anchorAndFocus;\n const lastIndex = selectedNodesLength - 1;\n let firstNode = selectedNodes[0];\n let lastNode = selectedNodes[lastIndex];\n if (selection.isCollapsed() && $isRangeSelection(selection)) {\n $patchStyle(selection, patch);\n return;\n }\n const firstNodeText = firstNode.getTextContent();\n const firstNodeTextLength = firstNodeText.length;\n const focusOffset = focus.offset;\n let anchorOffset = anchor.offset;\n const isBefore = anchor.isBefore(focus);\n let startOffset = isBefore ? anchorOffset : focusOffset;\n let endOffset = isBefore ? focusOffset : anchorOffset;\n const startType = isBefore ? anchor.type : focus.type;\n const endType = isBefore ? focus.type : anchor.type;\n const endKey = isBefore ? focus.key : anchor.key;\n\n // This is the case where the user only selected the very end of the\n // first node so we don't want to include it in the formatting change.\n if ($isTextNode(firstNode) && startOffset === firstNodeTextLength) {\n const nextSibling = firstNode.getNextSibling();\n if ($isTextNode(nextSibling)) {\n // we basically make the second node the firstNode, changing offsets accordingly\n anchorOffset = 0;\n startOffset = 0;\n firstNode = nextSibling;\n }\n }\n\n // This is the case where we only selected a single node\n if (selectedNodes.length === 1) {\n if ($isTextNode(firstNode) && firstNode.canHaveFormat()) {\n startOffset = startType === 'element' ? 0 : anchorOffset > focusOffset ? focusOffset : anchorOffset;\n endOffset = endType === 'element' ? firstNodeTextLength : anchorOffset > focusOffset ? anchorOffset : focusOffset;\n\n // No actual text is selected, so do nothing.\n if (startOffset === endOffset) {\n return;\n }\n\n // The entire node is selected or a token/segment, so just format it\n if ($isTokenOrSegmented(firstNode) || startOffset === 0 && endOffset === firstNodeTextLength) {\n $patchStyle(firstNode, patch);\n firstNode.select(startOffset, endOffset);\n } else {\n // The node is partially selected, so split it into two nodes\n // and style the selected one.\n const splitNodes = firstNode.splitText(startOffset, endOffset);\n const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];\n $patchStyle(replacement, patch);\n replacement.select(0, endOffset - startOffset);\n }\n } // multiple nodes selected.\n } else {\n if ($isTextNode(firstNode) && startOffset < firstNode.getTextContentSize() && firstNode.canHaveFormat()) {\n if (startOffset !== 0 && !$isTokenOrSegmented(firstNode)) {\n // the entire first node isn't selected and it isn't a token or segmented, so split it\n firstNode = firstNode.splitText(startOffset)[1];\n startOffset = 0;\n if (isBefore) {\n anchor.set(firstNode.getKey(), startOffset, 'text');\n } else {\n focus.set(firstNode.getKey(), startOffset, 'text');\n }\n }\n $patchStyle(firstNode, patch);\n }\n if ($isTextNode(lastNode) && lastNode.canHaveFormat()) {\n const lastNodeText = lastNode.getTextContent();\n const lastNodeTextLength = lastNodeText.length;\n\n // The last node might not actually be the end node\n //\n // If not, assume the last node is fully-selected unless the end offset is\n // zero.\n if (lastNode.__key !== endKey && endOffset !== 0) {\n endOffset = lastNodeTextLength;\n }\n\n // if the entire last node isn't selected and it isn't a token or segmented, split it\n if (endOffset !== lastNodeTextLength && !$isTokenOrSegmented(lastNode)) {\n [lastNode] = lastNode.splitText(endOffset);\n }\n if (endOffset !== 0 || endType === 'element') {\n $patchStyle(lastNode, patch);\n }\n }\n\n // style all the text nodes in between\n for (let i = 1; i < lastIndex; i++) {\n const selectedNode = selectedNodes[i];\n const selectedNodeKey = selectedNode.getKey();\n if ($isTextNode(selectedNode) && selectedNode.canHaveFormat() && selectedNodeKey !== firstNode.getKey() && selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken()) {\n $patchStyle(selectedNode, patch);\n }\n }\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n/**\n * Converts all nodes in the selection that are of one block type to another.\n * @param selection - The selected blocks to be converted.\n * @param createElement - The function that creates the node. eg. $createParagraphNode.\n */\nfunction $setBlocksType(selection, createElement) {\n if (selection === null) {\n return;\n }\n const anchorAndFocus = selection.getStartEndPoints();\n const anchor = anchorAndFocus ? anchorAndFocus[0] : null;\n if (anchor !== null && anchor.key === 'root') {\n const element = createElement();\n const root = $getRoot();\n const firstChild = root.getFirstChild();\n if (firstChild) {\n firstChild.replace(element, true);\n } else {\n root.append(element);\n }\n return;\n }\n const nodes = selection.getNodes();\n const firstSelectedBlock = anchor !== null ? $getAncestor(anchor.getNode(), INTERNAL_$isBlock) : false;\n if (firstSelectedBlock && nodes.indexOf(firstSelectedBlock) === -1) {\n nodes.push(firstSelectedBlock);\n }\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n if (!INTERNAL_$isBlock(node)) {\n continue;\n }\n if (!$isElementNode(node)) {\n throw Error(`Expected block node to be an ElementNode`);\n }\n const targetElement = createElement();\n targetElement.setFormat(node.getFormatType());\n targetElement.setIndent(node.getIndent());\n node.replace(targetElement, true);\n }\n}\nfunction isPointAttached(point) {\n return point.getNode().isAttached();\n}\nfunction $removeParentEmptyElements(startingNode) {\n let node = startingNode;\n while (node !== null && !$isRootOrShadowRoot(node)) {\n const latest = node.getLatest();\n const parentNode = node.getParent();\n if (latest.getChildrenSize() === 0) {\n node.remove(true);\n }\n node = parentNode;\n }\n}\n\n/**\n * @deprecated\n * Wraps all nodes in the selection into another node of the type returned by createElement.\n * @param selection - The selection of nodes to be wrapped.\n * @param createElement - A function that creates the wrapping ElementNode. eg. $createParagraphNode.\n * @param wrappingElement - An element to append the wrapped selection and its children to.\n */\nfunction $wrapNodes(selection, createElement, wrappingElement = null) {\n const anchorAndFocus = selection.getStartEndPoints();\n const anchor = anchorAndFocus ? anchorAndFocus[0] : null;\n const nodes = selection.getNodes();\n const nodesLength = nodes.length;\n if (anchor !== null && (nodesLength === 0 || nodesLength === 1 && anchor.type === 'element' && anchor.getNode().getChildrenSize() === 0)) {\n const target = anchor.type === 'text' ? anchor.getNode().getParentOrThrow() : anchor.getNode();\n const children = target.getChildren();\n let element = createElement();\n element.setFormat(target.getFormatType());\n element.setIndent(target.getIndent());\n children.forEach(child => element.append(child));\n if (wrappingElement) {\n element = wrappingElement.append(element);\n }\n target.replace(element);\n return;\n }\n let topLevelNode = null;\n let descendants = [];\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n // Determine whether wrapping has to be broken down into multiple chunks. This can happen if the\n // user selected multiple Root-like nodes that have to be treated separately as if they are\n // their own branch. I.e. you don't want to wrap a whole table, but rather the contents of each\n // of each of the cell nodes.\n if ($isRootOrShadowRoot(node)) {\n $wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);\n descendants = [];\n topLevelNode = node;\n } else if (topLevelNode === null || topLevelNode !== null && $hasAncestor(node, topLevelNode)) {\n descendants.push(node);\n } else {\n $wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);\n descendants = [node];\n }\n }\n $wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);\n}\n\n/**\n * Wraps each node into a new ElementNode.\n * @param selection - The selection of nodes to wrap.\n * @param nodes - An array of nodes, generally the descendants of the selection.\n * @param nodesLength - The length of nodes.\n * @param createElement - A function that creates the wrapping ElementNode. eg. $createParagraphNode.\n * @param wrappingElement - An element to wrap all the nodes into.\n * @returns\n */\nfunction $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingElement = null) {\n if (nodes.length === 0) {\n return;\n }\n const firstNode = nodes[0];\n const elementMapping = new Map();\n const elements = [];\n // The below logic is to find the right target for us to\n // either insertAfter/insertBefore/append the corresponding\n // elements to. This is made more complicated due to nested\n // structures.\n let target = $isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();\n if (target.isInline()) {\n target = target.getParentOrThrow();\n }\n let targetIsPrevSibling = false;\n while (target !== null) {\n const prevSibling = target.getPreviousSibling();\n if (prevSibling !== null) {\n target = prevSibling;\n targetIsPrevSibling = true;\n break;\n }\n target = target.getParentOrThrow();\n if ($isRootOrShadowRoot(target)) {\n break;\n }\n }\n const emptyElements = new Set();\n\n // Find any top level empty elements\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n if ($isElementNode(node) && node.getChildrenSize() === 0) {\n emptyElements.add(node.getKey());\n }\n }\n const movedNodes = new Set();\n\n // Move out all leaf nodes into our elements array.\n // If we find a top level empty element, also move make\n // an element for that.\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n let parent = node.getParent();\n if (parent !== null && parent.isInline()) {\n parent = parent.getParent();\n }\n if (parent !== null && $isLeafNode(node) && !movedNodes.has(node.getKey())) {\n const parentKey = parent.getKey();\n if (elementMapping.get(parentKey) === undefined) {\n const targetElement = createElement();\n targetElement.setFormat(parent.getFormatType());\n targetElement.setIndent(parent.getIndent());\n elements.push(targetElement);\n elementMapping.set(parentKey, targetElement);\n // Move node and its siblings to the new\n // element.\n parent.getChildren().forEach(child => {\n targetElement.append(child);\n movedNodes.add(child.getKey());\n if ($isElementNode(child)) {\n // Skip nested leaf nodes if the parent has already been moved\n child.getChildrenKeys().forEach(key => movedNodes.add(key));\n }\n });\n $removeParentEmptyElements(parent);\n }\n } else if (emptyElements.has(node.getKey())) {\n if (!$isElementNode(node)) {\n throw Error(`Expected node in emptyElements to be an ElementNode`);\n }\n const targetElement = createElement();\n targetElement.setFormat(node.getFormatType());\n targetElement.setIndent(node.getIndent());\n elements.push(targetElement);\n node.remove(true);\n }\n }\n if (wrappingElement !== null) {\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n wrappingElement.append(element);\n }\n }\n let lastElement = null;\n\n // If our target is Root-like, let's see if we can re-adjust\n // so that the target is the first child instead.\n if ($isRootOrShadowRoot(target)) {\n if (targetIsPrevSibling) {\n if (wrappingElement !== null) {\n target.insertAfter(wrappingElement);\n } else {\n for (let i = elements.length - 1; i >= 0; i--) {\n const element = elements[i];\n target.insertAfter(element);\n }\n }\n } else {\n const firstChild = target.getFirstChild();\n if ($isElementNode(firstChild)) {\n target = firstChild;\n }\n if (firstChild === null) {\n if (wrappingElement) {\n target.append(wrappingElement);\n } else {\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n target.append(element);\n lastElement = element;\n }\n }\n } else {\n if (wrappingElement !== null) {\n firstChild.insertBefore(wrappingElement);\n } else {\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n firstChild.insertBefore(element);\n lastElement = element;\n }\n }\n }\n }\n } else {\n if (wrappingElement) {\n target.insertAfter(wrappingElement);\n } else {\n for (let i = elements.length - 1; i >= 0; i--) {\n const element = elements[i];\n target.insertAfter(element);\n lastElement = element;\n }\n }\n }\n const prevSelection = $getPreviousSelection();\n if ($isRangeSelection(prevSelection) && isPointAttached(prevSelection.anchor) && isPointAttached(prevSelection.focus)) {\n $setSelection(prevSelection.clone());\n } else if (lastElement !== null) {\n lastElement.selectEnd();\n } else {\n selection.dirty = true;\n }\n}\n\n/**\n * Determines if the default character selection should be overridden. Used with DecoratorNodes\n * @param selection - The selection whose default character selection may need to be overridden.\n * @param isBackward - Is the selection backwards (the focus comes before the anchor)?\n * @returns true if it should be overridden, false if not.\n */\nfunction $shouldOverrideDefaultCharacterSelection(selection, isBackward) {\n const possibleNode = $getAdjacentNode(selection.focus, isBackward);\n return $isDecoratorNode(possibleNode) && !possibleNode.isIsolated() || $isElementNode(possibleNode) && !possibleNode.isInline() && !possibleNode.canBeEmpty();\n}\n\n/**\n * Moves the selection according to the arguments.\n * @param selection - The selected text or nodes.\n * @param isHoldingShift - Is the shift key being held down during the operation.\n * @param isBackward - Is the selection selected backwards (the focus comes before the anchor)?\n * @param granularity - The distance to adjust the current selection.\n */\nfunction $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) {\n selection.modify(isHoldingShift ? 'extend' : 'move', isBackward, granularity);\n}\n\n/**\n * Tests a parent element for right to left direction.\n * @param selection - The selection whose parent is to be tested.\n * @returns true if the selections' parent element has a direction of 'rtl' (right to left), false otherwise.\n */\nfunction $isParentElementRTL(selection) {\n const anchorNode = selection.anchor.getNode();\n const parent = $isRootNode(anchorNode) ? anchorNode : anchorNode.getParentOrThrow();\n return parent.getDirection() === 'rtl';\n}\n\n/**\n * Moves selection by character according to arguments.\n * @param selection - The selection of the characters to move.\n * @param isHoldingShift - Is the shift key being held down during the operation.\n * @param isBackward - Is the selection backward (the focus comes before the anchor)?\n */\nfunction $moveCharacter(selection, isHoldingShift, isBackward) {\n const isRTL = $isParentElementRTL(selection);\n $moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');\n}\n\n/**\n * Expands the current Selection to cover all of the content in the editor.\n * @param selection - The current selection.\n */\nfunction $selectAll(selection) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const topParent = anchorNode.getTopLevelElementOrThrow();\n const root = topParent.getParentOrThrow();\n let firstNode = root.getFirstDescendant();\n let lastNode = root.getLastDescendant();\n let firstType = 'element';\n let lastType = 'element';\n let lastOffset = 0;\n if ($isTextNode(firstNode)) {\n firstType = 'text';\n } else if (!$isElementNode(firstNode) && firstNode !== null) {\n firstNode = firstNode.getParentOrThrow();\n }\n if ($isTextNode(lastNode)) {\n lastType = 'text';\n lastOffset = lastNode.getTextContentSize();\n } else if (!$isElementNode(lastNode) && lastNode !== null) {\n lastNode = lastNode.getParentOrThrow();\n }\n if (firstNode && lastNode) {\n anchor.set(firstNode.getKey(), 0, firstType);\n focus.set(lastNode.getKey(), lastOffset, lastType);\n }\n}\n\n/**\n * Returns the current value of a CSS property for Nodes, if set. If not set, it returns the defaultValue.\n * @param node - The node whose style value to get.\n * @param styleProperty - The CSS style property.\n * @param defaultValue - The default value for the property.\n * @returns The value of the property for node.\n */\nfunction $getNodeStyleValueForProperty(node, styleProperty, defaultValue) {\n const css = node.getStyle();\n const styleObject = getStyleObjectFromCSS(css);\n if (styleObject !== null) {\n return styleObject[styleProperty] || defaultValue;\n }\n return defaultValue;\n}\n\n/**\n * Returns the current value of a CSS property for TextNodes in the Selection, if set. If not set, it returns the defaultValue.\n * If all TextNodes do not have the same value, it returns an empty string.\n * @param selection - The selection of TextNodes whose value to find.\n * @param styleProperty - The CSS style property.\n * @param defaultValue - The default value for the property, defaults to an empty string.\n * @returns The value of the property for the selected TextNodes.\n */\nfunction $getSelectionStyleValueForProperty(selection, styleProperty, defaultValue = '') {\n let styleValue = null;\n const nodes = selection.getNodes();\n const anchor = selection.anchor;\n const focus = selection.focus;\n const isBackward = selection.isBackward();\n const endOffset = isBackward ? focus.offset : anchor.offset;\n const endNode = isBackward ? focus.getNode() : anchor.getNode();\n if ($isRangeSelection(selection) && selection.isCollapsed() && selection.style !== '') {\n const css = selection.style;\n const styleObject = getStyleObjectFromCSS(css);\n if (styleObject !== null && styleProperty in styleObject) {\n return styleObject[styleProperty];\n }\n }\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n\n // if no actual characters in the end node are selected, we don't\n // include it in the selection for purposes of determining style\n // value\n if (i !== 0 && endOffset === 0 && node.is(endNode)) {\n continue;\n }\n if ($isTextNode(node)) {\n const nodeStyleValue = $getNodeStyleValueForProperty(node, styleProperty, defaultValue);\n if (styleValue === null) {\n styleValue = nodeStyleValue;\n } else if (styleValue !== nodeStyleValue) {\n // multiple text nodes are in the selection and they don't all\n // have the same style.\n styleValue = '';\n break;\n }\n }\n }\n return styleValue === null ? defaultValue : styleValue;\n}\n\n/**\n * This function is for internal use of the library.\n * Please do not use it as it may change in the future.\n */\nfunction INTERNAL_$isBlock(node) {\n if ($isDecoratorNode(node)) {\n return false;\n }\n if (!$isElementNode(node) || $isRootOrShadowRoot(node)) {\n return false;\n }\n const firstChild = node.getFirstChild();\n const isLeafElement = firstChild === null || $isLineBreakNode(firstChild) || $isTextNode(firstChild) || firstChild.isInline();\n return !node.isInline() && node.canBeEmpty() !== false && isLeafElement;\n}\nfunction $getAncestor(node, predicate) {\n let parent = node;\n while (parent !== null && parent.getParent() !== null && !predicate(parent)) {\n parent = parent.getParentOrThrow();\n }\n return predicate(parent) ? parent : null;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/** @deprecated renamed to {@link $trimTextContentFromAnchor} by @lexical/eslint-plugin rules-of-lexical */\nconst trimTextContentFromAnchor = $trimTextContentFromAnchor;\n\nexport { $addNodeStyle, $getSelectionStyleValueForProperty, $isAtNodeEnd, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $patchStyleText, $selectAll, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $sliceSelectedTextNodeContent, $trimTextContentFromAnchor, $wrapNodes, createDOMRange, createRectsFromDOMRange, getStyleObjectFromCSS, trimTextContentFromAnchor };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { $getRoot, $isDecoratorNode, $isElementNode, $isParagraphNode, $isTextNode, TextNode, $createTextNode } from 'lexical';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Returns the root's text content.\n * @returns The root's text content.\n */\nfunction $rootTextContent() {\n const root = $getRoot();\n return root.getTextContent();\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Determines if the root has any text content and can trim any whitespace if it does.\n * @param isEditorComposing - Is the editor in composition mode due to an active Input Method Editor?\n * @param trim - Should the root text have its whitespaced trimmed? Defaults to true.\n * @returns true if text content is empty, false if there is text or isEditorComposing is true.\n */\nfunction $isRootTextContentEmpty(isEditorComposing, trim = true) {\n if (isEditorComposing) {\n return false;\n }\n let text = $rootTextContent();\n if (trim) {\n text = text.trim();\n }\n return text === '';\n}\n\n/**\n * Returns a function that executes {@link $isRootTextContentEmpty}\n * @param isEditorComposing - Is the editor in composition mode due to an active Input Method Editor?\n * @param trim - Should the root text have its whitespaced trimmed? Defaults to true.\n * @returns A function that executes $isRootTextContentEmpty based on arguments.\n */\nfunction $isRootTextContentEmptyCurry(isEditorComposing, trim) {\n return () => $isRootTextContentEmpty(isEditorComposing, trim);\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Determines if the input should show the placeholder. If anything is in\n * in the root the placeholder should not be shown.\n * @param isComposing - Is the editor in composition mode due to an active Input Method Editor?\n * @returns true if the input should show the placeholder, false otherwise.\n */\nfunction $canShowPlaceholder(isComposing) {\n if (!$isRootTextContentEmpty(isComposing, false)) {\n return false;\n }\n const root = $getRoot();\n const children = root.getChildren();\n const childrenLength = children.length;\n if (childrenLength > 1) {\n return false;\n }\n for (let i = 0; i < childrenLength; i++) {\n const topBlock = children[i];\n if ($isDecoratorNode(topBlock)) {\n return false;\n }\n if ($isElementNode(topBlock)) {\n if (!$isParagraphNode(topBlock)) {\n return false;\n }\n if (topBlock.__indent !== 0) {\n return false;\n }\n const topBlockChildren = topBlock.getChildren();\n const topBlockChildrenLength = topBlockChildren.length;\n for (let s = 0; s < topBlockChildrenLength; s++) {\n const child = topBlockChildren[i];\n if (!$isTextNode(child)) {\n return false;\n }\n }\n }\n }\n return true;\n}\n\n/**\n * Returns a function that executes {@link $canShowPlaceholder}\n * @param isEditorComposing - Is the editor in composition mode due to an active Input Method Editor?\n * @returns A function that executes $canShowPlaceholder with arguments.\n */\nfunction $canShowPlaceholderCurry(isEditorComposing) {\n return () => $canShowPlaceholder(isEditorComposing);\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Finds a TextNode with a size larger than targetCharacters and returns\n * the node along with the remaining length of the text.\n * @param root - The RootNode.\n * @param targetCharacters - The number of characters whose TextNode must be larger than.\n * @returns The TextNode and the intersections offset, or null if no TextNode is found.\n */\nfunction $findTextIntersectionFromCharacters(root, targetCharacters) {\n let node = root.getFirstChild();\n let currentCharacters = 0;\n mainLoop: while (node !== null) {\n if ($isElementNode(node)) {\n const child = node.getFirstChild();\n if (child !== null) {\n node = child;\n continue;\n }\n } else if ($isTextNode(node)) {\n const characters = node.getTextContentSize();\n if (currentCharacters + characters > targetCharacters) {\n return {\n node,\n offset: targetCharacters - currentCharacters\n };\n }\n currentCharacters += characters;\n }\n const sibling = node.getNextSibling();\n if (sibling !== null) {\n node = sibling;\n continue;\n }\n let parent = node.getParent();\n while (parent !== null) {\n const parentSibling = parent.getNextSibling();\n if (parentSibling !== null) {\n node = parentSibling;\n continue mainLoop;\n }\n parent = parent.getParent();\n }\n break;\n }\n return null;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Returns a tuple that can be rested (...) into mergeRegister to clean up\n * node transforms listeners that transforms text into another node, eg. a HashtagNode.\n * @example\n * ```ts\n * useEffect(() => {\n return mergeRegister(\n ...registerLexicalTextEntity(editor, getMatch, targetNode, createNode),\n );\n }, [createNode, editor, getMatch, targetNode]);\n * ```\n * Where targetNode is the type of node containing the text you want to transform (like a text input),\n * then getMatch uses a regex to find a matching text and creates the proper node to include the matching text.\n * @param editor - The lexical editor.\n * @param getMatch - Finds a matching string that satisfies a regex expression.\n * @param targetNode - The node type that contains text to match with. eg. HashtagNode\n * @param createNode - A function that creates a new node to contain the matched text. eg createHashtagNode\n * @returns An array containing the plain text and reverse node transform listeners.\n */\nfunction registerLexicalTextEntity(editor, getMatch, targetNode, createNode) {\n const isTargetNode = node => {\n return node instanceof targetNode;\n };\n const $replaceWithSimpleText = node => {\n const textNode = $createTextNode(node.getTextContent());\n textNode.setFormat(node.getFormat());\n node.replace(textNode);\n };\n const getMode = node => {\n return node.getLatest().__mode;\n };\n const $textNodeTransform = node => {\n if (!node.isSimpleText()) {\n return;\n }\n let prevSibling = node.getPreviousSibling();\n let text = node.getTextContent();\n let currentNode = node;\n let match;\n if ($isTextNode(prevSibling)) {\n const previousText = prevSibling.getTextContent();\n const combinedText = previousText + text;\n const prevMatch = getMatch(combinedText);\n if (isTargetNode(prevSibling)) {\n if (prevMatch === null || getMode(prevSibling) !== 0) {\n $replaceWithSimpleText(prevSibling);\n return;\n } else {\n const diff = prevMatch.end - previousText.length;\n if (diff > 0) {\n const concatText = text.slice(0, diff);\n const newTextContent = previousText + concatText;\n prevSibling.select();\n prevSibling.setTextContent(newTextContent);\n if (diff === text.length) {\n node.remove();\n } else {\n const remainingText = text.slice(diff);\n node.setTextContent(remainingText);\n }\n return;\n }\n }\n } else if (prevMatch === null || prevMatch.start < previousText.length) {\n return;\n }\n }\n let prevMatchLengthToSkip = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n match = getMatch(text);\n let nextText = match === null ? '' : text.slice(match.end);\n text = nextText;\n if (nextText === '') {\n const nextSibling = currentNode.getNextSibling();\n if ($isTextNode(nextSibling)) {\n nextText = currentNode.getTextContent() + nextSibling.getTextContent();\n const nextMatch = getMatch(nextText);\n if (nextMatch === null) {\n if (isTargetNode(nextSibling)) {\n $replaceWithSimpleText(nextSibling);\n } else {\n nextSibling.markDirty();\n }\n return;\n } else if (nextMatch.start !== 0) {\n return;\n }\n }\n }\n if (match === null) {\n return;\n }\n if (match.start === 0 && $isTextNode(prevSibling) && prevSibling.isTextEntity()) {\n prevMatchLengthToSkip += match.end;\n continue;\n }\n let nodeToReplace;\n if (match.start === 0) {\n [nodeToReplace, currentNode] = currentNode.splitText(match.end);\n } else {\n [, nodeToReplace, currentNode] = currentNode.splitText(match.start + prevMatchLengthToSkip, match.end + prevMatchLengthToSkip);\n }\n if (!(nodeToReplace !== undefined)) {\n throw Error(`${'nodeToReplace'} should not be undefined. You may want to check splitOffsets passed to the splitText.`);\n }\n const replacementNode = createNode(nodeToReplace);\n replacementNode.setFormat(nodeToReplace.getFormat());\n nodeToReplace.replace(replacementNode);\n if (currentNode == null) {\n return;\n }\n prevMatchLengthToSkip = 0;\n prevSibling = replacementNode;\n }\n };\n const $reverseNodeTransform = node => {\n const text = node.getTextContent();\n const match = getMatch(text);\n if (match === null || match.start !== 0) {\n $replaceWithSimpleText(node);\n return;\n }\n if (text.length > match.end) {\n // This will split out the rest of the text as simple text\n node.splitText(match.end);\n return;\n }\n const prevSibling = node.getPreviousSibling();\n if ($isTextNode(prevSibling) && prevSibling.isTextEntity()) {\n $replaceWithSimpleText(prevSibling);\n $replaceWithSimpleText(node);\n }\n const nextSibling = node.getNextSibling();\n if ($isTextNode(nextSibling) && nextSibling.isTextEntity()) {\n $replaceWithSimpleText(nextSibling);\n\n // This may have already been converted in the previous block\n if (isTargetNode(node)) {\n $replaceWithSimpleText(node);\n }\n }\n };\n const removePlainTextTransform = editor.registerNodeTransform(TextNode, $textNodeTransform);\n const removeReverseNodeTransform = editor.registerNodeTransform(targetNode, $reverseNodeTransform);\n return [removePlainTextTransform, removeReverseNodeTransform];\n}\n\nexport { $canShowPlaceholder, $canShowPlaceholderCurry, $findTextIntersectionFromCharacters, $isRootTextContentEmpty, $isRootTextContentEmptyCurry, $rootTextContent, registerLexicalTextEntity };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { $getSelection, $isRangeSelection, TextNode, $getRoot, $isElementNode, $cloneWithProperties, $setSelection, $getPreviousSelection, $isRootOrShadowRoot, $isTextNode, $splitNode, $createParagraphNode } from 'lexical';\nexport { $splitNode, isBlockDomNode, isHTMLAnchorElement, isHTMLElement, isInlineDomNode } from 'lexical';\nimport { createRectsFromDOMRange } from '@lexical/selection';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM$1 = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst documentMode = CAN_USE_DOM$1 && 'documentMode' in document ? document.documentMode : null;\nconst IS_APPLE$1 = CAN_USE_DOM$1 && /Mac|iPod|iPhone|iPad/.test(navigator.platform);\nconst IS_FIREFOX$1 = CAN_USE_DOM$1 && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);\nconst CAN_USE_BEFORE_INPUT$1 = CAN_USE_DOM$1 && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;\nconst IS_SAFARI$1 = CAN_USE_DOM$1 && /Version\\/[\\d.]+.*Safari/.test(navigator.userAgent);\nconst IS_IOS$1 = CAN_USE_DOM$1 && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\nconst IS_ANDROID$1 = CAN_USE_DOM$1 && /Android/.test(navigator.userAgent);\n\n// Keep these in case we need to use them in the future.\n// export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);\nconst IS_CHROME$1 = CAN_USE_DOM$1 && /^(?=.*Chrome).*/i.test(navigator.userAgent);\n// export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;\n\nconst IS_ANDROID_CHROME$1 = CAN_USE_DOM$1 && IS_ANDROID$1 && IS_CHROME$1;\nconst IS_APPLE_WEBKIT$1 = CAN_USE_DOM$1 && /AppleWebKit\\/[\\d.]+/.test(navigator.userAgent) && !IS_CHROME$1;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction normalizeClassNames(...classNames) {\n const rval = [];\n for (const className of classNames) {\n if (className && typeof className === 'string') {\n for (const [s] of className.matchAll(/\\S+/g)) {\n rval.push(s);\n }\n }\n }\n return rval;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Returns a function that will execute all functions passed when called. It is generally used\n * to register multiple lexical listeners and then tear them down with a single function call, such\n * as React's useEffect hook.\n * @example\n * ```ts\n * useEffect(() => {\n * return mergeRegister(\n * editor.registerCommand(...registerCommand1 logic),\n * editor.registerCommand(...registerCommand2 logic),\n * editor.registerCommand(...registerCommand3 logic)\n * )\n * }, [editor])\n * ```\n * In this case, useEffect is returning the function returned by mergeRegister as a cleanup\n * function to be executed after either the useEffect runs again (due to one of its dependencies\n * updating) or the component it resides in unmounts.\n * Note the functions don't neccesarily need to be in an array as all arguments\n * are considered to be the func argument and spread from there.\n * The order of cleanup is the reverse of the argument order. Generally it is\n * expected that the first \"acquire\" will be \"released\" last (LIFO order),\n * because a later step may have some dependency on an earlier one.\n * @param func - An array of cleanup functions meant to be executed by the returned function.\n * @returns the function which executes all the passed cleanup functions.\n */\nfunction mergeRegister(...func) {\n return () => {\n for (let i = func.length - 1; i >= 0; i--) {\n func[i]();\n }\n // Clean up the references and make future calls a no-op\n func.length = 0;\n };\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction px(value) {\n return `${value}px`;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst mutationObserverConfig = {\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true\n};\nfunction positionNodeOnRange(editor, range, onReposition) {\n let rootDOMNode = null;\n let parentDOMNode = null;\n let observer = null;\n let lastNodes = [];\n const wrapperNode = document.createElement('div');\n function position() {\n if (!(rootDOMNode !== null)) {\n throw Error(`Unexpected null rootDOMNode`);\n }\n if (!(parentDOMNode !== null)) {\n throw Error(`Unexpected null parentDOMNode`);\n }\n const {\n left: rootLeft,\n top: rootTop\n } = rootDOMNode.getBoundingClientRect();\n const parentDOMNode_ = parentDOMNode;\n const rects = createRectsFromDOMRange(editor, range);\n if (!wrapperNode.isConnected) {\n parentDOMNode_.append(wrapperNode);\n }\n let hasRepositioned = false;\n for (let i = 0; i < rects.length; i++) {\n const rect = rects[i];\n // Try to reuse the previously created Node when possible, no need to\n // remove/create on the most common case reposition case\n const rectNode = lastNodes[i] || document.createElement('div');\n const rectNodeStyle = rectNode.style;\n if (rectNodeStyle.position !== 'absolute') {\n rectNodeStyle.position = 'absolute';\n hasRepositioned = true;\n }\n const left = px(rect.left - rootLeft);\n if (rectNodeStyle.left !== left) {\n rectNodeStyle.left = left;\n hasRepositioned = true;\n }\n const top = px(rect.top - rootTop);\n if (rectNodeStyle.top !== top) {\n rectNode.style.top = top;\n hasRepositioned = true;\n }\n const width = px(rect.width);\n if (rectNodeStyle.width !== width) {\n rectNode.style.width = width;\n hasRepositioned = true;\n }\n const height = px(rect.height);\n if (rectNodeStyle.height !== height) {\n rectNode.style.height = height;\n hasRepositioned = true;\n }\n if (rectNode.parentNode !== wrapperNode) {\n wrapperNode.append(rectNode);\n hasRepositioned = true;\n }\n lastNodes[i] = rectNode;\n }\n while (lastNodes.length > rects.length) {\n lastNodes.pop();\n }\n if (hasRepositioned) {\n onReposition(lastNodes);\n }\n }\n function stop() {\n parentDOMNode = null;\n rootDOMNode = null;\n if (observer !== null) {\n observer.disconnect();\n }\n observer = null;\n wrapperNode.remove();\n for (const node of lastNodes) {\n node.remove();\n }\n lastNodes = [];\n }\n function restart() {\n const currentRootDOMNode = editor.getRootElement();\n if (currentRootDOMNode === null) {\n return stop();\n }\n const currentParentDOMNode = currentRootDOMNode.parentElement;\n if (!(currentParentDOMNode instanceof HTMLElement)) {\n return stop();\n }\n stop();\n rootDOMNode = currentRootDOMNode;\n parentDOMNode = currentParentDOMNode;\n observer = new MutationObserver(mutations => {\n const nextRootDOMNode = editor.getRootElement();\n const nextParentDOMNode = nextRootDOMNode && nextRootDOMNode.parentElement;\n if (nextRootDOMNode !== rootDOMNode || nextParentDOMNode !== parentDOMNode) {\n return restart();\n }\n for (const mutation of mutations) {\n if (!wrapperNode.contains(mutation.target)) {\n // TODO throttle\n return position();\n }\n }\n });\n observer.observe(currentParentDOMNode, mutationObserverConfig);\n position();\n }\n const removeRootListener = editor.registerRootListener(restart);\n return () => {\n removeRootListener();\n stop();\n };\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction markSelection(editor, onReposition) {\n let previousAnchorNode = null;\n let previousAnchorOffset = null;\n let previousFocusNode = null;\n let previousFocusOffset = null;\n let removeRangeListener = () => {};\n function compute(editorState) {\n editorState.read(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n // TODO\n previousAnchorNode = null;\n previousAnchorOffset = null;\n previousFocusNode = null;\n previousFocusOffset = null;\n removeRangeListener();\n removeRangeListener = () => {};\n return;\n }\n const {\n anchor,\n focus\n } = selection;\n const currentAnchorNode = anchor.getNode();\n const currentAnchorNodeKey = currentAnchorNode.getKey();\n const currentAnchorOffset = anchor.offset;\n const currentFocusNode = focus.getNode();\n const currentFocusNodeKey = currentFocusNode.getKey();\n const currentFocusOffset = focus.offset;\n const currentAnchorNodeDOM = editor.getElementByKey(currentAnchorNodeKey);\n const currentFocusNodeDOM = editor.getElementByKey(currentFocusNodeKey);\n const differentAnchorDOM = previousAnchorNode === null || currentAnchorNodeDOM === null || currentAnchorOffset !== previousAnchorOffset || currentAnchorNodeKey !== previousAnchorNode.getKey() || currentAnchorNode !== previousAnchorNode && (!(previousAnchorNode instanceof TextNode) || currentAnchorNode.updateDOM(previousAnchorNode, currentAnchorNodeDOM, editor._config));\n const differentFocusDOM = previousFocusNode === null || currentFocusNodeDOM === null || currentFocusOffset !== previousFocusOffset || currentFocusNodeKey !== previousFocusNode.getKey() || currentFocusNode !== previousFocusNode && (!(previousFocusNode instanceof TextNode) || currentFocusNode.updateDOM(previousFocusNode, currentFocusNodeDOM, editor._config));\n if (differentAnchorDOM || differentFocusDOM) {\n const anchorHTMLElement = editor.getElementByKey(anchor.getNode().getKey());\n const focusHTMLElement = editor.getElementByKey(focus.getNode().getKey());\n // TODO handle selection beyond the common TextNode\n if (anchorHTMLElement !== null && focusHTMLElement !== null && anchorHTMLElement.tagName === 'SPAN' && focusHTMLElement.tagName === 'SPAN') {\n const range = document.createRange();\n let firstHTMLElement;\n let firstOffset;\n let lastHTMLElement;\n let lastOffset;\n if (focus.isBefore(anchor)) {\n firstHTMLElement = focusHTMLElement;\n firstOffset = focus.offset;\n lastHTMLElement = anchorHTMLElement;\n lastOffset = anchor.offset;\n } else {\n firstHTMLElement = anchorHTMLElement;\n firstOffset = anchor.offset;\n lastHTMLElement = focusHTMLElement;\n lastOffset = focus.offset;\n }\n const firstTextNode = firstHTMLElement.firstChild;\n if (!(firstTextNode !== null)) {\n throw Error(`Expected text node to be first child of span`);\n }\n const lastTextNode = lastHTMLElement.firstChild;\n if (!(lastTextNode !== null)) {\n throw Error(`Expected text node to be first child of span`);\n }\n range.setStart(firstTextNode, firstOffset);\n range.setEnd(lastTextNode, lastOffset);\n removeRangeListener();\n removeRangeListener = positionNodeOnRange(editor, range, domNodes => {\n for (const domNode of domNodes) {\n const domNodeStyle = domNode.style;\n if (domNodeStyle.background !== 'Highlight') {\n domNodeStyle.background = 'Highlight';\n }\n if (domNodeStyle.color !== 'HighlightText') {\n domNodeStyle.color = 'HighlightText';\n }\n if (domNodeStyle.zIndex !== '-1') {\n domNodeStyle.zIndex = '-1';\n }\n if (domNodeStyle.pointerEvents !== 'none') {\n domNodeStyle.pointerEvents = 'none';\n }\n if (domNodeStyle.marginTop !== px(-1.5)) {\n domNodeStyle.marginTop = px(-1.5);\n }\n if (domNodeStyle.paddingTop !== px(4)) {\n domNodeStyle.paddingTop = px(4);\n }\n if (domNodeStyle.paddingBottom !== px(0)) {\n domNodeStyle.paddingBottom = px(0);\n }\n }\n if (onReposition !== undefined) {\n onReposition(domNodes);\n }\n });\n }\n }\n previousAnchorNode = currentAnchorNode;\n previousAnchorOffset = currentAnchorOffset;\n previousFocusNode = currentFocusNode;\n previousFocusOffset = currentFocusOffset;\n });\n }\n compute(editor.getEditorState());\n return mergeRegister(editor.registerUpdateListener(({\n editorState\n }) => compute(editorState)), removeRangeListener, () => {\n removeRangeListener();\n });\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n// Hotfix to export these with inlined types #5918\nconst CAN_USE_BEFORE_INPUT = CAN_USE_BEFORE_INPUT$1;\nconst CAN_USE_DOM = CAN_USE_DOM$1;\nconst IS_ANDROID = IS_ANDROID$1;\nconst IS_ANDROID_CHROME = IS_ANDROID_CHROME$1;\nconst IS_APPLE = IS_APPLE$1;\nconst IS_APPLE_WEBKIT = IS_APPLE_WEBKIT$1;\nconst IS_CHROME = IS_CHROME$1;\nconst IS_FIREFOX = IS_FIREFOX$1;\nconst IS_IOS = IS_IOS$1;\nconst IS_SAFARI = IS_SAFARI$1;\n/**\n * Takes an HTML element and adds the classNames passed within an array,\n * ignoring any non-string types. A space can be used to add multiple classes\n * eg. addClassNamesToElement(element, ['element-inner active', true, null])\n * will add both 'element-inner' and 'active' as classes to that element.\n * @param element - The element in which the classes are added\n * @param classNames - An array defining the class names to add to the element\n */\nfunction addClassNamesToElement(element, ...classNames) {\n const classesToAdd = normalizeClassNames(...classNames);\n if (classesToAdd.length > 0) {\n element.classList.add(...classesToAdd);\n }\n}\n\n/**\n * Takes an HTML element and removes the classNames passed within an array,\n * ignoring any non-string types. A space can be used to remove multiple classes\n * eg. removeClassNamesFromElement(element, ['active small', true, null])\n * will remove both the 'active' and 'small' classes from that element.\n * @param element - The element in which the classes are removed\n * @param classNames - An array defining the class names to remove from the element\n */\nfunction removeClassNamesFromElement(element, ...classNames) {\n const classesToRemove = normalizeClassNames(...classNames);\n if (classesToRemove.length > 0) {\n element.classList.remove(...classesToRemove);\n }\n}\n\n/**\n * Returns true if the file type matches the types passed within the acceptableMimeTypes array, false otherwise.\n * The types passed must be strings and are CASE-SENSITIVE.\n * eg. if file is of type 'text' and acceptableMimeTypes = ['TEXT', 'IMAGE'] the function will return false.\n * @param file - The file you want to type check.\n * @param acceptableMimeTypes - An array of strings of types which the file is checked against.\n * @returns true if the file is an acceptable mime type, false otherwise.\n */\nfunction isMimeType(file, acceptableMimeTypes) {\n for (const acceptableType of acceptableMimeTypes) {\n if (file.type.startsWith(acceptableType)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Lexical File Reader with:\n * 1. MIME type support\n * 2. batched results (HistoryPlugin compatibility)\n * 3. Order aware (respects the order when multiple Files are passed)\n *\n * const filesResult = await mediaFileReader(files, ['image/']);\n * filesResult.forEach(file => editor.dispatchCommand('INSERT_IMAGE', \\\\{\n * src: file.result,\n * \\\\}));\n */\nfunction mediaFileReader(files, acceptableMimeTypes) {\n const filesIterator = files[Symbol.iterator]();\n return new Promise((resolve, reject) => {\n const processed = [];\n const handleNextFile = () => {\n const {\n done,\n value: file\n } = filesIterator.next();\n if (done) {\n return resolve(processed);\n }\n const fileReader = new FileReader();\n fileReader.addEventListener('error', reject);\n fileReader.addEventListener('load', () => {\n const result = fileReader.result;\n if (typeof result === 'string') {\n processed.push({\n file,\n result\n });\n }\n handleNextFile();\n });\n if (isMimeType(file, acceptableMimeTypes)) {\n fileReader.readAsDataURL(file);\n } else {\n handleNextFile();\n }\n };\n handleNextFile();\n });\n}\n\n/**\n * \"Depth-First Search\" starts at the root/top node of a tree and goes as far as it can down a branch end\n * before backtracking and finding a new path. Consider solving a maze by hugging either wall, moving down a\n * branch until you hit a dead-end (leaf) and backtracking to find the nearest branching path and repeat.\n * It will then return all the nodes found in the search in an array of objects.\n * @param startingNode - The node to start the search, if ommitted, it will start at the root node.\n * @param endingNode - The node to end the search, if ommitted, it will find all descendants of the startingNode.\n * @returns An array of objects of all the nodes found by the search, including their depth into the tree.\n * \\\\{depth: number, node: LexicalNode\\\\} It will always return at least 1 node (the ending node) so long as it exists\n */\nfunction $dfs(startingNode, endingNode) {\n const nodes = [];\n const start = (startingNode || $getRoot()).getLatest();\n const end = endingNode || ($isElementNode(start) ? start.getLastDescendant() || start : start);\n let node = start;\n let depth = $getDepth(node);\n while (node !== null && !node.is(end)) {\n nodes.push({\n depth,\n node\n });\n if ($isElementNode(node) && node.getChildrenSize() > 0) {\n node = node.getFirstChild();\n depth++;\n } else {\n // Find immediate sibling or nearest parent sibling\n let sibling = null;\n while (sibling === null && node !== null) {\n sibling = node.getNextSibling();\n if (sibling === null) {\n node = node.getParent();\n depth--;\n } else {\n node = sibling;\n }\n }\n }\n }\n if (node !== null && node.is(end)) {\n nodes.push({\n depth,\n node\n });\n }\n return nodes;\n}\nfunction $getDepth(node) {\n let innerNode = node;\n let depth = 0;\n while ((innerNode = innerNode.getParent()) !== null) {\n depth++;\n }\n return depth;\n}\n\n/**\n * Performs a right-to-left preorder tree traversal.\n * From the starting node it goes to the rightmost child, than backtracks to paret and finds new rightmost path.\n * It will return the next node in traversal sequence after the startingNode.\n * The traversal is similar to $dfs functions above, but the nodes are visited right-to-left, not left-to-right.\n * @param startingNode - The node to start the search.\n * @returns The next node in pre-order right to left traversal sequence or `null`, if the node does not exist\n */\nfunction $getNextRightPreorderNode(startingNode) {\n let node = startingNode;\n if ($isElementNode(node) && node.getChildrenSize() > 0) {\n node = node.getLastChild();\n } else {\n let sibling = null;\n while (sibling === null && node !== null) {\n sibling = node.getPreviousSibling();\n if (sibling === null) {\n node = node.getParent();\n } else {\n node = sibling;\n }\n }\n }\n return node;\n}\n\n/**\n * Takes a node and traverses up its ancestors (toward the root node)\n * in order to find a specific type of node.\n * @param node - the node to begin searching.\n * @param klass - an instance of the type of node to look for.\n * @returns the node of type klass that was passed, or null if none exist.\n */\nfunction $getNearestNodeOfType(node, klass) {\n let parent = node;\n while (parent != null) {\n if (parent instanceof klass) {\n return parent;\n }\n parent = parent.getParent();\n }\n return null;\n}\n\n/**\n * Returns the element node of the nearest ancestor, otherwise throws an error.\n * @param startNode - The starting node of the search\n * @returns The ancestor node found\n */\nfunction $getNearestBlockElementAncestorOrThrow(startNode) {\n const blockNode = $findMatchingParent(startNode, node => $isElementNode(node) && !node.isInline());\n if (!$isElementNode(blockNode)) {\n {\n throw Error(`Expected node ${startNode.__key} to have closest block element node.`);\n }\n }\n return blockNode;\n}\n/**\n * Starts with a node and moves up the tree (toward the root node) to find a matching node based on\n * the search parameters of the findFn. (Consider JavaScripts' .find() function where a testing function must be\n * passed as an argument. eg. if( (node) => node.__type === 'div') ) return true; otherwise return false\n * @param startingNode - The node where the search starts.\n * @param findFn - A testing function that returns true if the current node satisfies the testing parameters.\n * @returns A parent node that matches the findFn parameters, or null if one wasn't found.\n */\nconst $findMatchingParent = (startingNode, findFn) => {\n let curr = startingNode;\n while (curr !== $getRoot() && curr != null) {\n if (findFn(curr)) {\n return curr;\n }\n curr = curr.getParent();\n }\n return null;\n};\n\n/**\n * Attempts to resolve nested element nodes of the same type into a single node of that type.\n * It is generally used for marks/commenting\n * @param editor - The lexical editor\n * @param targetNode - The target for the nested element to be extracted from.\n * @param cloneNode - See {@link $createMarkNode}\n * @param handleOverlap - Handles any overlap between the node to extract and the targetNode\n * @returns The lexical editor\n */\nfunction registerNestedElementResolver(editor, targetNode, cloneNode, handleOverlap) {\n const $isTargetNode = node => {\n return node instanceof targetNode;\n };\n const $findMatch = node => {\n // First validate we don't have any children that are of the target,\n // as we need to handle them first.\n const children = node.getChildren();\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if ($isTargetNode(child)) {\n return null;\n }\n }\n let parentNode = node;\n let childNode = node;\n while (parentNode !== null) {\n childNode = parentNode;\n parentNode = parentNode.getParent();\n if ($isTargetNode(parentNode)) {\n return {\n child: childNode,\n parent: parentNode\n };\n }\n }\n return null;\n };\n const $elementNodeTransform = node => {\n const match = $findMatch(node);\n if (match !== null) {\n const {\n child,\n parent\n } = match;\n\n // Simple path, we can move child out and siblings into a new parent.\n\n if (child.is(node)) {\n handleOverlap(parent, node);\n const nextSiblings = child.getNextSiblings();\n const nextSiblingsLength = nextSiblings.length;\n parent.insertAfter(child);\n if (nextSiblingsLength !== 0) {\n const newParent = cloneNode(parent);\n child.insertAfter(newParent);\n for (let i = 0; i < nextSiblingsLength; i++) {\n newParent.append(nextSiblings[i]);\n }\n }\n if (!parent.canBeEmpty() && parent.getChildrenSize() === 0) {\n parent.remove();\n }\n }\n }\n };\n return editor.registerNodeTransform(targetNode, $elementNodeTransform);\n}\n\n/**\n * Clones the editor and marks it as dirty to be reconciled. If there was a selection,\n * it would be set back to its previous state, or null otherwise.\n * @param editor - The lexical editor\n * @param editorState - The editor's state\n */\nfunction $restoreEditorState(editor, editorState) {\n const FULL_RECONCILE = 2;\n const nodeMap = new Map();\n const activeEditorState = editor._pendingEditorState;\n for (const [key, node] of editorState._nodeMap) {\n nodeMap.set(key, $cloneWithProperties(node));\n }\n if (activeEditorState) {\n activeEditorState._nodeMap = nodeMap;\n }\n editor._dirtyType = FULL_RECONCILE;\n const selection = editorState._selection;\n $setSelection(selection === null ? null : selection.clone());\n}\n\n/**\n * If the selected insertion area is the root/shadow root node (see {@link lexical!$isRootOrShadowRoot}),\n * the node will be appended there, otherwise, it will be inserted before the insertion area.\n * If there is no selection where the node is to be inserted, it will be appended after any current nodes\n * within the tree, as a child of the root node. A paragraph node will then be added after the inserted node and selected.\n * @param node - The node to be inserted\n * @returns The node after its insertion\n */\nfunction $insertNodeToNearestRoot(node) {\n const selection = $getSelection() || $getPreviousSelection();\n if ($isRangeSelection(selection)) {\n const {\n focus\n } = selection;\n const focusNode = focus.getNode();\n const focusOffset = focus.offset;\n if ($isRootOrShadowRoot(focusNode)) {\n const focusChild = focusNode.getChildAtIndex(focusOffset);\n if (focusChild == null) {\n focusNode.append(node);\n } else {\n focusChild.insertBefore(node);\n }\n node.selectNext();\n } else {\n let splitNode;\n let splitOffset;\n if ($isTextNode(focusNode)) {\n splitNode = focusNode.getParentOrThrow();\n splitOffset = focusNode.getIndexWithinParent();\n if (focusOffset > 0) {\n splitOffset += 1;\n focusNode.splitText(focusOffset);\n }\n } else {\n splitNode = focusNode;\n splitOffset = focusOffset;\n }\n const [, rightTree] = $splitNode(splitNode, splitOffset);\n rightTree.insertBefore(node);\n rightTree.selectStart();\n }\n } else {\n if (selection != null) {\n const nodes = selection.getNodes();\n nodes[nodes.length - 1].getTopLevelElementOrThrow().insertAfter(node);\n } else {\n const root = $getRoot();\n root.append(node);\n }\n const paragraphNode = $createParagraphNode();\n node.insertAfter(paragraphNode);\n paragraphNode.select();\n }\n return node.getLatest();\n}\n\n/**\n * Wraps the node into another node created from a createElementNode function, eg. $createParagraphNode\n * @param node - Node to be wrapped.\n * @param createElementNode - Creates a new lexical element to wrap the to-be-wrapped node and returns it.\n * @returns A new lexical element with the previous node appended within (as a child, including its children).\n */\nfunction $wrapNodeInElement(node, createElementNode) {\n const elementNode = createElementNode();\n node.replace(elementNode);\n elementNode.append(node);\n return elementNode;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\n/**\n * @param object = The instance of the type\n * @param objectClass = The class of the type\n * @returns Whether the object is has the same Klass of the objectClass, ignoring the difference across window (e.g. different iframs)\n */\nfunction objectKlassEquals(object, objectClass) {\n return object !== null ? Object.getPrototypeOf(object).constructor.name === objectClass.name : false;\n}\n\n/**\n * Filter the nodes\n * @param nodes Array of nodes that needs to be filtered\n * @param filterFn A filter function that returns node if the current node satisfies the condition otherwise null\n * @returns Array of filtered nodes\n */\n\nfunction $filter(nodes, filterFn) {\n const result = [];\n for (let i = 0; i < nodes.length; i++) {\n const node = filterFn(nodes[i]);\n if (node !== null) {\n result.push(node);\n }\n }\n return result;\n}\n/**\n * Appends the node before the first child of the parent node\n * @param parent A parent node\n * @param node Node that needs to be appended\n */\nfunction $insertFirst(parent, node) {\n const firstChild = parent.getFirstChild();\n if (firstChild !== null) {\n firstChild.insertBefore(node);\n } else {\n parent.append(node);\n }\n}\n\n/**\n * Calculates the zoom level of an element as a result of using\n * css zoom property.\n * @param element\n */\nfunction calculateZoomLevel(element) {\n if (IS_FIREFOX) {\n return 1;\n }\n let zoom = 1;\n while (element) {\n zoom *= Number(window.getComputedStyle(element).getPropertyValue('zoom'));\n element = element.parentElement;\n }\n return zoom;\n}\n\n/**\n * Checks if the editor is a nested editor created by LexicalNestedComposer\n */\nfunction $isEditorIsNestedEditor(editor) {\n return editor._parentEditor !== null;\n}\n\nexport { $dfs, $filter, $findMatchingParent, $getNearestBlockElementAncestorOrThrow, $getNearestNodeOfType, $getNextRightPreorderNode, $insertFirst, $insertNodeToNearestRoot, $isEditorIsNestedEditor, $restoreEditorState, $wrapNodeInElement, CAN_USE_BEFORE_INPUT, CAN_USE_DOM, IS_ANDROID, IS_ANDROID_CHROME, IS_APPLE, IS_APPLE_WEBKIT, IS_CHROME, IS_FIREFOX, IS_IOS, IS_SAFARI, addClassNamesToElement, calculateZoomLevel, isMimeType, markSelection, mediaFileReader, mergeRegister, objectKlassEquals, positionNodeOnRange, registerNestedElementResolver, removeClassNamesFromElement };\n","import { cn } from '@/utilities/functions';\nimport { getIcon, getAction, getContent, getTitle } from '../toaster/utils';\nimport { X } from 'lucide-react';\n\nconst Alert = ( {\n\tdesign = 'inline', // stack/inline\n\ttheme = 'light', // light/dark\n\tvariant = 'neutral',\n\tclassName = '',\n\ttitle = 'Title',\n\tcontent = 'Description',\n\ticon = null,\n\tonClose = () => {},\n\taction = {\n\t\tlabel: 'Action',\n\t\tonClick: () => {},\n\t\ttype: 'link',\n\t},\n} ) => {\n\tconst closeAlert = () => {\n\t\tonClose();\n\t};\n\n\tconst containerVariantClassNames = {\n\t\tstack: 'w-[22.5rem]',\n\t\tinline: 'lg:w-[47.5rem] w-full',\n\t};\n\n\t// Variant classes - Based on the variant prop.\n\tconst variantClassNames = {\n\t\tlight: {\n\t\t\tneutral: 'border-alert-border-neutral bg-alert-background-neutral',\n\t\t\tcustom: 'border-alert-border-neutral bg-alert-background-neutral',\n\t\t\tinfo: 'border-alert-border-info bg-alert-background-info',\n\t\t\tsuccess: 'border-alert-border-green bg-alert-background-green',\n\t\t\twarning: 'border-alert-border-warning bg-alert-background-warning',\n\t\t\terror: 'border-alert-border-danger bg-alert-background-danger',\n\t\t},\n\t\tdark: 'bg-background-inverse border-background-inverse',\n\t};\n\n\t// Close icon class names.\n\tconst closeIconClassNames = {\n\t\tlight: 'text-icon-secondary',\n\t\tdark: 'text-icon-inverse',\n\t};\n\n\tconst handleAction = () => {\n\t\taction?.onClick?.( () => closeAlert() );\n\t};\n\n\tif ( design === 'stack' ) {\n\t\treturn (\n\t\t\t
\n\t\t\t\t<>\n\t\t\t\t\t
\n\t\t\t\t\t\t{ getIcon( { variant, icon, theme } ) }\n\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t{ getTitle( { title, theme } ) }\n\t\t\t\t\t\t{ getContent( { content, theme } ) }\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taction?.label &&\n\t\t\t\t\t\t\t\ttypeof action?.onClick === 'function' && (\n\t\t\t\t\t\t\t/* eslint-disable */\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t{getAction({\n\t\t\t\t\t\t\t\t\t\t\tactionLabel: action?.label,\n\t\t\t\t\t\t\t\t\t\t\tactionType:\n\t\t\t\t\t\t\t\t\t\t\t\taction?.type ?? 'button',\n\t\t\t\t\t\t\t\t\t\t\tonAction: handleAction,\n\t\t\t\t\t\t\t\t\t\t\ttheme,\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/* eslint-enable */\n\t\t\t\t\t\t}\n\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>\n\t\t\t
\n\t\t);\n\t}\n\n\treturn (\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t{ getIcon( { variant, icon, theme } ) }\n\t\t\t\t
\n\t\t\t\t
span:first-child]:shrink-0\">\n\t\t\t\t\t{ getTitle( { title, theme } ) }\n\t\t\t\t\t{ getContent( { content, theme } ) }\n\t\t\t\t
\n\t\t\t
\n\t\t\t
\n\t\t\t\t{\n\t\t\t\t\taction?.label && typeof action?.onClick === 'function' && (\n\t\t\t\t\t\t/* eslint-disable */\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{getAction({\n\t\t\t\t\t\t\t\tactionLabel: action?.label,\n\t\t\t\t\t\t\t\tactionType: action?.type ?? 'button',\n\t\t\t\t\t\t\t\tonAction: handleAction,\n\t\t\t\t\t\t\t\ttheme,\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\t/* eslint-enable */\n\t\t\t\t}\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t);\n};\n\nexport default Alert;\n","import { cn } from '@/utilities/functions';\n\nconst Avatar = ( props ) => {\n\tconst {\n\t\tvariant = 'primary',\n\t\tsize = 'md',\n\t\tborder = 'subtle',\n\t\turl = '',\n\t\tchildren,\n\t\tclassName,\n\t} = props;\n\n\tconst effectiveBorder = url && border === 'none' ? 'subtle' : border;\n\n\tconst baseClasses =\n\t\t'rounded-full overflow-hidden flex items-center justify-center';\n\n\tconst variantClasses = {\n\t\twhite: 'text-text-primary bg-background-primary',\n\t\tgray: 'text-text-primary bg-background-secondary',\n\t\tprimary: 'text-text-on-color bg-background-brand',\n\t\tprimaryLight: 'text-text-primary bg-brand-background-50',\n\t\tdark: 'text-text-on-color bg-button-secondary',\n\t}?.[ variant ];\n\n\tconst sizeClasses = {\n\t\txs: 'w-5 h-5 [&>svg]:h-3 [&>svg]:w-3 text-xs',\n\t\tsm: 'w-6 h-6 [&>svg]:h-4 [&>svg]:w-4 text-sm',\n\t\tmd: 'w-8 h-8 [&>svg]:h-5 [&>svg]:w-5 text-base',\n\t\tlg: 'w-10 h-10 [&>svg]:h-6 [&>svg]:w-6 text-lg',\n\t}?.[ size ];\n\n\tconst borderClasses = {\n\t\tnone: '',\n\t\tsubtle: 'border border-solid border-border-transparent-subtle',\n\t\tring: 'border-4 border-solid border-border-white',\n\t}?.[ effectiveBorder ];\n\n\tconst contentClasses = url ? 'bg-cover bg-center bg-no-repeat' : '';\n\n\tconst getChildren = () => {\n\t\tif ( ! children ) {\n\t\t\treturn null;\n\t\t}\n\t\tif ( typeof children === 'string' ) {\n\t\t\treturn children?.[ 0 ]?.toUpperCase();\n\t\t}\n\t\treturn children;\n\t};\n\n\treturn (\n\t\t
\n\t\t\t{ getChildren() }\n\t\t
\n\t);\n};\n\nexport default Avatar;\n","import { forwardRef } from 'react';\nimport { cn } from '@/utilities/functions';\nimport { X } from 'lucide-react';\n\n/**\n * Badge component.\n */\n\nconst BadgeComponent = ( props, ref ) => {\n\tconst {\n\t\tlabel = '',\n\t\tsize = 'sm', // xs, sm, md, lg\n\t\tclassName = '',\n\t\ttype = 'pill', // pill, rounded\n\t\tvariant = 'neutral', // neutral, red, yellow, green, blue, inverse\n\t\ticon = null,\n\t\tdisabled = false,\n\t\tonClose = () => {},\n\t\tclosable = false,\n\t\tonMouseDown = () => {},\n\t} = props;\n\n\t// Base classes. - Mandatory classes.\n\tconst baseClasses =\n\t\t'font-medium border-badge-border-gray flex gap-1 items-center justify-center border border-solid';\n\n\t// Size classes - Based on the size prop.\n\tconst sizeClasses = {\n\t\txs: 'py-0.5 px-1 text-xs',\n\t\tsm: 'py-1 px-1.5 text-xs',\n\t\tmd: 'py-1 px-1.5 text-sm',\n\t\tlg: 'py-1 px-1.5 text-base',\n\t};\n\n\t// Type classes - Based on the type prop.\n\tconst typeClasses = {\n\t\tpill: 'rounded-full',\n\t\trounded: 'rounded',\n\t};\n\n\t// Variant classes - Based on the variant prop.\n\tconst variantClasses = {\n\t\tneutral:\n\t\t\t'bg-badge-background-gray hover:bg-badge-hover-gray text-badge-color-gray border-badge-border-gray',\n\t\tred: 'bg-badge-background-red hover:bg-badge-hover-red text-badge-color-red border-badge-border-red',\n\t\tyellow: 'bg-badge-background-yellow hover:bg-badge-hover-yellow text-badge-color-yellow border-badge-border-yellow',\n\t\tgreen: 'bg-badge-background-green hover:bg-badge-hover-green text-badge-color-green border-badge-border-green',\n\t\tblue: 'bg-badge-background-sky hover:bg-badge-hover-sky text-badge-color-sky border-badge-border-sky',\n\t\tinverse:\n\t\t\t'bg-background-inverse hover:bg-badge-hover-inverse text-text-inverse border-background-inverse',\n\t\tdisabled:\n\t\t\t'bg-badge-background-disabled hover:bg-badge-hover-disabled text-badge-color-disabled border-badge-border-disabled disabled cursor-not-allowed',\n\t};\n\n\tlet filteredClasses = '';\n\tlet buttonClasses =\n\t\t'group relative justify-center flex items-center [&>svg]:h-4 [&>svg]:w-4 cursor-pointer';\n\n\tif ( disabled ) {\n\t\tfilteredClasses = variantClasses.disabled;\n\t\tbuttonClasses += ' cursor-not-allowed disabled';\n\t} else {\n\t\tfilteredClasses = variantClasses[ variant ];\n\t}\n\n\tif ( ! label ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t
\n\t\t\t{ icon ? (\n\t\t\t\tsvg]:h-4 [&>svg]:w-4\">\n\t\t\t\t\t{ icon }\n\t\t\t\t\n\t\t\t) : null }\n\t\t\t{ label }\n\t\t\t{ closable && (\n\t\t\t\t\n\t\t\t\t\t{ `Remove ${ label }` }\n\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};\n\nconst Badge = forwardRef( BadgeComponent );\nBadge.displayName = 'Badge';\n\nexport default Badge;\n","import React, { createContext, useContext } from 'react';\nimport { cn } from '@/utilities/functions';\nimport { ChevronRight, Ellipsis } from 'lucide-react';\n\nconst BreadcrumbContext = createContext();\n\nconst sizeClasses = {\n\tsm: {\n\t\ttext: 'text-sm',\n\t\tseparator: 'text-sm',\n\t\tseparatorIconSize: 16,\n\t},\n\tmd: {\n\t\ttext: 'text-base',\n\t\tseparator: 'text-base',\n\t\tseparatorIconSize: 18,\n\t},\n};\n\nconst Breadcrumb = ( { children, size = 'sm' } ) => {\n\tconst sizes = sizeClasses[ size ] || sizeClasses.sm;\n\n\treturn (\n\t\t
\n\t\t\t\n\t\t\n\t);\n};\n\nconst BreadcrumbList = ( { children } ) => {\n\treturn <>{ children }>;\n};\n\nconst BreadcrumbItem = ( { children } ) => {\n\treturn
{ children };\n};\n\nconst BreadcrumbLink = ( {\n\thref,\n\tchildren,\n\tclassName,\n\tas: AsElement = 'a',\n\t...props\n} ) => {\n\tconst { sizes } = useContext( BreadcrumbContext );\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\n\nconst BreadcrumbSeparator = ( { type } ) => {\n\tconst { sizes } = useContext( BreadcrumbContext );\n\tconst separatorIcons = {\n\t\tslash:
/,\n\t\tarrow:
,\n\t};\n\n\treturn (\n\t\t
\n\t\t\t{ separatorIcons[ type ] || separatorIcons.arrow }\n\t\t\n\t);\n};\n\nconst BreadcrumbEllipsis = () => {\n\tconst { sizes } = useContext( BreadcrumbContext );\n\n\treturn (\n\t\t
\n\t);\n};\n\nconst BreadcrumbPage = ( { children } ) => {\n\tconst { sizes } = useContext( BreadcrumbContext );\n\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\n\nexport {\n\tBreadcrumb,\n\tBreadcrumbList,\n\tBreadcrumbItem,\n\tBreadcrumbLink,\n\tBreadcrumbSeparator,\n\tBreadcrumbEllipsis,\n\tBreadcrumbPage,\n};\n","import React, {\n\tuseCallback,\n\tforwardRef,\n\tisValidElement,\n\tcreateContext,\n\tuseContext,\n} from 'react';\nimport { cn } from '@/utilities/functions';\n\n/**\n * Context for managing the ButtonGroup state.\n */\nconst ButtonGroupContext = createContext();\n\n/**\n * Hook to use the ButtonGroup context.\n * @return {Object} The context value of the ButtonGroup.\n */\nconst useButtonGroup = () => useContext( ButtonGroupContext );\n\n/**\n * ButtonGroup component to wrap Button components.\n * @param {Object} props - The properties passed to the component.\n * @param {React.ReactNode} props.children - The children elements, expected to be Button components.\n * @param {string|null} [props.activeItem=null] - The currently active item in the group.\n * @param {Function} [props.onChange] - Callback when the active item changes.\n * @param {string} [props.className] - Additional class names for styling.\n * @param {string} [props.size='md'] - Size of the buttons in the group ('xs', 'sm', 'md').\n * @param {string} [props.iconPosition='left'] - Position of the icon in the button ('left' or 'right').\n */\nconst ButtonGroup = ( props ) => {\n\tconst {\n\t\tchildren,\n\t\tactiveItem = null,\n\t\tonChange,\n\t\tclassName,\n\t\tsize = 'md',\n\t\ticonPosition = 'left',\n\t} = props;\n\n\tconst handleChange = useCallback(\n\t\t( event, value ) => {\n\t\t\tif ( onChange ) {\n\t\t\t\tonChange( { event, value } );\n\t\t\t}\n\t\t},\n\t\t[ onChange ]\n\t);\n\n\tconst groupClassName = cn(\n\t\t'box-border flex border border-border-subtle border-solid rounded',\n\t\tclassName\n\t);\n\n\treturn (\n\t\t
\n\t\t\t\n\t\t\t\t{ React.Children.map( children, ( child, index ) => {\n\t\t\t\t\tif ( ! isValidElement( child ) ) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tconst isFirstChild = index === 0;\n\t\t\t\t\tconst isLastChild =\n\t\t\t\t\t\tindex === React.Children.count( children ) - 1;\n\t\t\t\t\treturn React.cloneElement( child, {\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tisFirstChild,\n\t\t\t\t\t\tisLastChild,\n\t\t\t\t\t} );\n\t\t\t\t} ) }\n\t\t\t\n\t\t
\n\t);\n};\n\n/**\n * Button component to be used within a ButtonGroup.\n * @param {Object} props - The properties passed to the component.\n * @param {string} props.slug - Unique identifier for the button.\n * @param {string} props.text - Text to be displayed inside the button.\n * @param {React.ReactNode} [props.icon] - Optional icon to be displayed inside the button.\n * @param {string} [props.className] - Additional class names for styling.\n * @param {boolean} props.isFirstChild - Flag indicating if this button is the first child in the group.\n * @param {boolean} props.isLastChild - Flag indicating if this button is the last child in the group.\n * @param {boolean} [props.disabled=false] - Flag indicating if the button is disabled.\n * @param {Object} [props.rest] - Other properties to be passed to the button element.\n * @param {React.Ref} ref - Reference to the button element.\n */\nconst ButtonComponent = ( props, ref ) => {\n\tconst providerValue = useButtonGroup();\n\tconst {\n\t\tslug,\n\t\ttext,\n\t\ticon,\n\t\tclassName,\n\t\tdisabled = false,\n\t\tisFirstChild,\n\t\tisLastChild,\n\t\t...rest\n\t} = props;\n\n\tif ( ! providerValue ) {\n\t\tthrow new Error( 'Button should be used inside Button Group' );\n\t}\n\n\tconst { activeItem, onChange, size, iconPosition } = providerValue;\n\n\tconst sizes = {\n\t\txs: 'py-1 px-1 text-sm gap-0.5 [&>svg]:h-4 [&>svg]:w-4',\n\t\tsm: 'py-2 px-2 text-base gap-1 [&>svg]:h-4 [&>svg]:w-4',\n\t\tmd: 'py-2.5 px-2.5 text-base gap-1 [&>svg]:h-5 [&>svg]:w-5',\n\t};\n\n\tconst baseClasses =\n\t\t'bg-background-primary text-primary cursor-pointer flex items-center justify-center';\n\n\t// Button hover classes.\n\tconst hoverClasses = 'hover:bg-button-tertiary-hover';\n\n\t// Button focus classes.\n\tconst focusClasses = 'focus:outline-none';\n\n\t// Button disabled classes.\n\tconst disabledClasses = disabled\n\t\t? 'text-text-disabled cursor-not-allowed'\n\t\t: '';\n\n\tconst firstChildClasses = isFirstChild\n\t\t? 'rounded-tl rounded-bl border-0 border-r border-border-subtle'\n\t\t: '';\n\tconst lastChildClasses = isLastChild\n\t\t? 'rounded-tr rounded-br border-0'\n\t\t: '';\n\tconst borderClasses = 'border-0 border-r border-border-subtle border-solid';\n\tconst activeClasses = activeItem === slug ? 'bg-button-disabled' : '';\n\n\tconst buttonClassName = cn(\n\t\tbaseClasses,\n\t\thoverClasses,\n\t\tfocusClasses,\n\t\tdisabledClasses,\n\t\tsizes[ size ],\n\t\tborderClasses,\n\t\tactiveClasses,\n\t\tfirstChildClasses,\n\t\tlastChildClasses,\n\t\tclassName\n\t);\n\n\tconst handleClick = ( event ) => {\n\t\tonChange( event, { slug, text } );\n\t};\n\n\treturn (\n\t\t
\n\t);\n};\nconst Button = forwardRef( ButtonComponent );\nButton.displayName = 'Button';\n\nconst exports = {\n\tGroup: ButtonGroup,\n\tButton,\n};\n\nexport default exports;\n","import React, { forwardRef } from 'react';\nimport { cn } from '@/utilities/functions';\n\nconst Button = forwardRef( ( props, ref ) => {\n\tconst {\n\t\tvariant = 'primary', // primary, secondary, outline, ghost, link\n\t\tsize = 'md', // xs, sm, md, lg\n\t\ttype = 'button',\n\t\ttag = 'button',\n\t\tclassName,\n\t\tchildren,\n\t\tdisabled = false,\n\t\tdestructive = false, // true, false\n\t\ticon = null, // icon component\n\t\ticonPosition = 'left', // left, right,\n\t\tloading = false,\n\t\t...rest\n\t} = props;\n\n\tconst commonClass =\n\t\t'border border-solid cursor-pointer transition-colors duration-300 ease-in-out text-xs font-semibold focus:ring-2 focus:ring-toggle-on focus:ring-offset-2 disabled:text-text-disabled';\n\n\tconst loadingClass = loading\n\t\t? 'opacity-50 disabled:cursor-not-allowed'\n\t\t: '';\n\n\tconst variantClassNames = {\n\t\tprimary:\n\t\t\t'text-text-on-color bg-button-primary hover:bg-button-primary-hover border-button-primary hover:border-button-primary-hover disabled:bg-button-disabled disabled:border-button-disabled',\n\t\tsecondary:\n\t\t\t'text-text-on-color bg-button-secondary hover:bg-button-secondary-hover border-button-secondary hover:border-button-secondary-hover disabled:bg-button-disabled disabled:border-button-disabled',\n\t\toutline:\n\t\t\t'text-button-tertiary-color border border-border-subtle bg-button-tertiary hover:bg-button-tertiary-hover hover:border-border-subtle disabled:bg-button-tertiary disabled:border-border-disabled',\n\t\tghost: 'text-text-primary bg-transparent border border-transparent hover:bg-button-tertiary-hover',\n\t\tlink: 'text-link-primary bg-transparent hover:text-link-primary-hover hover:underline p-0 border-0 leading-none',\n\t}?.[ variant ];\n\n\tconst destructiveClassNames =\n\t\tdestructive && ! disabled\n\t\t\t? {\n\t\t\t\tprimary:\n\t\t\t\t\t\t'bg-button-danger hover:bg-button-danger-hover border-button-danger hover:border-button-danger-hover',\n\t\t\t\toutline:\n\t\t\t\t\t\t'text-button-danger border border-button-danger hover:border-button-danger bg-button-tertiary hover:bg-field-background-error',\n\t\t\t\tghost: 'text-button-danger hover:bg-field-background-error',\n\t\t\t\tlink: 'text-button-danger hover:text-button-danger-secondary',\n\t\t\t}?.[ variant ]\n\t\t\t: '';\n\n\tconst sizeClassNames = {\n\t\txs: 'p-1 rounded-sm [&>svg]:h-4 [&>svg]:w-4',\n\t\tsm: 'p-2 rounded-sm [&>svg]:h-4 [&>svg]:w-4',\n\t\tmd: 'p-2.5 rounded-md text-sm [&>svg]:h-5 [&>svg]:w-5',\n\t\tlg: 'p-3 rounded-lg text-base [&>svg]:h-6 [&>svg]:w-6',\n\t}?.[ size ];\n\n\tlet iconLeft,\n\t\ticonRight = null;\n\tlet iconClass = '';\n\tif ( icon ) {\n\t\ticonClass = 'flex items-center justify-center gap-1';\n\t\tif ( iconPosition === 'left' ) {\n\t\t\ticonLeft = icon;\n\t\t} else {\n\t\t\ticonRight = icon;\n\t\t}\n\t}\n\n\tconst Tag = tag;\n\treturn (\n\t\t
\n\t\t\t{ iconLeft }\n\t\t\t{ children }\n\t\t\t{ iconRight }\n\t\t\n\t);\n} );\n\nexport default Button;\n","import {\n\tuseState,\n\tuseCallback,\n\tuseMemo,\n\tforwardRef,\n\tisValidElement,\n} from 'react';\nimport { nanoid } from 'nanoid';\nimport { cn } from '@/utilities/functions';\nimport { Check, Minus } from 'lucide-react';\n\nconst CheckboxComponent = (\n\t{\n\t\tid,\n\t\tlabel,\n\t\tdefaultChecked = false,\n\t\tchecked,\n\t\tonChange,\n\t\tvalue,\n\t\tindeterminate,\n\t\tdisabled,\n\t\tsize = 'md',\n\t\t...props\n\t},\n\tref\n) => {\n\tconst checkboxId = useMemo( () => id || `checkbox-${ nanoid() }`, [ id ] );\n\tconst isControlled = useMemo(\n\t\t() => typeof checked !== 'undefined',\n\t\t[ checked ]\n\t);\n\tconst [ isChecked, setIsChecked ] = useState( defaultChecked || false );\n\tconst color = 'primary';\n\n\tconst sizeClassNames = {\n\t\tsm: {\n\t\t\tcheckbox: 'size-4 rounded-sm',\n\t\t\ticon: 'size-3',\n\t\t},\n\t\tmd: {\n\t\t\tcheckbox: 'size-5 rounded',\n\t\t\ticon: 'size-4',\n\t\t},\n\t};\n\tconst colorClassNames = {\n\t\tprimary: {\n\t\t\tcheckbox:\n\t\t\t\t'border-border-strong hover:border-border-interactive checked:border-border-interactive bg-white checked:bg-toggle-on checked:hover:bg-toggle-on-hover checked:hover:border-toggle-on-hover focus:ring-2 focus:ring-offset-4 focus:ring-focus',\n\t\t\ticon: 'text-white',\n\t\t},\n\t};\n\tconst disabledClassNames = {\n\t\tcheckbox:\n\t\t\t'disabled:bg-white checked:disabled:bg-white disabled:border-border-disabled checked:disabled:border-border-disabled',\n\t\ticon: 'peer-disabled:text-border-disabled',\n\t};\n\n\tconst getValue = useCallback(\n\t\t() => ( isControlled ? checked : isChecked ),\n\t\t[ isControlled, checked, isChecked ]\n\t);\n\n\tconst handleChange = ( event ) => {\n\t\tif ( disabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newValue = event.target.checked;\n\t\tif ( ! isControlled ) {\n\t\t\tsetIsChecked( newValue );\n\t\t}\n\n\t\tif ( typeof onChange !== 'function' ) {\n\t\t\treturn;\n\t\t}\n\t\tonChange( newValue );\n\t};\n\n\tconst renderLabel = useCallback( () => {\n\t\tif ( isValidElement( label ) ) {\n\t\t\treturn label;\n\t\t}\n\n\t\tif ( ! label.heading && ! label.description ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn (\n\t\t\t
\n\t\t\t\t{ label.heading && (\n\t\t\t\t\t
\n\t\t\t\t\t\t{ label.heading }\n\t\t\t\t\t
\n\t\t\t\t) }\n\t\t\t\t{ label.description && (\n\t\t\t\t\t
\n\t\t\t\t\t\t{ label.description }\n\t\t\t\t\t
\n\t\t\t\t) }\n\t\t\t
\n\t\t);\n\t}, [ label ] );\n\n\treturn (\n\t\t
\n\t\t\t\n\t\t\t{ !! label && (\n\t\t\t\t\n\t\t\t) }\n\t\t
\n\t);\n};\n\nconst Checkbox = forwardRef( CheckboxComponent );\nCheckbox.displayName = 'Checkbox';\n\nexport default Checkbox;\n","export const gridColumnClassNames = {\n\tsm: {\n\t\t1: 'grid-cols-1',\n\t\t2: 'grid-cols-2',\n\t\t3: 'grid-cols-3',\n\t\t4: 'grid-cols-4',\n\t\t5: 'grid-cols-5',\n\t\t6: 'grid-cols-6',\n\t\t7: 'grid-cols-7',\n\t\t8: 'grid-cols-8',\n\t\t9: 'grid-cols-9',\n\t\t10: 'grid-cols-10',\n\t\t11: 'grid-cols-11',\n\t\t12: 'grid-cols-12',\n\t},\n\tmd: {\n\t\t1: 'md:grid-cols-1',\n\t\t2: 'md:grid-cols-2',\n\t\t3: 'md:grid-cols-3',\n\t\t4: 'md:grid-cols-4',\n\t\t5: 'md:grid-cols-5',\n\t\t6: 'md:grid-cols-6',\n\t\t7: 'md:grid-cols-7',\n\t\t8: 'md:grid-cols-8',\n\t\t9: 'md:grid-cols-9',\n\t\t10: 'md:grid-cols-10',\n\t\t11: 'md:grid-cols-11',\n\t\t12: 'md:grid-cols-12',\n\t},\n\tlg: {\n\t\t1: 'lg:grid-cols-1',\n\t\t2: 'lg:grid-cols-2',\n\t\t3: 'lg:grid-cols-3',\n\t\t4: 'lg:grid-cols-4',\n\t\t5: 'lg:grid-cols-5',\n\t\t6: 'lg:grid-cols-6',\n\t\t7: 'lg:grid-cols-7',\n\t\t8: 'lg:grid-cols-8',\n\t\t9: 'lg:grid-cols-9',\n\t\t10: 'lg:grid-cols-10',\n\t\t11: 'lg:grid-cols-11',\n\t\t12: 'lg:grid-cols-12',\n\t},\n};\n\nexport const gapClassNames = {\n\tsm: {\n\t\txs: 'gap-2',\n\t\tsm: 'gap-4',\n\t\tmd: 'gap-5',\n\t\tlg: 'gap-6',\n\t\txl: 'gap-6',\n\t\t'2xl': 'gap-8',\n\t},\n\tmd: {\n\t\txs: 'md:gap-2',\n\t\tsm: 'md:gap-4',\n\t\tmd: 'md:gap-5',\n\t\tlg: 'md:gap-6',\n\t\txl: 'md:gap-6',\n\t\t'2xl': 'md:gap-8',\n\t},\n\tlg: {\n\t\txs: 'lg:gap-2',\n\t\tsm: 'lg:gap-4',\n\t\tmd: 'lg:gap-5',\n\t\tlg: 'lg:gap-6',\n\t\txl: 'lg:gap-6',\n\t\t'2xl': 'lg:gap-8',\n\t},\n};\n\nexport const gapXClassNames = {\n\tsm: {\n\t\txs: 'gap-x-2',\n\t\tsm: 'gap-x-4',\n\t\tmd: 'gap-x-5',\n\t\tlg: 'gap-x-6',\n\t\txl: 'gap-x-6',\n\t\t'2xl': 'gap-x-8',\n\t},\n\tmd: {\n\t\txs: 'md:gap-x-2',\n\t\tsm: 'md:gap-x-4',\n\t\tmd: 'md:gap-x-5',\n\t\tlg: 'md:gap-x-6',\n\t\txl: 'md:gap-x-6',\n\t\t'2xl': 'md:gap-x-8',\n\t},\n\tlg: {\n\t\txs: 'lg:gap-x-2',\n\t\tsm: 'lg:gap-x-4',\n\t\tmd: 'lg:gap-x-5',\n\t\tlg: 'lg:gap-x-6',\n\t\txl: 'lg:gap-x-6',\n\t\t'2xl': 'lg:gap-x-8',\n\t},\n};\n\nexport const gapYClassNames = {\n\tsm: {\n\t\txs: 'gap-y-2',\n\t\tsm: 'gap-y-4',\n\t\tmd: 'gap-y-5',\n\t\tlg: 'gap-y-6',\n\t\txl: 'gap-y-6',\n\t\t'2xl': 'gap-y-8',\n\t},\n\tmd: {\n\t\txs: 'md:gap-y-2',\n\t\tsm: 'md:gap-y-4',\n\t\tmd: 'md:gap-y-5',\n\t\tlg: 'md:gap-y-6',\n\t\txl: 'md:gap-y-6',\n\t\t'2xl': 'md:gap-y-8',\n\t},\n\tlg: {\n\t\txs: 'lg:gap-y-2',\n\t\tsm: 'lg:gap-y-4',\n\t\tmd: 'lg:gap-y-5',\n\t\tlg: 'lg:gap-y-6',\n\t\txl: 'lg:gap-y-6',\n\t\t'2xl': 'lg:gap-y-8',\n\t},\n};\n\nexport const gridColSpanClassNames = {\n\tsm: {\n\t\t1: 'col-span-1',\n\t\t2: 'col-span-2',\n\t\t3: 'col-span-3',\n\t\t4: 'col-span-4',\n\t\t5: 'col-span-5',\n\t\t6: 'col-span-6',\n\t\t7: 'col-span-7',\n\t\t8: 'col-span-8',\n\t\t9: 'col-span-9',\n\t\t10: 'col-span-10',\n\t\t11: 'col-span-11',\n\t\t12: 'col-span-12',\n\t},\n\tmd: {\n\t\t1: 'md:col-span-1',\n\t\t2: 'md:col-span-2',\n\t\t3: 'md:col-span-3',\n\t\t4: 'md:col-span-4',\n\t\t5: 'md:col-span-5',\n\t\t6: 'md:col-span-6',\n\t\t7: 'md:col-span-7',\n\t\t8: 'md:col-span-8',\n\t\t9: 'md:col-span-9',\n\t\t10: 'md:col-span-10',\n\t\t11: 'md:col-span-11',\n\t\t12: 'md:col-span-12',\n\t},\n\tlg: {\n\t\t1: 'lg:col-span-1',\n\t\t2: 'lg:col-span-2',\n\t\t3: 'lg:col-span-3',\n\t\t4: 'lg:col-span-4',\n\t\t5: 'lg:col-span-5',\n\t\t6: 'lg:col-span-6',\n\t\t7: 'lg:col-span-7',\n\t\t8: 'lg:col-span-8',\n\t\t9: 'lg:col-span-9',\n\t\t10: 'lg:col-span-10',\n\t\t11: 'lg:col-span-11',\n\t\t12: 'lg:col-span-12',\n\t},\n};\n\nexport const gridColStartClassNames = {\n\tsm: {\n\t\t1: 'col-start-1',\n\t\t2: 'col-start-2',\n\t\t3: 'col-start-3',\n\t\t4: 'col-start-4',\n\t\t5: 'col-start-5',\n\t\t6: 'col-start-6',\n\t\t7: 'col-start-7',\n\t\t8: 'col-start-8',\n\t\t9: 'col-start-9',\n\t\t10: 'col-start-10',\n\t\t11: 'col-start-11',\n\t\t12: 'col-start-12',\n\t},\n\tmd: {\n\t\t1: 'md:col-start-1',\n\t\t2: 'md:col-start-2',\n\t\t3: 'md:col-start-3',\n\t\t4: 'md:col-start-4',\n\t\t5: 'md:col-start-5',\n\t\t6: 'md:col-start-6',\n\t\t7: 'md:col-start-7',\n\t\t8: 'md:col-start-8',\n\t\t9: 'md:col-start-9',\n\t\t10: 'md:col-start-10',\n\t\t11: 'md:col-start-11',\n\t\t12: 'md:col-start-12',\n\t},\n\tlg: {\n\t\t1: 'lg:col-start-1',\n\t\t2: 'lg:col-start-2',\n\t\t3: 'lg:col-start-3',\n\t\t4: 'lg:col-start-4',\n\t\t5: 'lg:col-start-5',\n\t\t6: 'lg:col-start-6',\n\t\t7: 'lg:col-start-7',\n\t\t8: 'lg:col-start-8',\n\t\t9: 'lg:col-start-9',\n\t\t10: 'lg:col-start-10',\n\t\t11: 'lg:col-start-11',\n\t\t12: 'lg:col-start-12',\n\t},\n};\n\nexport const gridFlowClassNames = {\n\tsm: {\n\t\trow: 'grid-flow-row',\n\t\tcolumn: 'grid-flow-col',\n\t\t'row-dense': 'grid-flow-row-dense',\n\t\t'column-dense': 'grid-flow-col-dense',\n\t},\n\tmd: {\n\t\trow: 'md:grid-flow-row',\n\t\tcolumn: 'md:grid-flow-col',\n\t\t'row-dense': 'md:grid-flow-row-dense',\n\t\t'column-dense': 'md:grid-flow-col-dense',\n\t},\n\tlg: {\n\t\trow: 'lg:grid-flow-row',\n\t\tcolumn: 'lg:grid-flow-col',\n\t\t'row-dense': 'lg:grid-flow-row-dense',\n\t\t'column-dense': 'lg:grid-flow-col-dense',\n\t},\n};\n\nexport const justifyClassNames = {\n\tsm: {\n\t\tnormal: 'justify-normal',\n\t\tstart: 'justify-start',\n\t\tend: 'justify-end',\n\t\tcenter: 'justify-center',\n\t\tbetween: 'justify-between',\n\t\taround: 'justify-around',\n\t\tevenly: 'justify-evenly',\n\t\tstretch: 'justify-stretch',\n\t},\n\tmd: {\n\t\tnormal: 'md:justify-normal',\n\t\tstart: 'md:justify-start',\n\t\tend: 'md:justify-end',\n\t\tcenter: 'md:justify-center',\n\t\tbetween: 'md:justify-between',\n\t\taround: 'md:justify-around',\n\t\tevenly: 'md:justify-evenly',\n\t\tstretch: 'md:justify-stretch',\n\t},\n\tlg: {\n\t\tnormal: 'lg:justify-normal',\n\t\tstart: 'lg:justify-start',\n\t\tend: 'lg:justify-end',\n\t\tcenter: 'lg:justify-center',\n\t\tbetween: 'lg:justify-between',\n\t\taround: 'lg:justify-around',\n\t\tevenly: 'lg:justify-evenly',\n\t\tstretch: 'lg:justify-stretch',\n\t},\n};\n\nexport const alignClassNames = {\n\tsm: {\n\t\tstart: 'items-start',\n\t\tend: 'items-end',\n\t\tcenter: 'items-center',\n\t\tbaseline: 'items-baseline',\n\t\tstretch: 'items-stretch',\n\t},\n\tmd: {\n\t\tstart: 'md:items-start',\n\t\tend: 'md:items-end',\n\t\tcenter: 'md:items-center',\n\t\tbaseline: 'md:items-baseline',\n\t\tstretch: 'md:items-stretch',\n\t},\n\tlg: {\n\t\tstart: 'lg:items-start',\n\t\tend: 'lg:items-end',\n\t\tcenter: 'lg:items-center',\n\t\tbaseline: 'lg:items-baseline',\n\t\tstretch: 'lg:items-stretch',\n\t},\n};\n\nexport const alignSelfClassNames = {\n\tsm: {\n\t\tstart: 'self-start',\n\t\tend: 'self-end',\n\t\tcenter: 'self-center',\n\t\tbaseline: 'self-baseline',\n\t\tstretch: 'self-stretch',\n\t},\n\tmd: {\n\t\tstart: 'md:self-start',\n\t\tend: 'md:self-end',\n\t\tcenter: 'md:self-center',\n\t\tbaseline: 'md:self-baseline',\n\t\tstretch: 'md:self-stretch',\n\t},\n\tlg: {\n\t\tstart: 'lg:self-start',\n\t\tend: 'lg:self-end',\n\t\tcenter: 'lg:self-center',\n\t\tbaseline: 'lg:self-baseline',\n\t\tstretch: 'lg:self-stretch',\n\t},\n};\n\nexport const justifySelfClassNames = {\n\tsm: {\n\t\tauto: 'justify-self-auto',\n\t\tstart: 'justify-self-start',\n\t\tend: 'justify-self-end',\n\t\tcenter: 'justify-self-center',\n\t\tbaseline: 'justify-self-baseline',\n\t\tstretch: 'justify-self-stretch',\n\t},\n\tmd: {\n\t\tauto: 'md:justify-self-auto',\n\t\tstart: 'md:justify-self-start',\n\t\tend: 'md:justify-self-end',\n\t\tcenter: 'md:justify-self-center',\n\t\tbaseline: 'md:justify-self-baseline',\n\t\tstretch: 'md:justify-self-stretch',\n\t},\n\tlg: {\n\t\tauto: 'lg:justify-self-auto',\n\t\tstart: 'lg:justify-self-start',\n\t\tend: 'lg:justify-self-end',\n\t\tcenter: 'lg:justify-self-center',\n\t\tbaseline: 'lg:justify-self-baseline',\n\t\tstretch: 'lg:justify-self-stretch',\n\t},\n};\n\nexport const flexDirectionClassNames = {\n\tsm: {\n\t\trow: 'flex-row',\n\t\t'row-reverse': 'flex-row-reverse',\n\t\tcolumn: 'flex-col',\n\t\t'column-reverse': 'flex-col-reverse',\n\t},\n\tmd: {\n\t\trow: 'md:flex-row',\n\t\t'row-reverse': 'md:flex-row-reverse',\n\t\tcolumn: 'md:flex-col',\n\t\t'column-reverse': 'md:flex-col-reverse',\n\t},\n\tlg: {\n\t\trow: 'lg:flex-row',\n\t\t'row-reverse': 'lg:flex-row-reverse',\n\t\tcolumn: 'lg:flex-col',\n\t\t'column-reverse': 'lg:flex-col-reverse',\n\t},\n};\n\nexport const flexWrapClassNames = {\n\tsm: {\n\t\twrap: 'flex-wrap',\n\t\t'wrap-reverse': 'flex-wrap-reverse',\n\t\tnowrap: 'flex-nowrap',\n\t},\n\tmd: {\n\t\twrap: 'md:flex-wrap',\n\t\t'wrap-reverse': 'md:flex-wrap-reverse',\n\t\tnowrap: 'md:flex-nowrap',\n\t},\n\tlg: {\n\t\twrap: 'lg:flex-wrap',\n\t\t'wrap-reverse': 'lg:flex-wrap-reverse',\n\t\tnowrap: 'lg:flex-nowrap',\n\t},\n};\n\nexport const flexColumnClassNames = {\n\tsm: {\n\t\t1: 'w-full',\n\t\t2: 'w-1/2',\n\t\t3: 'w-1/3',\n\t\t4: 'w-1/4',\n\t\t5: 'w-1/5',\n\t\t6: 'w-1/6',\n\t\t7: 'w-1/7',\n\t\t8: 'w-1/8',\n\t\t9: 'w-1/9',\n\t\t10: 'w-1/10',\n\t\t11: 'w-1/11',\n\t\t12: 'w-1/12',\n\t},\n\tmd: {\n\t\t1: 'md:w-full',\n\t\t2: 'md:w-1/2',\n\t\t3: 'md:w-1/3',\n\t\t4: 'md:w-1/4',\n\t\t5: 'md:w-1/5',\n\t\t6: 'md:w-1/6',\n\t\t7: 'md:w-1/7',\n\t\t8: 'md:w-1/8',\n\t\t9: 'md:w-1/9',\n\t\t10: 'md:w-1/10',\n\t\t11: 'md:w-1/11',\n\t\t12: 'md:w-1/12',\n\t},\n\tlg: {\n\t\t1: 'lg:w-full',\n\t\t2: 'lg:w-1/2',\n\t\t3: 'lg:w-1/3',\n\t\t4: 'lg:w-1/4',\n\t\t5: 'lg:w-1/5',\n\t\t6: 'lg:w-1/6',\n\t\t7: 'lg:w-1/7',\n\t\t8: 'lg:w-1/8',\n\t\t9: 'lg:w-1/9',\n\t\t10: 'lg:w-1/10',\n\t\t11: 'lg:w-1/11',\n\t\t12: 'lg:w-1/12',\n\t},\n};\n\nexport const flexOrderClassNames = {\n\tsm: {\n\t\t1: 'order-1',\n\t\t2: 'order-2',\n\t\t3: 'order-3',\n\t\t4: 'order-4',\n\t\t5: 'order-5',\n\t\t6: 'order-6',\n\t\t7: 'order-7',\n\t\t8: 'order-8',\n\t\t9: 'order-9',\n\t\t10: 'order-10',\n\t\t11: 'order-11',\n\t\t12: 'order-12',\n\t\tfirst: 'order-first',\n\t\tlast: 'order-last',\n\t\tnone: 'order-none',\n\t},\n\tmd: {\n\t\t1: 'md:order-1',\n\t\t2: 'md:order-2',\n\t\t3: 'md:order-3',\n\t\t4: 'md:order-4',\n\t\t5: 'md:order-5',\n\t\t6: 'md:order-6',\n\t\t7: 'md:order-7',\n\t\t8: 'md:order-8',\n\t\t9: 'md:order-9',\n\t\t10: 'md:order-10',\n\t\t11: 'md:order-11',\n\t\t12: 'md:order-12',\n\t\tfirst: 'md:order-first',\n\t\tlast: 'md:order-last',\n\t\tnone: 'md:order-none',\n\t},\n\tlg: {\n\t\t1: 'lg:order-1',\n\t\t2: 'lg:order-2',\n\t\t3: 'lg:order-3',\n\t\t4: 'lg:order-4',\n\t\t5: 'lg:order-5',\n\t\t6: 'lg:order-6',\n\t\t7: 'lg:order-7',\n\t\t8: 'lg:order-8',\n\t\t9: 'lg:order-9',\n\t\t10: 'lg:order-10',\n\t\t11: 'lg:order-11',\n\t\t12: 'lg:order-12',\n\t\tfirst: 'lg:order-first',\n\t\tlast: 'lg:order-last',\n\t\tnone: 'lg:order-none',\n\t},\n};\n\nexport const flexGrowClassNames = {\n\tsm: {\n\t\t0: 'grow-0',\n\t\t1: 'grow',\n\t},\n\tmd: {\n\t\t0: 'md:grow-0',\n\t\t1: 'md:grow',\n\t},\n\tlg: {\n\t\t0: 'lg:grow-0',\n\t\t1: 'lg:grow',\n\t},\n};\n\nexport const flexShrinkClassNames = {\n\tsm: {\n\t\t0: 'shrink-0',\n\t\t1: 'shrink',\n\t},\n\tmd: {\n\t\t0: 'md:shrink-0',\n\t\t1: 'md:shrink',\n\t},\n\tlg: {\n\t\t0: 'lg:shrink-0',\n\t\t1: 'lg:shrink',\n\t},\n};\n","export const getClassNames = (\n\tvalueKeys,\n\tclassNames,\n\tdefaultValueKeys,\n\tdefaultScreenSize = 'sm'\n) => {\n\tconst classNamesArray = [];\n\n\tswitch ( typeof valueKeys ) {\n\t\tcase 'object':\n\t\t\tfor ( const [ screenSize, valueKey ] of Object.entries( valueKeys ) ) {\n\t\t\t\tif ( classNames[ screenSize ] ) {\n\t\t\t\t\tclassNamesArray.push(\n\t\t\t\t\t\tclassNames?.[ screenSize ]?.[ valueKey ] ??\n\t\t\t\t\t\t\tclassNames?.[ screenSize ]?.[\n\t\t\t\t\t\t\t\tdefaultValueKeys?.[ screenSize ]\n\t\t\t\t\t\t\t] ??\n\t\t\t\t\t\t\t''\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'string':\n\t\tcase 'number':\n\t\t\tconst screenSize = defaultScreenSize;\n\t\t\tclassNamesArray.push(\n\t\t\t\tclassNames?.[ screenSize ]?.[ valueKeys ] ??\n\t\t\t\t\tclassNames?.[ screenSize ]?.[\n\t\t\t\t\t\tdefaultValueKeys?.[ screenSize ]\n\t\t\t\t\t] ??\n\t\t\t\t\t''\n\t\t\t);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tclassNamesArray.push(\n\t\t\t\tclassNames?.[ defaultScreenSize ]?.[ defaultValueKeys ] ?? ''\n\t\t\t);\n\t\t\tbreak;\n\t}\n\n\treturn classNamesArray.join( ' ' );\n};\n","import React, { createContext, useContext } from 'react';\nimport { cn } from '@/utilities/functions';\nimport GridContainer from './grid-container';\nimport { getClassNames } from './container-utils';\nimport {\n\talignClassNames,\n\talignSelfClassNames,\n\tflexColumnClassNames,\n\tflexDirectionClassNames,\n\tflexGrowClassNames,\n\tflexOrderClassNames,\n\tflexShrinkClassNames,\n\tflexWrapClassNames,\n\tgapClassNames,\n\tgapXClassNames,\n\tgapYClassNames,\n\tjustifyClassNames,\n\tjustifySelfClassNames,\n} from './container-styles';\n\nconst ContainerContext = createContext();\nconst useContainerState = () => useContext( ContainerContext );\n\nconst Container = ( props ) => {\n\tconst {\n\t\tcontainerType = 'flex', // flex, (grid - functionality not implemented)\n\t\tgap = 'sm', // xs, sm, md, lg, xl, 2xl\n\t\tgapX = '',\n\t\tgapY = '',\n\t\tdirection = '', // row, row-reverse, column, column reverse\n\t\tjustify = '', // justify-content (normal, start, end, center, between, around, evenly, stretch)\n\t\talign = '', // align-items (start, end, center, baseline, stretch)\n\t\twrap, // nowrap, wrap, wrap-reverse\n\t\tcols = '',\n\t\tclassName,\n\t\tchildren,\n\t\t...extraProps\n\t} = props;\n\n\tif ( containerType === 'grid' ) {\n\t\tconst { containerType: type, ...rest } = props;\n\t\treturn (\n\t\t\t
\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n\n\tconst wrapClassName = getClassNames( wrap, flexWrapClassNames, '' );\n\tconst gapClassName = getClassNames( gap, gapClassNames, 'sm' );\n\tconst gapXClassName = getClassNames( gapX, gapXClassNames, '' );\n\tconst gapYClassName = getClassNames( gapY, gapYClassNames, '' );\n\tconst directionClassName = getClassNames(\n\t\tdirection,\n\t\tflexDirectionClassNames,\n\t\t''\n\t);\n\tconst justifyContentClassName = getClassNames(\n\t\tjustify,\n\t\tjustifyClassNames,\n\t\t''\n\t);\n\tconst alignItemsClassName = getClassNames( align, alignClassNames, '' );\n\n\tconst combinedClasses = cn(\n\t\t'flex',\n\t\twrapClassName,\n\t\tgapClassName,\n\t\tgapXClassName,\n\t\tgapYClassName,\n\t\tdirectionClassName,\n\t\tjustifyContentClassName,\n\t\talignItemsClassName,\n\t\tclassName\n\t);\n\n\tconst renderContainerBasedOnType = () => {\n\t\tif ( containerType === 'grid' ) {\n\t\t\treturn
;\n\t\t}\n\n\t\treturn (\n\t\t\t
\n\t\t\t\t{ children }\n\t\t\t
\n\t\t);\n\t};\n\n\treturn (\n\t\t
\n\t\t\t{ renderContainerBasedOnType() }\n\t\t\n\t);\n};\n\nconst Item = ( props ) => {\n\tconst {\n\t\tgrow,\n\t\tshrink,\n\t\torder,\n\t\talignSelf,\n\t\tjustifySelf,\n\t\tclassName,\n\t\tchildren,\n\t\t...extraProps\n\t} = props;\n\tconst { containerType, cols } = useContainerState();\n\n\tif ( containerType === 'grid' ) {\n\t\tconst { ...rest } = props;\n\t\treturn
;\n\t}\n\n\tconst alignSelfClassName = getClassNames(\n\t\talignSelf,\n\t\talignSelfClassNames,\n\t\t''\n\t);\n\tconst justifySelfClassName = getClassNames(\n\t\tjustifySelf,\n\t\tjustifySelfClassNames,\n\t\t''\n\t);\n\tconst growClassName = getClassNames( grow, flexGrowClassNames, 0 );\n\tconst shrinkClassName = getClassNames( shrink, flexShrinkClassNames, 0 );\n\tconst orderClassName = getClassNames( order, flexOrderClassNames, 0 );\n\tconst columnClassName = getClassNames( cols, flexColumnClassNames, 1 );\n\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nContainer.Item = Item;\n\nContainer.displayName = 'Container';\nContainer.Item.displayName = 'Container.Item';\n\nexport default Container;\n","import React from 'react';\nimport { cn } from '@/utilities/functions';\nimport {\n\tgridColumnClassNames,\n\tgridColSpanClassNames,\n\tgridColStartClassNames,\n\tgapClassNames,\n\tgapXClassNames,\n\tgapYClassNames,\n\tgridFlowClassNames,\n\talignClassNames,\n\tjustifyClassNames,\n\talignSelfClassNames,\n\tjustifySelfClassNames,\n} from './container-styles.js';\nimport { getClassNames } from './container-utils.js';\n\nconst GridContainer = ( {\n\tclassName,\n\tcols,\n\tgap,\n\tgapX,\n\tgapY,\n\talign,\n\tjustify,\n\tgridFlow = '',\n\tcolsSubGrid = false,\n\trowsSubGrid = false,\n\tautoRows = false,\n\tautoCols = false,\n\tchildren,\n\t...props\n} ) => {\n\tconst columnClassName = getClassNames( cols, gridColumnClassNames, 1 );\n\tconst gapClassName = getClassNames( gap, gapClassNames, 'sm' );\n\tconst gapXClassName = getClassNames( gapX, gapXClassNames, '' );\n\tconst gapYClassName = getClassNames( gapY, gapYClassNames, '' );\n\tconst alignClassName = getClassNames( align, alignClassNames, '' );\n\tconst justifyClassName = getClassNames( justify, justifyClassNames, '' );\n\tconst gridFlowClassName = getClassNames( gridFlow, gridFlowClassNames, '' );\n\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nexport const GridItem = ( {\n\tclassName,\n\tchildren,\n\tcolSpan,\n\tcolStart,\n\talignSelf,\n\tjustifySelf,\n\t...props\n} ) => {\n\tconst colSpanClassName = getClassNames( colSpan, gridColSpanClassNames, 0 );\n\tconst colStartClassName = getClassNames(\n\t\tcolStart,\n\t\tgridColStartClassNames,\n\t\t0\n\t);\n\tconst alignSelfClassName = getClassNames(\n\t\talignSelf,\n\t\talignSelfClassNames,\n\t\t''\n\t);\n\tconst justifySelfClassName = getClassNames(\n\t\tjustifySelf,\n\t\tjustifySelfClassNames,\n\t\t''\n\t);\n\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nObject.assign( GridContainer, { Item: GridItem } );\n\nexport default GridContainer;\n","import {\n\tcloneElement,\n\tcreateContext,\n\tFragment,\n\tisValidElement,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from 'react';\nimport { AnimatePresence, motion } from 'framer-motion';\nimport { callAll, cn } from '@/utilities/functions';\nimport { X } from 'lucide-react';\nimport { createPortal } from 'react-dom';\n\nconst DialogContext = createContext();\nconst useDialogState = () => useContext( DialogContext );\n\nconst animationVariants = {\n\topen: {\n\t\topacity: 1,\n\t},\n\texit: {\n\t\topacity: 0,\n\t},\n};\nconst TRANSITION_DURATION = { duration: 0.2 };\n\n// Dialog component.\nconst Dialog = ( {\n\topen,\n\tsetOpen,\n\tchildren,\n\ttrigger,\n\tclassName,\n\texitOnClickOutside = false,\n\texitOnEsc = true,\n\tdesign = 'simple',\n\tscrollLock = true,\n} ) => {\n\tconst isControlled = open !== undefined && setOpen !== undefined;\n\tconst [ isOpen, setIsOpen ] = useState( false );\n\tconst dialogRef = useRef( null );\n\tconst dialogContainerRef = useRef( null );\n\n\tconst openState = useMemo(\n\t\t() => ( isControlled ? open : isOpen ),\n\t\t[ open, isOpen ]\n\t);\n\tconst setOpenState = useMemo(\n\t\t() => ( isControlled ? setOpen : setIsOpen ),\n\t\t[ setIsOpen, setIsOpen ]\n\t);\n\n\tconst handleOpen = () => {\n\t\tif ( openState ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetOpenState( true );\n\t};\n\n\tconst handleClose = () => {\n\t\tif ( ! openState ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetOpenState( false );\n\t};\n\n\tconst renderTrigger = useCallback( () => {\n\t\tif ( isValidElement( trigger ) ) {\n\t\t\treturn cloneElement( trigger, {\n\t\t\t\tonClick: callAll( handleOpen, trigger.props.onClick ),\n\t\t\t} );\n\t\t}\n\n\t\tif ( typeof trigger === 'function' ) {\n\t\t\treturn trigger( { onClick: handleOpen } );\n\t\t}\n\n\t\treturn null;\n\t}, [ trigger, handleOpen, handleClose ] );\n\n\tconst handleKeyDown = ( event ) => {\n\t\tswitch ( event.key ) {\n\t\t\tcase 'Escape':\n\t\t\t\tif ( exitOnEsc ) {\n\t\t\t\t\thandleClose();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\tconst handleClickOutside = ( event ) => {\n\t\tif (\n\t\t\texitOnClickOutside &&\n\t\t\tdialogRef.current &&\n\t\t\t! dialogRef.current.contains( event.target )\n\t\t) {\n\t\t\thandleClose();\n\t\t}\n\t};\n\n\tuseEffect( () => {\n\t\twindow.addEventListener( 'keydown', handleKeyDown );\n\t\tdocument.addEventListener( 'mousedown', handleClickOutside );\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener( 'keydown', handleKeyDown );\n\t\t\tdocument.removeEventListener( 'mousedown', handleClickOutside );\n\t\t};\n\t}, [ openState ] );\n\n\t// Prevent scrolling when dialog is open.\n\tuseEffect( () => {\n\t\tif ( ! scrollLock ) {\n\t\t\treturn;\n\t\t}\n\t\tif ( openState ) {\n\t\t\tdocument.querySelector( 'html' ).style.overflow = 'hidden';\n\t\t}\n\n\t\treturn () => {\n\t\t\tdocument.querySelector( 'html' ).style.overflow = '';\n\t\t};\n\t}, [ openState ] );\n\n\treturn (\n\t\t<>\n\t\t\t{ renderTrigger() }\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t{ children }\n\t\t\t\t
\n\t\t\t\n\t\t>\n\t);\n};\nDialog.displayName = 'Dialog';\n\nconst DialogPanel = ( { children, className } ) => {\n\tconst { open, handleClose, dialogRef } = useDialogState();\n\n\treturn (\n\t\t
\n\t\t\t{ open && (\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{ typeof children === 'function'\n\t\t\t\t\t\t\t\t? children( { close: handleClose } )\n\t\t\t\t\t\t\t\t: children }\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};\nDialogPanel.displayName = 'Dialog.Panel';\n\n// Backdrop for the dialog.\nconst DialogBackdrop = ( { className, ...props } ) => {\n\tconst { open, dialogContainerRef } = useDialogState();\n\n\treturn (\n\t\tdialogContainerRef.current &&\n\t\tcreatePortal(\n\t\t\t
\n\t\t\t\t{ open && (\n\t\t\t\t\t\n\t\t\t\t) }\n\t\t\t,\n\t\t\tdialogContainerRef.current\n\t\t)\n\t);\n};\nDialogBackdrop.displayName = 'Dialog.Backdrop';\n\n// Dialog header wrapper.\nconst DialogHeader = ( { children, className, ...props } ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t
\n\t);\n};\nDialogHeader.displayName = 'Dialog.Header';\n\n// Dialog title.\nconst DialogTitle = ( { children, as: Tag = 'h3', className, ...props } ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\nDialogTitle.displayName = 'Dialog.Title';\n\n// Dialog description.\nconst DialogDescription = ( {\n\tchildren,\n\tas: Tag = 'p',\n\tclassName,\n\t...props\n} ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\nDialogDescription.displayName = 'Dialog.Description';\n\n// Default close button for the dialog.\nconst DefaultCloseButton = ( { className, ...props } ) => {\n\treturn (\n\t\t
\n\t);\n};\n\n// Close button for the dialog.\nconst DialogCloseButton = ( { children, as: Tag = Fragment, ...props } ) => {\n\tconst { handleClose } = useDialogState();\n\n\tif ( ! isValidElement( children ) || ! children ) {\n\t\treturn
;\n\t}\n\n\tif ( Tag === Fragment ) {\n\t\tif ( typeof children === 'function' ) {\n\t\t\treturn children( { close: handleClose } );\n\t\t}\n\n\t\treturn cloneElement( children, {\n\t\t\tonClick: handleClose,\n\t\t} );\n\t}\n\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\nDialogCloseButton.displayName = 'Dialog.CloseButton';\n\n// Dialog body.\nconst DialogBody = ( { children, className, ...props } ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t
\n\t);\n};\nDialogBody.displayName = 'Dialog.Body';\n\n// Dialog footer.\nconst DialogFooter = ( { children, className } ) => {\n\tconst { design, handleClose } = useDialogState();\n\n\tconst renderChildren = () => {\n\t\tif ( ! children ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( typeof children === 'function' ) {\n\t\t\treturn children( { close: handleClose } );\n\t\t}\n\n\t\treturn children;\n\t};\n\n\treturn (\n\t\t
\n\t\t\t{ renderChildren() }\n\t\t
\n\t);\n};\nDialogFooter.displayName = 'Dialog.Footer';\n\nexport default Object.assign( Dialog, {\n\tPanel: DialogPanel,\n\tBackdrop: DialogBackdrop,\n\tTitle: DialogTitle,\n\tDescription: DialogDescription,\n\tCloseButton: DialogCloseButton,\n\tHeader: DialogHeader,\n\tBody: DialogBody,\n\tFooter: DialogFooter,\n} );\n","import { AnimatePresence, motion } from 'framer-motion';\nimport { useDrawerState } from './drawer';\nimport { createPortal } from 'react-dom';\nimport { cn } from '@/utilities/functions';\n\nconst backdropAnimationVariants = {\n\topen: {\n\t\topacity: 1,\n\t},\n\texit: {\n\t\topacity: 0,\n\t},\n};\n\n// Backdrop for the drawer.\nconst DrawerBackdrop = ( { className, ...props } ) => {\n\tconst { open, drawerContainerRef, transitionDuration } = useDrawerState();\n\n\treturn (\n\t\tdrawerContainerRef.current &&\n\t\tcreatePortal(\n\t\t\t
\n\t\t\t\t{ open && (\n\t\t\t\t\t\n\t\t\t\t) }\n\t\t\t,\n\t\t\tdrawerContainerRef.current\n\t\t)\n\t);\n};\n\nexport default Object.assign( DrawerBackdrop, {\n\tdisplayName: 'Drawer.Backdrop',\n} );\n","import { cn } from '@/utilities/functions';\n\n// Drawer body.\nconst DrawerBody = ( { children, className, ...props } ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nexport default Object.assign( DrawerBody, {\n\tdisplayName: 'Drawer.Body',\n} );\n","import { cloneElement, Fragment, isValidElement } from 'react';\nimport { useDrawerState } from './drawer';\nimport { cn } from '@/utilities/functions';\nimport { X } from 'lucide-react';\n\n// Default close button for the drawer.\nconst DefaultCloseButton = ( { className, ...props } ) => {\n\treturn (\n\t\t
\n\t);\n};\n\n// Close button for the drawer.\nconst DrawerCloseButton = ( { children, as: Tag = Fragment, ...props } ) => {\n\tconst { handleClose } = useDrawerState();\n\n\tif ( ! isValidElement( children ) || ! children ) {\n\t\treturn
;\n\t}\n\n\tif ( Tag === Fragment ) {\n\t\tif ( typeof children === 'function' ) {\n\t\t\treturn children( { close: handleClose } );\n\t\t}\n\n\t\treturn cloneElement( children, {\n\t\t\tonClick: handleClose,\n\t\t} );\n\t}\n\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\n\nexport default Object.assign( DrawerCloseButton, {\n\tdisplayName: 'Drawer.CloseButton',\n} );\n","import { cn } from '@/utilities/functions';\n\n// Drawer description.\nconst DrawerDescription = ( {\n\tchildren,\n\tas: Tag = 'p',\n\tclassName,\n\t...props\n} ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\n\nexport default Object.assign( DrawerDescription, {\n\tdisplayName: 'Drawer.Description',\n} );\n","import { cn } from '@/utilities/functions';\nimport { useDrawerState } from './drawer';\n\n// Drawer footer.\nconst DrawerFooter = ( { children, className } ) => {\n\tconst { design, handleClose } = useDrawerState();\n\n\tconst renderChildren = () => {\n\t\tif ( ! children ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( typeof children === 'function' ) {\n\t\t\treturn children( { close: handleClose } );\n\t\t}\n\n\t\treturn children;\n\t};\n\n\treturn (\n\t\t
\n\t\t\t{ renderChildren() }\n\t\t
\n\t);\n};\n\nexport default Object.assign( DrawerFooter, {\n\tdisplayName: 'Drawer.Footer',\n} );\n","import { cn } from '@/utilities/functions';\n\n// Drawer header wrapper.\nconst DrawerHeader = ( { children, className, ...props } ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nexport default Object.assign( DrawerHeader, {\n\tdisplayName: 'Drawer.Header',\n} );\n","import { AnimatePresence, motion } from 'framer-motion';\nimport { useDrawerState } from './drawer';\nimport { cn } from '@/utilities/functions';\n\nconst animationVariants = {\n\tleft: {\n\t\topen: {\n\t\t\tx: 0,\n\t\t},\n\t\texit: {\n\t\t\tx: '-100%',\n\t\t},\n\t},\n\tright: {\n\t\topen: {\n\t\t\tx: 0,\n\t\t},\n\t\texit: {\n\t\t\tx: '100%',\n\t\t},\n\t},\n};\n\nconst DrawerPanel = ( { children, className } ) => {\n\tconst { open, position, handleClose, drawerRef, transitionDuration } =\n\t\tuseDrawerState();\n\n\treturn (\n\t\t
\n\t\t\t{ open && (\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{ typeof children === 'function'\n\t\t\t\t\t\t\t\t? children( { close: handleClose } )\n\t\t\t\t\t\t\t\t: children }\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};\n\nexport default Object.assign( DrawerPanel, {\n\tdisplayName: 'Drawer.Panel',\n} );\n","import { cn } from '@/utilities/functions';\n\n// Drawer title.\nconst DrawerTitle = ( { children, as: Tag = 'h3', className, ...props } ) => {\n\treturn (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t);\n};\n\nexport default Object.assign( DrawerTitle, {\n\tdisplayName: 'Drawer.Title',\n} );\n","import {\n\tcloneElement,\n\tcreateContext,\n\tisValidElement,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from 'react';\nimport { callAll, cn } from '@/utilities/functions';\n\nconst DrawerContext = createContext();\nexport const useDrawerState = () => useContext( DrawerContext );\n\nconst TRANSITION_DURATION = 0.2;\n\n// Drawer component.\nconst Drawer = ( {\n\topen,\n\tsetOpen,\n\tchildren,\n\ttrigger,\n\tclassName,\n\texitOnClickOutside = false,\n\texitOnEsc = true,\n\tdesign = 'simple',\n\tposition = 'right',\n\ttransitionDuration = TRANSITION_DURATION,\n\tscrollLock = true,\n} ) => {\n\tconst isControlled = open !== undefined && setOpen !== undefined;\n\tconst [ isOpen, setIsOpen ] = useState( false );\n\tconst drawerRef = useRef( null );\n\tconst drawerContainerRef = useRef( null );\n\n\tconst openState = useMemo(\n\t\t() => ( isControlled ? open : isOpen ),\n\t\t[ open, isOpen ]\n\t);\n\tconst setOpenState = useMemo(\n\t\t() => ( isControlled ? setOpen : setIsOpen ),\n\t\t[ setIsOpen, setIsOpen ]\n\t);\n\n\tconst handleOpen = () => {\n\t\tif ( openState ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetOpenState( true );\n\t};\n\n\tconst handleClose = () => {\n\t\tif ( ! openState ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetOpenState( false );\n\t};\n\n\tconst renderTrigger = useCallback( () => {\n\t\tif ( isValidElement( trigger ) ) {\n\t\t\treturn cloneElement( trigger, {\n\t\t\t\tonClick: callAll( handleOpen, trigger.props.onClick ),\n\t\t\t} );\n\t\t}\n\n\t\tif ( typeof trigger === 'function' ) {\n\t\t\treturn trigger( { onClick: handleOpen } );\n\t\t}\n\n\t\treturn null;\n\t}, [ trigger, handleOpen, handleClose ] );\n\n\tconst handleKeyDown = ( event ) => {\n\t\tswitch ( event.key ) {\n\t\t\tcase 'Escape':\n\t\t\t\tif ( exitOnEsc ) {\n\t\t\t\t\thandleClose();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\tconst handleClickOutside = ( event ) => {\n\t\tif (\n\t\t\texitOnClickOutside &&\n\t\t\tdrawerRef.current &&\n\t\t\t! drawerRef.current.contains( event.target )\n\t\t) {\n\t\t\thandleClose();\n\t\t}\n\t};\n\n\tuseEffect( () => {\n\t\twindow.addEventListener( 'keydown', handleKeyDown );\n\t\tdocument.addEventListener( 'mousedown', handleClickOutside );\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener( 'keydown', handleKeyDown );\n\t\t\tdocument.removeEventListener( 'mousedown', handleClickOutside );\n\t\t};\n\t}, [ openState ] );\n\n\t// Prevent scrolling when drawer is open.\n\tuseEffect( () => {\n\t\tif ( ! scrollLock ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( openState ) {\n\t\t\tdocument.querySelector( 'html' ).style.overflow = 'hidden';\n\t\t}\n\n\t\treturn () => {\n\t\t\tdocument.querySelector( 'html' ).style.overflow = '';\n\t\t};\n\t}, [ openState ] );\n\n\treturn (\n\t\t<>\n\t\t\t{ renderTrigger() }\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t{ children }\n\t\t\t\t
\n\t\t\t\n\t\t>\n\t);\n};\n\nexport default Object.assign( Drawer, {\n\tdisplayName: 'Drawer',\n} );\n","import Drawer from './drawer';\nimport DrawerPanel from './drawer-panel';\nimport DrawerHeader from './drawer-header';\nimport DrawerTitle from './drawer-title';\nimport DrawerDescription from './drawer-description';\nimport DrawerBody from './drawer-body';\nimport DrawerFooter from './drawer-footer';\nimport DrawerCloseButton from './drawer-close-button';\nimport DrawerBackdrop from './drawer-backdrop';\n\nexport default Object.assign( Drawer, {\n\tPanel: DrawerPanel,\n\tHeader: DrawerHeader,\n\tTitle: DrawerTitle,\n\tDescription: DrawerDescription,\n\tBody: DrawerBody,\n\tCloseButton: DrawerCloseButton,\n\tFooter: DrawerFooter,\n\tBackdrop: DrawerBackdrop,\n} );\n","export const editableContentAreaCommonClassNames =\n\t'w-full min-h-[1.625rem] [&>p]:w-full [&>p]:m-0';\n\nexport const editorCommonClassNames =\n\t'border border-solid focus-within:ring-2 focus-within:ring-offset-2 border-field-border hover:border-border-strong focus-within:!border-focus-border focus-within:ring-focus transition duration-150 ease-in-out';\n\nexport const editorDisabledClassNames =\n\t'bg-field-secondary-background border-field-border-disabled hover:border-field-border-disabled [&_p]:text-badge-color-disabled cursor-not-allowed';\n\nexport const editorInputClassNames = {\n\tsm: 'py-1.5 px-2 rounded [&_.editor-content>p]:text-sm [&_.editor-content>p]:font-medium [&_.editor-content>p]:leading-[1.625rem]',\n\tmd: 'py-2 px-2.5 rounded-md [&_.editor-content>p]:text-sm [&_.editor-content>p]:font-medium [&_.editor-content>p]:leading-[1.625rem]',\n\tlg: 'py-2.5 px-3 rounded-md [&_.editor-content>p]:text-sm [&_.editor-content>p]:font-medium [&_.editor-content>p]:leading-[1.6875rem]',\n};\n\nexport const comboboxDropdownCommonClassNames =\n\t'absolute inset-x-0 top-full mt-2 mx-0 mb-0 w-full h-auto overflow-y-auto overflow-x-hidden z-10 bg-background-primary border border-solid border-border-subtle shadow-lg';\n\nexport const comboboxDropdownClassNames = {\n\tsm: 'p-1.5 rounded-md max-h-[10.75rem]',\n\tmd: 'p-2 rounded-lg max-h-[13.5rem]',\n\tlg: 'p-2 rounded-lg max-h-[13.5rem]',\n};\n\nexport const comboboxItemCommonClassNames =\n\t'm-0 text-text-primary cursor-pointer';\n\nexport const comboboxItemClassNames = {\n\tsm: 'p-1.5 rounded text-sm leading-5 font-normal',\n\tmd: 'p-2 rounded-md text-base leading-6 font-normal',\n\tlg: 'p-2 rounded-md text-base leading-6 font-normal',\n};\n\nexport const comboboxSelectedItemClassNames = 'bg-button-tertiary-hover';\n","import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';\nimport { LexicalComposer } from '@lexical/react/LexicalComposer';\nimport { PlainTextPlugin } from '@lexical/react/LexicalPlainTextPlugin';\nimport { ContentEditable } from '@lexical/react/LexicalContentEditable';\nimport { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';\nimport { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';\nimport { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';\nimport { EditorRefPlugin } from '@lexical/react/LexicalEditorRefPlugin';\nimport { cn } from '@/utilities/functions';\nimport {\n\teditableContentAreaCommonClassNames,\n\teditorCommonClassNames,\n\teditorDisabledClassNames,\n\teditorInputClassNames,\n} from './editor-input-style';\nimport MentionPlugin from './mention-plugin/mention-plugin';\nimport MentionNode from './mention-plugin/mention-node';\nimport editorTheme from './editor-theme';\nimport EditorPlaceholder from './editor-placeholder';\nimport { forwardRef, isValidElement } from 'react';\n\nfunction onError( error ) {\n\t// eslint-disable-next-line no-console\n\tconsole.error( error );\n}\n\nconst EMPTY_CONTENT = `{\n \"root\": {\n \"children\": [\n {\n \"children\": [],\n \"direction\": null,\n \"format\": \"\",\n \"indent\": 0,\n \"type\": \"paragraph\",\n \"version\": 1,\n \"textFormat\": 0,\n \"textStyle\": \"\"\n }\n ],\n \"direction\": null,\n \"format\": \"\",\n \"indent\": 0,\n \"type\": \"root\",\n \"version\": 1\n }\n}`;\n\nconst EditorInputComponent = (\n\t{\n\t\tdefaultValue = '',\n\t\tplaceholder = 'Press @ to view variable suggestions',\n\t\tonChange,\n\t\tsize = 'md',\n\t\tautoFocus = false,\n\t\toptions = [],\n\t\tby = 'name',\n\t\ttrigger = '@',\n\t\tmenuComponent,\n\t\tmenuItemComponent,\n\t\tclassName,\n\t\tdisabled = false,\n\t},\n\tref\n) => {\n\tconst initialConfig = {\n\t\tnamespace: 'Editor',\n\t\teditorTheme,\n\t\tonError,\n\t\tnodes: [ MentionNode ],\n\t\teditorState: defaultValue ? defaultValue : EMPTY_CONTENT,\n\t\teditable: disabled ? false : true,\n\t};\n\n\tconst handleOnChange = ( editorState, editor ) => {\n\t\tif ( typeof onChange !== 'function' ) {\n\t\t\treturn;\n\t\t}\n\t\tonChange( editorState, editor );\n\t};\n\n\tlet menuComponentToUse;\n\tlet menuItemComponentToUse;\n\tif ( isValidElement( menuComponent ) ) {\n\t\tmenuComponentToUse = menuComponent;\n\t}\n\tif ( isValidElement( menuItemComponent ) ) {\n\t\tmenuItemComponentToUse = menuItemComponent;\n\t}\n\n\treturn (\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\tplaceholder={\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t}\n\t\t\t\t\t\tErrorBoundary={ LexicalErrorBoundary }\n\t\t\t\t\t/>\n\t\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t{ ref && }\n\t\t\t\t{ autoFocus && }\n\t\t\t\n\t\t
\n\t);\n};\nconst EditorInput = forwardRef( EditorInputComponent );\nEditorInput.displayName = 'EditorInput';\n\nexport default EditorInput;\n","const EditorPlaceholder = ( { content } ) => (\n\t
\n\t\t{ content }\n\t
\n);\n\nexport default EditorPlaceholder;\n","const editorTheme = {\n\tltr: 'ltr',\n\trtl: 'rtl',\n\tparagraph: 'editor-paragraph',\n\tquote: 'editor-quote',\n\theading: {\n\t\th1: 'editor-heading-h1',\n\t\th2: 'editor-heading-h2',\n\t\th3: 'editor-heading-h3',\n\t\th4: 'editor-heading-h4',\n\t\th5: 'editor-heading-h5',\n\t\th6: 'editor-heading-h6',\n\t},\n\tlist: {\n\t\tnested: {\n\t\t\tlistitem: 'editor-nested-listitem',\n\t\t},\n\t\tol: 'editor-list-ol',\n\t\tul: 'editor-list-ul',\n\t\tlistitem: 'editor-listItem',\n\t\tlistitemChecked: 'editor-listItemChecked',\n\t\tlistitemUnchecked: 'editor-listItemUnchecked',\n\t},\n\thashtag: 'editor-hashtag',\n\timage: 'editor-image',\n\tlink: 'editor-link',\n\ttext: {\n\t\tbold: 'editor-textBold',\n\t\tcode: 'editor-textCode',\n\t\titalic: 'editor-textItalic',\n\t\tstrikethrough: 'editor-textStrikethrough',\n\t\tsubscript: 'editor-textSubscript',\n\t\tsuperscript: 'editor-textSuperscript',\n\t\tunderline: 'editor-textUnderline',\n\t\tunderlineStrikethrough: 'editor-textUnderlineStrikethrough',\n\t},\n\tcode: 'editor-code',\n\tcodeHighlight: {\n\t\tatrule: 'editor-tokenAttr',\n\t\tattr: 'editor-tokenAttr',\n\t\tboolean: 'editor-tokenProperty',\n\t\tbuiltin: 'editor-tokenSelector',\n\t\tcdata: 'editor-tokenComment',\n\t\tchar: 'editor-tokenSelector',\n\t\tclass: 'editor-tokenFunction',\n\t\t'class-name': 'editor-tokenFunction',\n\t\tcomment: 'editor-tokenComment',\n\t\tconstant: 'editor-tokenProperty',\n\t\tdeleted: 'editor-tokenProperty',\n\t\tdoctype: 'editor-tokenComment',\n\t\tentity: 'editor-tokenOperator',\n\t\tfunction: 'editor-tokenFunction',\n\t\timportant: 'editor-tokenVariable',\n\t\tinserted: 'editor-tokenSelector',\n\t\tkeyword: 'editor-tokenAttr',\n\t\tnamespace: 'editor-tokenVariable',\n\t\tnumber: 'editor-tokenProperty',\n\t\toperator: 'editor-tokenOperator',\n\t\tprolog: 'editor-tokenComment',\n\t\tproperty: 'editor-tokenProperty',\n\t\tpunctuation: 'editor-tokenPunctuation',\n\t\tregex: 'editor-tokenVariable',\n\t\tselector: 'editor-tokenSelector',\n\t\tstring: 'editor-tokenSelector',\n\t\tsymbol: 'editor-tokenProperty',\n\t\ttag: 'editor-tokenProperty',\n\t\turl: 'editor-tokenOperator',\n\t\tvariable: 'editor-tokenVariable',\n\t},\n};\n\nexport default editorTheme;\n","import { cn } from '@/utilities/functions';\nimport {\n\tcomboboxDropdownClassNames,\n\tcomboboxDropdownCommonClassNames,\n\tcomboboxItemClassNames,\n\tcomboboxItemCommonClassNames,\n\tcomboboxSelectedItemClassNames,\n} from '../editor-input-style';\nimport { forwardRef } from 'react';\n\nconst EditorComboboxWrapper = ( { size, className, children } ) => (\n\t
\n);\n\nconst EditorComboboxItem = forwardRef(\n\t( { size, children, selected = false, className, ...props }, ref ) => (\n\t\t
\n\t\t\t{ children }\n\t\t\n\t)\n);\nEditorComboboxItem.displayName = 'Item';\n\nconst EditorCombobox = Object.assign( EditorComboboxWrapper, {\n\tItem: EditorComboboxItem,\n} );\n\nexport default EditorCombobox;\n","import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { $getNodeByKey } from 'lexical';\nimport { Badge } from '@/components';\n\nconst mapSizeToBadgeSize = ( size ) => {\n\tswitch ( size ) {\n\t\tcase 'sm':\n\t\t\treturn 'xs';\n\t\tcase 'md':\n\t\t\treturn 'sm';\n\t\tcase 'lg':\n\t\t\treturn 'md';\n\t\tdefault:\n\t\t\treturn 'sm';\n\t}\n};\n\nconst MentionComponent = ( { data, by, size, nodeKey } ) => {\n\tconst [ editor ] = useLexicalComposerContext();\n\tconst disabled = ! editor.isEditable();\n\n\tconst removeMention = ( event ) => {\n\t\tevent.stopPropagation();\n\t\tevent.preventDefault();\n\n\t\tif ( disabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\teditor.update( () => {\n\t\t\tconst node = $getNodeByKey( nodeKey );\n\t\t\tif ( ! node ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnode.remove();\n\t\t} );\n\t};\n\n\tlet renderLabel = data;\n\tif ( typeof data === 'object' ) {\n\t\trenderLabel = data[ by ];\n\t}\n\n\treturn (\n\t\t
\n\t);\n};\n\nexport default MentionComponent;\n","import { useEffect, useState } from 'react';\n\nconst mentionsCache = new Map();\n\nfunction useMentionLookupService( options, mentionString, by = 'name' ) {\n\tconst [ results, setResults ] = useState( [] );\n\n\tuseEffect( () => {\n\t\tif ( mentionString === null ) {\n\t\t\tsetResults( [] );\n\t\t\treturn;\n\t\t}\n\n\t\tconst cachedResults = mentionsCache.get( mentionString );\n\t\tif ( cachedResults === null ) {\n\t\t\treturn;\n\t\t} else if ( cachedResults !== undefined ) {\n\t\t\tsetResults( cachedResults );\n\t\t\treturn;\n\t\t}\n\n\t\tmentionsCache.set( mentionString, null );\n\t\tlookupService.search(\n\t\t\toptions,\n\t\t\tmentionString,\n\t\t\t( newResults ) => {\n\t\t\t\tmentionsCache.set( mentionString, newResults );\n\t\t\t\tsetResults( newResults );\n\t\t\t},\n\t\t\tby\n\t\t);\n\t}, [ mentionString ] );\n\n\treturn results;\n}\n\nconst lookupService = {\n\tsearch( options, string, callback, by ) {\n\t\tsetTimeout( () => {\n\t\t\tconst results = options.filter( ( mention ) => {\n\t\t\t\tif ( typeof mention === 'string' ) {\n\t\t\t\t\treturn mention.toLowerCase().includes( string.toLowerCase() );\n\t\t\t\t}\n\n\t\t\t\tconst strValue = mention?.[ by ]?.toString();\n\t\t\t\tif ( ! strValue ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn strValue.toLowerCase().includes( string.toLowerCase() );\n\t\t\t} );\n\t\t\tcallback( results );\n\t\t}, 500 );\n\t},\n};\n\nexport default useMentionLookupService;\n","import { DecoratorNode } from 'lexical';\nimport MentionComponent from './mention-component';\n\nclass MentionNode extends DecoratorNode {\n\t__data;\n\t__by;\n\t__size;\n\n\tconstructor( data, by, size, key ) {\n\t\tsuper( key );\n\t\tthis.__data = data;\n\t\tthis.__by = by;\n\t\tthis.__size = size;\n\t}\n\n\tstatic getType() {\n\t\treturn 'mention';\n\t}\n\n\tstatic clone( node ) {\n\t\treturn new MentionNode( node.__data, node.__by, node.__size, node.__key );\n\t}\n\n\tstatic importJSON( serializeNode ) {\n\t\tconst node = $createMentionNode(\n\t\t\tserializeNode.data,\n\t\t\tserializeNode.by,\n\t\t\tserializeNode.size\n\t\t);\n\t\treturn node;\n\t}\n\n\tcreateDOM() {\n\t\treturn document.createElement( 'span' );\n\t}\n\n\tupdateDOM() {\n\t\treturn false;\n\t}\n\n\texportDOM() {\n\t\tconst element = document.createElement( 'span' );\n\n\t\treturn { element };\n\t}\n\n\texportJSON() {\n\t\treturn {\n\t\t\ttype: MentionNode.getType(),\n\t\t\tdata: this.__data,\n\t\t\tby: this.__by,\n\t\t\tsize: this.__size,\n\t\t\tversion: 1,\n\t\t};\n\t}\n\n\tdecorate() {\n\t\treturn (\n\t\t\t
\n\t\t);\n\t}\n}\n\nexport const $createMentionNode = ( data, by, size ) =>\n\tnew MentionNode( data, by, size );\n\nexport const $isMentionNode = ( node ) => node instanceof MentionNode;\n\nexport default MentionNode;\n","class OptionItem {\n\tdata;\n\tref = { current: null };\n\n\tconstructor( data ) {\n\t\tthis.data = data;\n\t}\n}\n\nexport default OptionItem;\n","import { useCallback, useState, useMemo } from 'react';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { LexicalTypeaheadMenuPlugin } from '@lexical/react/LexicalTypeaheadMenuPlugin';\nimport { $createMentionNode } from './mention-node';\nimport OptionItem from './mention-option-item';\nimport useMentionLookupService from './mention-hooks';\nimport EditorCombobox from './mention-combobox';\n\nconst MentionPlugin = ( {\n\toptionsArray,\n\tby = 'name',\n\tsize = 'md',\n\ttrigger = '@', // Default trigger value\n\tmenuComponent: MenuComponent = EditorCombobox,\n\tmenuItemComponent: MenuItemComponent = EditorCombobox.Item,\n} ) => {\n\t// Define PUNCTUATION and other necessary variables inside the component\n\tconst PUNCTUATION =\n\t\t'\\\\.,\\\\+\\\\*\\\\?\\\\$\\\\@\\\\|#{}\\\\(\\\\)\\\\^\\\\-\\\\[\\\\]\\\\\\\\/!%\\'\"~=<>_:;';\n\n\tconst TRIGGERS = [ trigger ].join( '' ); // Use the trigger prop dynamically\n\n\tconst VALID_CHARS = '[^' + TRIGGERS + PUNCTUATION + '\\\\s]';\n\n\tconst VALID_JOINS =\n\t\t'(?:' +\n\t\t'\\\\.[ |$]|' + // E.g. \"r. \" in \"Mr. Smith\"\n\t\t' |' + // E.g. \" \" in \"Josh Duck\"\n\t\t'[' +\n\t\tPUNCTUATION +\n\t\t']|' + // E.g. \"-' in \"Salier-Hellendag\"\n\t\t')';\n\n\tconst LENGTH_LIMIT = 75;\n\n\tconst AtSignMentionsRegex = new RegExp(\n\t\t`(^|\\\\s|\\\\()([${ TRIGGERS }]((?:${ VALID_CHARS }${ VALID_JOINS }){0,${ LENGTH_LIMIT }}))$`\n\t);\n\n\t// 50 is the longest alias length limit\n\tconst ALIAS_LENGTH_LIMIT = 50;\n\n\t// Regex used to match alias\n\tconst AtSignMentionsRegexAliasRegex = new RegExp(\n\t\t`(^|\\\\s|\\\\()([${ TRIGGERS }]((?:${ VALID_CHARS }){0,${ ALIAS_LENGTH_LIMIT }}))$`\n\t);\n\n\t// Define checkForAtSignMentions function inside the component where it has access to the regex\n\tconst checkForAtSignMentions = ( text ) => {\n\t\tlet match = AtSignMentionsRegex.exec( text );\n\n\t\tif ( match === null ) {\n\t\t\tmatch = AtSignMentionsRegexAliasRegex.exec( text );\n\t\t}\n\t\tif ( match !== null ) {\n\t\t\t// The strategy ignores leading whitespace but we need to know its\n\t\t\t// length to add it to the leadOffset\n\t\t\tconst maybeLeadingWhitespace = match[ 1 ];\n\n\t\t\tconst matchingString = match[ 3 ];\n\t\t\tif ( matchingString.length >= 0 ) {\n\t\t\t\treturn {\n\t\t\t\t\tleadOffset: match.index + maybeLeadingWhitespace.length,\n\t\t\t\t\tmatchingString,\n\t\t\t\t\treplaceableString: match[ 2 ],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n\n\tconst [ editor ] = useLexicalComposerContext();\n\tconst [ queryString, setQueryString ] = useState( null );\n\n\t// Use the hook to get lookup results\n\tconst results = useMentionLookupService( optionsArray, queryString, by );\n\n\tconst onSelectOption = useCallback(\n\t\t( selectedOption, nodeToReplace, closeMenu ) => {\n\t\t\teditor.update( () => {\n\t\t\t\tconst mentionNode = $createMentionNode(\n\t\t\t\t\tselectedOption.data,\n\t\t\t\t\tby,\n\t\t\t\t\tsize\n\t\t\t\t);\n\t\t\t\tif ( nodeToReplace ) {\n\t\t\t\t\tnodeToReplace.replace( mentionNode );\n\t\t\t\t}\n\t\t\t\tcloseMenu();\n\t\t\t} );\n\t\t},\n\t\t[ editor ]\n\t);\n\n\tconst options = useMemo( () => {\n\t\treturn results.map( ( result ) => new OptionItem( result ) );\n\t}, [ editor, results ] );\n\n\treturn (\n\t\t
{\n\t\t\t\treturn (\n\t\t\t\t\tanchorElementRef.current &&\n\t\t\t\t\t!! options?.length && (\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{ options.map( ( option, index ) => (\n\t\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\t\tsetHighlightedIndex( index );\n\t\t\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\t\t\tonClick={ () =>\n\t\t\t\t\t\t\t\t\t\tselectOptionAndCleanUp( option )\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\t\t{ typeof option.data === 'string'\n\t\t\t\t\t\t\t\t\t\t? option.data\n\t\t\t\t\t\t\t\t\t\t: option.data?.[ by ] }\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} }\n\t\t/>\n\t);\n};\n\nexport default MentionPlugin;\n","export { default as Button } from './button/index';\nexport { default as Switch } from './switch/index';\nexport { default as Checkbox } from './checkbox/index';\nexport { RadioButtonGroup, RadioButton } from './radio-button-group/index';\nexport { default as Badge } from './badge/index';\nexport { default as TextArea } from './textarea/index';\nexport { default as Avatar } from './avatar/index';\nexport { default as Input } from './input/index';\nexport { default as Label } from './label/index';\nexport { default as Title } from './title/index';\nexport { default as Loader } from './loader/index';\nexport { default as ProgressBar } from './progress-bar/index';\nexport { default as Tooltip } from './tooltip/index';\nexport { default as ButtonGroup } from './button-group/index';\nexport { default as Tabs } from './tabs/index';\nexport { default as Select } from './select/index';\nexport * from './toaster/index';\nexport { default as Container } from './container/index';\nexport { default as Alert } from './alert/index';\nexport { default as EditorInput } from './editor-input/index';\nexport { default as ProgressSteps } from './progress-steps/index';\nexport { default as Skeleton } from './skeleton/index';\nexport { default as Menu } from './menu-item/index';\nexport { default as Sidebar } from './sidebar/index';\nexport {\n\tBreadcrumb,\n\tBreadcrumbList,\n\tBreadcrumbItem,\n\tBreadcrumbLink,\n\tBreadcrumbSeparator,\n\tBreadcrumbEllipsis,\n\tBreadcrumbPage,\n} from './breadcrumb/index';\nexport { default as Dialog } from './dialog/index';\nexport { default as Topbar } from './topbar/index';\nexport { default as Drawer } from './drawer/index';\n","import { useState, useCallback, useMemo, forwardRef } from 'react';\nimport { nanoid } from 'nanoid';\nimport { cn } from '@/utilities/functions';\nimport { Upload } from 'lucide-react';\n\nconst InputComponent = (\n\t{\n\t\tid,\n\t\ttype = 'text',\n\t\tdefaultValue = '',\n\t\tvalue,\n\t\tsize = 'sm', // sm, md, lg\n\t\tclassName = '',\n\t\tdisabled = false,\n\t\tonChange = () => {},\n\t\terror = false,\n\t\tonError = () => {},\n\t\tprefix = null,\n\t\tsuffix = null,\n\t\t...props\n\t},\n\tref\n) => {\n\tconst inputId = useMemo( () => id || `input-${ type }-${ nanoid() }`, [ id ] );\n\tconst isControlled = useMemo( () => typeof value !== 'undefined', [ value ] );\n\tconst [ inputValue, setInputValue ] = useState( defaultValue );\n\tconst [ selectedFile, setSelectedFile ] = useState( null );\n\n\tconst getValue = useCallback(\n\t\t() => ( isControlled ? value : inputValue ),\n\t\t[ isControlled, value, inputValue ]\n\t);\n\n\tconst handleChange = ( event ) => {\n\t\tif ( disabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet newValue;\n\t\tif ( type === 'file' ) {\n\t\t\tnewValue = event.target.files;\n\t\t\tif ( newValue.length > 0 ) {\n\t\t\t\tsetSelectedFile( newValue[ 0 ].name );\n\t\t\t} else {\n\t\t\t\tsetSelectedFile( null );\n\t\t\t}\n\t\t} else {\n\t\t\tnewValue = event.target.value;\n\t\t}\n\n\t\tif ( ! isControlled && type !== 'file' ) {\n\t\t\tsetInputValue( newValue );\n\t\t}\n\n\t\tif ( typeof onChange !== 'function' ) {\n\t\t\treturn;\n\t\t}\n\t\tonChange( newValue );\n\t};\n\n\tconst baseClasses =\n\t\t'border border-solid border-border-subtle bg-field-secondary-background font-normal placeholder-text-tertiary text-text-primary w-full focus:outline-none';\n\tconst sizeClasses = {\n\t\tsm: 'px-2 py-2 rounded',\n\t\tmd: 'px-2.5 py-2.5 rounded-md',\n\t\tlg: 'px-3 py-3 rounded-lg',\n\t};\n\tconst textClasses = {\n\t\tsm: 'text-xs',\n\t\tmd: 'text-base',\n\t\tlg: 'text-base',\n\t};\n\tconst sizeClassesWithPrefix = {\n\t\tsm: prefix ? 'pl-8' : '',\n\t\tmd: prefix ? 'pl-9' : '',\n\t\tlg: prefix ? 'pl-10' : '',\n\t};\n\tconst sizeClassesWithSuffix = {\n\t\tsm: suffix ? 'pr-8' : '',\n\t\tmd: suffix ? 'pr-9' : '',\n\t\tlg: suffix ? 'pr-10' : '',\n\t};\n\n\tconst hoverClasses = disabled\n\t\t? 'hover:border-border-disabled'\n\t\t: 'hover:border-border-strong';\n\tconst focusClasses =\n\t\t'focus:border-focus-border focus:ring-2 focus:ring-toggle-on focus:ring-offset-2';\n\tconst errorClasses = error\n\t\t? 'focus:border-focus-error-border focus:ring-field-color-error bg-field-background-error'\n\t\t: '';\n\tconst errorFileClasses = error\n\t\t? 'focus:border-focus-error-border focus:ring-field-color-error'\n\t\t: '';\n\tconst disabledClasses = disabled\n\t\t? 'border-border-disabled bg-field-background-disabled cursor-not-allowed text-text-disabled'\n\t\t: '';\n\tconst disabledUploadFileClasses = disabled\n\t\t? 'border-border-disabled cursor-not-allowed text-text-disabled file:text-text-tertiary'\n\t\t: '';\n\tconst iconClasses =\n\t\t'font-normal placeholder-text-tertiary text-text-primary pointer-events-none absolute inset-y-0 flex flex-1 items-center [&>svg]:h-4 [&>svg]:w-4';\n\tconst uploadIconClasses = disabled\n\t\t? 'font-normal placeholder-text-tertiary text-icon-disabled pointer-events-none absolute inset-y-0 flex flex-1 items-center'\n\t\t: 'font-normal placeholder-text-tertiary text-field-placeholder pointer-events-none absolute inset-y-0 flex flex-1 items-center';\n\n\tconst uploadIconSizeClasses = {\n\t\tsm: '[&>svg]:h-4 [&>svg]:w-4',\n\t\tmd: '[&>svg]:h-5 [&>svg]:w-5',\n\t\tlg: '[&>svg]:h-6 [&>svg]:w-6',\n\t};\n\n\tconst getPrefix = () => {\n\t\tif ( ! prefix ) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (\n\t\t\t\n\t\t\t\t{ prefix }\n\t\t\t
\n\t\t);\n\t};\n\n\tconst getSuffix = () => {\n\t\tif ( ! suffix ) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (\n\t\t\t\n\t\t\t\t{ suffix }\n\t\t\t
\n\t\t);\n\t};\n\n\tconst fileClasses = selectedFile\n\t\t? 'file:border-0 file:bg-transparent'\n\t\t: 'text-text-tertiary file:border-0 file:bg-transparent';\n\n\tif ( type === 'file' ) {\n\t\treturn (\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
\n\t\t\t
\n\t\t);\n\t}\n\n\treturn (\n\t\t\n\t\t\t{ getPrefix() }\n\t\t\t\n\t\t\t{ getSuffix() }\n\t\t
\n\t);\n};\nconst Input = forwardRef( InputComponent );\nInput.displayName = 'Input';\n\nexport default Input;\n","import { cn } from '@/utilities/functions';\nimport React, { forwardRef } from 'react';\n\n/**\n * Label component.\n */\n\nconst Label = forwardRef(\n\t(\n\t\t{\n\t\t\tchildren = null,\n\t\t\ttag = 'label',\n\t\t\tsize = 'sm', // xs, sm, md\n\t\t\tclassName = '',\n\t\t\tvariant = 'neutral', // neutral, help, error, disabled\n\t\t\trequired = false,\n\t\t\t...props\n\t\t},\n\t\tref\n\t) => {\n\t\t// Base classes. - Mandatory classes.\n\t\tconst baseClasses =\n\t\t\t'font-medium text-field-label flex items-center gap-0.5';\n\n\t\t// Size classes - Based on the size prop.\n\t\tconst sizeClasses = {\n\t\t\txs: 'text-xs [&>*]:text-xs [&>svg]:h-3 [&>svg]:w-3',\n\t\t\tsm: 'text-sm [&>*]:text-sm [&>svg]:h-4 [&>svg]:w-4',\n\t\t\tmd: 'text-base [&>*]:text-base [&>svg]:h-5 [&>svg]:w-5',\n\t\t};\n\n\t\t// Variant classes - Based on the variant prop.\n\t\tconst variantClasses = {\n\t\t\tneutral: 'text-field-label [&>*]:text-field-label',\n\t\t\thelp: 'text-field-helper [&>*]:text-field-helper',\n\t\t\terror: 'text-support-error [&>*]:text-support-error',\n\t\t\tdisabled:\n\t\t\t\t'text-field-color-disabled disabled cursor-not-allowed [&>*]:text-field-color-disabled',\n\t\t};\n\n\t\tif ( ! children ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet requiredClasses = '';\n\n\t\tif ( required ) {\n\t\t\trequiredClasses =\n\t\t\t\t\"after:content-['*'] after:text-field-required after:ml-0.5\";\n\t\t}\n\n\t\tconst Tag = tag;\n\n\t\treturn (\n\t\t\t\n\t\t\t\t{ children }\n\t\t\t\n\t\t);\n\t}\n);\n\nexport default Label;\n","import { cn } from '@/utilities/functions';\nimport { LoaderCircle } from 'lucide-react';\n\nconst Loader = ( {\n\tvariant = 'primary', // primary, secondary\n\tsize = 'md', // sm, md, lg, xl,\n\ticon = null,\n\tclassName = '',\n} ) => {\n\tconst variantClassNames = {\n\t\tprimary: 'text-brand-primary-600 bg-background-primary',\n\t\tsecondary: 'text-background-primary bg-brand-primary-600',\n\t}?.[ variant ];\n\n\tconst sizeClassNames = {\n\t\tsm: '[&>svg]:h-4 [&>svg]:w-4',\n\t\tmd: '[&>svg]:h-5 [&>svg]:w-5',\n\t\tlg: '[&>svg]:h-6 [&>svg]:w-6',\n\t\txl: '[&>svg]:h-8 [&>svg]:w-8',\n\t}?.[ size ];\n\n\treturn (\n\t\t\n\t\t\t{ icon ? icon : }\n\t\t\n\t);\n};\n\nexport default Loader;\n","import React, { useState, createContext, useContext } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { ChevronDown } from 'lucide-react';\nimport { cn } from '@/utilities/functions';\n\nconst MenuContext = createContext();\nconst useMenuContext = () => useContext( MenuContext );\n\nconst Menu = ( { size = 'md', children, className } ) => {\n\tconst baseClasses = 'w-64 flex flex-col bg-background-primary p-2';\n\n\treturn (\n\t\t\n\t\t\t{ children }
\n\t\t\n\t);\n};\n\nconst MenuList = ( {\n\theading,\n\tarrow = false,\n\topen: initialOpen = false,\n\tonClick,\n\tchildren,\n\tclassName,\n} ) => {\n\tconst [ isOpen, setIsOpen ] = useState( initialOpen );\n\tconst { size } = useMenuContext();\n\n\tconst baseClasses =\n\t\t'text-text-primary bg-transparent cursor-pointer flex justify-between items-center p-1 gap-1';\n\n\tconst sizeClasses = {\n\t\tsm: 'text-xs',\n\t\tmd: 'text-sm',\n\t}?.[ size ];\n\tconst iconSizeClasses = {\n\t\tsm: '[&>svg]:size-4',\n\t\tmd: '[&>svg]:size-5',\n\t}?.[ size ];\n\n\tconst handleToggle = () => {\n\t\tsetIsOpen( ! isOpen );\n\t\tif ( onClick ) {\n\t\t\tonClick( ! isOpen );\n\t\t}\n\t};\n\n\tconst arrowAnimationVariants = {\n\t\topen: { rotate: 180 },\n\t\tclosed: { rotate: 0 },\n\t};\n\n\tconst listAnimationVariants = {\n\t\topen: { height: 'auto', opacity: 1 },\n\t\tclosed: { height: 0, opacity: 0 },\n\t};\n\n\treturn (\n\t\t\n\t\t\t
{\n\t\t\t\t\tif ( event.key === 'Enter' || event.key === ' ' ) {\n\t\t\t\t\t\thandleToggle();\n\t\t\t\t\t}\n\t\t\t\t} }\n\t\t\t\tclassName={ cn( baseClasses, sizeClasses, className ) }\n\t\t\t\taria-expanded={ isOpen }\n\t\t\t>\n\t\t\t\t{ heading }\n\n\t\t\t\t{ arrow && (\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\n\t\t\t
\n\t\t\t\t{ isOpen && (\n\t\t\t\t\t\n\t\t\t\t\t\t{ children }\n\t\t\t\t\t\n\t\t\t\t) }\n\t\t\t\n\t\t
\n\t);\n};\n\nconst MenuItem = ( {\n\tdisabled = false,\n\tactive,\n\tonClick,\n\tchildren,\n\tclassName,\n} ) => {\n\tconst { size } = useMenuContext();\n\n\tconst baseClasses =\n\t\t'flex p-1 gap-1 items-center bg-transparent w-full border-none rounded text-text-secondary cursor-pointer m-0';\n\tconst sizeClasses = {\n\t\tsm: '[&>svg]:size-4 [&>svg]:m-1 [&>*:not(svg)]:mx-1 [&>*:not(svg)]:my-0.5 text-sm',\n\t\tmd: '[&>svg]:size-5 [&>svg]:m-1.5 [&>*:not(svg)]:m-1 text-base',\n\t}?.[ size ];\n\tconst hoverClasses =\n\t\t'hover:bg-background-secondary hover:text-text-primary';\n\tconst disabledClasses = disabled\n\t\t? 'text-text-disabled hover:text-text-disabled cursor-not-allowed hover:bg-transparent'\n\t\t: '';\n\tconst activeClasses = active\n\t\t? 'text-icon-primary [&>svg]:text-icon-interactive bg-background-secondary'\n\t\t: '';\n\tconst transitionClasses = 'transition-colors duration-300 ease-in-out';\n\n\treturn (\n\t\t {\n\t\t\t\tif ( event.key === 'Enter' || event.key === ' ' ) {\n\t\t\t\t\tonClick();\n\t\t\t\t}\n\t\t\t} }\n\t\t\tclassName={ cn(\n\t\t\t\tbaseClasses,\n\t\t\t\tsizeClasses,\n\t\t\t\thoverClasses,\n\t\t\t\tdisabledClasses,\n\t\t\t\tactiveClasses,\n\t\t\t\ttransitionClasses,\n\t\t\t\tclassName\n\t\t\t) }\n\t\t>\n\t\t\t{ children }\n\t\t\n\t);\n};\n\nconst MenuSeparator = ( { variant = 'solid', className } ) => {\n\tconst variantClasses = {\n\t\tsolid: 'border-solid',\n\t\tdashed: 'border-dashed',\n\t\tdotted: 'border-dotted',\n\t\tdouble: 'border-double',\n\t\thidden: 'border-hidden',\n\t\tnone: 'border-none',\n\t}?.[ variant ];\n\n\treturn (\n\t\t<>\n\t\t\t
\n\t\t>\n\t);\n};\n\nMenu.List = MenuList;\nMenu.Item = MenuItem;\nMenu.Separator = MenuSeparator;\n\nexport default Menu;\n","import { cn } from '@/utilities/functions';\n\nconst ProgressBar = ( {\n\tprogress = 0, // 0-100\n\tspeed = 200,\n\tclassName = '',\n} ) => {\n\tif ( ! progress ) {\n\t\treturn null;\n\t}\n\tlet percent = progress;\n\tif ( progress < 0 ) {\n\t\tpercent = 0;\n\t}\n\tif ( progress > 100 ) {\n\t\tpercent = 100;\n\t}\n\n\tconst translateProperty = `translateX(-${ 100 - percent }%)`;\n\tconst innerClasses = `h-2 rounded-full bg-background-brand absolute left-0 top-0 w-full bottom-0 origin-left transition-transform duration-${ speed } ease-linear`;\n\n\treturn (\n\t\t\n\t);\n};\n\nexport default ProgressBar;\n","import React from 'react';\nimport { cn } from '@/utilities/functions';\nimport { Plus, Check } from 'lucide-react';\nimport {\n\tgetVariantClasses,\n\tcompletedStepCommonClasses,\n\tstepWrapperClasses,\n} from './utils';\n\nconst ProgressSteps = ( {\n\tvariant = 'dot',\n\tsize = 'sm',\n\ttype = 'inline',\n\tcurrentStep = 1,\n\tchildren,\n\tclassName,\n\t...rest\n} ) => {\n\tconst totalSteps = React.Children.count( children );\n\n\tconst sizeClasses = {\n\t\tsm: {\n\t\t\tdot: 'size-2.5',\n\t\t\tring: 'size-5',\n\t\t\tnumberIcon: 'size-5 text-tiny',\n\t\t\ticon: 'size-5',\n\t\t\tlabel: 'text-xs',\n\t\t},\n\t\tmd: {\n\t\t\tdot: 'size-3',\n\t\t\tring: 'size-6',\n\t\t\tnumberIcon: 'size-6 text-sm',\n\t\t\ticon: 'size-6',\n\t\t\tlabel: 'text-sm',\n\t\t},\n\t\tlg: {\n\t\t\tdot: 'size-3.5',\n\t\t\tring: 'size-7',\n\t\t\tnumberIcon: 'size-7 text-md',\n\t\t\ticon: 'size-7',\n\t\t\tlabel: 'text-sm',\n\t\t},\n\t};\n\n\tconst steps = React.Children.map( children, ( child, index ) => {\n\t\tconst isCompleted = index + 1 < currentStep;\n\t\tconst isCurrent = index + 1 === currentStep;\n\t\tconst isLast = index + 1 === totalSteps;\n\n\t\tconst stepProps = {\n\t\t\tisCompleted,\n\t\t\tisCurrent,\n\t\t\tsizeClasses,\n\t\t\tsize,\n\t\t\tvariant,\n\t\t\ttype,\n\t\t\tisLast,\n\t\t\tindex,\n\t\t};\n\n\t\treturn (\n\t\t\t\n\t\t\t\t{ React.cloneElement( child, stepProps ) }\n\t\t\t\n\t\t);\n\t} );\n\n\treturn (\n\t\t\n\t\t\t{ steps }\n\t\t
\n\t);\n};\n\n// ProgressStep component as {ProgressSteps.Step}\nconst ProgressStep = ( {\n\tlabelText,\n\ticon = ,\n\tstepClasses,\n\tisCurrent,\n\tisCompleted,\n\tclassName,\n\ttype,\n\tvariant,\n\tsizeClasses,\n\tsize,\n\tisLast,\n\tindex,\n\t...rest\n} ) => {\n\tconst stepContent = createStepContent(\n\t\tvariant,\n\t\tisCompleted,\n\t\tisCurrent,\n\t\tsizeClasses,\n\t\tsize,\n\t\ticon,\n\t\tindex\n\t);\n\n\tconst stackSizeOffset = {\n\t\tlg: 'left-[calc(50%+14px)] right-[calc(-50%+14px)]',\n\t\tmd: 'left-[calc(50%+12px)] right-[calc(-50%+12px)]',\n\t\tsm: 'left-[calc(50%+10px)] right-[calc(-50%+10px)]',\n\t};\n\n\tconst topClass = {\n\t\tlg: 'top-3.5',\n\t\tmd: 'top-3',\n\t\tsm: 'top-2.5',\n\t};\n\n\tconst renderLabel = () => {\n\t\tif ( labelText ) {\n\t\t\tconst labelClasses = cn(\n\t\t\t\tsizeClasses[ size ].label,\n\t\t\t\t'text-text-tertiary',\n\t\t\t\tisCurrent ? 'text-brand-primary-600' : '',\n\t\t\t\t'break-word', // max width for inline and stack\n\t\t\t\ttype === 'stack' ? 'mt-2 transform max-w-xs' : 'mx-2 max-w-32'\n\t\t\t);\n\t\t\treturn { labelText };\n\t\t}\n\t\treturn null;\n\t};\n\n\tconst renderConnectingLine = () => {\n\t\tif ( ! isLast ) {\n\t\t\tconst lineClasses = cn(\n\t\t\t\t'block',\n\t\t\t\tisCompleted\n\t\t\t\t\t? 'border-brand-primary-600'\n\t\t\t\t\t: 'border-border-subtle'\n\t\t\t);\n\n\t\t\tif ( type === 'stack' ) {\n\t\t\t\treturn (\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\treturn (\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\treturn null;\n\t};\n\n\t// Main return logic based on type\n\tif ( type === 'stack' ) {\n\t\treturn (\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{ stepContent }\n\t\t\t\t\t{ renderLabel() }\n\t\t\t\t
\n\t\t\t\t{ renderConnectingLine() }\n\t\t\t
\n\t\t);\n\t}\n\treturn (\n\t\t<>\n\t\t\t\n\t\t\t\t{ stepContent }\n\t\t\t\t{ renderLabel() }\n\t\t\t
\n\t\t\t{ renderConnectingLine() }\n\t\t>\n\t);\n};\n\n// Create step content\nconst createStepContent = (\n\tvariant,\n\tisCompleted,\n\tisCurrent,\n\tsizeClasses,\n\tsize,\n\ticon,\n\tindex\n) => {\n\tif ( isCompleted ) {\n\t\treturn (\n\t\t\t\n\t\t);\n\t}\n\n\tconst commonClasses = stepWrapperClasses( isCurrent, sizeClasses, size );\n\tconst variantClasses = getVariantClasses(\n\t\tvariant,\n\t\tisCurrent,\n\t\tsizeClasses,\n\t\tsize\n\t);\n\n\tlet content = null;\n\tif ( variant === 'number' ) {\n\t\tcontent = index + 1;\n\t} else if ( variant === 'icon' && icon ) {\n\t\tcontent = icon;\n\t}\n\n\treturn (\n\t\t\n\t\t\t{ content }\n\t\t\n\t);\n};\n\nProgressSteps.Step = ProgressStep;\n\nexport default ProgressSteps;\n","import { cn } from '@/utilities/functions';\n\n/**\n * Helper function to generate classes for different step variants.\n *\n * @param {'dot' | 'number' | 'icon'} variant - The type of step indicator.\n * @param {boolean} isCurrent - Whether the step is the current step.\n * @param {Object} sizeClasses - The size classes for different step sizes.\n * @param {'sm' | 'md' | 'lg'} size - The size of the step indicator.\n * @return {string} The combined class names.\n */\nexport const getVariantClasses = ( variant, isCurrent, sizeClasses, size ) => {\n\tconst baseClass = `absolute rounded-full transition-colors duration-500 ${ sizeClasses[ size ].dot }`;\n\n\tif ( variant === 'dot' ) {\n\t\treturn cn(\n\t\t\tbaseClass,\n\t\t\tsizeClasses[ size ].dot,\n\t\t\tisCurrent ? 'bg-brand-primary-600' : 'bg-text-tertiary'\n\t\t);\n\t}\n\n\tif ( variant === 'number' ) {\n\t\treturn cn(\n\t\t\tbaseClass,\n\t\t\tsizeClasses[ size ].dot,\n\t\t\tisCurrent ? 'text-brand-primary-600' : 'text-text-tertiary',\n\t\t\t'flex items-center justify-center'\n\t\t);\n\t}\n\n\tif ( variant === 'icon' ) {\n\t\treturn cn(\n\t\t\tbaseClass,\n\t\t\tisCurrent ? 'text-brand-primary-600' : 'text-text-tertiary',\n\t\t\t'flex items-center justify-center'\n\t\t);\n\t}\n\n\treturn '';\n};\n\n/**\n * Helper function to generate common classes for step indicators.\n *\n * @param {boolean} isCurrent - Whether the step is the current step.\n * @param {Object} sizeClasses - The size classes for different step sizes.\n * @param {'sm' | 'md' | 'lg'} size - The size of the step indicator.\n * @return {string} The combined class names.\n */\nexport const stepWrapperClasses = ( isCurrent, sizeClasses, size ) => {\n\treturn cn(\n\t\t'relative flex items-center rounded-full justify-center transition-colors z-10 duration-500 ring-1',\n\t\tisCurrent ? 'ring-brand-primary-600' : 'ring-border-subtle',\n\t\tsizeClasses[ size ].ring\n\t);\n};\n\n/**\n * Helper function to generate common classes for completed steps.\n *\n * @param {Object} sizeClasses - The size classes for different step sizes.\n * @param {'sm' | 'md' | 'lg'} size - The size of the step indicator.\n * @return {string} The combined class names.\n */\nexport const completedStepCommonClasses = ( sizeClasses, size ) => {\n\treturn cn(\n\t\t'rounded-full text-brand-primary-600 transition-colors duration-300',\n\t\tsizeClasses[ size ].dot,\n\t\tsizeClasses[ size ].ring\n\t);\n};\n","import React, {\n\tuseState,\n\tuseCallback,\n\tuseMemo,\n\tforwardRef,\n\tisValidElement,\n\tcreateContext,\n\tuseContext,\n\tFragment,\n} from 'react';\nimport { nanoid } from 'nanoid';\nimport { Check } from 'lucide-react';\n\nimport { cn, columnClasses } from '@/utilities/functions';\nimport Switch from '../switch';\nimport {\n\tcolorClassNames,\n\tdisabledClassNames,\n\tsizeClassNames,\n\tsizes,\n\tborderClasses,\n\tbaseClasses,\n\thoverClasses,\n\tfocusClasses,\n} from './styles';\n\nconst RadioButtonContext = createContext();\nconst useRadioButton = () => useContext( RadioButtonContext );\n\nconst RadioButtonGroup = ( {\n\tchildren,\n\tname,\n\tstyle = 'simple',\n\tsize = 'md',\n\tvalue,\n\tdefaultValue,\n\tby = 'id',\n\tas: AsElement = 'div',\n\tonChange,\n\tclassName,\n\tdisableGroup = false,\n\tvertical = false,\n\tcolumns = 4,\n\tmultiSelection = false,\n} ) => {\n\tconst isControlled = useMemo( () => typeof value !== 'undefined', [ value ] );\n\tconst nameAttr = useMemo(\n\t\t() => name || `radio-button-group-${ nanoid() }`,\n\t\t[ name ]\n\t);\n\tlet initialSelectedValue;\n\tif ( isControlled ) {\n\t\tinitialSelectedValue = value;\n\t} else if ( multiSelection ) {\n\t\tinitialSelectedValue = defaultValue ?? [];\n\t} else {\n\t\tinitialSelectedValue = defaultValue;\n\t}\n\n\tconst [ selectedValue, setSelectedValue ] = useState( initialSelectedValue );\n\n\tconst handleChange = useCallback(\n\t\t( newValue ) => {\n\t\t\tif ( multiSelection ) {\n\t\t\t\t// Handles multi-selection logic\n\t\t\t\tsetSelectedValue( ( prevValue ) => {\n\t\t\t\t\tconst isAlreadySelected = prevValue.includes( newValue );\n\t\t\t\t\tconst updatedValue = isAlreadySelected\n\t\t\t\t\t\t? prevValue.filter( ( val ) => val !== newValue )\n\t\t\t\t\t\t: [ ...prevValue, newValue ];\n\n\t\t\t\t\tif ( typeof onChange === 'function' ) {\n\t\t\t\t\t\tonChange( updatedValue );\n\t\t\t\t\t}\n\t\t\t\t\treturn updatedValue;\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t// Handles single selection logic\n\t\t\t\tif ( ! isControlled ) {\n\t\t\t\t\tsetSelectedValue( newValue );\n\t\t\t\t}\n\t\t\t\tif ( typeof onChange !== 'function' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tonChange( newValue );\n\t\t\t}\n\t\t},\n\t\t[ onChange ]\n\t);\n\tclassName = cn(\n\t\t`grid grid-cols-4 gap-2`,\n\t\tcolumnClasses[ columns ],\n\t\tstyle === 'tile' && 'gap-0',\n\t\tvertical && 'grid-cols-1',\n\t\tclassName\n\t);\n\n\tconst groupClassName = cn(\n\t\tstyle === 'tile'\n\t\t\t? 'border border-border-subtle border-solid rounded-md shadow-sm'\n\t\t\t: 'gap-6',\n\t\tclassName\n\t);\n\n\tconst renderRadioButtonContext = () => (\n\t\t\n\t\t\t{ React.Children.map( children, ( child ) => {\n\t\t\t\tif ( ! isValidElement( child ) ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\treturn child;\n\t\t\t} ) }\n\t\t\n\t);\n\n\treturn (\n\t\t<>\n\t\t\t{ style === 'tile' ? (\n\t\t\t\t\n\t\t\t\t\t{ renderRadioButtonContext() }\n\t\t\t\t
\n\t\t\t) : (\n\t\t\t\t\n\t\t\t\t\t{ renderRadioButtonContext() }\n\t\t\t\t\n\t\t\t) }\n\t\t>\n\t);\n};\n\nconst RadioButtonComponent = (\n\t{\n\t\tid,\n\t\tlabel,\n\t\tvalue,\n\t\tchildren,\n\t\tdisabled,\n\t\ticon = null,\n\t\tinlineIcon = false,\n\t\thideSelection = false,\n\t\treversePosition = false,\n\t\tborderOn = false,\n\t\tbadgeItem = null,\n\t\tuseSwitch = false,\n\t\t...props\n\t},\n\tref\n) => {\n\tconst providerValue = useRadioButton();\n\tconst {\n\t\tname,\n\t\tvalue: selectedValue,\n\t\tby,\n\t\tonChange,\n\t\tdisableAll,\n\t\tchecked,\n\t\tmultiSelection,\n\t\tsize,\n\t} = providerValue;\n\n\tconst color = 'primary';\n\tconst radioButtonId = useMemo( () => id || `radio-button-${ nanoid() }`, [ id ] ),\n\t\tisDisabled = useMemo(\n\t\t\t() => disableAll || disabled,\n\t\t\t[ disableAll, disabled ]\n\t\t);\n\tconst checkedValue = useMemo( () => {\n\t\tif ( multiSelection ) {\n\t\t\treturn (\n\t\t\t\tArray.isArray( selectedValue ) && selectedValue.includes( value )\n\t\t\t);\n\t\t}\n\t\tif ( typeof checked !== 'undefined' ) {\n\t\t\treturn checked;\n\t\t}\n\n\t\tif ( typeof selectedValue !== typeof value ) {\n\t\t\treturn false;\n\t\t}\n\t\tif ( typeof selectedValue === 'string' ) {\n\t\t\treturn selectedValue === value;\n\t\t}\n\n\t\tif ( Array.isArray( selectedValue ) ) {\n\t\t\treturn selectedValue.includes( value );\n\t\t}\n\n\t\treturn selectedValue[ by ] === value[ by ];\n\t}, [ selectedValue, value, checked ] );\n\n\tconst renderLabel = useCallback( () => {\n\t\tif ( isValidElement( label ) ) {\n\t\t\treturn label;\n\t\t}\n\n\t\tif ( ! label.heading ) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (\n\t\t\t\n\t\t\t\t{ icon &&
{ icon } }\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t{ label.heading }\n\t\t\t\t\t
\n\t\t\t\t\t{ label.description && (\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{ label.description }\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}, [ label ] );\n\n\tif ( providerValue.style === 'tile' ) {\n\t\treturn (\n\t\t\t\n\t\t\t\t{ children }\n\t\t\t\n\t\t);\n\t}\n\tconst handleLabelClick = () => {\n\t\tif ( ! isDisabled ) {\n\t\t\tif ( multiSelection ) {\n\t\t\t\t// In multi-selection, toggle each individual selection\n\t\t\t\tonChange( value, ! checkedValue ); // Pass the toggled value\n\t\t\t} else {\n\t\t\t\t// In single selection, only one can be selected\n\t\t\t\tonChange( value ); // Trigger onChange with the selected value\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t\n\t);\n};\nconst RadioButton = forwardRef( RadioButtonComponent );\nRadioButton.displayName = 'RadioButton';\n\nconst ButtonGroupItem = ( {\n\tid,\n\tchildren,\n\tvalue,\n\tdisabled,\n\tsize = 'md',\n\t...props\n} ) => {\n\tconst providerValue = useRadioButton();\n\n\tconst {\n\t\tname,\n\t\tvalue: selectedValue,\n\t\tby,\n\t\tonChange,\n\t\tdisableAll,\n\t\tchecked,\n\t} = providerValue || {};\n\n\tconst radioButtonId = useMemo( () => id || `radio-button-${ nanoid() }`, [ id ] );\n\tconst isDisabled = useMemo(\n\t\t() => disableAll || disabled,\n\t\t[ disableAll, disabled ]\n\t);\n\n\tconst checkedValue = useMemo( () => {\n\t\tif ( typeof checked !== 'undefined' ) {\n\t\t\treturn checked;\n\t\t}\n\n\t\tif ( typeof selectedValue !== typeof value ) {\n\t\t\treturn false;\n\t\t}\n\t\tif ( typeof selectedValue === 'string' ) {\n\t\t\treturn selectedValue === value;\n\t\t}\n\n\t\tif ( Array.isArray( selectedValue ) ) {\n\t\t\treturn selectedValue.includes( value );\n\t\t}\n\n\t\treturn selectedValue[ by ] === value[ by ];\n\t}, [ selectedValue, value, checked, by ] );\n\n\tconst handleClick = () => {\n\t\tif ( onChange ) {\n\t\t\tonChange( value );\n\t\t}\n\t};\n\n\tconst disabledClasses = isDisabled\n\t\t? 'text-text-disabled cursor-not-allowed'\n\t\t: '';\n\tconst buttonClassName = cn(\n\t\tbaseClasses,\n\t\thoverClasses,\n\t\tfocusClasses,\n\t\tdisabledClasses,\n\t\tsizes[ size ],\n\t\tborderClasses\n\t);\n\n\treturn (\n\t\t<>\n\t\t\t\n\t\t>\n\t);\n};\n\nexport { RadioButtonGroup, RadioButton };\n","export const colorClassNames = {\n\tprimary: {\n\t\tcheckbox:\n\t\t\t'border-border-strong hover:border-border-interactive checked:border-border-interactive bg-white checked:bg-toggle-on checked:hover:bg-toggle-on-hover checked:hover:border-toggle-on-hover focus:ring-2 focus:ring-offset-4 focus:ring-focus',\n\t\ticon: 'text-white',\n\t},\n};\nexport const disabledClassNames = {\n\tcheckbox:\n\t\t'disabled:bg-white checked:disabled:bg-white disabled:border-border-disabled checked:disabled:border-border-disabled cursor-not-allowed',\n\ticon: 'peer-disabled:text-border-disabled cursor-not-allowed',\n};\n\nexport const sizeClassNames = {\n\tsm: {\n\t\tcheckbox: 'size-4',\n\t\ticon: 'size-1.5',\n\t},\n\tmd: {\n\t\tcheckbox: 'size-5',\n\t\ticon: 'size-2',\n\t},\n};\n\nexport const sizes = {\n\txs: 'py-1 px-1 text-sm gap-0.5 [&>svg]:h-4 [&>svg]:w-4',\n\tsm: 'py-2 px-2 text-base gap-1 [&>svg]:h-4 [&>svg]:w-4',\n\tmd: 'py-2.5 px-2.5 text-base gap-1 [&>svg]:h-5 [&>svg]:w-5',\n};\n\nexport const borderClasses =\n\t'border-0 border-r border-border-subtle border-solid';\n\nexport const baseClasses =\n\t'bg-background-primary text-primary cursor-pointer flex items-center justify-center';\nexport const hoverClasses = 'hover:bg-button-tertiary-hover';\nexport const focusClasses = 'focus:outline-none';\n","export const sizeClassNames = {\n\tsm: {\n\t\ticon: '[&>svg]:size-4',\n\t\tsearchIcon: '[&>svg]:size-4',\n\t\tselectButton:\n\t\t\t'px-2 py-2 rounded text-xs font-medium leading-4 min-h-[2.25rem]',\n\t\tmultiSelect: 'pl-2 pr-2 py-1.5',\n\t\tdisplaySelected: 'text-xs font-normal',\n\t\tdropdown: 'rounded-md',\n\t\tdropdownItemsWrapper: 'p-1.5',\n\t\tsearchbarWrapper: 'p-3 flex items-center gap-0.5',\n\t\tsearchbar: 'font-medium text-xs',\n\t\tsearchbarIcon: '[&>svg]:size-4',\n\t\tlabel: 'text-xs font-medium',\n\t},\n\tmd: {\n\t\ticon: '[&>svg]:size-5',\n\t\tsearchIcon: '[&>svg]:size-5',\n\t\tselectButton:\n\t\t\t'px-2.5 py-2.5 rounded-md text-xs font-medium leading-4 min-h-[2.5rem]',\n\t\tmultiSelect: 'pl-2 pr-2.5 py-2',\n\t\tdisplaySelected: 'text-sm font-normal',\n\t\tdropdown: 'rounded-lg',\n\t\tdropdownItemsWrapper: 'p-2',\n\t\tsearchbarWrapper: 'p-2.5 flex items-center gap-1',\n\t\tsearchbar: 'font-medium text-sm',\n\t\tsearchbarIcon: '[&>svg]:size-5',\n\t\tlabel: 'text-sm font-medium',\n\t},\n\tlg: {\n\t\ticon: '[&>svg]:size-6',\n\t\tsearchIcon: '[&>svg]:size-5',\n\t\tselectButton:\n\t\t\t'px-3 py-3 rounded-lg text-sm font-medium leading-5 min-h-[3rem]',\n\t\tmultiSelect: 'pl-2.5 pr-3 py-2.5',\n\t\tdisplaySelected: 'text-sm font-normal',\n\t\tdropdown: 'rounded-lg',\n\t\tdropdownItemsWrapper: 'p-2',\n\t\tsearchbarWrapper: 'p-2.5 flex items-center gap-1',\n\t\tsearchbar: 'font-medium text-sm',\n\t\tsearchbarIcon: '[&>svg]:size-5',\n\t\tlabel: 'text-base font-medium',\n\t},\n};\n\nexport const disabledClassNames = {\n\tselectButton:\n\t\t'group disabled:border-field-border-disabled [&:hover:has(:disabled)]:border-field-border-disabled',\n\ticon: 'group-disabled:text-icon-disabled',\n\ttext: 'group-disabled:text-field-color-disabled',\n};\n","import {\n\tuseState,\n\tuseCallback,\n\tuseMemo,\n\tuseRef,\n\tcreateContext,\n\tuseContext,\n\tChildren,\n\tcloneElement,\n\tisValidElement,\n\tuseEffect,\n\tuseLayoutEffect,\n} from 'react';\nimport { cn } from '@/utilities/functions';\nimport { CheckIcon, ChevronDown, ChevronsUpDown, Search } from 'lucide-react';\nimport {\n\tuseFloating,\n\tuseClick,\n\tuseDismiss,\n\tuseRole,\n\tuseListNavigation,\n\tuseInteractions,\n\tFloatingFocusManager,\n\tuseTypeahead,\n\toffset,\n\tflip,\n\tsize,\n\tautoUpdate,\n\tFloatingPortal,\n} from '@floating-ui/react';\nimport Badge from '../badge';\nimport { nanoid } from 'nanoid';\nimport { disabledClassNames, sizeClassNames } from './component-style';\n\n// Context to manage the state of the select component.\nconst SelectContext = createContext();\nconst useSelectContext = () => useContext( SelectContext );\n\nfunction SelectButton( {\n\tchildren,\n\ticon = null, // Icon to show in the select button.\n\tplaceholder = 'Select an option', // Placeholder text.\n\toptionIcon = null, // Icon to show in the selected option.\n\tdisplayBy = 'name', // Used to display the value. Default is 'name'.\n\tlabel, // Label for the select component.\n} ) {\n\tconst {\n\t\tsizeValue,\n\t\tgetReferenceProps,\n\t\tgetValues,\n\t\tselectId,\n\t\trefs,\n\t\tisOpen,\n\t\tmultiple,\n\t\tcombobox,\n\t\tsetSelected,\n\t\tonChange,\n\t\tisControlled,\n\t\tdisabled,\n\t\tby,\n\t} = useSelectContext();\n\n\tconst badgeSize = {\n\t\tsm: 'xs',\n\t\tmd: 'sm',\n\t\tlg: 'md',\n\t}?.[ sizeValue ];\n\n\t// Get icon based on the Select component type and user provided icon.\n\tconst getIcon = useCallback( () => {\n\t\tif ( icon ) {\n\t\t\treturn icon;\n\t\t}\n\n\t\tconst iconClassNames =\n\t\t\t'text-field-placeholder ' + disabledClassNames.icon;\n\n\t\treturn combobox ? (\n\t\t\t\n\t\t) : (\n\t\t\t\n\t\t);\n\t}, [ icon ] );\n\n\tconst renderSelected = useCallback( () => {\n\t\tconst selectedValue = getValues();\n\n\t\tif ( ! selectedValue ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( typeof children === 'function' ) {\n\t\t\tconst childProps = {\n\t\t\t\tvalue: selectedValue,\n\t\t\t\t...( multiple ? { onClose: handleOnCloseItem } : {} ),\n\t\t\t};\n\t\t\treturn children( childProps );\n\t\t}\n\n\t\tif ( multiple ) {\n\t\t\treturn selectedValue.map( ( valueItem, index ) => (\n\t\t\t\t\n\t\t\t) );\n\t\t}\n\n\t\tlet renderValue =\n\t\t\ttypeof selectedValue === 'object'\n\t\t\t\t? selectedValue[ displayBy ]\n\t\t\t\t: selectedValue;\n\n\t\tif ( isValidElement( children ) ) {\n\t\t\trenderValue = children;\n\t\t}\n\n\t\treturn (\n\t\t\t\n\t\t\t\t{ renderValue }\n\t\t\t\n\t\t);\n\t}, [ getValues ] );\n\n\tconst handleOnCloseItem = ( value ) => ( event ) => {\n\t\tevent?.preventDefault();\n\t\tevent?.stopPropagation();\n\n\t\tconst selectedValues = [ ...( getValues() ?? [] ) ];\n\t\tconst selectedIndex = selectedValues.findIndex( ( val ) => {\n\t\t\tif ( typeof val === 'object' ) {\n\t\t\t\treturn val[ by ] === value[ by ];\n\t\t\t}\n\t\t\treturn val === value;\n\t\t} );\n\n\t\tif ( selectedIndex === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tselectedValues.splice( selectedIndex, 1 );\n\n\t\tif ( ! isControlled ) {\n\t\t\tsetSelected( selectedValues );\n\t\t}\n\t\tif ( typeof onChange === 'function' ) {\n\t\t\tonChange( selectedValues );\n\t\t}\n\t};\n\n\treturn (\n\t\t\n\t\t\t
\n\t\t\t\t{ label }\n\t\t\t\n\t\t\t
\n\t\t
\n\t);\n}\n\nfunction SelectOptions( {\n\tchildren,\n\tsearchBy = 'id', // Used to identify searched value using the key. Default is 'id'.\n\tsearchPlaceholder = 'Search...', // Placeholder text for search box.\n\tdropdownPortalRoot = null, // Root element where the dropdown will be rendered.\n\tdropdownPortalId = '', // Id of the dropdown portal where the dropdown will be rendered.\n} ) {\n\tconst {\n\t\tisOpen,\n\t\tcontext,\n\t\trefs,\n\t\tcombobox,\n\t\tfloatingStyles,\n\t\tgetFloatingProps,\n\t\tsizeValue,\n\t\tsetSearchKeyword,\n\t\tsetActiveIndex,\n\t\tsetSelectedIndex,\n\t\tvalue,\n\t\tselected,\n\t\tgetValues,\n\t\tsearchKeyword,\n\t\tlistContentRef,\n\t\tby,\n\t} = useSelectContext();\n\n\tconst initialSelectedValueIndex = useMemo( () => {\n\t\tconst currentValue = getValues();\n\t\tlet indexValue = 0;\n\n\t\tif ( currentValue ) {\n\t\t\tindexValue = Children.toArray( children ).findIndex( ( child ) => {\n\t\t\t\tif ( typeof child.props.value === 'object' ) {\n\t\t\t\t\treturn child.props.value[ by ] === currentValue[ by ];\n\t\t\t\t}\n\t\t\t\treturn child.props.value === currentValue;\n\t\t\t} );\n\t\t}\n\n\t\treturn indexValue === -1 ? 0 : indexValue;\n\t}, [ value, selected, children ] );\n\n\tuseLayoutEffect( () => {\n\t\tsetActiveIndex( initialSelectedValueIndex );\n\t\tsetSelectedIndex( initialSelectedValueIndex );\n\t}, [] );\n\n\t// Render children based on the search keyword.\n\tconst renderChildren = useMemo( () => {\n\t\treturn Children.map( children, ( child, index ) => {\n\t\t\tif ( ! isValidElement( child ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif ( searchKeyword ) {\n\t\t\t\tconst valueProp = child.props.value;\n\t\t\t\tif ( typeof valueProp === 'object' ) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tvalueProp[ searchBy ]\n\t\t\t\t\t\t\t.toLowerCase()\n\t\t\t\t\t\t\t.indexOf( searchKeyword.toLowerCase() ) === -1\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t} else if (\n\t\t\t\t\tvalueProp\n\t\t\t\t\t\t.toLowerCase()\n\t\t\t\t\t\t.indexOf( searchKeyword.toLowerCase() ) === -1\n\t\t\t\t) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn cloneElement( child, {\n\t\t\t\t...child.props,\n\t\t\t\tindex,\n\t\t\t} );\n\t\t} );\n\t}, [ searchKeyword, value, selected, children ] );\n\tconst childrenCount = Children.count( renderChildren );\n\n\t// Update the content list reference.\n\tuseEffect( () => {\n\t\tlistContentRef.current = [];\n\t\tChildren.forEach( children, ( child ) => {\n\t\t\tif ( ! isValidElement( child ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( child.props.value ) {\n\t\t\t\tif ( searchKeyword ) {\n\t\t\t\t\tconst valueProp = child.props.value;\n\t\t\t\t\tif ( typeof valueProp === 'object' ) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tvalueProp[ searchBy ]\n\t\t\t\t\t\t\t\t.toLowerCase()\n\t\t\t\t\t\t\t\t.indexOf( searchKeyword.toLowerCase() ) === -1\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tvalueProp\n\t\t\t\t\t\t\t.toLowerCase()\n\t\t\t\t\t\t\t.indexOf( searchKeyword.toLowerCase() ) === -1\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlistContentRef.current.push( child.props.value );\n\t\t\t}\n\t\t} );\n\t}, [ searchKeyword ] );\n\n\treturn (\n\t\t<>\n\t\t\t{ /* Dropdown */ }\n\t\t\t{ isOpen && (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{ /* Dropdown Wrapper */ }\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{ /* Searchbox */ }\n\t\t\t\t\t\t\t{ combobox && (\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\n\t\t\t\t\t\t\t\t\t\t\tsetSearchKeyword( event.target.value )\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"off\"\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\t{ /* Dropdown Items Wrapper */ }\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t{ /* Dropdown Items */ }\n\t\t\t\t\t\t\t\t{ !! childrenCount && renderChildren }\n\n\t\t\t\t\t\t\t\t{ /* No items found */ }\n\t\t\t\t\t\t\t\t{ ! childrenCount && (\n\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\tNo items found\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\n\t\t\t\t\n\t\t\t) }\n\t\t>\n\t);\n}\n\nfunction SelectItem( { value, selected, children, ...props } ) {\n\tconst {\n\t\tsizeValue,\n\t\tgetItemProps,\n\t\tonKeyDownItem,\n\t\tonClickItem,\n\t\tactiveIndex,\n\t\tselectedIndex,\n\t\tupdateListRef,\n\t\tgetValues,\n\t\tby,\n\t\tmultiple,\n\t} = useSelectContext();\n\tconst { index: indx } = props;\n\n\tconst selectItemClassNames = {\n\t\tsm: 'py-1.5 px-2 text-sm font-normal',\n\t\tmd: 'p-2 text-base font-normal',\n\t\tlg: 'p-2 text-base font-normal',\n\t};\n\tconst selectedIconClassName = {\n\t\tsm: 'size-4',\n\t\tmd: 'size-5',\n\t\tlg: 'size-5',\n\t};\n\n\tconst multipleChecked = useMemo( () => {\n\t\tif ( ! multiple ) {\n\t\t\treturn false;\n\t\t}\n\t\tconst currentValue = getValues();\n\t\tif ( ! currentValue ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn currentValue.some( ( val ) => {\n\t\t\tif ( typeof val === 'object' ) {\n\t\t\t\treturn val[ by ] === value[ by ];\n\t\t\t}\n\t\t\treturn val === value;\n\t\t} );\n\t}, [ value, getValues ] );\n\n\tconst isChecked = useMemo( () => {\n\t\tif ( typeof selected === 'boolean' ) {\n\t\t\treturn selected;\n\t\t}\n\n\t\tif ( multiple ) {\n\t\t\treturn multipleChecked;\n\t\t}\n\n\t\treturn indx === selectedIndex;\n\t}, [ multipleChecked, selectedIndex, selected ] );\n\n\treturn (\n\t\t {\n\t\t\t\tupdateListRef( indx, node );\n\t\t\t} }\n\t\t\trole=\"option\"\n\t\t\ttabIndex={ indx === activeIndex ? 0 : -1 }\n\t\t\taria-selected={ isChecked && indx === activeIndex }\n\t\t\t{ ...getItemProps( {\n\t\t\t\t// Handle pointer select.\n\t\t\t\tonClick() {\n\t\t\t\t\tonClickItem( indx, value );\n\t\t\t\t},\n\t\t\t\t// Handle keyboard select.\n\t\t\t\tonKeyDown( event ) {\n\t\t\t\t\tonKeyDownItem( event, indx, value );\n\t\t\t\t},\n\t\t\t} ) }\n\t\t>\n\t\t\t{ children }\n\t\t\t{ isChecked && (\n\t\t\t\t\n\t\t\t) }\n\t\t
\n\t);\n}\n\nconst Select = ( {\n\tid,\n\tsize: sizeValue = 'md', // sm, md, lg\n\tvalue, // Value of the select (for controlled component).\n\tdefaultValue, // Default value of the select (for uncontrolled component).\n\tonChange, // Callback function to handle the change event.\n\tby = 'id', // Used to identify the select component. Default is 'id'.\n\tchildren,\n\tmultiple = false, // If true, it will allow multiple selection.\n\tcombobox = false, // If true, it will show a search box.\n\tdisabled = false, // If true, it will disable the select component.\n} ) => {\n\tconst selectId = useMemo( () => id || `select-${ nanoid() }`, [ id ] );\n\tconst isControlled = useMemo( () => typeof value !== 'undefined', [ value ] );\n\tconst [ selected, setSelected ] = useState( defaultValue );\n\tconst [ searchKeyword, setSearchKeyword ] = useState( '' );\n\n\tconst getValues = useCallback( () => {\n\t\tif ( isControlled ) {\n\t\t\treturn value;\n\t\t}\n\t\treturn selected;\n\t}, [ isControlled, value, selected ] );\n\n\t// Dropdown position related code (Start)\n\tconst [ isOpen, setIsOpen ] = useState( false );\n\tconst [ activeIndex, setActiveIndex ] = useState();\n\tconst [ selectedIndex, setSelectedIndex ] = useState();\n\n\tconst dropdownMaxHeightBySize = {\n\t\tsm: combobox ? 256 : 172,\n\t\tmd: combobox ? 256 : 216,\n\t\tlg: combobox ? 256 : 216,\n\t};\n\n\tconst { refs, floatingStyles, context } = useFloating( {\n\t\tplacement: 'bottom-start',\n\t\topen: isOpen,\n\t\tonOpenChange: setIsOpen,\n\t\twhileElementsMounted: autoUpdate,\n\t\tmiddleware: [\n\t\t\toffset( 5 ),\n\t\t\tflip( { padding: 10 } ),\n\t\t\tsize( {\n\t\t\t\tapply( { rects, elements, availableHeight } ) {\n\t\t\t\t\tObject.assign( elements.floating.style, {\n\t\t\t\t\t\tmaxHeight: `min(${ availableHeight }px, ${ dropdownMaxHeightBySize[ sizeValue ] }px)`,\n\t\t\t\t\t\tmaxWidth: `${ rects.reference.width }px`,\n\t\t\t\t\t} );\n\t\t\t\t},\n\t\t\t\tpadding: 10,\n\t\t\t} ),\n\t\t],\n\t} );\n\n\tconst listRef = useRef( [] );\n\tconst listContentRef = useRef( [] );\n\tconst isTypingRef = useRef( false );\n\n\tconst click = useClick( context, { event: 'mousedown' } );\n\tconst dismiss = useDismiss( context );\n\tconst role = useRole( context, { role: 'listbox' } );\n\tconst listNav = useListNavigation( context, {\n\t\tlistRef,\n\t\tactiveIndex,\n\t\tselectedIndex,\n\t\tonNavigate: setActiveIndex,\n\t\t// This is a large list, allow looping.\n\t\tloop: true,\n\t} );\n\tconst typeahead = useTypeahead( context, {\n\t\tlistRef: listContentRef,\n\t\tactiveIndex,\n\t\tselectedIndex,\n\t\tonMatch: isOpen ? setActiveIndex : setSelectedIndex,\n\t\tonTypingChange( isTyping ) {\n\t\t\tisTypingRef.current = isTyping;\n\t\t},\n\t} );\n\n\tconst { getReferenceProps, getFloatingProps, getItemProps } =\n\t\tuseInteractions( [\n\t\t\tdismiss,\n\t\t\trole,\n\t\t\tlistNav,\n\t\t\tclick,\n\t\t\t...( ! combobox ? [ typeahead ] : [] ),\n\t\t] );\n\n\tconst handleMultiSelect = ( index, newValue ) => {\n\t\tconst selectedValues = [ ...( getValues() ?? [] ) ];\n\t\tconst valueIndex = selectedValues.findIndex( ( selectedValue ) => {\n\t\t\tif ( typeof selectedValue === 'object' ) {\n\t\t\t\treturn selectedValue[ by ] === newValue[ by ];\n\t\t\t}\n\t\t\treturn selectedValue === newValue;\n\t\t} );\n\n\t\tif ( valueIndex !== -1 ) {\n\t\t\treturn;\n\t\t}\n\t\tselectedValues.push( newValue );\n\n\t\tif ( ! isControlled ) {\n\t\t\tsetSelected( selectedValues );\n\t\t}\n\t\tsetSelectedIndex( index );\n\t\trefs.reference.current.focus();\n\t\tsetIsOpen( false );\n\t\tsetSearchKeyword( '' );\n\t\tif ( typeof onChange === 'function' ) {\n\t\t\tonChange( selectedValues );\n\t\t}\n\t};\n\n\tconst handleSelect = ( index, newValue ) => {\n\t\tif ( multiple ) {\n\t\t\treturn handleMultiSelect( index, newValue );\n\t\t}\n\t\tsetSelectedIndex( index );\n\t\tif ( ! isControlled ) {\n\t\t\tsetSelected( newValue );\n\t\t}\n\t\trefs.reference.current.focus();\n\t\tsetIsOpen( false );\n\t\tsetSearchKeyword( '' );\n\t\tif ( typeof onChange === 'function' ) {\n\t\t\tonChange( newValue );\n\t\t}\n\t};\n\t// Dropdown position related code (End)\n\n\tconst updateListRef = useCallback( ( index, node ) => {\n\t\tlistRef.current[ index ] = node;\n\t}, [] );\n\n\tconst onClickItem = ( index, newValue ) => {\n\t\thandleSelect( index, newValue );\n\t};\n\n\tconst onKeyDownItem = ( event, index, newValue ) => {\n\t\tif ( event.key === 'Enter' ) {\n\t\t\tevent.preventDefault();\n\t\t\thandleSelect( index, newValue );\n\t\t}\n\n\t\tif ( event.key === ' ' && ! isTypingRef.current ) {\n\t\t\tevent.preventDefault();\n\t\t\thandleSelect( index, newValue );\n\t\t}\n\t};\n\n\treturn (\n\t\t\n\t\t\t{ children }\n\t\t\n\t);\n};\n\nSelect.Button = SelectButton;\nSelect.Options = SelectOptions;\nSelect.Option = SelectItem;\n\nexport default Select;\n","import React, {\n\tcreateContext,\n\tuseContext,\n\tuseState,\n\tuseRef,\n\tuseEffect,\n} from 'react';\nimport { cn } from '@/utilities/functions';\nimport { PanelLeftClose, PanelLeftOpen } from 'lucide-react';\nimport Tooltip from '../tooltip';\nconst SidebarContext = createContext();\n\nconst Sidebar = ( {\n\tchildren,\n\tclassName,\n\tonCollapseChange,\n\tcollapsible = true,\n\tscreenHeight = true,\n\tborderOn = true,\n\t...props\n} ) => {\n\tconst sideBarRef = useRef( null );\n\tconst [ isCollapsed, setIsCollapsed ] = useState( () => {\n\t\tconst storedState = localStorage.getItem( 'sidebar-collapsed' );\n\t\tconst isSmallScreen = window.innerWidth < 1280;\n\t\tif ( storedState ) {\n\t\t\treturn JSON.parse( storedState );\n\t\t}\n\t\treturn isSmallScreen;\n\t} );\n\n\tuseEffect( () => {\n\t\tif ( onCollapseChange ) {\n\t\t\tonCollapseChange( isCollapsed );\n\t\t}\n\t}, [ isCollapsed, onCollapseChange ] );\n\n\tuseEffect( () => {\n\t\tconst handleScreenResize = () => {\n\t\t\tconst isSmallScreen = window.innerWidth < 1280;\n\t\t\tif (!collapsible) {\n\t\t\t\tsetIsCollapsed(false);\n\t\t\t\tlocalStorage.removeItem('sidebar-collapsed');\n\t\t\t} else {\n\t\t\t\tif (isSmallScreen) {\n\t\t\t\t\tsetIsCollapsed(true);\n\t\t\t\t\tlocalStorage.setItem(\n\t\t\t\t\t\t'sidebar-collapsed',\n\t\t\t\t\t\tJSON.stringify(true)\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconst storedState =\n\t\t\t\t\t\tlocalStorage.getItem('sidebar-collapsed');\n\t\t\t\t\tsetIsCollapsed(\n\t\t\t\t\t\tstoredState ? JSON.parse(storedState) : false\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( sideBarRef.current ) {\n\t\t\t\tif ( !! screenHeight ) {\n\t\t\t\t\tsideBarRef.current.style.height = `${ window.innerHeight }px`;\n\t\t\t\t} else {\n\t\t\t\t\tsideBarRef.current.style.height = 'auto';\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\twindow.addEventListener( 'resize', handleScreenResize );\n\t\thandleScreenResize();\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener( 'resize', handleScreenResize );\n\t\t};\n\t}, [ screenHeight, collapsible ] );\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t{ children }\n\t\t\t
\n\t\t\n\t);\n};\nSidebar.displayName = 'Sidebar';\n\nconst SidebarHeader = ( { children } ) => {\n\treturn { children }
;\n};\nSidebarHeader.displayName = 'Sidebar.Header';\n\nconst SidebarBody = ( { children } ) => {\n\treturn { children }
;\n};\nSidebarBody.displayName = 'Sidebar.Body';\n\nconst SidebarFooter = ( { children } ) => {\n\tconst { isCollapsed, setIsCollapsed, collapsible } =\n\t\tuseContext( SidebarContext );\n\treturn (\n\t\t\n\t\t\t{ children }\n\t\t\t{ collapsible && (\n\t\t\t\t
\n\t\t\t) }\n\t\t
\n\t);\n};\nSidebarFooter.displayName = 'Sidebar.Footer';\n\nconst SidebarItem = ( { children, className } ) => {\n\treturn { children }
;\n};\nSidebarItem.displayName = 'Sidebar.Item';\n\nexport default Object.assign( Sidebar, {\n\tHeader: SidebarHeader,\n\tBody: SidebarBody,\n\tFooter: SidebarFooter,\n\tItem: SidebarItem,\n} );\n","import React from 'react';\nimport { cn } from '@/utilities/functions';\n\nconst Skeleton = ( {\n\tvariant = 'rectangular', // rectangular, circular\n\tclassName,\n\t...props\n} ) => {\n\tconst variantClasses = {\n\t\tcircular: 'rounded-full bg-gray-200 ',\n\t\trectangular: 'rounded-md bg-gray-200',\n\t}?.[ variant ];\n\n\tconst defaultWidth = {\n\t\tcircular: 'size-10',\n\t\trectangular: 'w-96 h-3',\n\t}?.[ variant ];\n\n\treturn (\n\t\t\n\t);\n};\n\nexport default Skeleton;\n","import {\n\tuseState,\n\tuseMemo,\n\tuseCallback,\n\tforwardRef,\n\tisValidElement,\n} from 'react';\nimport { nanoid } from 'nanoid';\nimport { cn } from '@/utilities/functions';\n\nconst SwitchLabel = ( { label, switchId, disabled = false, children } ) => {\n\tconst isLabelAComponent = isValidElement( label );\n\tif ( isLabelAComponent ) {\n\t\treturn (\n\t\t\t\n\t\t\t\t{ children }\n\t\t\t\t{ label }\n\t\t\t
\n\t\t);\n\t}\n\tconst renderLabel = () => {\n\t\tconst { heading = '', description = '' } = label || {};\n\t\treturn (\n\t\t\t\n\t\t\t\t{ heading && (\n\t\t\t\t\t
\n\t\t\t\t\t\t{ heading }\n\t\t\t\t\t
\n\t\t\t\t) }\n\t\t\t\t{ description && (\n\t\t\t\t\t
\n\t\t\t\t\t\t{ description }\n\t\t\t\t\t
\n\t\t\t\t) }\n\t\t\t
\n\t\t);\n\t};\n\n\tconst isEmptyLabel = ! label?.heading && ! label?.description;\n\tconst alignmentClass =\n\t\t! label?.heading || ! label?.description ? 'items-center' : 'items-start';\n\n\tif ( isEmptyLabel ) {\n\t\treturn children;\n\t}\n\n\treturn (\n\t\t\n\t\t\t{ children }\n\t\t\t\n\t\t\t\t{ renderLabel() }\n\t\t\t\n\t\t
\n\t);\n};\n\nconst SwitchComponent = (\n\t{\n\t\tid,\n\t\tonChange,\n\t\tvalue,\n\t\tdefaultValue = false,\n\t\tsize = 'lg',\n\t\tdisabled = false,\n\t\tlabel = { heading: '', description: '' },\n\t\tname,\n\t\tclassName,\n\t\t...props\n\t},\n\tref\n) => {\n\tconst isControlled = useMemo( () => typeof value !== 'undefined', [ value ] );\n\tconst switchId = useMemo( () => ( id ? id : `switch-${ nanoid() }` ), [] );\n\tconst [ checked, setChecked ] = useState( defaultValue );\n\tconst color = 'primary';\n\n\tconst getValue = useCallback(\n\t\t() => ( isControlled ? value : checked ),\n\t\t[ isControlled, value, checked ]\n\t);\n\n\tconst handleChange = ( event ) => {\n\t\tif ( disabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newValue = event.target.checked;\n\t\tif ( ! isControlled ) {\n\t\t\tsetChecked( newValue );\n\t\t}\n\n\t\tif ( typeof onChange !== 'function' ) {\n\t\t\treturn;\n\t\t}\n\t\tonChange( newValue );\n\t};\n\n\tconst colorClassNames = {\n\t\tprimary: {\n\t\t\tinput: 'bg-toggle-off hover:bg-toggle-off-hover checked:bg-toggle-on checked:hover:bg-toggle-on-hover focus:ring focus:ring-toggle-on focus:ring-offset-4 border border-solid border-toggle-off-border checked:border-toggle-on-border shadow-toggleContainer focus:outline-none checked:focus:border-toggle-on-border focus:border-toggle-off-border',\n\t\t\ttoggleDial: 'bg-toggle-dial-background shadow-toggleDial',\n\t\t},\n\t};\n\n\tconst sizeClassNames = {\n\t\tlg: {\n\t\t\tcontainer: 'w-11 h-6',\n\t\t\ttoggleDial:\n\t\t\t\t'size-4 top-2/4 left-1 -translate-y-2/4 peer-checked:translate-x-5 before:w-10 before:h-10 before:rounded-full before:absolute before:top-2/4 before:left-2/4 before:-translate-y-2/4 before:-translate-x-2/4',\n\t\t},\n\t\tsm: {\n\t\t\tcontainer: 'w-9 h-5',\n\t\t\ttoggleDial:\n\t\t\t\t'size-3 top-2/4 left-1 -translate-y-2/4 peer-checked:translate-x-4 before:w-10 before:h-10 before:rounded-full before:absolute before:top-2/4 before:left-2/4 before:-translate-y-2/4 before:-translate-x-2/4',\n\t\t},\n\t};\n\n\tconst disabledClassNames = {\n\t\tinput: 'bg-toggle-off-disabled disabled:border-transparent shadow-none disabled:cursor-not-allowed',\n\t\ttoggleDial: 'peer-disabled:cursor-not-allowed',\n\t};\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\t\t\n\t);\n};\nconst Switch = forwardRef( SwitchComponent );\nSwitch.displayName = 'Switch';\n\nexport default Switch;\n","import React, {\n\tuseCallback,\n\tforwardRef,\n\tisValidElement,\n\tcreateContext,\n\tuseContext,\n} from 'react';\nimport { cn } from '@/utilities/functions';\nimport { motion } from 'framer-motion';\n\n// Context for managing the TabsGroup state.\nconst TabsGroupContext = createContext();\n\n// Hook to use the TabsGroup context.\nconst useTabsGroup = () => useContext( TabsGroupContext );\n\n// TabsGroup component to wrap Tab components.\nconst TabsGroup = ( props ) => {\n\tconst {\n\t\tchildren,\n\t\tactiveItem = null, // The currently active item in the group.\n\t\tonChange, // Callback when the active item changes.\n\t\tclassName, // Additional class names for styling.\n\t\tsize = 'sm', // Size of the tabs in the group ('xs', 'sm', 'md', 'lg').\n\t\torientation = 'horizontal', // Orientation of the tabs ('horizontal', 'vertical').\n\t\tvariant = 'pill', // Style variant of the tabs ('pill', 'rounded', 'underline').\n\t\ticonPosition = 'left', // Position of the icon in the tab ('left' or 'right').\n\t\twidth = 'full', // Width of the tabs ('auto' or 'full').\n\t} = props;\n\n\t// Handle change event.\n\tconst handleChange = useCallback(\n\t\t( event, value ) => {\n\t\t\tif ( onChange ) {\n\t\t\t\tonChange( { event, value } );\n\t\t\t}\n\t\t},\n\t\t[ onChange ]\n\t);\n\n\t// Determine styles based on the variant and orientation.\n\tlet borderRadius = 'rounded-full',\n\t\tpadding = 'p-1',\n\t\tgap,\n\t\tborder = 'border border-tab-border border-solid';\n\n\tif ( orientation === 'vertical' ) {\n\t\tgap = 'gap-0.5';\n\t} else if ( variant === 'rounded' || variant === 'pill' ) {\n\t\tif ( size === 'xs' || size === 'sm' ) {\n\t\t\tgap = 'gap-0.5';\n\t\t} else if ( size === 'md' || size === 'lg' ) {\n\t\t\tgap = 'gap-1';\n\t\t}\n\t}\n\n\tif ( variant === 'rounded' || orientation === 'vertical' ) {\n\t\tborderRadius = 'rounded-md';\n\t} else if ( variant === 'underline' ) {\n\t\tborderRadius = 'rounded-none';\n\t\tpadding = 'p-0';\n\t\tborder =\n\t\t\t'border-t-0 border-r-0 border-l-0 border-b border-solid border-tab-border';\n\t\tif ( size === 'xs' ) {\n\t\t\tgap = 'gap-0';\n\t\t} else if ( size === 'sm' ) {\n\t\t\tgap = 'gap-2.5';\n\t\t} else if ( size === 'md' || size === 'lg' ) {\n\t\t\tgap = 'gap-3';\n\t\t}\n\t}\n\n\t// Determine width classes.\n\tconst widthClasses = width === 'full' ? 'w-full' : '';\n\t// Determine orientation classes.\n\tconst orientationClasses = orientation === 'vertical' ? 'flex-col' : '';\n\n\t// Base classes for the TabsGroup.\n\tconst baseClasses = `box-border [&>*]:box-border flex items-center ${ widthClasses } ${ orientationClasses }`;\n\n\t// Container background color.\n\tconst backgroundColorClass =\n\t\tvariant !== 'underline' ? 'bg-tab-background' : '';\n\n\t// Merge classes.\n\tconst groupClassName = cn(\n\t\tbaseClasses,\n\t\tborderRadius,\n\t\tpadding,\n\t\tgap,\n\t\tborder,\n\t\tbackgroundColorClass,\n\t\tclassName\n\t);\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t{ React.Children.map( children, ( child ) => {\n\t\t\t\t\tif ( ! isValidElement( child ) ) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\treturn React.cloneElement( child );\n\t\t\t\t} ) }\n\t\t\t\n\t\t
\n\t);\n};\n\n// Tab component to be used within a TabsGroup.\nconst TabComponent = ( props, ref ) => {\n\tconst providerValue = useTabsGroup();\n\tconst {\n\t\tslug,\n\t\ttext,\n\t\ticon,\n\t\tclassName,\n\t\tdisabled = false,\n\t\tbadge = null,\n\t\t...rest\n\t} = props;\n\n\tif ( ! providerValue ) {\n\t\tthrow new Error( 'Tab should be used inside Tabs Group' );\n\t}\n\n\tconst {\n\t\tactiveItem,\n\t\tonChange,\n\t\tsize,\n\t\tvariant,\n\t\torientation,\n\t\ticonPosition,\n\t\twidth,\n\t} = providerValue;\n\n\t// Determine size classes.\n\tconst sizes = {\n\t\txs: 'px-1.5 py-0.5 text-xs [&_svg]:size-3',\n\t\tsm:\n\t\t\tvariant === 'underline'\n\t\t\t\t? 'py-1.5 text-sm [&_svg]:size-4'\n\t\t\t\t: 'px-3 py-1.5 text-sm [&_svg]:size-4',\n\t\tmd:\n\t\t\tvariant === 'underline'\n\t\t\t\t? 'py-2 text-base [&_svg]:size-5'\n\t\t\t\t: 'px-3.5 py-1.5 text-base [&_svg]:size-5',\n\t\tlg:\n\t\t\tvariant === 'underline'\n\t\t\t\t? 'p-2.5 text-lg [&_svg]:size-6'\n\t\t\t\t: 'px-3.5 py-1.5 text-lg [&_svg]:size-6',\n\t}[ size ];\n\n\t// Determine width and orientation classes for tabs.\n\tconst fullWidth = width === 'full' ? 'flex-1' : '';\n\tconst orientationClasses =\n\t\torientation === 'vertical' ? 'w-full justify-between' : '';\n\n\t// Base classes for the Tab.\n\tconst baseClasses = cn(\n\t\t'relative border-none bg-transparent text-text-secondary cursor-pointer flex items-center justify-center transition-[box-shadow,color,background-color] duration-200',\n\t\tfullWidth,\n\t\torientationClasses\n\t);\n\n\tconst borderClasses = 'border-none';\n\n\tlet variantClasses = 'rounded-full';\n\tif ( variant === 'rounded' ) {\n\t\tvariantClasses = 'rounded-md';\n\t} else if ( variant === 'underline' ) {\n\t\tvariantClasses = 'rounded-none';\n\t}\n\n\t// Additional classes.\n\tconst hoverClasses = 'hover:text-text-primary group';\n\tconst focusClasses = 'focus:outline-none';\n\tconst disabledClasses = disabled\n\t\t? 'text-text-disabled cursor-not-allowed'\n\t\t: '';\n\tconst activeClasses =\n\t\tactiveItem === slug\n\t\t\t? 'bg-background-primary text-text-primary shadow-sm'\n\t\t\t: '';\n\n\t// Merge classes.\n\tconst tabClassName = cn(\n\t\tbaseClasses,\n\t\tborderClasses,\n\t\tvariantClasses,\n\t\thoverClasses,\n\t\tfocusClasses,\n\t\tdisabledClasses,\n\t\tsizes,\n\t\tactiveClasses,\n\t\tclassName\n\t);\n\n\tconst iconParentClasses = 'flex items-center gap-1';\n\n\t// Handle click event.\n\tconst handleClick = ( event ) => {\n\t\tonChange( event, { slug, text } );\n\t};\n\n\treturn (\n\t\t\n\t);\n};\nconst Tab = forwardRef( TabComponent );\nTab.displayName = 'Tab';\n\nconst exports = {\n\tGroup: TabsGroup,\n\tTab,\n};\n\nexport default exports;\n","import { useState, useCallback, useMemo, forwardRef } from 'react';\nimport { nanoid } from 'nanoid';\nimport { cn } from '@/utilities/functions';\n\nconst TextAreaComponent = (\n\t{\n\t\tid,\n\t\tdefaultValue = '',\n\t\tvalue,\n\t\tsize = 'sm', // sm, md, lg\n\t\tclassName = '',\n\t\tdisabled = false,\n\t\tonChange = () => {},\n\t\terror = false,\n\t\tonError = () => {},\n\t\t...props\n\t},\n\tref\n) => {\n\tconst inputId = useMemo( () => id || `input-textarea-${ nanoid() }`, [ id ] );\n\tconst isControlled = useMemo( () => typeof value !== 'undefined', [ value ] );\n\tconst [ inputValue, setInputValue ] = useState( defaultValue );\n\n\tconst getValue = useCallback(\n\t\t() => ( isControlled ? value : inputValue ),\n\t\t[ isControlled, value, inputValue ]\n\t);\n\n\tconst handleChange = ( event ) => {\n\t\tif ( disabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newValue = event.target.value;\n\t\tif ( ! isControlled ) {\n\t\t\tsetInputValue( newValue );\n\t\t}\n\n\t\tif ( typeof onChange !== 'function' ) {\n\t\t\treturn;\n\t\t}\n\t\tonChange( newValue );\n\t};\n\n\tconst baseClasses =\n\t\t'py-2 rounded border border-solid border-border-subtle bg-field-secondary-background font-normal placeholder-text-tertiary text-text-primary';\n\tconst sizeClasses = {\n\t\tsm: 'px-3 rounded text-xs',\n\t\tmd: 'px-3 rounded-md text-sm',\n\t\tlg: 'px-4 rounded-lg text-base',\n\t};\n\n\tconst hoverClasses = disabled\n\t\t? 'hover:border-border-disabled'\n\t\t: 'hover:border-border-strong';\n\tconst focusClasses =\n\t\t'focus:border-focus-border focus:ring-2 focus:ring-toggle-on focus:ring-offset-2';\n\tconst errorClasses = error\n\t\t? 'focus:border-focus-error-border focus:ring-field-color-error bg-field-background-error'\n\t\t: '';\n\tconst disabledClasses = disabled\n\t\t? 'border-border-disabled bg-field-background-disabled cursor-not-allowed text-text-disabled'\n\t\t: '';\n\n\treturn (\n\t\t\n\t);\n};\nconst TextArea = forwardRef( TextAreaComponent );\nTextArea.displayName = 'TextArea';\n\nexport default TextArea;\n","import { cn } from '@/utilities/functions';\n\n/**\n * Title component.\n */\n\nconst Title = ( {\n\ttitle = null,\n\tdescription = null,\n\ticon = null,\n\ticonPosition = 'right', // left, right\n\ttag = 'h2', // h1, h2, h3, h4, h5, h6\n\tsize = 'sm', // xs, sm, md, lg\n\tclassName = '',\n} ) => {\n\t// Base classes. - Mandatory classes.\n\tconst iconGap = {\n\t\txs: 'gap-1 [&>svg]:size-3.5',\n\t\tsm: 'gap-1 [&>svg]:size-4',\n\t\tmd: 'gap-1.5 [&>svg]:size-5',\n\t\tlg: 'gap-1.5 [&>svg]:size-5',\n\t};\n\n\tif ( ! title ) {\n\t\treturn null;\n\t}\n\n\tconst getTitle = () => {\n\t\tconst Tag = tag;\n\t\tconst titleCommonClasses = 'font-semibold p-0 m-0';\n\t\t// Size classes - Based on the size prop.\n\t\tconst sizeClasses = {\n\t\t\txs: 'text-base [&>*]:text-base gap-1',\n\t\t\tsm: 'text-lg [&>*]:text-lg gap-1',\n\t\t\tmd: 'text-xl [&>*]:text-xl gap-1.5',\n\t\t\tlg: 'text-2xl [&>*]:text-2xl gap-1.5',\n\t\t};\n\t\treturn (\n\t\t\t\n\t\t\t\t{ title }\n\t\t\t\n\t\t);\n\t};\n\n\tconst getDescription = () => {\n\t\tconst descriptionClasses = {\n\t\t\txs: 'text-base',\n\t\t\tsm: 'text-lg',\n\t\t\tmd: 'text-xl',\n\t\t\tlg: 'text-2xl',\n\t\t};\n\t\treturn (\n\t\t\t\n\t\t\t\t{ description }\n\t\t\t\n\t\t);\n\t};\n\n\tif ( description ) {\n\t\treturn (\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{ icon && iconPosition === 'left' && (\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{ icon }\n\t\t\t\t\t\t\t{ getTitle() }\n\t\t\t\t\t\t
\n\t\t\t\t\t) }\n\t\t\t\t\t{ icon && iconPosition === 'right' && (\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{ getTitle() }\n\t\t\t\t\t\t\t{ icon }\n\t\t\t\t\t\t
\n\t\t\t\t\t) }\n\t\t\t\t\t{ ! icon && getTitle() }\n\t\t\t\t
\n\t\t\t\t{ getDescription() }\n\t\t\t
\n\t\t);\n\t}\n\n\treturn (\n\t\t\n\t\t\t{ icon && iconPosition === 'left' && (\n\t\t\t\t
\n\t\t\t\t\t{ icon }\n\t\t\t\t\t{ getTitle() }\n\t\t\t\t
\n\t\t\t) }\n\t\t\t{ icon && iconPosition === 'right' && (\n\t\t\t\t
\n\t\t\t\t\t{ getTitle() }\n\t\t\t\t\t{ icon }\n\t\t\t\t
\n\t\t\t) }\n\t\t\t{ ! icon && getTitle() }\n\t\t
\n\t);\n};\n\nexport default Title;\n","// Available positions: top-left, top-right, bottom-left, bottom-right\nexport const positionClassNames = {\n\t'top-left': 'top-0 bottom-0 left-0 justify-start items-start',\n\t'top-right': 'top-0 bottom-0 right-0 justify-start items-end',\n\t'bottom-left': 'top-0 bottom-0 left-0 justify-end items-start',\n\t'bottom-right': 'top-0 bottom-0 right-0 justify-end items-end',\n};\n\nexport const containerVariantClassNames = {\n\tstack: 'w-[22.5rem]',\n\tinline: 'lg:w-[47.5rem] w-full',\n};\n\n// Variant classes - Based on the variant prop.\nexport const variantClassNames = {\n\tlight: {\n\t\tneutral: 'border-alert-border-neutral bg-alert-background-neutral',\n\t\tcustom: 'border-alert-border-neutral bg-alert-background-neutral',\n\t\tinfo: 'border-alert-border-info bg-alert-background-info',\n\t\tsuccess: 'border-alert-border-green bg-alert-background-green',\n\t\twarning: 'border-alert-border-warning bg-alert-background-warning',\n\t\terror: 'border-alert-border-danger bg-alert-background-danger',\n\t},\n\tdark: 'bg-background-inverse border-background-inverse',\n};\n\n// Close icon class names.\nexport const closeIconClassNames = {\n\tlight: 'text-icon-secondary',\n\tdark: 'text-icon-inverse',\n};\n","let toastCounter = 1;\n\nclass ToastController {\n\t#toasts;\n\t#subscribers;\n\n\tconstructor() {\n\t\tthis.#toasts = [];\n\t\tthis.#subscribers = [];\n\t}\n\n\t// Subscriber pattern.\n\tsubscribe( callback ) {\n\t\tthis.#subscribers.push( callback );\n\n\t\t// Return a callback for unsubscribe.\n\t\treturn () => {\n\t\t\tthis.#subscribers = this.#subscribers.filter(\n\t\t\t\t( subscriber ) => subscriber !== callback\n\t\t\t);\n\t\t};\n\t}\n\n\t// Notify subscribers.\n\tnotify() {\n\t\tthis.#subscribers.forEach( ( subscriber ) => subscriber( this.#toasts ) );\n\t}\n\n\t// Publish a new toast.\n\tpublish( toast ) {\n\t\tthis.#subscribers.forEach( ( subscriber ) => subscriber( toast ) );\n\t}\n\n\t// Add a new toast.\n\tadd( toast ) {\n\t\tthis.#toasts.push( toast );\n\n\t\t// Publish the new toast.\n\t\tthis.publish( toast );\n\t}\n\n\t// Remove a toast.\n\tremove( id ) {\n\t\tthis.#toasts = this.#toasts.filter( ( toast ) => toast.id !== id );\n\n\t\treturn id;\n\t}\n\n\t// Create a new toast.\n\tcreate( data ) {\n\t\tconst {\n\t\t\tid = undefined,\n\t\t\tmessage = '',\n\t\t\tjsx = undefined,\n\t\t\t...restData\n\t\t} = data;\n\n\t\tif ( ! message && typeof jsx !== 'function' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst toastId = typeof id === 'number' ? id : toastCounter++;\n\t\tconst toastExists = this.#toasts.find( ( toast ) => toast.id === toastId );\n\n\t\tif ( toastExists ) {\n\t\t\t// Update the existing toast.\n\t\t\tthis.#toasts = this.#toasts.map( ( toast ) => {\n\t\t\t\tif ( toast.id === toastId ) {\n\t\t\t\t\tthis.publish( {\n\t\t\t\t\t\t...toast,\n\t\t\t\t\t\ttitle: message,\n\t\t\t\t\t\tjsx,\n\t\t\t\t\t\t...restData,\n\t\t\t\t\t} );\n\t\t\t\t\treturn { ...toast, title: message, jsx, ...restData };\n\t\t\t\t}\n\t\t\t\treturn toast;\n\t\t\t} );\n\t\t}\n\n\t\t// Create a new toast.\n\t\tthis.add( { id: toastId, title: message, jsx, ...restData } );\n\n\t\treturn toastId;\n\t}\n\n\t// Update a toast.\n\tupdate( id, data ) {\n\t\tconst { render = undefined } = data;\n\t\tlet updatedData = data;\n\t\tswitch ( typeof render ) {\n\t\t\tcase 'function':\n\t\t\t\tupdatedData = {\n\t\t\t\t\tjsx: render,\n\t\t\t\t\t...data,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tupdatedData = {\n\t\t\t\t\ttitle: render,\n\t\t\t\t\t...data,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis.#toasts = this.#toasts.map( ( toast ) => {\n\t\t\tif ( toast.id === id ) {\n\t\t\t\tthis.publish( { ...toast, ...updatedData } );\n\t\t\t\treturn { ...toast, ...updatedData };\n\t\t\t}\n\t\t\treturn toast;\n\t\t} );\n\t}\n\n\t// Dismiss toast.\n\tdismiss( id ) {\n\t\tif ( ! id ) {\n\t\t\tthis.#toasts.forEach( ( toast ) =>\n\t\t\t\tthis.#subscribers.forEach( ( subscriber ) =>\n\t\t\t\t\tsubscriber( { id: toast.id, dismiss: true } )\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tthis.#subscribers.forEach( ( subscriber ) =>\n\t\t\tsubscriber( { id, dismiss: true } )\n\t\t);\n\t\treturn id;\n\t}\n\n\t// History of toasts.\n\thistory() {\n\t\treturn this.#toasts;\n\t}\n\n\t// Types of toasts.\n\n\t// Default toast.\n\tdefault( message = '', options = {} ) {\n\t\treturn this.create( { message, type: 'neutral', ...options } );\n\t}\n\n\t// Success toast.\n\tsuccess( message = '', options = {} ) {\n\t\treturn this.create( { message, type: 'success', ...options } );\n\t}\n\n\t// Error toast.\n\terror( message = '', options = {} ) {\n\t\treturn this.create( { message, type: 'error', ...options } );\n\t}\n\n\t// Warning toast.\n\twarning( message = '', options = {} ) {\n\t\treturn this.create( { message, type: 'warning', ...options } );\n\t}\n\n\t// Info toast\n\tinfo( message = '', options = {} ) {\n\t\treturn this.create( { message, type: 'info', ...options } );\n\t}\n\n\t// Custom toast.\n\tcustom( jsx = () => {}, options = {} ) {\n\t\treturn this.create( {\n\t\t\tjsx,\n\t\t\ttype: 'custom',\n\t\t\t...options,\n\t\t} );\n\t}\n}\n\nexport const ToastState = new ToastController();\n\nconst defaultToast = ( message, options ) => ToastState.default( message, options );\n\nexport const toast = Object.seal(\n\tObject.assign(\n\t\tdefaultToast,\n\t\t{\n\t\t\tsuccess: ToastState.success.bind( ToastState ),\n\t\t\terror: ToastState.error.bind( ToastState ),\n\t\t\twarning: ToastState.warning.bind( ToastState ),\n\t\t\tinfo: ToastState.info.bind( ToastState ),\n\t\t\tcustom: ToastState.custom.bind( ToastState ),\n\t\t\tdismiss: ToastState.dismiss.bind( ToastState ),\n\t\t\tupdate: ToastState.update.bind( ToastState ),\n\t\t},\n\t\t{\n\t\t\tgetHistory: ToastState.history.bind( ToastState ),\n\t\t}\n\t)\n);\n","export { default as Toaster } from './toaster';\nexport { toast } from './controller';\n","import { useEffect, useRef, useState } from 'react';\nimport { X } from 'lucide-react';\nimport { ToastState } from './controller';\nimport { withSingleton } from '@/hoc';\nimport { cn } from '@/utilities/functions';\nimport { getIcon, getAction, getContent, getTitle } from './utils';\nimport {\n\tcloseIconClassNames,\n\tcontainerVariantClassNames,\n\tpositionClassNames,\n\tvariantClassNames,\n} from './component-style';\nimport { flushSync } from 'react-dom';\nimport { motion, AnimatePresence } from 'framer-motion';\n\nconst Toaster = ( {\n\tposition = 'top-right', // top-right/top-left/bottom-right/bottom-left\n\tdesign = 'stack', // stack/inline\n\ttheme = 'light', // light/dark\n\tclassName = '',\n\tautoDismiss = true, // Auto dismiss the toast after a certain time.\n\tdismissAfter = 5000, // Time in milliseconds after which the toast will be dismissed.\n} ) => {\n\tconst [ toasts, setToasts ] = useState( [] );\n\n\tuseEffect( () => {\n\t\tToastState.subscribe( ( toastItem ) => {\n\t\t\tif ( toastItem?.dismiss ) {\n\t\t\t\tsetToasts( ( prevToasts ) =>\n\t\t\t\t\tprevToasts.map( ( tItem ) =>\n\t\t\t\t\t\ttItem.id === toastItem.id\n\t\t\t\t\t\t\t? { ...tItem, dismiss: true }\n\t\t\t\t\t\t\t: tItem\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetTimeout( () => {\n\t\t\t\tflushSync( () =>\n\t\t\t\t\tsetToasts( ( prevToasts ) => {\n\t\t\t\t\t\tconst itemExists = prevToasts.findIndex(\n\t\t\t\t\t\t\t( tItem ) => tItem.id === toastItem.id\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// Update the existing toast.\n\t\t\t\t\t\tif ( itemExists !== -1 ) {\n\t\t\t\t\t\t\treturn prevToasts.map( ( tItem ) => {\n\t\t\t\t\t\t\t\tif ( tItem.id === toastItem.id ) {\n\t\t\t\t\t\t\t\t\treturn { ...tItem, ...toastItem };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn tItem;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn [ ...prevToasts, toastItem ];\n\t\t\t\t\t} )\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t}, [] );\n\n\tconst removeToast = ( id ) => {\n\t\tsetToasts( ( prevToasts ) => prevToasts.filter( ( t ) => t.id !== id ) );\n\t};\n\n\treturn (\n\t\tli]:pointer-events-auto gap-3',\n\t\t\t\tpositionClassNames[ position ] ?? positionClassNames[ 'top-right' ],\n\t\t\t\tclassName\n\t\t\t) }\n\t\t>\n\t\t\t{ /* Main container */ }\n\t\t\t\n\t\t\t\t{ toasts.map( ( toastItem ) => (\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};\n\nexport const Toast = ( {\n\ttoastItem,\n\ttitle = null,\n\tcontent = null,\n\tautoDismiss = true,\n\tdismissAfter = 5000,\n\ttheme = 'light', // light/dark\n\tdesign = 'stack', // inline/stack\n\ticon = null,\n\tvariant = 'neutral', // neutral/info/success/warning/danger\n\tremoveToast, // Function to remove the toast.\n} ) => {\n\tconst closeTimerStart = useRef( 0 );\n\tconst lastCloseTimerStart = useRef( 0 );\n\tconst timeoutId = useRef( 0 );\n\n\tconst startTimer = ( tItem, remainingTime = dismissAfter ) => {\n\t\t// If auto dismiss is disabled, or the dismissAfter is less than 0, return.\n\t\tif ( ! autoDismiss || dismissAfter < 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcloseTimerStart.current = new Date().getTime();\n\t\treturn setTimeout( () => {\n\t\t\tremoveToast( tItem.id );\n\t\t}, remainingTime );\n\t};\n\n\tconst pauseTimer = () => {\n\t\tclearTimeout( timeoutId.current );\n\t\tlastCloseTimerStart.current = new Date().getTime();\n\t};\n\n\tconst continueTimer = () => {\n\t\ttimeoutId.current = startTimer(\n\t\t\ttoastItem,\n\t\t\tdismissAfter -\n\t\t\t\t( lastCloseTimerStart.current - closeTimerStart.current )\n\t\t);\n\t};\n\n\t// Start the timer when the component mounts.\n\tuseEffect( () => {\n\t\tconst remainingTime = dismissAfter;\n\n\t\ttimeoutId.current = startTimer( toastItem, remainingTime );\n\t\treturn () => {\n\t\t\tclearTimeout( timeoutId.current );\n\t\t};\n\t}, [] );\n\n\tuseEffect( () => {\n\t\tif ( ! toastItem?.dismiss ) {\n\t\t\treturn;\n\t\t}\n\t\tremoveToast( toastItem.id );\n\t}, [ toastItem ] );\n\n\tconst handleAction = () => {\n\t\ttoastItem?.action?.onClick?.( () => removeToast( toastItem.id ) );\n\t};\n\n\tlet render = null;\n\tif ( design === 'stack' ) {\n\t\trender = (\n\t\t\t\n\t\t\t\t{ toastItem.type !== 'custom' ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{ getIcon( { variant, icon, theme } ) }\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{ getTitle( { title, theme } ) }\n\t\t\t\t\t\t\t{ getContent( { content, theme } ) }\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttoastItem?.action?.label &&\n\t\t\t\t\t\t\t\t\ttypeof toastItem?.action?.onClick ===\n\t\t\t\t\t\t\t\t\t\t'function' && (\n\t\t\t\t\t\t\t\t/* eslint-disable */\n\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\t\t{getAction({\n\t\t\t\t\t\t\t\t\t\t\t\tactionLabel:\n\t\t\t\t\t\t\t\t\t\t\t\t\ttoastItem?.action?.label,\n\t\t\t\t\t\t\t\t\t\t\t\tactionType:\n\t\t\t\t\t\t\t\t\t\t\t\t\ttoastItem?.action?.type ??\n\t\t\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t\tonAction: handleAction,\n\t\t\t\t\t\t\t\t\t\t\t\ttheme,\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/* eslint-enable */\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
\n\t\t\t\t\t>\n\t\t\t\t) : (\n\t\t\t\t\ttoastItem?.jsx?.( {\n\t\t\t\t\t\tclose: () => removeToast( toastItem.id ),\n\t\t\t\t\t\taction: toastItem?.action\n\t\t\t\t\t\t\t? { ...toastItem?.action, onClick: handleAction }\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t} )\n\t\t\t\t) }\n\t\t\t
\n\t\t);\n\t}\n\n\tif ( design === 'inline' ) {\n\t\trender = (\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{ getIcon( { variant, icon, theme } ) }\n\t\t\t\t
\n\t\t\t\t
span:first-child]:shrink-0\">\n\t\t\t\t\t{ getTitle( { title, theme } ) }\n\t\t\t\t\t{ getContent( { content, theme } ) }\n\t\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\treturn render;\n};\n\nexport default withSingleton( Toaster );\n","import { cloneElement, isValidElement } from 'react';\nimport { Check, Info, AlertTriangle, Trash2 } from 'lucide-react';\nimport { cn } from '@/utilities/functions';\nimport Button from '../button/button.jsx';\n\nconst DEFAULT_THEME = 'light';\nconst DEFAULT_VARIANT = 'neutral';\nconst DEFAULT_ACTION_TYPE = 'button';\n\nexport const getIcon = ( {\n\ticon = null,\n\ttheme = DEFAULT_THEME,\n\tvariant = DEFAULT_VARIANT,\n} ) => {\n\tconst commonClasses = '[&>svg]:h-5 [&>svg]:w-5';\n\tconst nColor =\n\t\ttheme === 'light' ? 'text-icon-secondary' : 'text-icon-inverse';\n\tif ( icon && isValidElement( icon ) ) {\n\t\tconst updatedIcon = cloneElement( icon, {\n\t\t\tclassName: cn( commonClasses, nColor, icon.props.className ),\n\t\t} );\n\t\treturn updatedIcon;\n\t}\n\n\tswitch ( variant ) {\n\t\tcase 'neutral':\n\t\t\treturn ;\n\t\tcase 'info':\n\t\t\tconst iColor =\n\t\t\t\ttheme === 'light'\n\t\t\t\t\t? 'text-support-info'\n\t\t\t\t\t: 'text-support-info-inverse';\n\t\t\treturn ;\n\t\tcase 'success':\n\t\t\tconst sColor =\n\t\t\t\ttheme === 'light'\n\t\t\t\t\t? 'text-support-success'\n\t\t\t\t\t: 'text-support-success-inverse';\n\t\t\treturn ;\n\t\tcase 'warning':\n\t\t\tconst wColor =\n\t\t\t\ttheme === 'light'\n\t\t\t\t\t? 'text-support-warning'\n\t\t\t\t\t: 'text-support-warning-inverse';\n\t\t\treturn ;\n\t\tcase 'error':\n\t\t\tconst dColor =\n\t\t\t\ttheme === 'light'\n\t\t\t\t\t? 'text-support-error'\n\t\t\t\t\t: 'text-support-error-inverse';\n\t\t\treturn ;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\nexport const getAction = ( {\n\tactionType = DEFAULT_ACTION_TYPE,\n\tonAction = () => {},\n\tactionLabel = '',\n\ttheme = DEFAULT_THEME,\n} ) => {\n\tconst commonClassNames =\n\t\t'focus:ring-0 focus:ring-offset-0 ring-offset-0 focus:outline-none';\n\tlet classNames =\n\t\t'text-button-primary border-button-primary hover:border-button-primary hover:text-button-primary-hover';\n\tif ( theme === 'dark' ) {\n\t\tclassNames =\n\t\t\t'text-text-inverse border-text-inverse hover:border-text-inverse hover:text-text-inverse';\n\t}\n\tswitch ( actionType ) {\n\t\tcase 'button':\n\t\t\treturn (\n\t\t\t\t\n\t\t\t);\n\t\tcase 'link':\n\t\t\treturn (\n\t\t\t\t\n\t\t\t);\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\nexport const getTitle = ( { theme = DEFAULT_THEME, title = '' } ) => {\n\tif ( ! title && isNaN( title ) ) {\n\t\treturn null;\n\t}\n\tconst titleClasses = {\n\t\tlight: 'text-text-primary',\n\t\tdark: 'text-text-inverse',\n\t};\n\treturn (\n\t\t\n\t\t\t{ title }\n\t\t\n\t);\n};\n\nexport const getContent = ( { theme = DEFAULT_THEME, content = '' } ) => {\n\tif ( ! content && isNaN( content ) ) {\n\t\treturn null;\n\t}\n\tconst contentClasses = {\n\t\tlight: 'text-text-primary',\n\t\tdark: 'text-text-inverse',\n\t};\n\treturn (\n\t\t\n\t\t\t{ content }\n\t\t\n\t);\n};\n\n/**\n * Merge all refs into a single function.\n * @param {...Function} refs\n *\n * @return {Function} A function that will call all refs with the node.\n */\nexport const mergeRefs = ( ...refs ) => {\n\treturn ( node ) => {\n\t\trefs.forEach( ( ref ) => {\n\t\t\tif ( typeof ref === 'function' ) {\n\t\t\t\tref( node );\n\t\t\t} else if ( ref ) {\n\t\t\t\tref.current = node;\n\t\t\t}\n\t\t} );\n\t};\n};\n","import React, {\n\tuseRef,\n\tuseState,\n\tisValidElement,\n\tcloneElement,\n\tuseMemo,\n} from 'react';\nimport {\n\tuseFloating,\n\tautoUpdate,\n\toffset,\n\tflip,\n\tshift,\n\tuseHover,\n\tuseFocus,\n\tuseDismiss,\n\tuseClick,\n\tsafePolygon,\n\tuseRole,\n\tarrow as floatingArrow,\n\tFloatingPortal,\n\tFloatingArrow,\n\tuseInteractions,\n\tuseTransitionStyles,\n} from '@floating-ui/react';\nimport { cn } from '@/utilities/functions';\nimport { mergeRefs } from '../toaster/utils';\n\nconst Tooltip = ( {\n\tvariant = 'dark', // 'light' | 'dark';\n\tplacement = 'bottom', // | 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end';\n\ttitle = '',\n\tcontent,\n\tarrow = false,\n\topen,\n\tsetOpen,\n\tchildren,\n\tclassName,\n\ttooltipPortalRoot = null, // Root element where the dropdown will be rendered.\n\ttooltipPortalId = '', // Id of the dropdown portal where the dropdown will be rendered.\n\tboundary = 'clippingAncestors',\n\tstrategy = 'fixed', // 'fixed' | 'absolute';\n\toffset: offsetValue = 8, // Offset option or number value. Default is 8.\n\ttriggers = [ 'hover', 'focus' ], // 'click' | 'hover' | 'focus';\n\tinteractive = false,\n} ) => {\n\tconst isControlled = useMemo(\n\t\t() => typeof open === 'boolean' && typeof setOpen === 'function',\n\t\t[ open, setOpen ]\n\t);\n\n\tconst [ isOpen, setIsOpen ] = useState( false );\n\tconst arrowRef = useRef( null );\n\n\tconst { refs, floatingStyles, context } = useFloating( {\n\t\topen: isControlled ? open : isOpen,\n\t\tonOpenChange: isControlled ? setOpen : setIsOpen,\n\t\tplacement,\n\t\tstrategy,\n\t\tmiddleware: [\n\t\t\toffset( offsetValue ),\n\t\t\tflip( {\n\t\t\t\tboundary,\n\t\t\t} ),\n\t\t\tshift( {\n\t\t\t\tboundary,\n\t\t\t} ),\n\t\t\tfloatingArrow( { element: arrowRef } ),\n\t\t],\n\t\twhileElementsMounted: autoUpdate,\n\t} );\n\n\tconst click = useClick( context, {\n\t\tenabled: ! isControlled && triggers.includes( 'click' ),\n\t} );\n\tconst hover = useHover( context, {\n\t\tmove: false,\n\t\tenabled: ! isControlled && triggers.includes( 'hover' ),\n\t\t...( interactive && { handleClose: safePolygon() } ),\n\t} );\n\tconst focus = useFocus( context, {\n\t\tenabled: ! isControlled && triggers.includes( 'focus' ),\n\t} );\n\tconst dismiss = useDismiss( context );\n\tconst role = useRole( context, { role: 'tooltip' } );\n\n\tconst { getReferenceProps, getFloatingProps } = useInteractions( [\n\t\tclick,\n\t\thover,\n\t\tfocus,\n\t\tdismiss,\n\t\trole,\n\t] );\n\n\t// Fade-in and fade-out transition.\n\tconst { isMounted, styles } = useTransitionStyles( context, {\n\t\tduration: 150,\n\t\tinitial: { opacity: 0 },\n\t\topen: { opacity: 1 },\n\t\tclose: { opacity: 0 },\n\t} );\n\n\tconst tooltipClasses =\n\t\t'absolute z-20 py-2 px-3 rounded-md text-xs leading-4 shadow-soft-shadow-lg';\n\n\tconst variantClasses = {\n\t\tlight: 'bg-tooltip-background-light text-text-primary',\n\t\tdark: 'bg-tooltip-background-dark text-text-on-color',\n\t}?.[ variant ];\n\n\tconst arrowClasses =\n\t\tvariant === 'dark'\n\t\t\t? 'text-tooltip-background-dark'\n\t\t\t: 'text-tooltip-background-light';\n\n\tconst widthClasses = 'max-w-80 w-fit';\n\n\treturn (\n\t\t<>\n\t\t\t{ isValidElement( children ) &&\n\t\t\t\tcloneElement( children, {\n\t\t\t\t\t...children.props,\n\t\t\t\t\tref: mergeRefs( children.ref, refs.setReference ),\n\t\t\t\t\tclassName: cn( children.props.className ),\n\t\t\t\t\t...getReferenceProps(),\n\t\t\t\t} ) }\n\t\t\t\n\t\t\t\t{ isMounted && (\n\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{ !! title && (\n\t\t\t\t\t\t\t\t
{ title }\n\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t{ !! content && (\n\t\t\t\t\t\t\t\t
{ content }
\n\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t
\n\t\t\t\t\t\t{ arrow && (\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\n\t\t>\n\t);\n};\n\nexport default Tooltip;\n","import React from 'react';\nimport { cn, getGapClass } from '@/utilities/functions';\n\nconst Topbar = ( { children, gap = 'lg', className, ...props } ) => {\n\treturn (\n\t\t\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nconst Left = ( { gap = 'sm', children, className } ) => {\n\treturn (\n\t\t\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nconst Middle = ( { gap = 'md', children, align = 'center', className } ) => {\n\tconst alignmentClass = {\n\t\tleft: 'justify-start',\n\t\tcenter: 'justify-center',\n\t\tright: 'justify-end',\n\t}?.[ align ];\n\n\treturn (\n\t\t\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nconst Right = ( { gap = 'sm', children, className } ) => {\n\treturn (\n\t\t\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nconst Item = ( { children, className } ) => {\n\treturn (\n\t\tsvg]:block h-full', className ) }\n\t\t>\n\t\t\t{ children }\n\t\t
\n\t);\n};\n\nTopbar.Left = Left;\nTopbar.Middle = Middle;\nTopbar.Right = Right;\nTopbar.Item = Item;\n\nexport default Topbar;\n","import { memo } from 'react';\n\nlet hasRendered = false;\n\nconst withSingleton = ( WrappedComponent ) => {\n\tconst SingletonComponent = memo( ( props ) => {\n\t\tconst isSingleTon = props.singleTon; // singleTon is a prop passed to the component to check if it is a singleton component\n\t\tif ( hasRendered && isSingleTon ) {\n\t\t\treturn null; // or return an alternative component\n\t\t}\n\t\thasRendered = true;\n\t\treturn ;\n\t} );\n\n\treturn SingletonComponent;\n};\n\nexport default withSingleton;\n","import { twMerge } from 'tailwind-merge';\nimport { clsx } from 'clsx';\n\nexport function prefix() {\n\treturn 'force-ui-';\n}\n\n/**\n * For Conditional classNames and merging TailwindCSS classes.\n * @param {...any} classNames\n * @return {string} - Merged TailwindCSS classes.\n */\nexport const cn = ( ...classNames ) => twMerge( clsx( ...classNames ) );\n\n/**\n * Call provided functions with the given arguments.\n * @param {...Function} fns\n * @return {Function} - Function that calls all provided functions.\n */\nexport const callAll = ( ...fns ) => {\n\treturn ( ...args ) => fns.forEach( ( fn ) => fn?.( ...args ) );\n};\n\nexport const getGapClass = ( gap ) => {\n\tconst gapClasses = {\n\t\t0: 'gap-0',\n\t\txxs: 'gap-1',\n\t\txs: 'gap-2',\n\t\tsm: 'gap-3',\n\t\tmd: 'gap-4',\n\t\tlg: 'gap-5',\n\t\txl: 'gap-6',\n\t\t'2xl': 'gap-8',\n\t};\n\n\treturn gapClasses[ gap ] || gapClasses.md;\n};\n\nexport const columnClasses = {\n\t1: 'grid-cols-1',\n\t2: 'grid-cols-2',\n\t3: 'grid-cols-3',\n\t4: 'grid-cols-4',\n\t5: 'grid-cols-5',\n\t6: 'grid-cols-6',\n\t7: 'grid-cols-7',\n\t8: 'grid-cols-8',\n\t9: 'grid-cols-9',\n\t10: 'grid-cols-10',\n\t11: 'grid-cols-11',\n\t12: 'grid-cols-12',\n};\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t this.runAll(\"stop\");\n this.animations = animations.filter(Boolean);\n }\n then(onResolve, onReject) {\n return Promise.all(this.animations).then(onResolve).catch(onReject);\n }\n /**\n * TODO: Filter out cancelled or stopped animations before returning\n */\n getAll(propName) {\n return this.animations[0][propName];\n }\n setAll(propName, newValue) {\n for (let i = 0; i < this.animations.length; i++) {\n this.animations[i][propName] = newValue;\n }\n }\n attachTimeline(timeline) {\n const cancelAll = this.animations.map((animation) => {\n if (supportsScrollTimeline() && animation.attachTimeline) {\n animation.attachTimeline(timeline);\n }\n else {\n animation.pause();\n return observeTimeline((progress) => {\n animation.time = animation.duration * progress;\n }, timeline);\n }\n });\n return () => {\n cancelAll.forEach((cancelTimeline, i) => {\n if (cancelTimeline)\n cancelTimeline();\n this.animations[i].stop();\n });\n };\n }\n get time() {\n return this.getAll(\"time\");\n }\n set time(time) {\n this.setAll(\"time\", time);\n }\n get speed() {\n return this.getAll(\"speed\");\n }\n set speed(speed) {\n this.setAll(\"speed\", speed);\n }\n get startTime() {\n return this.getAll(\"startTime\");\n }\n get duration() {\n let max = 0;\n for (let i = 0; i < this.animations.length; i++) {\n max = Math.max(max, this.animations[i].duration);\n }\n return max;\n }\n runAll(methodName) {\n this.animations.forEach((controls) => controls[methodName]());\n }\n play() {\n this.runAll(\"play\");\n }\n pause() {\n this.runAll(\"pause\");\n }\n cancel() {\n this.runAll(\"cancel\");\n }\n complete() {\n this.runAll(\"complete\");\n }\n}\n\nexport { GroupPlaybackControls };\n","import { DOMKeyframesResolver } from '../../render/dom/DOMKeyframesResolver.mjs';\nimport { memo } from '../../utils/memo.mjs';\nimport { noop } from '../../utils/noop.mjs';\nimport { millisecondsToSeconds, secondsToMilliseconds } from '../../utils/time-conversion.mjs';\nimport { BaseAnimation } from './BaseAnimation.mjs';\nimport { MainThreadAnimation } from './MainThreadAnimation.mjs';\nimport { acceleratedValues } from './utils/accelerated-values.mjs';\nimport { animateStyle } from './waapi/index.mjs';\nimport { isWaapiSupportedEasing } from './waapi/easing.mjs';\nimport { getFinalKeyframe } from './waapi/utils/get-final-keyframe.mjs';\n\nconst supportsWaapi = memo(() => Object.hasOwnProperty.call(Element.prototype, \"animate\"));\n/**\n * 10ms is chosen here as it strikes a balance between smooth\n * results (more than one keyframe per frame at 60fps) and\n * keyframe quantity.\n */\nconst sampleDelta = 10; //ms\n/**\n * Implement a practical max duration for keyframe generation\n * to prevent infinite loops\n */\nconst maxDuration = 20000;\n/**\n * Check if an animation can run natively via WAAPI or requires pregenerated keyframes.\n * WAAPI doesn't support spring or function easings so we run these as JS animation before\n * handing off.\n */\nfunction requiresPregeneratedKeyframes(options) {\n return options.type === \"spring\" || !isWaapiSupportedEasing(options.ease);\n}\nfunction pregenerateKeyframes(keyframes, options) {\n /**\n * Create a main-thread animation to pregenerate keyframes.\n * We sample this at regular intervals to generate keyframes that we then\n * linearly interpolate between.\n */\n const sampleAnimation = new MainThreadAnimation({\n ...options,\n keyframes,\n repeat: 0,\n delay: 0,\n isGenerator: true,\n });\n let state = { done: false, value: keyframes[0] };\n const pregeneratedKeyframes = [];\n /**\n * Bail after 20 seconds of pre-generated keyframes as it's likely\n * we're heading for an infinite loop.\n */\n let t = 0;\n while (!state.done && t < maxDuration) {\n state = sampleAnimation.sample(t);\n pregeneratedKeyframes.push(state.value);\n t += sampleDelta;\n }\n return {\n times: undefined,\n keyframes: pregeneratedKeyframes,\n duration: t - sampleDelta,\n ease: \"linear\",\n };\n}\nclass AcceleratedAnimation extends BaseAnimation {\n constructor(options) {\n super(options);\n const { name, motionValue, element, keyframes } = this.options;\n this.resolver = new DOMKeyframesResolver(keyframes, (resolvedKeyframes, finalKeyframe) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe), name, motionValue, element);\n this.resolver.scheduleResolve();\n }\n initPlayback(keyframes, finalKeyframe) {\n var _a;\n let { duration = 300, times, ease, type, motionValue, name, startTime, } = this.options;\n /**\n * If element has since been unmounted, return false to indicate\n * the animation failed to initialised.\n */\n if (!((_a = motionValue.owner) === null || _a === void 0 ? void 0 : _a.current)) {\n return false;\n }\n /**\n * If this animation needs pre-generated keyframes then generate.\n */\n if (requiresPregeneratedKeyframes(this.options)) {\n const { onComplete, onUpdate, motionValue, element, ...options } = this.options;\n const pregeneratedAnimation = pregenerateKeyframes(keyframes, options);\n keyframes = pregeneratedAnimation.keyframes;\n // If this is a very short animation, ensure we have\n // at least two keyframes to animate between as older browsers\n // can't animate between a single keyframe.\n if (keyframes.length === 1) {\n keyframes[1] = keyframes[0];\n }\n duration = pregeneratedAnimation.duration;\n times = pregeneratedAnimation.times;\n ease = pregeneratedAnimation.ease;\n type = \"keyframes\";\n }\n const animation = animateStyle(motionValue.owner.current, name, keyframes, { ...this.options, duration, times, ease });\n // Override the browser calculated startTime with one synchronised to other JS\n // and WAAPI animations starting this event loop.\n animation.startTime = startTime !== null && startTime !== void 0 ? startTime : this.calcStartTime();\n if (this.pendingTimeline) {\n animation.timeline = this.pendingTimeline;\n this.pendingTimeline = undefined;\n }\n else {\n /**\n * Prefer the `onfinish` prop as it's more widely supported than\n * the `finished` promise.\n *\n * Here, we synchronously set the provided MotionValue to the end\n * keyframe. If we didn't, when the WAAPI animation is finished it would\n * be removed from the element which would then revert to its old styles.\n */\n animation.onfinish = () => {\n const { onComplete } = this.options;\n motionValue.set(getFinalKeyframe(keyframes, this.options, finalKeyframe));\n onComplete && onComplete();\n this.cancel();\n this.resolveFinishedPromise();\n };\n }\n return {\n animation,\n duration,\n times,\n type,\n ease,\n keyframes: keyframes,\n };\n }\n get duration() {\n const { resolved } = this;\n if (!resolved)\n return 0;\n const { duration } = resolved;\n return millisecondsToSeconds(duration);\n }\n get time() {\n const { resolved } = this;\n if (!resolved)\n return 0;\n const { animation } = resolved;\n return millisecondsToSeconds(animation.currentTime || 0);\n }\n set time(newTime) {\n const { resolved } = this;\n if (!resolved)\n return;\n const { animation } = resolved;\n animation.currentTime = secondsToMilliseconds(newTime);\n }\n get speed() {\n const { resolved } = this;\n if (!resolved)\n return 1;\n const { animation } = resolved;\n return animation.playbackRate;\n }\n set speed(newSpeed) {\n const { resolved } = this;\n if (!resolved)\n return;\n const { animation } = resolved;\n animation.playbackRate = newSpeed;\n }\n get state() {\n const { resolved } = this;\n if (!resolved)\n return \"idle\";\n const { animation } = resolved;\n return animation.playState;\n }\n get startTime() {\n const { resolved } = this;\n if (!resolved)\n return null;\n const { animation } = resolved;\n // Coerce to number as TypeScript incorrectly types this\n // as CSSNumberish\n return animation.startTime;\n }\n /**\n * Replace the default DocumentTimeline with another AnimationTimeline.\n * Currently used for scroll animations.\n */\n attachTimeline(timeline) {\n if (!this._resolved) {\n this.pendingTimeline = timeline;\n }\n else {\n const { resolved } = this;\n if (!resolved)\n return noop;\n const { animation } = resolved;\n animation.timeline = timeline;\n animation.onfinish = null;\n }\n return noop;\n }\n play() {\n if (this.isStopped)\n return;\n const { resolved } = this;\n if (!resolved)\n return;\n const { animation } = resolved;\n if (animation.playState === \"finished\") {\n this.updateFinishedPromise();\n }\n animation.play();\n }\n pause() {\n const { resolved } = this;\n if (!resolved)\n return;\n const { animation } = resolved;\n animation.pause();\n }\n stop() {\n this.resolver.cancel();\n this.isStopped = true;\n if (this.state === \"idle\")\n return;\n this.resolveFinishedPromise();\n this.updateFinishedPromise();\n const { resolved } = this;\n if (!resolved)\n return;\n const { animation, keyframes, duration, type, ease, times } = resolved;\n if (animation.playState === \"idle\" ||\n animation.playState === \"finished\") {\n return;\n }\n /**\n * WAAPI doesn't natively have any interruption capabilities.\n *\n * Rather than read commited styles back out of the DOM, we can\n * create a renderless JS animation and sample it twice to calculate\n * its current value, \"previous\" value, and therefore allow\n * Motion to calculate velocity for any subsequent animation.\n */\n if (this.time) {\n const { motionValue, onUpdate, onComplete, element, ...options } = this.options;\n const sampleAnimation = new MainThreadAnimation({\n ...options,\n keyframes,\n duration,\n type,\n ease,\n times,\n isGenerator: true,\n });\n const sampleTime = secondsToMilliseconds(this.time);\n motionValue.setWithVelocity(sampleAnimation.sample(sampleTime - sampleDelta).value, sampleAnimation.sample(sampleTime).value, sampleDelta);\n }\n const { onStop } = this.options;\n onStop && onStop();\n this.cancel();\n }\n complete() {\n const { resolved } = this;\n if (!resolved)\n return;\n resolved.animation.finish();\n }\n cancel() {\n const { resolved } = this;\n if (!resolved)\n return;\n resolved.animation.cancel();\n }\n static supports(options) {\n const { motionValue, name, repeatDelay, repeatType, damping, type } = options;\n return (supportsWaapi() &&\n name &&\n acceleratedValues.has(name) &&\n motionValue &&\n motionValue.owner &&\n motionValue.owner.current instanceof HTMLElement &&\n /**\n * If we're outputting values to onUpdate then we can't use WAAPI as there's\n * no way to read the value from WAAPI every frame.\n */\n !motionValue.owner.getProps().onUpdate &&\n !repeatDelay &&\n repeatType !== \"mirror\" &&\n damping !== 0 &&\n type !== \"inertia\");\n }\n}\n\nexport { AcceleratedAnimation };\n","import { time } from '../../frameloop/sync-time.mjs';\nimport { flushKeyframeResolvers } from '../../render/utils/KeyframesResolver.mjs';\nimport { instantAnimationState } from '../../utils/use-instant-transition-state.mjs';\nimport { canAnimate } from './utils/can-animate.mjs';\nimport { getFinalKeyframe } from './waapi/utils/get-final-keyframe.mjs';\n\n/**\n * Maximum time allowed between an animation being created and it being\n * resolved for us to use the latter as the start time.\n *\n * This is to ensure that while we prefer to \"start\" an animation as soon\n * as it's triggered, we also want to avoid a visual jump if there's a big delay\n * between these two moments.\n */\nconst MAX_RESOLVE_DELAY = 40;\nclass BaseAnimation {\n constructor({ autoplay = true, delay = 0, type = \"keyframes\", repeat = 0, repeatDelay = 0, repeatType = \"loop\", ...options }) {\n // Track whether the animation has been stopped. Stopped animations won't restart.\n this.isStopped = false;\n this.hasAttemptedResolve = false;\n this.createdAt = time.now();\n this.options = {\n autoplay,\n delay,\n type,\n repeat,\n repeatDelay,\n repeatType,\n ...options,\n };\n this.updateFinishedPromise();\n }\n /**\n * This method uses the createdAt and resolvedAt to calculate the\n * animation startTime. *Ideally*, we would use the createdAt time as t=0\n * as the following frame would then be the first frame of the animation in\n * progress, which would feel snappier.\n *\n * However, if there's a delay (main thread work) between the creation of\n * the animation and the first commited frame, we prefer to use resolvedAt\n * to avoid a sudden jump into the animation.\n */\n calcStartTime() {\n if (!this.resolvedAt)\n return this.createdAt;\n return this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY\n ? this.resolvedAt\n : this.createdAt;\n }\n /**\n * A getter for resolved data. If keyframes are not yet resolved, accessing\n * this.resolved will synchronously flush all pending keyframe resolvers.\n * This is a deoptimisation, but at its worst still batches read/writes.\n */\n get resolved() {\n if (!this._resolved && !this.hasAttemptedResolve) {\n flushKeyframeResolvers();\n }\n return this._resolved;\n }\n /**\n * A method to be called when the keyframes resolver completes. This method\n * will check if its possible to run the animation and, if not, skip it.\n * Otherwise, it will call initPlayback on the implementing class.\n */\n onKeyframesResolved(keyframes, finalKeyframe) {\n this.resolvedAt = time.now();\n this.hasAttemptedResolve = true;\n const { name, type, velocity, delay, onComplete, onUpdate, isGenerator, } = this.options;\n /**\n * If we can't animate this value with the resolved keyframes\n * then we should complete it immediately.\n */\n if (!isGenerator && !canAnimate(keyframes, name, type, velocity)) {\n // Finish immediately\n if (instantAnimationState.current || !delay) {\n onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(getFinalKeyframe(keyframes, this.options, finalKeyframe));\n onComplete === null || onComplete === void 0 ? void 0 : onComplete();\n this.resolveFinishedPromise();\n return;\n }\n // Finish after a delay\n else {\n this.options.duration = 0;\n }\n }\n const resolvedAnimation = this.initPlayback(keyframes, finalKeyframe);\n if (resolvedAnimation === false)\n return;\n this._resolved = {\n keyframes,\n finalKeyframe,\n ...resolvedAnimation,\n };\n this.onPostResolved();\n }\n onPostResolved() { }\n /**\n * Allows the returned animation to be awaited or promise-chained. Currently\n * resolves when the animation finishes at all but in a future update could/should\n * reject if its cancels.\n */\n then(resolve, reject) {\n return this.currentFinishedPromise.then(resolve, reject);\n }\n updateFinishedPromise() {\n this.currentFinishedPromise = new Promise((resolve) => {\n this.resolveFinishedPromise = resolve;\n });\n }\n}\n\nexport { BaseAnimation };\n","import { KeyframeResolver } from '../../render/utils/KeyframesResolver.mjs';\nimport { spring } from '../generators/spring/index.mjs';\nimport { inertia } from '../generators/inertia.mjs';\nimport { keyframes } from '../generators/keyframes.mjs';\nimport { BaseAnimation } from './BaseAnimation.mjs';\nimport { pipe } from '../../utils/pipe.mjs';\nimport { mix } from '../../utils/mix/index.mjs';\nimport { calcGeneratorDuration } from '../generators/utils/calc-duration.mjs';\nimport { millisecondsToSeconds, secondsToMilliseconds } from '../../utils/time-conversion.mjs';\nimport { clamp } from '../../utils/clamp.mjs';\nimport { invariant } from '../../utils/errors.mjs';\nimport { frameloopDriver } from './drivers/driver-frameloop.mjs';\nimport { getFinalKeyframe } from './waapi/utils/get-final-keyframe.mjs';\n\nconst generators = {\n decay: inertia,\n inertia,\n tween: keyframes,\n keyframes: keyframes,\n spring,\n};\nconst percentToProgress = (percent) => percent / 100;\n/**\n * Animation that runs on the main thread. Designed to be WAAPI-spec in the subset of\n * features we expose publically. Mostly the compatibility is to ensure visual identity\n * between both WAAPI and main thread animations.\n */\nclass MainThreadAnimation extends BaseAnimation {\n constructor(options) {\n super(options);\n /**\n * The time at which the animation was paused.\n */\n this.holdTime = null;\n /**\n * The time at which the animation was cancelled.\n */\n this.cancelTime = null;\n /**\n * The current time of the animation.\n */\n this.currentTime = 0;\n /**\n * Playback speed as a factor. 0 would be stopped, -1 reverse and 2 double speed.\n */\n this.playbackSpeed = 1;\n /**\n * The state of the animation to apply when the animation is resolved. This\n * allows calls to the public API to control the animation before it is resolved,\n * without us having to resolve it first.\n */\n this.pendingPlayState = \"running\";\n /**\n * The time at which the animation was started.\n */\n this.startTime = null;\n this.state = \"idle\";\n /**\n * This method is bound to the instance to fix a pattern where\n * animation.stop is returned as a reference from a useEffect.\n */\n this.stop = () => {\n this.resolver.cancel();\n this.isStopped = true;\n if (this.state === \"idle\")\n return;\n this.teardown();\n const { onStop } = this.options;\n onStop && onStop();\n };\n const { name, motionValue, element, keyframes } = this.options;\n const KeyframeResolver$1 = (element === null || element === void 0 ? void 0 : element.KeyframeResolver) || KeyframeResolver;\n const onResolved = (resolvedKeyframes, finalKeyframe) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe);\n this.resolver = new KeyframeResolver$1(keyframes, onResolved, name, motionValue, element);\n this.resolver.scheduleResolve();\n }\n initPlayback(keyframes$1) {\n const { type = \"keyframes\", repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = this.options;\n const generatorFactory = generators[type] || keyframes;\n /**\n * If our generator doesn't support mixing numbers, we need to replace keyframes with\n * [0, 100] and then make a function that maps that to the actual keyframes.\n *\n * 100 is chosen instead of 1 as it works nicer with spring animations.\n */\n let mapPercentToKeyframes;\n let mirroredGenerator;\n if (generatorFactory !== keyframes &&\n typeof keyframes$1[0] !== \"number\") {\n if (process.env.NODE_ENV !== \"production\") {\n invariant(keyframes$1.length === 2, `Only two keyframes currently supported with spring and inertia animations. Trying to animate ${keyframes$1}`);\n }\n mapPercentToKeyframes = pipe(percentToProgress, mix(keyframes$1[0], keyframes$1[1]));\n keyframes$1 = [0, 100];\n }\n const generator = generatorFactory({ ...this.options, keyframes: keyframes$1 });\n /**\n * If we have a mirror repeat type we need to create a second generator that outputs the\n * mirrored (not reversed) animation and later ping pong between the two generators.\n */\n if (repeatType === \"mirror\") {\n mirroredGenerator = generatorFactory({\n ...this.options,\n keyframes: [...keyframes$1].reverse(),\n velocity: -velocity,\n });\n }\n /**\n * If duration is undefined and we have repeat options,\n * we need to calculate a duration from the generator.\n *\n * We set it to the generator itself to cache the duration.\n * Any timeline resolver will need to have already precalculated\n * the duration by this step.\n */\n if (generator.calculatedDuration === null) {\n generator.calculatedDuration = calcGeneratorDuration(generator);\n }\n const { calculatedDuration } = generator;\n const resolvedDuration = calculatedDuration + repeatDelay;\n const totalDuration = resolvedDuration * (repeat + 1) - repeatDelay;\n return {\n generator,\n mirroredGenerator,\n mapPercentToKeyframes,\n calculatedDuration,\n resolvedDuration,\n totalDuration,\n };\n }\n onPostResolved() {\n const { autoplay = true } = this.options;\n this.play();\n if (this.pendingPlayState === \"paused\" || !autoplay) {\n this.pause();\n }\n else {\n this.state = this.pendingPlayState;\n }\n }\n tick(timestamp, sample = false) {\n const { resolved } = this;\n // If the animations has failed to resolve, return the final keyframe.\n if (!resolved) {\n const { keyframes } = this.options;\n return { done: true, value: keyframes[keyframes.length - 1] };\n }\n const { finalKeyframe, generator, mirroredGenerator, mapPercentToKeyframes, keyframes, calculatedDuration, totalDuration, resolvedDuration, } = resolved;\n if (this.startTime === null)\n return generator.next(0);\n const { delay, repeat, repeatType, repeatDelay, onUpdate } = this.options;\n /**\n * requestAnimationFrame timestamps can come through as lower than\n * the startTime as set by performance.now(). Here we prevent this,\n * though in the future it could be possible to make setting startTime\n * a pending operation that gets resolved here.\n */\n if (this.speed > 0) {\n this.startTime = Math.min(this.startTime, timestamp);\n }\n else if (this.speed < 0) {\n this.startTime = Math.min(timestamp - totalDuration / this.speed, this.startTime);\n }\n // Update currentTime\n if (sample) {\n this.currentTime = timestamp;\n }\n else if (this.holdTime !== null) {\n this.currentTime = this.holdTime;\n }\n else {\n // Rounding the time because floating point arithmetic is not always accurate, e.g. 3000.367 - 1000.367 =\n // 2000.0000000000002. This is a problem when we are comparing the currentTime with the duration, for\n // example.\n this.currentTime =\n Math.round(timestamp - this.startTime) * this.speed;\n }\n // Rebase on delay\n const timeWithoutDelay = this.currentTime - delay * (this.speed >= 0 ? 1 : -1);\n const isInDelayPhase = this.speed >= 0\n ? timeWithoutDelay < 0\n : timeWithoutDelay > totalDuration;\n this.currentTime = Math.max(timeWithoutDelay, 0);\n // If this animation has finished, set the current time to the total duration.\n if (this.state === \"finished\" && this.holdTime === null) {\n this.currentTime = totalDuration;\n }\n let elapsed = this.currentTime;\n let frameGenerator = generator;\n if (repeat) {\n /**\n * Get the current progress (0-1) of the animation. If t is >\n * than duration we'll get values like 2.5 (midway through the\n * third iteration)\n */\n const progress = Math.min(this.currentTime, totalDuration) / resolvedDuration;\n /**\n * Get the current iteration (0 indexed). For instance the floor of\n * 2.5 is 2.\n */\n let currentIteration = Math.floor(progress);\n /**\n * Get the current progress of the iteration by taking the remainder\n * so 2.5 is 0.5 through iteration 2\n */\n let iterationProgress = progress % 1.0;\n /**\n * If iteration progress is 1 we count that as the end\n * of the previous iteration.\n */\n if (!iterationProgress && progress >= 1) {\n iterationProgress = 1;\n }\n iterationProgress === 1 && currentIteration--;\n currentIteration = Math.min(currentIteration, repeat + 1);\n /**\n * Reverse progress if we're not running in \"normal\" direction\n */\n const isOddIteration = Boolean(currentIteration % 2);\n if (isOddIteration) {\n if (repeatType === \"reverse\") {\n iterationProgress = 1 - iterationProgress;\n if (repeatDelay) {\n iterationProgress -= repeatDelay / resolvedDuration;\n }\n }\n else if (repeatType === \"mirror\") {\n frameGenerator = mirroredGenerator;\n }\n }\n elapsed = clamp(0, 1, iterationProgress) * resolvedDuration;\n }\n /**\n * If we're in negative time, set state as the initial keyframe.\n * This prevents delay: x, duration: 0 animations from finishing\n * instantly.\n */\n const state = isInDelayPhase\n ? { done: false, value: keyframes[0] }\n : frameGenerator.next(elapsed);\n if (mapPercentToKeyframes) {\n state.value = mapPercentToKeyframes(state.value);\n }\n let { done } = state;\n if (!isInDelayPhase && calculatedDuration !== null) {\n done =\n this.speed >= 0\n ? this.currentTime >= totalDuration\n : this.currentTime <= 0;\n }\n const isAnimationFinished = this.holdTime === null &&\n (this.state === \"finished\" || (this.state === \"running\" && done));\n if (isAnimationFinished && finalKeyframe !== undefined) {\n state.value = getFinalKeyframe(keyframes, this.options, finalKeyframe);\n }\n if (onUpdate) {\n onUpdate(state.value);\n }\n if (isAnimationFinished) {\n this.finish();\n }\n return state;\n }\n get duration() {\n const { resolved } = this;\n return resolved ? millisecondsToSeconds(resolved.calculatedDuration) : 0;\n }\n get time() {\n return millisecondsToSeconds(this.currentTime);\n }\n set time(newTime) {\n newTime = secondsToMilliseconds(newTime);\n this.currentTime = newTime;\n if (this.holdTime !== null || this.speed === 0) {\n this.holdTime = newTime;\n }\n else if (this.driver) {\n this.startTime = this.driver.now() - newTime / this.speed;\n }\n }\n get speed() {\n return this.playbackSpeed;\n }\n set speed(newSpeed) {\n const hasChanged = this.playbackSpeed !== newSpeed;\n this.playbackSpeed = newSpeed;\n if (hasChanged) {\n this.time = millisecondsToSeconds(this.currentTime);\n }\n }\n play() {\n if (!this.resolver.isScheduled) {\n this.resolver.resume();\n }\n if (!this._resolved) {\n this.pendingPlayState = \"running\";\n return;\n }\n if (this.isStopped)\n return;\n const { driver = frameloopDriver, onPlay, startTime } = this.options;\n if (!this.driver) {\n this.driver = driver((timestamp) => this.tick(timestamp));\n }\n onPlay && onPlay();\n const now = this.driver.now();\n if (this.holdTime !== null) {\n this.startTime = now - this.holdTime;\n }\n else if (!this.startTime) {\n this.startTime = startTime !== null && startTime !== void 0 ? startTime : this.calcStartTime();\n }\n else if (this.state === \"finished\") {\n this.startTime = now;\n }\n if (this.state === \"finished\") {\n this.updateFinishedPromise();\n }\n this.cancelTime = this.startTime;\n this.holdTime = null;\n /**\n * Set playState to running only after we've used it in\n * the previous logic.\n */\n this.state = \"running\";\n this.driver.start();\n }\n pause() {\n var _a;\n if (!this._resolved) {\n this.pendingPlayState = \"paused\";\n return;\n }\n this.state = \"paused\";\n this.holdTime = (_a = this.currentTime) !== null && _a !== void 0 ? _a : 0;\n }\n complete() {\n if (this.state !== \"running\") {\n this.play();\n }\n this.pendingPlayState = this.state = \"finished\";\n this.holdTime = null;\n }\n finish() {\n this.teardown();\n this.state = \"finished\";\n const { onComplete } = this.options;\n onComplete && onComplete();\n }\n cancel() {\n if (this.cancelTime !== null) {\n this.tick(this.cancelTime);\n }\n this.teardown();\n this.updateFinishedPromise();\n }\n teardown() {\n this.state = \"idle\";\n this.stopDriver();\n this.resolveFinishedPromise();\n this.updateFinishedPromise();\n this.startTime = this.cancelTime = null;\n this.resolver.cancel();\n }\n stopDriver() {\n if (!this.driver)\n return;\n this.driver.stop();\n this.driver = undefined;\n }\n sample(time) {\n this.startTime = 0;\n return this.tick(time, true);\n }\n}\n// Legacy interface\nfunction animateValue(options) {\n return new MainThreadAnimation(options);\n}\n\nexport { MainThreadAnimation, animateValue };\n","import { time } from '../../../frameloop/sync-time.mjs';\nimport { frame, cancelFrame, frameData } from '../../../frameloop/frame.mjs';\n\nconst frameloopDriver = (update) => {\n const passTimestamp = ({ timestamp }) => update(timestamp);\n return {\n start: () => frame.update(passTimestamp, true),\n stop: () => cancelFrame(passTimestamp),\n /**\n * If we're processing this frame we can use the\n * framelocked timestamp to keep things in sync.\n */\n now: () => (frameData.isProcessing ? frameData.timestamp : time.now()),\n };\n};\n\nexport { frameloopDriver };\n","/**\n * A list of values that can be hardware-accelerated.\n */\nconst acceleratedValues = new Set([\n \"opacity\",\n \"clipPath\",\n \"filter\",\n \"transform\",\n // TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved\n // or until we implement support for linear() easing.\n // \"background-color\"\n]);\n\nexport { acceleratedValues };\n","import { warning } from '../../../utils/errors.mjs';\nimport { isAnimatable } from '../../utils/is-animatable.mjs';\n\nfunction hasKeyframesChanged(keyframes) {\n const current = keyframes[0];\n if (keyframes.length === 1)\n return true;\n for (let i = 0; i < keyframes.length; i++) {\n if (keyframes[i] !== current)\n return true;\n }\n}\nfunction canAnimate(keyframes, name, type, velocity) {\n /**\n * Check if we're able to animate between the start and end keyframes,\n * and throw a warning if we're attempting to animate between one that's\n * animatable and another that isn't.\n */\n const originKeyframe = keyframes[0];\n if (originKeyframe === null)\n return false;\n /**\n * These aren't traditionally animatable but we do support them.\n * In future we could look into making this more generic or replacing\n * this function with mix() === mixImmediate\n */\n if (name === \"display\" || name === \"visibility\")\n return true;\n const targetKeyframe = keyframes[keyframes.length - 1];\n const isOriginAnimatable = isAnimatable(originKeyframe, name);\n const isTargetAnimatable = isAnimatable(targetKeyframe, name);\n warning(isOriginAnimatable === isTargetAnimatable, `You are trying to animate ${name} from \"${originKeyframe}\" to \"${targetKeyframe}\". ${originKeyframe} is not an animatable value - to enable this animation set ${originKeyframe} to a value animatable to ${targetKeyframe} via the \\`style\\` property.`);\n // Always skip if any of these are true\n if (!isOriginAnimatable || !isTargetAnimatable) {\n return false;\n }\n return hasKeyframesChanged(keyframes) || (type === \"spring\" && velocity);\n}\n\nexport { canAnimate };\n","import { isBezierDefinition } from '../../../easing/utils/is-bezier-definition.mjs';\n\nfunction isWaapiSupportedEasing(easing) {\n return Boolean(!easing ||\n (typeof easing === \"string\" && easing in supportedWaapiEasing) ||\n isBezierDefinition(easing) ||\n (Array.isArray(easing) && easing.every(isWaapiSupportedEasing)));\n}\nconst cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;\nconst supportedWaapiEasing = {\n linear: \"linear\",\n ease: \"ease\",\n easeIn: \"ease-in\",\n easeOut: \"ease-out\",\n easeInOut: \"ease-in-out\",\n circIn: cubicBezierAsString([0, 0.65, 0.55, 1]),\n circOut: cubicBezierAsString([0.55, 0, 1, 0.45]),\n backIn: cubicBezierAsString([0.31, 0.01, 0.66, -0.59]),\n backOut: cubicBezierAsString([0.33, 1.53, 0.69, 0.99]),\n};\nfunction mapEasingToNativeEasingWithDefault(easing) {\n return (mapEasingToNativeEasing(easing) ||\n supportedWaapiEasing.easeOut);\n}\nfunction mapEasingToNativeEasing(easing) {\n if (!easing) {\n return undefined;\n }\n else if (isBezierDefinition(easing)) {\n return cubicBezierAsString(easing);\n }\n else if (Array.isArray(easing)) {\n return easing.map(mapEasingToNativeEasingWithDefault);\n }\n else {\n return supportedWaapiEasing[easing];\n }\n}\n\nexport { cubicBezierAsString, isWaapiSupportedEasing, mapEasingToNativeEasing, supportedWaapiEasing };\n","import { mapEasingToNativeEasing } from './easing.mjs';\n\nfunction animateStyle(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = \"loop\", ease, times, } = {}) {\n const keyframeOptions = { [valueName]: keyframes };\n if (times)\n keyframeOptions.offset = times;\n const easing = mapEasingToNativeEasing(ease);\n /**\n * If this is an easing array, apply to keyframes, not animation as a whole\n */\n if (Array.isArray(easing))\n keyframeOptions.easing = easing;\n return element.animate(keyframeOptions, {\n delay,\n duration,\n easing: !Array.isArray(easing) ? easing : \"linear\",\n fill: \"both\",\n iterations: repeat + 1,\n direction: repeatType === \"reverse\" ? \"alternate\" : \"normal\",\n });\n}\n\nexport { animateStyle };\n","const isNotNull = (value) => value !== null;\nfunction getFinalKeyframe(keyframes, { repeat, repeatType = \"loop\" }, finalKeyframe) {\n const resolvedKeyframes = keyframes.filter(isNotNull);\n const index = repeat && repeatType !== \"loop\" && repeat % 2 === 1\n ? 0\n : resolvedKeyframes.length - 1;\n return !index || finalKeyframe === undefined\n ? resolvedKeyframes[index]\n : finalKeyframe;\n}\n\nexport { getFinalKeyframe };\n","import { spring } from './spring/index.mjs';\nimport { calcGeneratorVelocity } from './utils/velocity.mjs';\n\nfunction inertia({ keyframes, velocity = 0.0, power = 0.8, timeConstant = 325, bounceDamping = 10, bounceStiffness = 500, modifyTarget, min, max, restDelta = 0.5, restSpeed, }) {\n const origin = keyframes[0];\n const state = {\n done: false,\n value: origin,\n };\n const isOutOfBounds = (v) => (min !== undefined && v < min) || (max !== undefined && v > max);\n const nearestBoundary = (v) => {\n if (min === undefined)\n return max;\n if (max === undefined)\n return min;\n return Math.abs(min - v) < Math.abs(max - v) ? min : max;\n };\n let amplitude = power * velocity;\n const ideal = origin + amplitude;\n const target = modifyTarget === undefined ? ideal : modifyTarget(ideal);\n /**\n * If the target has changed we need to re-calculate the amplitude, otherwise\n * the animation will start from the wrong position.\n */\n if (target !== ideal)\n amplitude = target - origin;\n const calcDelta = (t) => -amplitude * Math.exp(-t / timeConstant);\n const calcLatest = (t) => target + calcDelta(t);\n const applyFriction = (t) => {\n const delta = calcDelta(t);\n const latest = calcLatest(t);\n state.done = Math.abs(delta) <= restDelta;\n state.value = state.done ? target : latest;\n };\n /**\n * Ideally this would resolve for t in a stateless way, we could\n * do that by always precalculating the animation but as we know\n * this will be done anyway we can assume that spring will\n * be discovered during that.\n */\n let timeReachedBoundary;\n let spring$1;\n const checkCatchBoundary = (t) => {\n if (!isOutOfBounds(state.value))\n return;\n timeReachedBoundary = t;\n spring$1 = spring({\n keyframes: [state.value, nearestBoundary(state.value)],\n velocity: calcGeneratorVelocity(calcLatest, t, state.value), // TODO: This should be passing * 1000\n damping: bounceDamping,\n stiffness: bounceStiffness,\n restDelta,\n restSpeed,\n });\n };\n checkCatchBoundary(0);\n return {\n calculatedDuration: null,\n next: (t) => {\n /**\n * We need to resolve the friction to figure out if we need a\n * spring but we don't want to do this twice per frame. So here\n * we flag if we updated for this frame and later if we did\n * we can skip doing it again.\n */\n let hasUpdatedFrame = false;\n if (!spring$1 && timeReachedBoundary === undefined) {\n hasUpdatedFrame = true;\n applyFriction(t);\n checkCatchBoundary(t);\n }\n /**\n * If we have a spring and the provided t is beyond the moment the friction\n * animation crossed the min/max boundary, use the spring.\n */\n if (timeReachedBoundary !== undefined && t >= timeReachedBoundary) {\n return spring$1.next(t - timeReachedBoundary);\n }\n else {\n !hasUpdatedFrame && applyFriction(t);\n return state;\n }\n },\n };\n}\n\nexport { inertia };\n","import { easeInOut } from '../../easing/ease.mjs';\nimport { isEasingArray } from '../../easing/utils/is-easing-array.mjs';\nimport { easingDefinitionToFunction } from '../../easing/utils/map.mjs';\nimport { interpolate } from '../../utils/interpolate.mjs';\nimport { defaultOffset } from '../../utils/offsets/default.mjs';\nimport { convertOffsetToTimes } from '../../utils/offsets/time.mjs';\n\nfunction defaultEasing(values, easing) {\n return values.map(() => easing || easeInOut).splice(0, values.length - 1);\n}\nfunction keyframes({ duration = 300, keyframes: keyframeValues, times, ease = \"easeInOut\", }) {\n /**\n * Easing functions can be externally defined as strings. Here we convert them\n * into actual functions.\n */\n const easingFunctions = isEasingArray(ease)\n ? ease.map(easingDefinitionToFunction)\n : easingDefinitionToFunction(ease);\n /**\n * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator\n * to reduce GC during animation.\n */\n const state = {\n done: false,\n value: keyframeValues[0],\n };\n /**\n * Create a times array based on the provided 0-1 offsets\n */\n const absoluteTimes = convertOffsetToTimes(\n // Only use the provided offsets if they're the correct length\n // TODO Maybe we should warn here if there's a length mismatch\n times && times.length === keyframeValues.length\n ? times\n : defaultOffset(keyframeValues), duration);\n const mapTimeToKeyframe = interpolate(absoluteTimes, keyframeValues, {\n ease: Array.isArray(easingFunctions)\n ? easingFunctions\n : defaultEasing(keyframeValues, easingFunctions),\n });\n return {\n calculatedDuration: duration,\n next: (t) => {\n state.value = mapTimeToKeyframe(t);\n state.done = t >= duration;\n return state;\n },\n };\n}\n\nexport { defaultEasing, keyframes };\n","import { warning } from '../../../utils/errors.mjs';\nimport { clamp } from '../../../utils/clamp.mjs';\nimport { secondsToMilliseconds, millisecondsToSeconds } from '../../../utils/time-conversion.mjs';\n\nconst safeMin = 0.001;\nconst minDuration = 0.01;\nconst maxDuration = 10.0;\nconst minDamping = 0.05;\nconst maxDamping = 1;\nfunction findSpring({ duration = 800, bounce = 0.25, velocity = 0, mass = 1, }) {\n let envelope;\n let derivative;\n warning(duration <= secondsToMilliseconds(maxDuration), \"Spring duration must be 10 seconds or less\");\n let dampingRatio = 1 - bounce;\n /**\n * Restrict dampingRatio and duration to within acceptable ranges.\n */\n dampingRatio = clamp(minDamping, maxDamping, dampingRatio);\n duration = clamp(minDuration, maxDuration, millisecondsToSeconds(duration));\n if (dampingRatio < 1) {\n /**\n * Underdamped spring\n */\n envelope = (undampedFreq) => {\n const exponentialDecay = undampedFreq * dampingRatio;\n const delta = exponentialDecay * duration;\n const a = exponentialDecay - velocity;\n const b = calcAngularFreq(undampedFreq, dampingRatio);\n const c = Math.exp(-delta);\n return safeMin - (a / b) * c;\n };\n derivative = (undampedFreq) => {\n const exponentialDecay = undampedFreq * dampingRatio;\n const delta = exponentialDecay * duration;\n const d = delta * velocity + velocity;\n const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;\n const f = Math.exp(-delta);\n const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);\n const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;\n return (factor * ((d - e) * f)) / g;\n };\n }\n else {\n /**\n * Critically-damped spring\n */\n envelope = (undampedFreq) => {\n const a = Math.exp(-undampedFreq * duration);\n const b = (undampedFreq - velocity) * duration + 1;\n return -safeMin + a * b;\n };\n derivative = (undampedFreq) => {\n const a = Math.exp(-undampedFreq * duration);\n const b = (velocity - undampedFreq) * (duration * duration);\n return a * b;\n };\n }\n const initialGuess = 5 / duration;\n const undampedFreq = approximateRoot(envelope, derivative, initialGuess);\n duration = secondsToMilliseconds(duration);\n if (isNaN(undampedFreq)) {\n return {\n stiffness: 100,\n damping: 10,\n duration,\n };\n }\n else {\n const stiffness = Math.pow(undampedFreq, 2) * mass;\n return {\n stiffness,\n damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),\n duration,\n };\n }\n}\nconst rootIterations = 12;\nfunction approximateRoot(envelope, derivative, initialGuess) {\n let result = initialGuess;\n for (let i = 1; i < rootIterations; i++) {\n result = result - envelope(result) / derivative(result);\n }\n return result;\n}\nfunction calcAngularFreq(undampedFreq, dampingRatio) {\n return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);\n}\n\nexport { calcAngularFreq, findSpring, maxDamping, maxDuration, minDamping, minDuration };\n","import { millisecondsToSeconds, secondsToMilliseconds } from '../../../utils/time-conversion.mjs';\nimport { calcGeneratorVelocity } from '../utils/velocity.mjs';\nimport { findSpring, calcAngularFreq } from './find.mjs';\n\nconst durationKeys = [\"duration\", \"bounce\"];\nconst physicsKeys = [\"stiffness\", \"damping\", \"mass\"];\nfunction isSpringType(options, keys) {\n return keys.some((key) => options[key] !== undefined);\n}\nfunction getSpringOptions(options) {\n let springOptions = {\n velocity: 0.0,\n stiffness: 100,\n damping: 10,\n mass: 1.0,\n isResolvedFromDuration: false,\n ...options,\n };\n // stiffness/damping/mass overrides duration/bounce\n if (!isSpringType(options, physicsKeys) &&\n isSpringType(options, durationKeys)) {\n const derived = findSpring(options);\n springOptions = {\n ...springOptions,\n ...derived,\n mass: 1.0,\n };\n springOptions.isResolvedFromDuration = true;\n }\n return springOptions;\n}\nfunction spring({ keyframes, restDelta, restSpeed, ...options }) {\n const origin = keyframes[0];\n const target = keyframes[keyframes.length - 1];\n /**\n * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator\n * to reduce GC during animation.\n */\n const state = { done: false, value: origin };\n const { stiffness, damping, mass, duration, velocity, isResolvedFromDuration, } = getSpringOptions({\n ...options,\n velocity: -millisecondsToSeconds(options.velocity || 0),\n });\n const initialVelocity = velocity || 0.0;\n const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));\n const initialDelta = target - origin;\n const undampedAngularFreq = millisecondsToSeconds(Math.sqrt(stiffness / mass));\n /**\n * If we're working on a granular scale, use smaller defaults for determining\n * when the spring is finished.\n *\n * These defaults have been selected emprically based on what strikes a good\n * ratio between feeling good and finishing as soon as changes are imperceptible.\n */\n const isGranularScale = Math.abs(initialDelta) < 5;\n restSpeed || (restSpeed = isGranularScale ? 0.01 : 2);\n restDelta || (restDelta = isGranularScale ? 0.005 : 0.5);\n let resolveSpring;\n if (dampingRatio < 1) {\n const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);\n // Underdamped spring\n resolveSpring = (t) => {\n const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n return (target -\n envelope *\n (((initialVelocity +\n dampingRatio * undampedAngularFreq * initialDelta) /\n angularFreq) *\n Math.sin(angularFreq * t) +\n initialDelta * Math.cos(angularFreq * t)));\n };\n }\n else if (dampingRatio === 1) {\n // Critically damped spring\n resolveSpring = (t) => target -\n Math.exp(-undampedAngularFreq * t) *\n (initialDelta +\n (initialVelocity + undampedAngularFreq * initialDelta) * t);\n }\n else {\n // Overdamped spring\n const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);\n resolveSpring = (t) => {\n const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n // When performing sinh or cosh values can hit Infinity so we cap them here\n const freqForT = Math.min(dampedAngularFreq * t, 300);\n return (target -\n (envelope *\n ((initialVelocity +\n dampingRatio * undampedAngularFreq * initialDelta) *\n Math.sinh(freqForT) +\n dampedAngularFreq *\n initialDelta *\n Math.cosh(freqForT))) /\n dampedAngularFreq);\n };\n }\n return {\n calculatedDuration: isResolvedFromDuration ? duration || null : null,\n next: (t) => {\n const current = resolveSpring(t);\n if (!isResolvedFromDuration) {\n let currentVelocity = 0.0;\n /**\n * We only need to calculate velocity for under-damped springs\n * as over- and critically-damped springs can't overshoot, so\n * checking only for displacement is enough.\n */\n if (dampingRatio < 1) {\n currentVelocity =\n t === 0\n ? secondsToMilliseconds(initialVelocity)\n : calcGeneratorVelocity(resolveSpring, t, current);\n }\n const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;\n const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;\n state.done =\n isBelowVelocityThreshold && isBelowDisplacementThreshold;\n }\n else {\n state.done = t >= duration;\n }\n state.value = state.done ? target : current;\n return state;\n },\n };\n}\n\nexport { spring };\n","/**\n * Implement a practical max duration for keyframe generation\n * to prevent infinite loops\n */\nconst maxGeneratorDuration = 20000;\nfunction calcGeneratorDuration(generator) {\n let duration = 0;\n const timeStep = 50;\n let state = generator.next(duration);\n while (!state.done && duration < maxGeneratorDuration) {\n duration += timeStep;\n state = generator.next(duration);\n }\n return duration >= maxGeneratorDuration ? Infinity : duration;\n}\n\nexport { calcGeneratorDuration, maxGeneratorDuration };\n","import { velocityPerSecond } from '../../../utils/velocity-per-second.mjs';\n\nconst velocitySampleDuration = 5; // ms\nfunction calcGeneratorVelocity(resolveValue, t, current) {\n const prevT = Math.max(t - velocitySampleDuration, 0);\n return velocityPerSecond(current - resolveValue(prevT), t - prevT);\n}\n\nexport { calcGeneratorVelocity };\n","import { secondsToMilliseconds } from '../../utils/time-conversion.mjs';\nimport { getDefaultTransition } from '../utils/default-transitions.mjs';\nimport { getValueTransition, isTransitionDefined } from '../utils/transitions.mjs';\nimport { MotionGlobalConfig } from '../../utils/GlobalConfig.mjs';\nimport { instantAnimationState } from '../../utils/use-instant-transition-state.mjs';\nimport { getFinalKeyframe } from '../animators/waapi/utils/get-final-keyframe.mjs';\nimport { frame } from '../../frameloop/frame.mjs';\nimport { AcceleratedAnimation } from '../animators/AcceleratedAnimation.mjs';\nimport { MainThreadAnimation } from '../animators/MainThreadAnimation.mjs';\nimport { GroupPlaybackControls } from '../GroupPlaybackControls.mjs';\n\nconst animateMotionValue = (name, value, target, transition = {}, element, isHandoff, \n/**\n * Currently used to remove values from will-change when an animation ends.\n * Preferably this would be handled by event listeners on the MotionValue\n * but these aren't consistent enough yet when considering the different ways\n * an animation can be cancelled.\n */\nonEnd) => (onComplete) => {\n const valueTransition = getValueTransition(transition, name) || {};\n /**\n * Most transition values are currently completely overwritten by value-specific\n * transitions. In the future it'd be nicer to blend these transitions. But for now\n * delay actually does inherit from the root transition if not value-specific.\n */\n const delay = valueTransition.delay || transition.delay || 0;\n /**\n * Elapsed isn't a public transition option but can be passed through from\n * optimized appear effects in milliseconds.\n */\n let { elapsed = 0 } = transition;\n elapsed = elapsed - secondsToMilliseconds(delay);\n let options = {\n keyframes: Array.isArray(target) ? target : [null, target],\n ease: \"easeOut\",\n velocity: value.getVelocity(),\n ...valueTransition,\n delay: -elapsed,\n onUpdate: (v) => {\n value.set(v);\n valueTransition.onUpdate && valueTransition.onUpdate(v);\n },\n onComplete: () => {\n onComplete();\n valueTransition.onComplete && valueTransition.onComplete();\n onEnd && onEnd();\n },\n onStop: onEnd,\n name,\n motionValue: value,\n element: isHandoff ? undefined : element,\n };\n /**\n * If there's no transition defined for this value, we can generate\n * unqiue transition settings for this value.\n */\n if (!isTransitionDefined(valueTransition)) {\n options = {\n ...options,\n ...getDefaultTransition(name, options),\n };\n }\n /**\n * Both WAAPI and our internal animation functions use durations\n * as defined by milliseconds, while our external API defines them\n * as seconds.\n */\n if (options.duration) {\n options.duration = secondsToMilliseconds(options.duration);\n }\n if (options.repeatDelay) {\n options.repeatDelay = secondsToMilliseconds(options.repeatDelay);\n }\n if (options.from !== undefined) {\n options.keyframes[0] = options.from;\n }\n let shouldSkip = false;\n if (options.type === false ||\n (options.duration === 0 && !options.repeatDelay)) {\n options.duration = 0;\n if (options.delay === 0) {\n shouldSkip = true;\n }\n }\n if (instantAnimationState.current ||\n MotionGlobalConfig.skipAnimations) {\n shouldSkip = true;\n options.duration = 0;\n options.delay = 0;\n }\n /**\n * If we can or must skip creating the animation, and apply only\n * the final keyframe, do so. We also check once keyframes are resolved but\n * this early check prevents the need to create an animation at all.\n */\n if (shouldSkip && !isHandoff && value.get() !== undefined) {\n const finalKeyframe = getFinalKeyframe(options.keyframes, valueTransition);\n if (finalKeyframe !== undefined) {\n frame.update(() => {\n options.onUpdate(finalKeyframe);\n options.onComplete();\n });\n // We still want to return some animation controls here rather\n // than returning undefined\n return new GroupPlaybackControls([]);\n }\n }\n /**\n * Animate via WAAPI if possible. If this is a handoff animation, the optimised animation will be running via\n * WAAPI. Therefore, this animation must be JS to ensure it runs \"under\" the\n * optimised animation.\n */\n if (!isHandoff && AcceleratedAnimation.supports(options)) {\n return new AcceleratedAnimation(options);\n }\n else {\n return new MainThreadAnimation(options);\n }\n};\n\nexport { animateMotionValue };\n","import { animateMotionValue } from './motion-value.mjs';\nimport { motionValue } from '../../value/index.mjs';\nimport { isMotionValue } from '../../value/utils/is-motion-value.mjs';\n\nfunction animateSingleValue(value, keyframes, options) {\n const motionValue$1 = isMotionValue(value) ? value : motionValue(value);\n motionValue$1.start(animateMotionValue(\"\", motionValue$1, keyframes, options));\n return motionValue$1.animation;\n}\n\nexport { animateSingleValue };\n","import { transformProps } from '../../render/html/utils/transform.mjs';\nimport { animateMotionValue } from './motion-value.mjs';\nimport { setTarget } from '../../render/utils/setters.mjs';\nimport { getValueTransition } from '../utils/transitions.mjs';\nimport { getOptimisedAppearId } from '../optimized-appear/get-appear-id.mjs';\nimport { addValueToWillChange } from '../../value/use-will-change/add-will-change.mjs';\nimport { frame } from '../../frameloop/frame.mjs';\n\n/**\n * Decide whether we should block this animation. Previously, we achieved this\n * just by checking whether the key was listed in protectedKeys, but this\n * posed problems if an animation was triggered by afterChildren and protectedKeys\n * had been set to true in the meantime.\n */\nfunction shouldBlockAnimation({ protectedKeys, needsAnimating }, key) {\n const shouldBlock = protectedKeys.hasOwnProperty(key) && needsAnimating[key] !== true;\n needsAnimating[key] = false;\n return shouldBlock;\n}\nfunction animateTarget(visualElement, targetAndTransition, { delay = 0, transitionOverride, type } = {}) {\n var _a;\n let { transition = visualElement.getDefaultTransition(), transitionEnd, ...target } = targetAndTransition;\n if (transitionOverride)\n transition = transitionOverride;\n const animations = [];\n const animationTypeState = type &&\n visualElement.animationState &&\n visualElement.animationState.getState()[type];\n for (const key in target) {\n const value = visualElement.getValue(key, (_a = visualElement.latestValues[key]) !== null && _a !== void 0 ? _a : null);\n const valueTarget = target[key];\n if (valueTarget === undefined ||\n (animationTypeState &&\n shouldBlockAnimation(animationTypeState, key))) {\n continue;\n }\n const valueTransition = {\n delay,\n ...getValueTransition(transition || {}, key),\n };\n /**\n * If this is the first time a value is being animated, check\n * to see if we're handling off from an existing animation.\n */\n let isHandoff = false;\n if (window.MotionHandoffAnimation) {\n const appearId = getOptimisedAppearId(visualElement);\n if (appearId) {\n const startTime = window.MotionHandoffAnimation(appearId, key, frame);\n if (startTime !== null) {\n valueTransition.startTime = startTime;\n isHandoff = true;\n }\n }\n }\n value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && transformProps.has(key)\n ? { type: false }\n : valueTransition, visualElement, isHandoff, addValueToWillChange(visualElement, key)));\n const animation = value.animation;\n if (animation) {\n animations.push(animation);\n }\n }\n if (transitionEnd) {\n Promise.all(animations).then(() => {\n frame.update(() => {\n transitionEnd && setTarget(visualElement, transitionEnd);\n });\n });\n }\n return animations;\n}\n\nexport { animateTarget };\n","import { resolveVariant } from '../../render/utils/resolve-dynamic-variants.mjs';\nimport { animateTarget } from './visual-element-target.mjs';\n\nfunction animateVariant(visualElement, variant, options = {}) {\n var _a;\n const resolved = resolveVariant(visualElement, variant, options.type === \"exit\"\n ? (_a = visualElement.presenceContext) === null || _a === void 0 ? void 0 : _a.custom\n : undefined);\n let { transition = visualElement.getDefaultTransition() || {} } = resolved || {};\n if (options.transitionOverride) {\n transition = options.transitionOverride;\n }\n /**\n * If we have a variant, create a callback that runs it as an animation.\n * Otherwise, we resolve a Promise immediately for a composable no-op.\n */\n const getAnimation = resolved\n ? () => Promise.all(animateTarget(visualElement, resolved, options))\n : () => Promise.resolve();\n /**\n * If we have children, create a callback that runs all their animations.\n * Otherwise, we resolve a Promise immediately for a composable no-op.\n */\n const getChildAnimations = visualElement.variantChildren && visualElement.variantChildren.size\n ? (forwardDelay = 0) => {\n const { delayChildren = 0, staggerChildren, staggerDirection, } = transition;\n return animateChildren(visualElement, variant, delayChildren + forwardDelay, staggerChildren, staggerDirection, options);\n }\n : () => Promise.resolve();\n /**\n * If the transition explicitly defines a \"when\" option, we need to resolve either\n * this animation or all children animations before playing the other.\n */\n const { when } = transition;\n if (when) {\n const [first, last] = when === \"beforeChildren\"\n ? [getAnimation, getChildAnimations]\n : [getChildAnimations, getAnimation];\n return first().then(() => last());\n }\n else {\n return Promise.all([getAnimation(), getChildAnimations(options.delay)]);\n }\n}\nfunction animateChildren(visualElement, variant, delayChildren = 0, staggerChildren = 0, staggerDirection = 1, options) {\n const animations = [];\n const maxStaggerDuration = (visualElement.variantChildren.size - 1) * staggerChildren;\n const generateStaggerDuration = staggerDirection === 1\n ? (i = 0) => i * staggerChildren\n : (i = 0) => maxStaggerDuration - i * staggerChildren;\n Array.from(visualElement.variantChildren)\n .sort(sortByTreeOrder)\n .forEach((child, i) => {\n child.notify(\"AnimationStart\", variant);\n animations.push(animateVariant(child, variant, {\n ...options,\n delay: delayChildren + generateStaggerDuration(i),\n }).then(() => child.notify(\"AnimationComplete\", variant)));\n });\n return Promise.all(animations);\n}\nfunction sortByTreeOrder(a, b) {\n return a.sortNodePosition(b);\n}\n\nexport { animateVariant, sortByTreeOrder };\n","import { resolveVariant } from '../../render/utils/resolve-dynamic-variants.mjs';\nimport { animateTarget } from './visual-element-target.mjs';\nimport { animateVariant } from './visual-element-variant.mjs';\n\nfunction animateVisualElement(visualElement, definition, options = {}) {\n visualElement.notify(\"AnimationStart\", definition);\n let animation;\n if (Array.isArray(definition)) {\n const animations = definition.map((variant) => animateVariant(visualElement, variant, options));\n animation = Promise.all(animations);\n }\n else if (typeof definition === \"string\") {\n animation = animateVariant(visualElement, definition, options);\n }\n else {\n const resolvedDefinition = typeof definition === \"function\"\n ? resolveVariant(visualElement, definition, options.custom)\n : definition;\n animation = Promise.all(animateTarget(visualElement, resolvedDefinition, options));\n }\n return animation.then(() => {\n visualElement.notify(\"AnimationComplete\", definition);\n });\n}\n\nexport { animateVisualElement };\n","import { camelToDash } from '../../render/dom/utils/camel-to-dash.mjs';\n\nconst optimizedAppearDataId = \"framerAppearId\";\nconst optimizedAppearDataAttribute = \"data-\" + camelToDash(optimizedAppearDataId);\n\nexport { optimizedAppearDataAttribute, optimizedAppearDataId };\n","import { optimizedAppearDataAttribute } from './data-id.mjs';\n\nfunction getOptimisedAppearId(visualElement) {\n return visualElement.props[optimizedAppearDataAttribute];\n}\n\nexport { getOptimisedAppearId };\n","import { transformProps } from '../../render/html/utils/transform.mjs';\n\nconst underDampedSpring = {\n type: \"spring\",\n stiffness: 500,\n damping: 25,\n restSpeed: 10,\n};\nconst criticallyDampedSpring = (target) => ({\n type: \"spring\",\n stiffness: 550,\n damping: target === 0 ? 2 * Math.sqrt(550) : 30,\n restSpeed: 10,\n});\nconst keyframesTransition = {\n type: \"keyframes\",\n duration: 0.8,\n};\n/**\n * Default easing curve is a slightly shallower version of\n * the default browser easing curve.\n */\nconst ease = {\n type: \"keyframes\",\n ease: [0.25, 0.1, 0.35, 1],\n duration: 0.3,\n};\nconst getDefaultTransition = (valueKey, { keyframes }) => {\n if (keyframes.length > 2) {\n return keyframesTransition;\n }\n else if (transformProps.has(valueKey)) {\n return valueKey.startsWith(\"scale\")\n ? criticallyDampedSpring(keyframes[1])\n : underDampedSpring;\n }\n return ease;\n};\n\nexport { getDefaultTransition };\n","import { complex } from '../../value/types/complex/index.mjs';\n\n/**\n * Check if a value is animatable. Examples:\n *\n * ✅: 100, \"100px\", \"#fff\"\n * ❌: \"block\", \"url(2.jpg)\"\n * @param value\n *\n * @internal\n */\nconst isAnimatable = (value, name) => {\n // If the list of keys tat might be non-animatable grows, replace with Set\n if (name === \"zIndex\")\n return false;\n // If it's a number or a keyframes array, we can animate it. We might at some point\n // need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,\n // but for now lets leave it like this for performance reasons\n if (typeof value === \"number\" || Array.isArray(value))\n return true;\n if (typeof value === \"string\" && // It's animatable if we have a string\n (complex.test(value) || value === \"0\") && // And it contains numbers and/or colors\n !value.startsWith(\"url(\") // Unless it starts with \"url(\"\n ) {\n return true;\n }\n return false;\n};\n\nexport { isAnimatable };\n","function isAnimationControls(v) {\n return (v !== null &&\n typeof v === \"object\" &&\n typeof v.start === \"function\");\n}\n\nexport { isAnimationControls };\n","const isKeyframesTarget = (v) => {\n return Array.isArray(v);\n};\n\nexport { isKeyframesTarget };\n","import { isZeroValueString } from '../../utils/is-zero-value-string.mjs';\n\nfunction isNone(value) {\n if (typeof value === \"number\") {\n return value === 0;\n }\n else if (value !== null) {\n return value === \"none\" || value === \"0\" || isZeroValueString(value);\n }\n else {\n return true;\n }\n}\n\nexport { isNone };\n","/**\n * Decide whether a transition is defined on a given Transition.\n * This filters out orchestration options and returns true\n * if any options are left.\n */\nfunction isTransitionDefined({ when, delay: _delay, delayChildren, staggerChildren, staggerDirection, repeat, repeatType, repeatDelay, from, elapsed, ...transition }) {\n return !!Object.keys(transition).length;\n}\nfunction getValueTransition(transition, key) {\n return (transition[key] ||\n transition[\"default\"] ||\n transition);\n}\n\nexport { getValueTransition, isTransitionDefined };\n","\"use client\";\nimport { jsx } from 'react/jsx-runtime';\nimport * as React from 'react';\nimport { useId, useRef, useContext, useInsertionEffect } from 'react';\nimport { MotionConfigContext } from '../../context/MotionConfigContext.mjs';\n\n/**\n * Measurement functionality has to be within a separate component\n * to leverage snapshot lifecycle.\n */\nclass PopChildMeasure extends React.Component {\n getSnapshotBeforeUpdate(prevProps) {\n const element = this.props.childRef.current;\n if (element && prevProps.isPresent && !this.props.isPresent) {\n const size = this.props.sizeRef.current;\n size.height = element.offsetHeight || 0;\n size.width = element.offsetWidth || 0;\n size.top = element.offsetTop;\n size.left = element.offsetLeft;\n }\n return null;\n }\n /**\n * Required with getSnapshotBeforeUpdate to stop React complaining.\n */\n componentDidUpdate() { }\n render() {\n return this.props.children;\n }\n}\nfunction PopChild({ children, isPresent }) {\n const id = useId();\n const ref = useRef(null);\n const size = useRef({\n width: 0,\n height: 0,\n top: 0,\n left: 0,\n });\n const { nonce } = useContext(MotionConfigContext);\n /**\n * We create and inject a style block so we can apply this explicit\n * sizing in a non-destructive manner by just deleting the style block.\n *\n * We can't apply size via render as the measurement happens\n * in getSnapshotBeforeUpdate (post-render), likewise if we apply the\n * styles directly on the DOM node, we might be overwriting\n * styles set via the style prop.\n */\n useInsertionEffect(() => {\n const { width, height, top, left } = size.current;\n if (isPresent || !ref.current || !width || !height)\n return;\n ref.current.dataset.motionPopId = id;\n const style = document.createElement(\"style\");\n if (nonce)\n style.nonce = nonce;\n document.head.appendChild(style);\n if (style.sheet) {\n style.sheet.insertRule(`\n [data-motion-pop-id=\"${id}\"] {\n position: absolute !important;\n width: ${width}px !important;\n height: ${height}px !important;\n top: ${top}px !important;\n left: ${left}px !important;\n }\n `);\n }\n return () => {\n document.head.removeChild(style);\n };\n }, [isPresent]);\n return (jsx(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size, children: React.cloneElement(children, { ref }) }));\n}\n\nexport { PopChild };\n","\"use client\";\nimport { jsx } from 'react/jsx-runtime';\nimport * as React from 'react';\nimport { useId, useMemo } from 'react';\nimport { PresenceContext } from '../../context/PresenceContext.mjs';\nimport { useConstant } from '../../utils/use-constant.mjs';\nimport { PopChild } from './PopChild.mjs';\n\nconst PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, }) => {\n const presenceChildren = useConstant(newChildrenMap);\n const id = useId();\n const context = useMemo(() => ({\n id,\n initial,\n isPresent,\n custom,\n onExitComplete: (childId) => {\n presenceChildren.set(childId, true);\n for (const isComplete of presenceChildren.values()) {\n if (!isComplete)\n return; // can stop searching when any is incomplete\n }\n onExitComplete && onExitComplete();\n },\n register: (childId) => {\n presenceChildren.set(childId, false);\n return () => presenceChildren.delete(childId);\n },\n }), \n /**\n * If the presence of a child affects the layout of the components around it,\n * we want to make a new context value to ensure they get re-rendered\n * so they can detect that layout change.\n */\n presenceAffectsLayout ? [Math.random()] : [isPresent]);\n useMemo(() => {\n presenceChildren.forEach((_, key) => presenceChildren.set(key, false));\n }, [isPresent]);\n /**\n * If there's no `motion` components to fire exit animations, we want to remove this\n * component immediately.\n */\n React.useEffect(() => {\n !isPresent &&\n !presenceChildren.size &&\n onExitComplete &&\n onExitComplete();\n }, [isPresent]);\n if (mode === \"popLayout\") {\n children = jsx(PopChild, { isPresent: isPresent, children: children });\n }\n return (jsx(PresenceContext.Provider, { value: context, children: children }));\n};\nfunction newChildrenMap() {\n return new Map();\n}\n\nexport { PresenceChild };\n","\"use client\";\nimport { jsx, Fragment } from 'react/jsx-runtime';\nimport { useMemo, useRef, useState, useContext } from 'react';\nimport { PresenceChild } from './PresenceChild.mjs';\nimport { LayoutGroupContext } from '../../context/LayoutGroupContext.mjs';\nimport { invariant } from '../../utils/errors.mjs';\nimport { useConstant } from '../../utils/use-constant.mjs';\nimport { onlyElements, getChildKey } from './utils.mjs';\nimport { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';\n\n/**\n * `AnimatePresence` enables the animation of components that have been removed from the tree.\n *\n * When adding/removing more than a single child, every child **must** be given a unique `key` prop.\n *\n * Any `motion` components that have an `exit` property defined will animate out when removed from\n * the tree.\n *\n * ```jsx\n * import { motion, AnimatePresence } from 'framer-motion'\n *\n * export const Items = ({ items }) => (\n * \n * {items.map(item => (\n * \n * ))}\n * \n * )\n * ```\n *\n * You can sequence exit animations throughout a tree using variants.\n *\n * If a child contains multiple `motion` components with `exit` props, it will only unmount the child\n * once all `motion` components have finished animating out. Likewise, any components using\n * `usePresence` all need to call `safeToRemove`.\n *\n * @public\n */\nconst AnimatePresence = ({ children, exitBeforeEnter, custom, initial = true, onExitComplete, presenceAffectsLayout = true, mode = \"sync\", }) => {\n invariant(!exitBeforeEnter, \"Replace exitBeforeEnter with mode='wait'\");\n /**\n * Filter any children that aren't ReactElements. We can only track components\n * between renders with a props.key.\n */\n const presentChildren = useMemo(() => onlyElements(children), [children]);\n /**\n * Track the keys of the currently rendered children. This is used to\n * determine which children are exiting.\n */\n const presentKeys = presentChildren.map(getChildKey);\n /**\n * If `initial={false}` we only want to pass this to components in the first render.\n */\n const isInitialRender = useRef(true);\n /**\n * A ref containing the currently present children. When all exit animations\n * are complete, we use this to re-render the component with the latest children\n * *committed* rather than the latest children *rendered*.\n */\n const pendingPresentChildren = useRef(presentChildren);\n /**\n * Track which exiting children have finished animating out.\n */\n const exitComplete = useConstant(() => new Map());\n /**\n * Save children to render as React state. To ensure this component is concurrent-safe,\n * we check for exiting children via an effect.\n */\n const [diffedChildren, setDiffedChildren] = useState(presentChildren);\n const [renderedChildren, setRenderedChildren] = useState(presentChildren);\n useIsomorphicLayoutEffect(() => {\n isInitialRender.current = false;\n pendingPresentChildren.current = presentChildren;\n /**\n * Update complete status of exiting children.\n */\n for (let i = 0; i < renderedChildren.length; i++) {\n const key = getChildKey(renderedChildren[i]);\n if (!presentKeys.includes(key)) {\n if (exitComplete.get(key) !== true) {\n exitComplete.set(key, false);\n }\n }\n else {\n exitComplete.delete(key);\n }\n }\n }, [renderedChildren, presentKeys.length, presentKeys.join(\"-\")]);\n const exitingChildren = [];\n if (presentChildren !== diffedChildren) {\n let nextChildren = [...presentChildren];\n /**\n * Loop through all the currently rendered components and decide which\n * are exiting.\n */\n for (let i = 0; i < renderedChildren.length; i++) {\n const child = renderedChildren[i];\n const key = getChildKey(child);\n if (!presentKeys.includes(key)) {\n nextChildren.splice(i, 0, child);\n exitingChildren.push(child);\n }\n }\n /**\n * If we're in \"wait\" mode, and we have exiting children, we want to\n * only render these until they've all exited.\n */\n if (mode === \"wait\" && exitingChildren.length) {\n nextChildren = exitingChildren;\n }\n setRenderedChildren(onlyElements(nextChildren));\n setDiffedChildren(presentChildren);\n /**\n * Early return to ensure once we've set state with the latest diffed\n * children, we can immediately re-render.\n */\n return;\n }\n if (process.env.NODE_ENV !== \"production\" &&\n mode === \"wait\" &&\n renderedChildren.length > 1) {\n console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to \"wait\". This will lead to odd visual behaviour.`);\n }\n /**\n * If we've been provided a forceRender function by the LayoutGroupContext,\n * we can use it to force a re-render amongst all surrounding components once\n * all components have finished animating out.\n */\n const { forceRender } = useContext(LayoutGroupContext);\n return (jsx(Fragment, { children: renderedChildren.map((child) => {\n const key = getChildKey(child);\n const isPresent = presentChildren === renderedChildren ||\n presentKeys.includes(key);\n const onExit = () => {\n if (exitComplete.has(key)) {\n exitComplete.set(key, true);\n }\n else {\n return;\n }\n let isEveryExitComplete = true;\n exitComplete.forEach((isExitComplete) => {\n if (!isExitComplete)\n isEveryExitComplete = false;\n });\n if (isEveryExitComplete) {\n forceRender === null || forceRender === void 0 ? void 0 : forceRender();\n setRenderedChildren(pendingPresentChildren.current);\n onExitComplete && onExitComplete();\n }\n };\n return (jsx(PresenceChild, { isPresent: isPresent, initial: !isInitialRender.current || initial\n ? undefined\n : false, custom: isPresent ? undefined : custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode, onExitComplete: isPresent ? undefined : onExit, children: child }, key));\n }) }));\n};\n\nexport { AnimatePresence };\n","import { useContext, useId, useEffect, useCallback } from 'react';\nimport { PresenceContext } from '../../context/PresenceContext.mjs';\n\n/**\n * When a component is the child of `AnimatePresence`, it can use `usePresence`\n * to access information about whether it's still present in the React tree.\n *\n * ```jsx\n * import { usePresence } from \"framer-motion\"\n *\n * export const Component = () => {\n * const [isPresent, safeToRemove] = usePresence()\n *\n * useEffect(() => {\n * !isPresent && setTimeout(safeToRemove, 1000)\n * }, [isPresent])\n *\n * return \n * }\n * ```\n *\n * If `isPresent` is `false`, it means that a component has been removed the tree, but\n * `AnimatePresence` won't really remove it until `safeToRemove` has been called.\n *\n * @public\n */\nfunction usePresence() {\n const context = useContext(PresenceContext);\n if (context === null)\n return [true, null];\n const { isPresent, onExitComplete, register } = context;\n // It's safe to call the following hooks conditionally (after an early return) because the context will always\n // either be null or non-null for the lifespan of the component.\n const id = useId();\n useEffect(() => register(id), []);\n const safeToRemove = useCallback(() => onExitComplete && onExitComplete(id), [id, onExitComplete]);\n return !isPresent && onExitComplete ? [false, safeToRemove] : [true];\n}\n/**\n * Similar to `usePresence`, except `useIsPresent` simply returns whether or not the component is present.\n * There is no `safeToRemove` function.\n *\n * ```jsx\n * import { useIsPresent } from \"framer-motion\"\n *\n * export const Component = () => {\n * const isPresent = useIsPresent()\n *\n * useEffect(() => {\n * !isPresent && console.log(\"I've been removed!\")\n * }, [isPresent])\n *\n * return \n * }\n * ```\n *\n * @public\n */\nfunction useIsPresent() {\n return isPresent(useContext(PresenceContext));\n}\nfunction isPresent(context) {\n return context === null ? true : context.isPresent;\n}\n\nexport { isPresent, useIsPresent, usePresence };\n","import { Children, isValidElement } from 'react';\n\nconst getChildKey = (child) => child.key || \"\";\nfunction onlyElements(children) {\n const filtered = [];\n // We use forEach here instead of map as map mutates the component key by preprending `.$`\n Children.forEach(children, (child) => {\n if (isValidElement(child))\n filtered.push(child);\n });\n return filtered;\n}\n\nexport { getChildKey, onlyElements };\n","\"use client\";\nimport { createContext } from 'react';\n\nconst LayoutGroupContext = createContext({});\n\nexport { LayoutGroupContext };\n","\"use client\";\nimport { createContext } from 'react';\n\nconst LazyContext = createContext({ strict: false });\n\nexport { LazyContext };\n","\"use client\";\nimport { createContext } from 'react';\n\n/**\n * @public\n */\nconst MotionConfigContext = createContext({\n transformPagePoint: (p) => p,\n isStatic: false,\n reducedMotion: \"never\",\n});\n\nexport { MotionConfigContext };\n","import { useContext, useMemo } from 'react';\nimport { MotionContext } from './index.mjs';\nimport { getCurrentTreeVariants } from './utils.mjs';\n\nfunction useCreateMotionContext(props) {\n const { initial, animate } = getCurrentTreeVariants(props, useContext(MotionContext));\n return useMemo(() => ({ initial, animate }), [variantLabelsAsDependency(initial), variantLabelsAsDependency(animate)]);\n}\nfunction variantLabelsAsDependency(prop) {\n return Array.isArray(prop) ? prop.join(\" \") : prop;\n}\n\nexport { useCreateMotionContext };\n","\"use client\";\nimport { createContext } from 'react';\n\nconst MotionContext = createContext({});\n\nexport { MotionContext };\n","import { isVariantLabel } from '../../render/utils/is-variant-label.mjs';\nimport { isControllingVariants } from '../../render/utils/is-controlling-variants.mjs';\n\nfunction getCurrentTreeVariants(props, context) {\n if (isControllingVariants(props)) {\n const { initial, animate } = props;\n return {\n initial: initial === false || isVariantLabel(initial)\n ? initial\n : undefined,\n animate: isVariantLabel(animate) ? animate : undefined,\n };\n }\n return props.inherit !== false ? context : {};\n}\n\nexport { getCurrentTreeVariants };\n","\"use client\";\nimport { createContext } from 'react';\n\n/**\n * @public\n */\nconst PresenceContext = createContext(null);\n\nexport { PresenceContext };\n","\"use client\";\nimport { createContext } from 'react';\n\n/**\n * Internal, exported only for usage in Framer\n */\nconst SwitchLayoutGroupContext = createContext({});\n\nexport { SwitchLayoutGroupContext };\n","import { backIn } from './back.mjs';\n\nconst anticipate = (p) => (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));\n\nexport { anticipate };\n","import { cubicBezier } from './cubic-bezier.mjs';\nimport { mirrorEasing } from './modifiers/mirror.mjs';\nimport { reverseEasing } from './modifiers/reverse.mjs';\n\nconst backOut = cubicBezier(0.33, 1.53, 0.69, 0.99);\nconst backIn = reverseEasing(backOut);\nconst backInOut = mirrorEasing(backIn);\n\nexport { backIn, backInOut, backOut };\n","import { mirrorEasing } from './modifiers/mirror.mjs';\nimport { reverseEasing } from './modifiers/reverse.mjs';\n\nconst circIn = (p) => 1 - Math.sin(Math.acos(p));\nconst circOut = reverseEasing(circIn);\nconst circInOut = mirrorEasing(circIn);\n\nexport { circIn, circInOut, circOut };\n","import { noop } from '../utils/noop.mjs';\n\n/*\n Bezier function generator\n This has been modified from Gaëtan Renaudeau's BezierEasing\n https://github.com/gre/bezier-easing/blob/master/src/index.js\n https://github.com/gre/bezier-easing/blob/master/LICENSE\n \n I've removed the newtonRaphsonIterate algo because in benchmarking it\n wasn't noticiably faster than binarySubdivision, indeed removing it\n usually improved times, depending on the curve.\n I also removed the lookup table, as for the added bundle size and loop we're\n only cutting ~4 or so subdivision iterations. I bumped the max iterations up\n to 12 to compensate and this still tended to be faster for no perceivable\n loss in accuracy.\n Usage\n const easeOut = cubicBezier(.17,.67,.83,.67);\n const x = easeOut(0.5); // returns 0.627...\n*/\n// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.\nconst calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *\n t;\nconst subdivisionPrecision = 0.0000001;\nconst subdivisionMaxIterations = 12;\nfunction binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {\n let currentX;\n let currentT;\n let i = 0;\n do {\n currentT = lowerBound + (upperBound - lowerBound) / 2.0;\n currentX = calcBezier(currentT, mX1, mX2) - x;\n if (currentX > 0.0) {\n upperBound = currentT;\n }\n else {\n lowerBound = currentT;\n }\n } while (Math.abs(currentX) > subdivisionPrecision &&\n ++i < subdivisionMaxIterations);\n return currentT;\n}\nfunction cubicBezier(mX1, mY1, mX2, mY2) {\n // If this is a linear gradient, return linear easing\n if (mX1 === mY1 && mX2 === mY2)\n return noop;\n const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);\n // If animation is at start/end, return t without easing\n return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);\n}\n\nexport { cubicBezier };\n","import { cubicBezier } from './cubic-bezier.mjs';\n\nconst easeIn = cubicBezier(0.42, 0, 1, 1);\nconst easeOut = cubicBezier(0, 0, 0.58, 1);\nconst easeInOut = cubicBezier(0.42, 0, 0.58, 1);\n\nexport { easeIn, easeInOut, easeOut };\n","// Accepts an easing function and returns a new one that outputs mirrored values for\n// the second half of the animation. Turns easeIn into easeInOut.\nconst mirrorEasing = (easing) => (p) => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;\n\nexport { mirrorEasing };\n","// Accepts an easing function and returns a new one that outputs reversed values.\n// Turns easeIn into easeOut.\nconst reverseEasing = (easing) => (p) => 1 - easing(1 - p);\n\nexport { reverseEasing };\n","const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === \"number\";\n\nexport { isBezierDefinition };\n","const isEasingArray = (ease) => {\n return Array.isArray(ease) && typeof ease[0] !== \"number\";\n};\n\nexport { isEasingArray };\n","import { invariant } from '../../utils/errors.mjs';\nimport { cubicBezier } from '../cubic-bezier.mjs';\nimport { noop } from '../../utils/noop.mjs';\nimport { easeIn, easeInOut, easeOut } from '../ease.mjs';\nimport { circIn, circInOut, circOut } from '../circ.mjs';\nimport { backIn, backInOut, backOut } from '../back.mjs';\nimport { anticipate } from '../anticipate.mjs';\n\nconst easingLookup = {\n linear: noop,\n easeIn,\n easeInOut,\n easeOut,\n circIn,\n circInOut,\n circOut,\n backIn,\n backInOut,\n backOut,\n anticipate,\n};\nconst easingDefinitionToFunction = (definition) => {\n if (Array.isArray(definition)) {\n // If cubic bezier definition, create bezier curve\n invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`);\n const [x1, y1, x2, y2] = definition;\n return cubicBezier(x1, y1, x2, y2);\n }\n else if (typeof definition === \"string\") {\n // Else lookup from table\n invariant(easingLookup[definition] !== undefined, `Invalid easing type '${definition}'`);\n return easingLookup[definition];\n }\n return definition;\n};\n\nexport { easingDefinitionToFunction };\n","function addDomEvent(target, eventName, handler, options = { passive: true }) {\n target.addEventListener(eventName, handler, options);\n return () => target.removeEventListener(eventName, handler);\n}\n\nexport { addDomEvent };\n","import { addDomEvent } from './add-dom-event.mjs';\nimport { addPointerInfo } from './event-info.mjs';\n\nfunction addPointerEvent(target, eventName, handler, options) {\n return addDomEvent(target, eventName, addPointerInfo(handler), options);\n}\n\nexport { addPointerEvent };\n","import { isPrimaryPointer } from './utils/is-primary-pointer.mjs';\n\nfunction extractEventInfo(event, pointType = \"page\") {\n return {\n point: {\n x: event[`${pointType}X`],\n y: event[`${pointType}Y`],\n },\n };\n}\nconst addPointerInfo = (handler) => {\n return (event) => isPrimaryPointer(event) && handler(event, extractEventInfo(event));\n};\n\nexport { addPointerInfo, extractEventInfo };\n","const isPrimaryPointer = (event) => {\n if (event.pointerType === \"mouse\") {\n return typeof event.button !== \"number\" || event.button <= 0;\n }\n else {\n /**\n * isPrimary is true for all mice buttons, whereas every touch point\n * is regarded as its own input. So subsequent concurrent touch points\n * will be false.\n *\n * Specifically match against false here as incomplete versions of\n * PointerEvents in very old browser might have it set as undefined.\n */\n return event.isPrimary !== false;\n }\n};\n\nexport { isPrimaryPointer };\n","import { MotionGlobalConfig } from '../utils/GlobalConfig.mjs';\nimport { createRenderStep } from './render-step.mjs';\n\nconst stepsOrder = [\n \"read\", // Read\n \"resolveKeyframes\", // Write/Read/Write/Read\n \"update\", // Compute\n \"preRender\", // Compute\n \"render\", // Write\n \"postRender\", // Compute\n];\nconst maxElapsed = 40;\nfunction createRenderBatcher(scheduleNextBatch, allowKeepAlive) {\n let runNextFrame = false;\n let useDefaultElapsed = true;\n const state = {\n delta: 0.0,\n timestamp: 0.0,\n isProcessing: false,\n };\n const flagRunNextFrame = () => (runNextFrame = true);\n const steps = stepsOrder.reduce((acc, key) => {\n acc[key] = createRenderStep(flagRunNextFrame);\n return acc;\n }, {});\n const { read, resolveKeyframes, update, preRender, render, postRender } = steps;\n const processBatch = () => {\n const timestamp = MotionGlobalConfig.useManualTiming\n ? state.timestamp\n : performance.now();\n runNextFrame = false;\n state.delta = useDefaultElapsed\n ? 1000 / 60\n : Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);\n state.timestamp = timestamp;\n state.isProcessing = true;\n // Unrolled render loop for better per-frame performance\n read.process(state);\n resolveKeyframes.process(state);\n update.process(state);\n preRender.process(state);\n render.process(state);\n postRender.process(state);\n state.isProcessing = false;\n if (runNextFrame && allowKeepAlive) {\n useDefaultElapsed = false;\n scheduleNextBatch(processBatch);\n }\n };\n const wake = () => {\n runNextFrame = true;\n useDefaultElapsed = true;\n if (!state.isProcessing) {\n scheduleNextBatch(processBatch);\n }\n };\n const schedule = stepsOrder.reduce((acc, key) => {\n const step = steps[key];\n acc[key] = (process, keepAlive = false, immediate = false) => {\n if (!runNextFrame)\n wake();\n return step.schedule(process, keepAlive, immediate);\n };\n return acc;\n }, {});\n const cancel = (process) => {\n for (let i = 0; i < stepsOrder.length; i++) {\n steps[stepsOrder[i]].cancel(process);\n }\n };\n return { schedule, cancel, state, steps };\n}\n\nexport { createRenderBatcher, stepsOrder };\n","import { noop } from '../utils/noop.mjs';\nimport { createRenderBatcher } from './batcher.mjs';\n\nconst { schedule: frame, cancel: cancelFrame, state: frameData, steps, } = createRenderBatcher(typeof requestAnimationFrame !== \"undefined\" ? requestAnimationFrame : noop, true);\n\nexport { cancelFrame, frame, frameData, steps };\n","import { createRenderBatcher } from './batcher.mjs';\n\nconst { schedule: microtask, cancel: cancelMicrotask } = createRenderBatcher(queueMicrotask, false);\n\nexport { cancelMicrotask, microtask };\n","function createRenderStep(runNextFrame) {\n /**\n * We create and reuse two queues, one to queue jobs for the current frame\n * and one for the next. We reuse to avoid triggering GC after x frames.\n */\n let thisFrame = new Set();\n let nextFrame = new Set();\n /**\n * Track whether we're currently processing jobs in this step. This way\n * we can decide whether to schedule new jobs for this frame or next.\n */\n let isProcessing = false;\n let flushNextFrame = false;\n /**\n * A set of processes which were marked keepAlive when scheduled.\n */\n const toKeepAlive = new WeakSet();\n let latestFrameData = {\n delta: 0.0,\n timestamp: 0.0,\n isProcessing: false,\n };\n function triggerCallback(callback) {\n if (toKeepAlive.has(callback)) {\n step.schedule(callback);\n runNextFrame();\n }\n callback(latestFrameData);\n }\n const step = {\n /**\n * Schedule a process to run on the next frame.\n */\n schedule: (callback, keepAlive = false, immediate = false) => {\n const addToCurrentFrame = immediate && isProcessing;\n const queue = addToCurrentFrame ? thisFrame : nextFrame;\n if (keepAlive)\n toKeepAlive.add(callback);\n if (!queue.has(callback))\n queue.add(callback);\n return callback;\n },\n /**\n * Cancel the provided callback from running on the next frame.\n */\n cancel: (callback) => {\n nextFrame.delete(callback);\n toKeepAlive.delete(callback);\n },\n /**\n * Execute all schedule callbacks.\n */\n process: (frameData) => {\n latestFrameData = frameData;\n /**\n * If we're already processing we've probably been triggered by a flushSync\n * inside an existing process. Instead of executing, mark flushNextFrame\n * as true and ensure we flush the following frame at the end of this one.\n */\n if (isProcessing) {\n flushNextFrame = true;\n return;\n }\n isProcessing = true;\n [thisFrame, nextFrame] = [nextFrame, thisFrame];\n // Clear the next frame queue\n nextFrame.clear();\n // Execute this frame\n thisFrame.forEach(triggerCallback);\n isProcessing = false;\n if (flushNextFrame) {\n flushNextFrame = false;\n step.process(frameData);\n }\n },\n };\n return step;\n}\n\nexport { createRenderStep };\n","import { MotionGlobalConfig } from '../utils/GlobalConfig.mjs';\nimport { frameData } from './frame.mjs';\n\nlet now;\nfunction clearTime() {\n now = undefined;\n}\n/**\n * An eventloop-synchronous alternative to performance.now().\n *\n * Ensures that time measurements remain consistent within a synchronous context.\n * Usually calling performance.now() twice within the same synchronous context\n * will return different values which isn't useful for animations when we're usually\n * trying to sync animations to the same frame.\n */\nconst time = {\n now: () => {\n if (now === undefined) {\n time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming\n ? frameData.timestamp\n : performance.now());\n }\n return now;\n },\n set: (newTime) => {\n now = newTime;\n queueMicrotask(clearTime);\n },\n};\n\nexport { time };\n","import { invariant } from '../../utils/errors.mjs';\nimport { PanSession } from '../pan/PanSession.mjs';\nimport { getGlobalLock } from './utils/lock.mjs';\nimport { isRefObject } from '../../utils/is-ref-object.mjs';\nimport { addPointerEvent } from '../../events/add-pointer-event.mjs';\nimport { applyConstraints, calcRelativeConstraints, resolveDragElastic, rebaseAxisConstraints, calcViewportConstraints, calcOrigin, defaultElastic } from './utils/constraints.mjs';\nimport { createBox } from '../../projection/geometry/models.mjs';\nimport { eachAxis } from '../../projection/utils/each-axis.mjs';\nimport { measurePageBox } from '../../projection/utils/measure.mjs';\nimport { extractEventInfo } from '../../events/event-info.mjs';\nimport { convertBoxToBoundingBox, convertBoundingBoxToBox } from '../../projection/geometry/conversion.mjs';\nimport { addDomEvent } from '../../events/add-dom-event.mjs';\nimport { calcLength } from '../../projection/geometry/delta-calc.mjs';\nimport { mixNumber } from '../../utils/mix/number.mjs';\nimport { percent } from '../../value/types/numbers/units.mjs';\nimport { animateMotionValue } from '../../animation/interfaces/motion-value.mjs';\nimport { getContextWindow } from '../../utils/get-context-window.mjs';\nimport { addValueToWillChange } from '../../value/use-will-change/add-will-change.mjs';\nimport { frame } from '../../frameloop/frame.mjs';\n\nconst elementDragControls = new WeakMap();\n/**\n *\n */\n// let latestPointerEvent: PointerEvent\nclass VisualElementDragControls {\n constructor(visualElement) {\n // This is a reference to the global drag gesture lock, ensuring only one component\n // can \"capture\" the drag of one or both axes.\n // TODO: Look into moving this into pansession?\n this.openGlobalLock = null;\n this.isDragging = false;\n this.currentDirection = null;\n this.originPoint = { x: 0, y: 0 };\n /**\n * The permitted boundaries of travel, in pixels.\n */\n this.constraints = false;\n this.hasMutatedConstraints = false;\n /**\n * The per-axis resolved elastic values.\n */\n this.elastic = createBox();\n this.visualElement = visualElement;\n }\n start(originEvent, { snapToCursor = false } = {}) {\n /**\n * Don't start dragging if this component is exiting\n */\n const { presenceContext } = this.visualElement;\n if (presenceContext && presenceContext.isPresent === false)\n return;\n const onSessionStart = (event) => {\n const { dragSnapToOrigin } = this.getProps();\n // Stop or pause any animations on both axis values immediately. This allows the user to throw and catch\n // the component.\n dragSnapToOrigin ? this.pauseAnimation() : this.stopAnimation();\n if (snapToCursor) {\n this.snapToCursor(extractEventInfo(event, \"page\").point);\n }\n };\n const onStart = (event, info) => {\n var _a;\n // Attempt to grab the global drag gesture lock - maybe make this part of PanSession\n const { drag, dragPropagation, onDragStart } = this.getProps();\n if (drag && !dragPropagation) {\n if (this.openGlobalLock)\n this.openGlobalLock();\n this.openGlobalLock = getGlobalLock(drag);\n // If we don 't have the lock, don't start dragging\n if (!this.openGlobalLock)\n return;\n }\n this.isDragging = true;\n this.currentDirection = null;\n this.resolveConstraints();\n if (this.visualElement.projection) {\n this.visualElement.projection.isAnimationBlocked = true;\n this.visualElement.projection.target = undefined;\n }\n /**\n * Record gesture origin\n */\n eachAxis((axis) => {\n let current = this.getAxisMotionValue(axis).get() || 0;\n /**\n * If the MotionValue is a percentage value convert to px\n */\n if (percent.test(current)) {\n const { projection } = this.visualElement;\n if (projection && projection.layout) {\n const measuredAxis = projection.layout.layoutBox[axis];\n if (measuredAxis) {\n const length = calcLength(measuredAxis);\n current = length * (parseFloat(current) / 100);\n }\n }\n }\n this.originPoint[axis] = current;\n });\n // Fire onDragStart event\n if (onDragStart) {\n frame.postRender(() => onDragStart(event, info));\n }\n (_a = this.removeWillChange) === null || _a === void 0 ? void 0 : _a.call(this);\n this.removeWillChange = addValueToWillChange(this.visualElement, \"transform\");\n const { animationState } = this.visualElement;\n animationState && animationState.setActive(\"whileDrag\", true);\n };\n const onMove = (event, info) => {\n // latestPointerEvent = event\n const { dragPropagation, dragDirectionLock, onDirectionLock, onDrag, } = this.getProps();\n // If we didn't successfully receive the gesture lock, early return.\n if (!dragPropagation && !this.openGlobalLock)\n return;\n const { offset } = info;\n // Attempt to detect drag direction if directionLock is true\n if (dragDirectionLock && this.currentDirection === null) {\n this.currentDirection = getCurrentDirection(offset);\n // If we've successfully set a direction, notify listener\n if (this.currentDirection !== null) {\n onDirectionLock && onDirectionLock(this.currentDirection);\n }\n return;\n }\n // Update each point with the latest position\n this.updateAxis(\"x\", info.point, offset);\n this.updateAxis(\"y\", info.point, offset);\n /**\n * Ideally we would leave the renderer to fire naturally at the end of\n * this frame but if the element is about to change layout as the result\n * of a re-render we want to ensure the browser can read the latest\n * bounding box to ensure the pointer and element don't fall out of sync.\n */\n this.visualElement.render();\n /**\n * This must fire after the render call as it might trigger a state\n * change which itself might trigger a layout update.\n */\n onDrag && onDrag(event, info);\n };\n const onSessionEnd = (event, info) => this.stop(event, info);\n const resumeAnimation = () => eachAxis((axis) => {\n var _a;\n return this.getAnimationState(axis) === \"paused\" &&\n ((_a = this.getAxisMotionValue(axis).animation) === null || _a === void 0 ? void 0 : _a.play());\n });\n const { dragSnapToOrigin } = this.getProps();\n this.panSession = new PanSession(originEvent, {\n onSessionStart,\n onStart,\n onMove,\n onSessionEnd,\n resumeAnimation,\n }, {\n transformPagePoint: this.visualElement.getTransformPagePoint(),\n dragSnapToOrigin,\n contextWindow: getContextWindow(this.visualElement),\n });\n }\n stop(event, info) {\n var _a;\n (_a = this.removeWillChange) === null || _a === void 0 ? void 0 : _a.call(this);\n const isDragging = this.isDragging;\n this.cancel();\n if (!isDragging)\n return;\n const { velocity } = info;\n this.startAnimation(velocity);\n const { onDragEnd } = this.getProps();\n if (onDragEnd) {\n frame.postRender(() => onDragEnd(event, info));\n }\n }\n cancel() {\n this.isDragging = false;\n const { projection, animationState } = this.visualElement;\n if (projection) {\n projection.isAnimationBlocked = false;\n }\n this.panSession && this.panSession.end();\n this.panSession = undefined;\n const { dragPropagation } = this.getProps();\n if (!dragPropagation && this.openGlobalLock) {\n this.openGlobalLock();\n this.openGlobalLock = null;\n }\n animationState && animationState.setActive(\"whileDrag\", false);\n }\n updateAxis(axis, _point, offset) {\n const { drag } = this.getProps();\n // If we're not dragging this axis, do an early return.\n if (!offset || !shouldDrag(axis, drag, this.currentDirection))\n return;\n const axisValue = this.getAxisMotionValue(axis);\n let next = this.originPoint[axis] + offset[axis];\n // Apply constraints\n if (this.constraints && this.constraints[axis]) {\n next = applyConstraints(next, this.constraints[axis], this.elastic[axis]);\n }\n axisValue.set(next);\n }\n resolveConstraints() {\n var _a;\n const { dragConstraints, dragElastic } = this.getProps();\n const layout = this.visualElement.projection &&\n !this.visualElement.projection.layout\n ? this.visualElement.projection.measure(false)\n : (_a = this.visualElement.projection) === null || _a === void 0 ? void 0 : _a.layout;\n const prevConstraints = this.constraints;\n if (dragConstraints && isRefObject(dragConstraints)) {\n if (!this.constraints) {\n this.constraints = this.resolveRefConstraints();\n }\n }\n else {\n if (dragConstraints && layout) {\n this.constraints = calcRelativeConstraints(layout.layoutBox, dragConstraints);\n }\n else {\n this.constraints = false;\n }\n }\n this.elastic = resolveDragElastic(dragElastic);\n /**\n * If we're outputting to external MotionValues, we want to rebase the measured constraints\n * from viewport-relative to component-relative.\n */\n if (prevConstraints !== this.constraints &&\n layout &&\n this.constraints &&\n !this.hasMutatedConstraints) {\n eachAxis((axis) => {\n if (this.constraints !== false &&\n this.getAxisMotionValue(axis)) {\n this.constraints[axis] = rebaseAxisConstraints(layout.layoutBox[axis], this.constraints[axis]);\n }\n });\n }\n }\n resolveRefConstraints() {\n const { dragConstraints: constraints, onMeasureDragConstraints } = this.getProps();\n if (!constraints || !isRefObject(constraints))\n return false;\n const constraintsElement = constraints.current;\n invariant(constraintsElement !== null, \"If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.\");\n const { projection } = this.visualElement;\n // TODO\n if (!projection || !projection.layout)\n return false;\n const constraintsBox = measurePageBox(constraintsElement, projection.root, this.visualElement.getTransformPagePoint());\n let measuredConstraints = calcViewportConstraints(projection.layout.layoutBox, constraintsBox);\n /**\n * If there's an onMeasureDragConstraints listener we call it and\n * if different constraints are returned, set constraints to that\n */\n if (onMeasureDragConstraints) {\n const userConstraints = onMeasureDragConstraints(convertBoxToBoundingBox(measuredConstraints));\n this.hasMutatedConstraints = !!userConstraints;\n if (userConstraints) {\n measuredConstraints = convertBoundingBoxToBox(userConstraints);\n }\n }\n return measuredConstraints;\n }\n startAnimation(velocity) {\n const { drag, dragMomentum, dragElastic, dragTransition, dragSnapToOrigin, onDragTransitionEnd, } = this.getProps();\n const constraints = this.constraints || {};\n const momentumAnimations = eachAxis((axis) => {\n if (!shouldDrag(axis, drag, this.currentDirection)) {\n return;\n }\n let transition = (constraints && constraints[axis]) || {};\n if (dragSnapToOrigin)\n transition = { min: 0, max: 0 };\n /**\n * Overdamp the boundary spring if `dragElastic` is disabled. There's still a frame\n * of spring animations so we should look into adding a disable spring option to `inertia`.\n * We could do something here where we affect the `bounceStiffness` and `bounceDamping`\n * using the value of `dragElastic`.\n */\n const bounceStiffness = dragElastic ? 200 : 1000000;\n const bounceDamping = dragElastic ? 40 : 10000000;\n const inertia = {\n type: \"inertia\",\n velocity: dragMomentum ? velocity[axis] : 0,\n bounceStiffness,\n bounceDamping,\n timeConstant: 750,\n restDelta: 1,\n restSpeed: 10,\n ...dragTransition,\n ...transition,\n };\n // If we're not animating on an externally-provided `MotionValue` we can use the\n // component's animation controls which will handle interactions with whileHover (etc),\n // otherwise we just have to animate the `MotionValue` itself.\n return this.startAxisValueAnimation(axis, inertia);\n });\n // Run all animations and then resolve the new drag constraints.\n return Promise.all(momentumAnimations).then(onDragTransitionEnd);\n }\n startAxisValueAnimation(axis, transition) {\n const axisValue = this.getAxisMotionValue(axis);\n return axisValue.start(animateMotionValue(axis, axisValue, 0, transition, this.visualElement, false, addValueToWillChange(this.visualElement, axis)));\n }\n stopAnimation() {\n eachAxis((axis) => this.getAxisMotionValue(axis).stop());\n }\n pauseAnimation() {\n eachAxis((axis) => { var _a; return (_a = this.getAxisMotionValue(axis).animation) === null || _a === void 0 ? void 0 : _a.pause(); });\n }\n getAnimationState(axis) {\n var _a;\n return (_a = this.getAxisMotionValue(axis).animation) === null || _a === void 0 ? void 0 : _a.state;\n }\n /**\n * Drag works differently depending on which props are provided.\n *\n * - If _dragX and _dragY are provided, we output the gesture delta directly to those motion values.\n * - Otherwise, we apply the delta to the x/y motion values.\n */\n getAxisMotionValue(axis) {\n const dragKey = `_drag${axis.toUpperCase()}`;\n const props = this.visualElement.getProps();\n const externalMotionValue = props[dragKey];\n return externalMotionValue\n ? externalMotionValue\n : this.visualElement.getValue(axis, (props.initial\n ? props.initial[axis]\n : undefined) || 0);\n }\n snapToCursor(point) {\n eachAxis((axis) => {\n const { drag } = this.getProps();\n // If we're not dragging this axis, do an early return.\n if (!shouldDrag(axis, drag, this.currentDirection))\n return;\n const { projection } = this.visualElement;\n const axisValue = this.getAxisMotionValue(axis);\n if (projection && projection.layout) {\n const { min, max } = projection.layout.layoutBox[axis];\n axisValue.set(point[axis] - mixNumber(min, max, 0.5));\n }\n });\n }\n /**\n * When the viewport resizes we want to check if the measured constraints\n * have changed and, if so, reposition the element within those new constraints\n * relative to where it was before the resize.\n */\n scalePositionWithinConstraints() {\n if (!this.visualElement.current)\n return;\n const { drag, dragConstraints } = this.getProps();\n const { projection } = this.visualElement;\n if (!isRefObject(dragConstraints) || !projection || !this.constraints)\n return;\n /**\n * Stop current animations as there can be visual glitching if we try to do\n * this mid-animation\n */\n this.stopAnimation();\n /**\n * Record the relative position of the dragged element relative to the\n * constraints box and save as a progress value.\n */\n const boxProgress = { x: 0, y: 0 };\n eachAxis((axis) => {\n const axisValue = this.getAxisMotionValue(axis);\n if (axisValue && this.constraints !== false) {\n const latest = axisValue.get();\n boxProgress[axis] = calcOrigin({ min: latest, max: latest }, this.constraints[axis]);\n }\n });\n /**\n * Update the layout of this element and resolve the latest drag constraints\n */\n const { transformTemplate } = this.visualElement.getProps();\n this.visualElement.current.style.transform = transformTemplate\n ? transformTemplate({}, \"\")\n : \"none\";\n projection.root && projection.root.updateScroll();\n projection.updateLayout();\n this.resolveConstraints();\n /**\n * For each axis, calculate the current progress of the layout axis\n * within the new constraints.\n */\n eachAxis((axis) => {\n if (!shouldDrag(axis, drag, null))\n return;\n /**\n * Calculate a new transform based on the previous box progress\n */\n const axisValue = this.getAxisMotionValue(axis);\n const { min, max } = this.constraints[axis];\n axisValue.set(mixNumber(min, max, boxProgress[axis]));\n });\n }\n addListeners() {\n if (!this.visualElement.current)\n return;\n elementDragControls.set(this.visualElement, this);\n const element = this.visualElement.current;\n /**\n * Attach a pointerdown event listener on this DOM element to initiate drag tracking.\n */\n const stopPointerListener = addPointerEvent(element, \"pointerdown\", (event) => {\n const { drag, dragListener = true } = this.getProps();\n drag && dragListener && this.start(event);\n });\n const measureDragConstraints = () => {\n const { dragConstraints } = this.getProps();\n if (isRefObject(dragConstraints) && dragConstraints.current) {\n this.constraints = this.resolveRefConstraints();\n }\n };\n const { projection } = this.visualElement;\n const stopMeasureLayoutListener = projection.addEventListener(\"measure\", measureDragConstraints);\n if (projection && !projection.layout) {\n projection.root && projection.root.updateScroll();\n projection.updateLayout();\n }\n frame.read(measureDragConstraints);\n /**\n * Attach a window resize listener to scale the draggable target within its defined\n * constraints as the window resizes.\n */\n const stopResizeListener = addDomEvent(window, \"resize\", () => this.scalePositionWithinConstraints());\n /**\n * If the element's layout changes, calculate the delta and apply that to\n * the drag gesture's origin point.\n */\n const stopLayoutUpdateListener = projection.addEventListener(\"didUpdate\", (({ delta, hasLayoutChanged }) => {\n if (this.isDragging && hasLayoutChanged) {\n eachAxis((axis) => {\n const motionValue = this.getAxisMotionValue(axis);\n if (!motionValue)\n return;\n this.originPoint[axis] += delta[axis].translate;\n motionValue.set(motionValue.get() + delta[axis].translate);\n });\n this.visualElement.render();\n }\n }));\n return () => {\n stopResizeListener();\n stopPointerListener();\n stopMeasureLayoutListener();\n stopLayoutUpdateListener && stopLayoutUpdateListener();\n };\n }\n getProps() {\n const props = this.visualElement.getProps();\n const { drag = false, dragDirectionLock = false, dragPropagation = false, dragConstraints = false, dragElastic = defaultElastic, dragMomentum = true, } = props;\n return {\n ...props,\n drag,\n dragDirectionLock,\n dragPropagation,\n dragConstraints,\n dragElastic,\n dragMomentum,\n };\n }\n}\nfunction shouldDrag(direction, drag, currentDirection) {\n return ((drag === true || drag === direction) &&\n (currentDirection === null || currentDirection === direction));\n}\n/**\n * Based on an x/y offset determine the current drag direction. If both axis' offsets are lower\n * than the provided threshold, return `null`.\n *\n * @param offset - The x/y offset from origin.\n * @param lockThreshold - (Optional) - the minimum absolute offset before we can determine a drag direction.\n */\nfunction getCurrentDirection(offset, lockThreshold = 10) {\n let direction = null;\n if (Math.abs(offset.y) > lockThreshold) {\n direction = \"y\";\n }\n else if (Math.abs(offset.x) > lockThreshold) {\n direction = \"x\";\n }\n return direction;\n}\n\nexport { VisualElementDragControls, elementDragControls };\n","import { Feature } from '../../motion/features/Feature.mjs';\nimport { noop } from '../../utils/noop.mjs';\nimport { VisualElementDragControls } from './VisualElementDragControls.mjs';\n\nclass DragGesture extends Feature {\n constructor(node) {\n super(node);\n this.removeGroupControls = noop;\n this.removeListeners = noop;\n this.controls = new VisualElementDragControls(node);\n }\n mount() {\n // If we've been provided a DragControls for manual control over the drag gesture,\n // subscribe this component to it on mount.\n const { dragControls } = this.node.getProps();\n if (dragControls) {\n this.removeGroupControls = dragControls.subscribe(this.controls);\n }\n this.removeListeners = this.controls.addListeners() || noop;\n }\n unmount() {\n this.removeGroupControls();\n this.removeListeners();\n }\n}\n\nexport { DragGesture };\n","import { progress } from '../../../utils/progress.mjs';\nimport { calcLength } from '../../../projection/geometry/delta-calc.mjs';\nimport { clamp } from '../../../utils/clamp.mjs';\nimport { mixNumber } from '../../../utils/mix/number.mjs';\n\n/**\n * Apply constraints to a point. These constraints are both physical along an\n * axis, and an elastic factor that determines how much to constrain the point\n * by if it does lie outside the defined parameters.\n */\nfunction applyConstraints(point, { min, max }, elastic) {\n if (min !== undefined && point < min) {\n // If we have a min point defined, and this is outside of that, constrain\n point = elastic\n ? mixNumber(min, point, elastic.min)\n : Math.max(point, min);\n }\n else if (max !== undefined && point > max) {\n // If we have a max point defined, and this is outside of that, constrain\n point = elastic\n ? mixNumber(max, point, elastic.max)\n : Math.min(point, max);\n }\n return point;\n}\n/**\n * Calculate constraints in terms of the viewport when defined relatively to the\n * measured axis. This is measured from the nearest edge, so a max constraint of 200\n * on an axis with a max value of 300 would return a constraint of 500 - axis length\n */\nfunction calcRelativeAxisConstraints(axis, min, max) {\n return {\n min: min !== undefined ? axis.min + min : undefined,\n max: max !== undefined\n ? axis.max + max - (axis.max - axis.min)\n : undefined,\n };\n}\n/**\n * Calculate constraints in terms of the viewport when\n * defined relatively to the measured bounding box.\n */\nfunction calcRelativeConstraints(layoutBox, { top, left, bottom, right }) {\n return {\n x: calcRelativeAxisConstraints(layoutBox.x, left, right),\n y: calcRelativeAxisConstraints(layoutBox.y, top, bottom),\n };\n}\n/**\n * Calculate viewport constraints when defined as another viewport-relative axis\n */\nfunction calcViewportAxisConstraints(layoutAxis, constraintsAxis) {\n let min = constraintsAxis.min - layoutAxis.min;\n let max = constraintsAxis.max - layoutAxis.max;\n // If the constraints axis is actually smaller than the layout axis then we can\n // flip the constraints\n if (constraintsAxis.max - constraintsAxis.min <\n layoutAxis.max - layoutAxis.min) {\n [min, max] = [max, min];\n }\n return { min, max };\n}\n/**\n * Calculate viewport constraints when defined as another viewport-relative box\n */\nfunction calcViewportConstraints(layoutBox, constraintsBox) {\n return {\n x: calcViewportAxisConstraints(layoutBox.x, constraintsBox.x),\n y: calcViewportAxisConstraints(layoutBox.y, constraintsBox.y),\n };\n}\n/**\n * Calculate a transform origin relative to the source axis, between 0-1, that results\n * in an asthetically pleasing scale/transform needed to project from source to target.\n */\nfunction calcOrigin(source, target) {\n let origin = 0.5;\n const sourceLength = calcLength(source);\n const targetLength = calcLength(target);\n if (targetLength > sourceLength) {\n origin = progress(target.min, target.max - sourceLength, source.min);\n }\n else if (sourceLength > targetLength) {\n origin = progress(source.min, source.max - targetLength, target.min);\n }\n return clamp(0, 1, origin);\n}\n/**\n * Rebase the calculated viewport constraints relative to the layout.min point.\n */\nfunction rebaseAxisConstraints(layout, constraints) {\n const relativeConstraints = {};\n if (constraints.min !== undefined) {\n relativeConstraints.min = constraints.min - layout.min;\n }\n if (constraints.max !== undefined) {\n relativeConstraints.max = constraints.max - layout.min;\n }\n return relativeConstraints;\n}\nconst defaultElastic = 0.35;\n/**\n * Accepts a dragElastic prop and returns resolved elastic values for each axis.\n */\nfunction resolveDragElastic(dragElastic = defaultElastic) {\n if (dragElastic === false) {\n dragElastic = 0;\n }\n else if (dragElastic === true) {\n dragElastic = defaultElastic;\n }\n return {\n x: resolveAxisElastic(dragElastic, \"left\", \"right\"),\n y: resolveAxisElastic(dragElastic, \"top\", \"bottom\"),\n };\n}\nfunction resolveAxisElastic(dragElastic, minLabel, maxLabel) {\n return {\n min: resolvePointElastic(dragElastic, minLabel),\n max: resolvePointElastic(dragElastic, maxLabel),\n };\n}\nfunction resolvePointElastic(dragElastic, label) {\n return typeof dragElastic === \"number\"\n ? dragElastic\n : dragElastic[label] || 0;\n}\n\nexport { applyConstraints, calcOrigin, calcRelativeAxisConstraints, calcRelativeConstraints, calcViewportAxisConstraints, calcViewportConstraints, defaultElastic, rebaseAxisConstraints, resolveAxisElastic, resolveDragElastic, resolvePointElastic };\n","function createLock(name) {\n let lock = null;\n return () => {\n const openLock = () => {\n lock = null;\n };\n if (lock === null) {\n lock = name;\n return openLock;\n }\n return false;\n };\n}\nconst globalHorizontalLock = createLock(\"dragHorizontal\");\nconst globalVerticalLock = createLock(\"dragVertical\");\nfunction getGlobalLock(drag) {\n let lock = false;\n if (drag === \"y\") {\n lock = globalVerticalLock();\n }\n else if (drag === \"x\") {\n lock = globalHorizontalLock();\n }\n else {\n const openHorizontal = globalHorizontalLock();\n const openVertical = globalVerticalLock();\n if (openHorizontal && openVertical) {\n lock = () => {\n openHorizontal();\n openVertical();\n };\n }\n else {\n // Release the locks because we don't use them\n if (openHorizontal)\n openHorizontal();\n if (openVertical)\n openVertical();\n }\n }\n return lock;\n}\nfunction isDragActive() {\n // Check the gesture lock - if we get it, it means no drag gesture is active\n // and we can safely fire the tap gesture.\n const openGestureLock = getGlobalLock(true);\n if (!openGestureLock)\n return true;\n openGestureLock();\n return false;\n}\n\nexport { createLock, getGlobalLock, isDragActive };\n","import { addDomEvent } from '../events/add-dom-event.mjs';\nimport { Feature } from '../motion/features/Feature.mjs';\nimport { pipe } from '../utils/pipe.mjs';\n\nclass FocusGesture extends Feature {\n constructor() {\n super(...arguments);\n this.isActive = false;\n }\n onFocus() {\n let isFocusVisible = false;\n /**\n * If this element doesn't match focus-visible then don't\n * apply whileHover. But, if matches throws that focus-visible\n * is not a valid selector then in that browser outline styles will be applied\n * to the element by default and we want to match that behaviour with whileFocus.\n */\n try {\n isFocusVisible = this.node.current.matches(\":focus-visible\");\n }\n catch (e) {\n isFocusVisible = true;\n }\n if (!isFocusVisible || !this.node.animationState)\n return;\n this.node.animationState.setActive(\"whileFocus\", true);\n this.isActive = true;\n }\n onBlur() {\n if (!this.isActive || !this.node.animationState)\n return;\n this.node.animationState.setActive(\"whileFocus\", false);\n this.isActive = false;\n }\n mount() {\n this.unmount = pipe(addDomEvent(this.node.current, \"focus\", () => this.onFocus()), addDomEvent(this.node.current, \"blur\", () => this.onBlur()));\n }\n unmount() { }\n}\n\nexport { FocusGesture };\n","import { addPointerEvent } from '../events/add-pointer-event.mjs';\nimport { pipe } from '../utils/pipe.mjs';\nimport { isDragActive } from './drag/utils/lock.mjs';\nimport { Feature } from '../motion/features/Feature.mjs';\nimport { frame } from '../frameloop/frame.mjs';\n\nfunction addHoverEvent(node, isActive) {\n const eventName = isActive ? \"pointerenter\" : \"pointerleave\";\n const callbackName = isActive ? \"onHoverStart\" : \"onHoverEnd\";\n const handleEvent = (event, info) => {\n if (event.pointerType === \"touch\" || isDragActive())\n return;\n const props = node.getProps();\n if (node.animationState && props.whileHover) {\n node.animationState.setActive(\"whileHover\", isActive);\n }\n const callback = props[callbackName];\n if (callback) {\n frame.postRender(() => callback(event, info));\n }\n };\n return addPointerEvent(node.current, eventName, handleEvent, {\n passive: !node.getProps()[callbackName],\n });\n}\nclass HoverGesture extends Feature {\n mount() {\n this.unmount = pipe(addHoverEvent(this.node, true), addHoverEvent(this.node, false));\n }\n unmount() { }\n}\n\nexport { HoverGesture };\n","import { extractEventInfo } from '../../events/event-info.mjs';\nimport { secondsToMilliseconds, millisecondsToSeconds } from '../../utils/time-conversion.mjs';\nimport { addPointerEvent } from '../../events/add-pointer-event.mjs';\nimport { pipe } from '../../utils/pipe.mjs';\nimport { distance2D } from '../../utils/distance.mjs';\nimport { isPrimaryPointer } from '../../events/utils/is-primary-pointer.mjs';\nimport { frame, cancelFrame, frameData } from '../../frameloop/frame.mjs';\n\n/**\n * @internal\n */\nclass PanSession {\n constructor(event, handlers, { transformPagePoint, contextWindow, dragSnapToOrigin = false } = {}) {\n /**\n * @internal\n */\n this.startEvent = null;\n /**\n * @internal\n */\n this.lastMoveEvent = null;\n /**\n * @internal\n */\n this.lastMoveEventInfo = null;\n /**\n * @internal\n */\n this.handlers = {};\n /**\n * @internal\n */\n this.contextWindow = window;\n this.updatePoint = () => {\n if (!(this.lastMoveEvent && this.lastMoveEventInfo))\n return;\n const info = getPanInfo(this.lastMoveEventInfo, this.history);\n const isPanStarted = this.startEvent !== null;\n // Only start panning if the offset is larger than 3 pixels. If we make it\n // any larger than this we'll want to reset the pointer history\n // on the first update to avoid visual snapping to the cursoe.\n const isDistancePastThreshold = distance2D(info.offset, { x: 0, y: 0 }) >= 3;\n if (!isPanStarted && !isDistancePastThreshold)\n return;\n const { point } = info;\n const { timestamp } = frameData;\n this.history.push({ ...point, timestamp });\n const { onStart, onMove } = this.handlers;\n if (!isPanStarted) {\n onStart && onStart(this.lastMoveEvent, info);\n this.startEvent = this.lastMoveEvent;\n }\n onMove && onMove(this.lastMoveEvent, info);\n };\n this.handlePointerMove = (event, info) => {\n this.lastMoveEvent = event;\n this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint);\n // Throttle mouse move event to once per frame\n frame.update(this.updatePoint, true);\n };\n this.handlePointerUp = (event, info) => {\n this.end();\n const { onEnd, onSessionEnd, resumeAnimation } = this.handlers;\n if (this.dragSnapToOrigin)\n resumeAnimation && resumeAnimation();\n if (!(this.lastMoveEvent && this.lastMoveEventInfo))\n return;\n const panInfo = getPanInfo(event.type === \"pointercancel\"\n ? this.lastMoveEventInfo\n : transformPoint(info, this.transformPagePoint), this.history);\n if (this.startEvent && onEnd) {\n onEnd(event, panInfo);\n }\n onSessionEnd && onSessionEnd(event, panInfo);\n };\n // If we have more than one touch, don't start detecting this gesture\n if (!isPrimaryPointer(event))\n return;\n this.dragSnapToOrigin = dragSnapToOrigin;\n this.handlers = handlers;\n this.transformPagePoint = transformPagePoint;\n this.contextWindow = contextWindow || window;\n const info = extractEventInfo(event);\n const initialInfo = transformPoint(info, this.transformPagePoint);\n const { point } = initialInfo;\n const { timestamp } = frameData;\n this.history = [{ ...point, timestamp }];\n const { onSessionStart } = handlers;\n onSessionStart &&\n onSessionStart(event, getPanInfo(initialInfo, this.history));\n this.removeListeners = pipe(addPointerEvent(this.contextWindow, \"pointermove\", this.handlePointerMove), addPointerEvent(this.contextWindow, \"pointerup\", this.handlePointerUp), addPointerEvent(this.contextWindow, \"pointercancel\", this.handlePointerUp));\n }\n updateHandlers(handlers) {\n this.handlers = handlers;\n }\n end() {\n this.removeListeners && this.removeListeners();\n cancelFrame(this.updatePoint);\n }\n}\nfunction transformPoint(info, transformPagePoint) {\n return transformPagePoint ? { point: transformPagePoint(info.point) } : info;\n}\nfunction subtractPoint(a, b) {\n return { x: a.x - b.x, y: a.y - b.y };\n}\nfunction getPanInfo({ point }, history) {\n return {\n point,\n delta: subtractPoint(point, lastDevicePoint(history)),\n offset: subtractPoint(point, startDevicePoint(history)),\n velocity: getVelocity(history, 0.1),\n };\n}\nfunction startDevicePoint(history) {\n return history[0];\n}\nfunction lastDevicePoint(history) {\n return history[history.length - 1];\n}\nfunction getVelocity(history, timeDelta) {\n if (history.length < 2) {\n return { x: 0, y: 0 };\n }\n let i = history.length - 1;\n let timestampedPoint = null;\n const lastPoint = lastDevicePoint(history);\n while (i >= 0) {\n timestampedPoint = history[i];\n if (lastPoint.timestamp - timestampedPoint.timestamp >\n secondsToMilliseconds(timeDelta)) {\n break;\n }\n i--;\n }\n if (!timestampedPoint) {\n return { x: 0, y: 0 };\n }\n const time = millisecondsToSeconds(lastPoint.timestamp - timestampedPoint.timestamp);\n if (time === 0) {\n return { x: 0, y: 0 };\n }\n const currentVelocity = {\n x: (lastPoint.x - timestampedPoint.x) / time,\n y: (lastPoint.y - timestampedPoint.y) / time,\n };\n if (currentVelocity.x === Infinity) {\n currentVelocity.x = 0;\n }\n if (currentVelocity.y === Infinity) {\n currentVelocity.y = 0;\n }\n return currentVelocity;\n}\n\nexport { PanSession };\n","import { PanSession } from './PanSession.mjs';\nimport { addPointerEvent } from '../../events/add-pointer-event.mjs';\nimport { Feature } from '../../motion/features/Feature.mjs';\nimport { noop } from '../../utils/noop.mjs';\nimport { getContextWindow } from '../../utils/get-context-window.mjs';\nimport { frame } from '../../frameloop/frame.mjs';\n\nconst asyncHandler = (handler) => (event, info) => {\n if (handler) {\n frame.postRender(() => handler(event, info));\n }\n};\nclass PanGesture extends Feature {\n constructor() {\n super(...arguments);\n this.removePointerDownListener = noop;\n }\n onPointerDown(pointerDownEvent) {\n this.session = new PanSession(pointerDownEvent, this.createPanHandlers(), {\n transformPagePoint: this.node.getTransformPagePoint(),\n contextWindow: getContextWindow(this.node),\n });\n }\n createPanHandlers() {\n const { onPanSessionStart, onPanStart, onPan, onPanEnd } = this.node.getProps();\n return {\n onSessionStart: asyncHandler(onPanSessionStart),\n onStart: asyncHandler(onPanStart),\n onMove: onPan,\n onEnd: (event, info) => {\n delete this.session;\n if (onPanEnd) {\n frame.postRender(() => onPanEnd(event, info));\n }\n },\n };\n }\n mount() {\n this.removePointerDownListener = addPointerEvent(this.node.current, \"pointerdown\", (event) => this.onPointerDown(event));\n }\n update() {\n this.session && this.session.updateHandlers(this.createPanHandlers());\n }\n unmount() {\n this.removePointerDownListener();\n this.session && this.session.end();\n }\n}\n\nexport { PanGesture };\n","import { extractEventInfo } from '../events/event-info.mjs';\nimport { addDomEvent } from '../events/add-dom-event.mjs';\nimport { addPointerEvent } from '../events/add-pointer-event.mjs';\nimport { Feature } from '../motion/features/Feature.mjs';\nimport { pipe } from '../utils/pipe.mjs';\nimport { isDragActive } from './drag/utils/lock.mjs';\nimport { isNodeOrChild } from './utils/is-node-or-child.mjs';\nimport { noop } from '../utils/noop.mjs';\nimport { frame } from '../frameloop/frame.mjs';\n\nfunction fireSyntheticPointerEvent(name, handler) {\n if (!handler)\n return;\n const syntheticPointerEvent = new PointerEvent(\"pointer\" + name);\n handler(syntheticPointerEvent, extractEventInfo(syntheticPointerEvent));\n}\nclass PressGesture extends Feature {\n constructor() {\n super(...arguments);\n this.removeStartListeners = noop;\n this.removeEndListeners = noop;\n this.removeAccessibleListeners = noop;\n this.startPointerPress = (startEvent, startInfo) => {\n if (this.isPressing)\n return;\n this.removeEndListeners();\n const props = this.node.getProps();\n const endPointerPress = (endEvent, endInfo) => {\n if (!this.checkPressEnd())\n return;\n const { onTap, onTapCancel, globalTapTarget } = this.node.getProps();\n /**\n * We only count this as a tap gesture if the event.target is the same\n * as, or a child of, this component's element\n */\n const handler = !globalTapTarget &&\n !isNodeOrChild(this.node.current, endEvent.target)\n ? onTapCancel\n : onTap;\n if (handler) {\n frame.update(() => handler(endEvent, endInfo));\n }\n };\n const removePointerUpListener = addPointerEvent(window, \"pointerup\", endPointerPress, {\n passive: !(props.onTap || props[\"onPointerUp\"]),\n });\n const removePointerCancelListener = addPointerEvent(window, \"pointercancel\", (cancelEvent, cancelInfo) => this.cancelPress(cancelEvent, cancelInfo), {\n passive: !(props.onTapCancel ||\n props[\"onPointerCancel\"]),\n });\n this.removeEndListeners = pipe(removePointerUpListener, removePointerCancelListener);\n this.startPress(startEvent, startInfo);\n };\n this.startAccessiblePress = () => {\n const handleKeydown = (keydownEvent) => {\n if (keydownEvent.key !== \"Enter\" || this.isPressing)\n return;\n const handleKeyup = (keyupEvent) => {\n if (keyupEvent.key !== \"Enter\" || !this.checkPressEnd())\n return;\n fireSyntheticPointerEvent(\"up\", (event, info) => {\n const { onTap } = this.node.getProps();\n if (onTap) {\n frame.postRender(() => onTap(event, info));\n }\n });\n };\n this.removeEndListeners();\n this.removeEndListeners = addDomEvent(this.node.current, \"keyup\", handleKeyup);\n fireSyntheticPointerEvent(\"down\", (event, info) => {\n this.startPress(event, info);\n });\n };\n const removeKeydownListener = addDomEvent(this.node.current, \"keydown\", handleKeydown);\n const handleBlur = () => {\n if (!this.isPressing)\n return;\n fireSyntheticPointerEvent(\"cancel\", (cancelEvent, cancelInfo) => this.cancelPress(cancelEvent, cancelInfo));\n };\n const removeBlurListener = addDomEvent(this.node.current, \"blur\", handleBlur);\n this.removeAccessibleListeners = pipe(removeKeydownListener, removeBlurListener);\n };\n }\n startPress(event, info) {\n this.isPressing = true;\n const { onTapStart, whileTap } = this.node.getProps();\n /**\n * Ensure we trigger animations before firing event callback\n */\n if (whileTap && this.node.animationState) {\n this.node.animationState.setActive(\"whileTap\", true);\n }\n if (onTapStart) {\n frame.postRender(() => onTapStart(event, info));\n }\n }\n checkPressEnd() {\n this.removeEndListeners();\n this.isPressing = false;\n const props = this.node.getProps();\n if (props.whileTap && this.node.animationState) {\n this.node.animationState.setActive(\"whileTap\", false);\n }\n return !isDragActive();\n }\n cancelPress(event, info) {\n if (!this.checkPressEnd())\n return;\n const { onTapCancel } = this.node.getProps();\n if (onTapCancel) {\n frame.postRender(() => onTapCancel(event, info));\n }\n }\n mount() {\n const props = this.node.getProps();\n const removePointerListener = addPointerEvent(props.globalTapTarget ? window : this.node.current, \"pointerdown\", this.startPointerPress, {\n passive: !(props.onTapStart ||\n props[\"onPointerStart\"]),\n });\n const removeFocusListener = addDomEvent(this.node.current, \"focus\", this.startAccessiblePress);\n this.removeStartListeners = pipe(removePointerListener, removeFocusListener);\n }\n unmount() {\n this.removeStartListeners();\n this.removeEndListeners();\n this.removeAccessibleListeners();\n }\n}\n\nexport { PressGesture };\n","/**\n * Recursively traverse up the tree to check whether the provided child node\n * is the parent or a descendant of it.\n *\n * @param parent - Element to find\n * @param child - Element to test against parent\n */\nconst isNodeOrChild = (parent, child) => {\n if (!child) {\n return false;\n }\n else if (parent === child) {\n return true;\n }\n else {\n return isNodeOrChild(parent, child.parentElement);\n }\n};\n\nexport { isNodeOrChild };\n","class Feature {\n constructor(node) {\n this.isMounted = false;\n this.node = node;\n }\n update() { }\n}\n\nexport { Feature };\n","import { Feature } from '../Feature.mjs';\n\nlet id = 0;\nclass ExitAnimationFeature extends Feature {\n constructor() {\n super(...arguments);\n this.id = id++;\n }\n update() {\n if (!this.node.presenceContext)\n return;\n const { isPresent, onExitComplete } = this.node.presenceContext;\n const { isPresent: prevIsPresent } = this.node.prevPresenceContext || {};\n if (!this.node.animationState || isPresent === prevIsPresent) {\n return;\n }\n const exitAnimation = this.node.animationState.setActive(\"exit\", !isPresent);\n if (onExitComplete && !isPresent) {\n exitAnimation.then(() => onExitComplete(this.id));\n }\n }\n mount() {\n const { register } = this.node.presenceContext || {};\n if (register) {\n this.unmount = register(this.id);\n }\n }\n unmount() { }\n}\n\nexport { ExitAnimationFeature };\n","import { isAnimationControls } from '../../../animation/utils/is-animation-controls.mjs';\nimport { createAnimationState } from '../../../render/utils/animation-state.mjs';\nimport { Feature } from '../Feature.mjs';\n\nclass AnimationFeature extends Feature {\n /**\n * We dynamically generate the AnimationState manager as it contains a reference\n * to the underlying animation library. We only want to load that if we load this,\n * so people can optionally code split it out using the `m` component.\n */\n constructor(node) {\n super(node);\n node.animationState || (node.animationState = createAnimationState(node));\n }\n updateAnimationControlsSubscription() {\n const { animate } = this.node.getProps();\n if (isAnimationControls(animate)) {\n this.unmountControls = animate.subscribe(this.node);\n }\n }\n /**\n * Subscribe any provided AnimationControls to the component's VisualElement\n */\n mount() {\n this.updateAnimationControlsSubscription();\n }\n update() {\n const { animate } = this.node.getProps();\n const { animate: prevAnimate } = this.node.prevProps || {};\n if (animate !== prevAnimate) {\n this.updateAnimationControlsSubscription();\n }\n }\n unmount() {\n var _a;\n this.node.animationState.reset();\n (_a = this.unmountControls) === null || _a === void 0 ? void 0 : _a.call(this);\n }\n}\n\nexport { AnimationFeature };\n","import { AnimationFeature } from './animation/index.mjs';\nimport { ExitAnimationFeature } from './animation/exit.mjs';\n\nconst animations = {\n animation: {\n Feature: AnimationFeature,\n },\n exit: {\n Feature: ExitAnimationFeature,\n },\n};\n\nexport { animations };\n","const featureProps = {\n animation: [\n \"animate\",\n \"variants\",\n \"whileHover\",\n \"whileTap\",\n \"exit\",\n \"whileInView\",\n \"whileFocus\",\n \"whileDrag\",\n ],\n exit: [\"exit\"],\n drag: [\"drag\", \"dragControls\"],\n focus: [\"whileFocus\"],\n hover: [\"whileHover\", \"onHoverStart\", \"onHoverEnd\"],\n tap: [\"whileTap\", \"onTap\", \"onTapStart\", \"onTapCancel\"],\n pan: [\"onPan\", \"onPanStart\", \"onPanSessionStart\", \"onPanEnd\"],\n inView: [\"whileInView\", \"onViewportEnter\", \"onViewportLeave\"],\n layout: [\"layout\", \"layoutId\"],\n};\nconst featureDefinitions = {};\nfor (const key in featureProps) {\n featureDefinitions[key] = {\n isEnabled: (props) => featureProps[key].some((name) => !!props[name]),\n };\n}\n\nexport { featureDefinitions };\n","import { DragGesture } from '../../gestures/drag/index.mjs';\nimport { PanGesture } from '../../gestures/pan/index.mjs';\nimport { MeasureLayout } from './layout/MeasureLayout.mjs';\nimport { HTMLProjectionNode } from '../../projection/node/HTMLProjectionNode.mjs';\n\nconst drag = {\n pan: {\n Feature: PanGesture,\n },\n drag: {\n Feature: DragGesture,\n ProjectionNode: HTMLProjectionNode,\n MeasureLayout,\n },\n};\n\nexport { drag };\n","import { HoverGesture } from '../../gestures/hover.mjs';\nimport { FocusGesture } from '../../gestures/focus.mjs';\nimport { PressGesture } from '../../gestures/press.mjs';\nimport { InViewFeature } from './viewport/index.mjs';\n\nconst gestureAnimations = {\n inView: {\n Feature: InViewFeature,\n },\n tap: {\n Feature: PressGesture,\n },\n focus: {\n Feature: FocusGesture,\n },\n hover: {\n Feature: HoverGesture,\n },\n};\n\nexport { gestureAnimations };\n","import { HTMLProjectionNode } from '../../projection/node/HTMLProjectionNode.mjs';\nimport { MeasureLayout } from './layout/MeasureLayout.mjs';\n\nconst layout = {\n layout: {\n ProjectionNode: HTMLProjectionNode,\n MeasureLayout,\n },\n};\n\nexport { layout };\n","\"use client\";\nimport { jsx } from 'react/jsx-runtime';\nimport { useContext, Component } from 'react';\nimport { usePresence } from '../../../components/AnimatePresence/use-presence.mjs';\nimport { LayoutGroupContext } from '../../../context/LayoutGroupContext.mjs';\nimport { SwitchLayoutGroupContext } from '../../../context/SwitchLayoutGroupContext.mjs';\nimport { globalProjectionState } from '../../../projection/node/state.mjs';\nimport { correctBorderRadius } from '../../../projection/styles/scale-border-radius.mjs';\nimport { correctBoxShadow } from '../../../projection/styles/scale-box-shadow.mjs';\nimport { addScaleCorrector } from '../../../projection/styles/scale-correction.mjs';\nimport { microtask } from '../../../frameloop/microtask.mjs';\nimport { frame } from '../../../frameloop/frame.mjs';\n\nclass MeasureLayoutWithContext extends Component {\n /**\n * This only mounts projection nodes for components that\n * need measuring, we might want to do it for all components\n * in order to incorporate transforms\n */\n componentDidMount() {\n const { visualElement, layoutGroup, switchLayoutGroup, layoutId } = this.props;\n const { projection } = visualElement;\n addScaleCorrector(defaultScaleCorrectors);\n if (projection) {\n if (layoutGroup.group)\n layoutGroup.group.add(projection);\n if (switchLayoutGroup && switchLayoutGroup.register && layoutId) {\n switchLayoutGroup.register(projection);\n }\n projection.root.didUpdate();\n projection.addEventListener(\"animationComplete\", () => {\n this.safeToRemove();\n });\n projection.setOptions({\n ...projection.options,\n onExitComplete: () => this.safeToRemove(),\n });\n }\n globalProjectionState.hasEverUpdated = true;\n }\n getSnapshotBeforeUpdate(prevProps) {\n const { layoutDependency, visualElement, drag, isPresent } = this.props;\n const projection = visualElement.projection;\n if (!projection)\n return null;\n /**\n * TODO: We use this data in relegate to determine whether to\n * promote a previous element. There's no guarantee its presence data\n * will have updated by this point - if a bug like this arises it will\n * have to be that we markForRelegation and then find a new lead some other way,\n * perhaps in didUpdate\n */\n projection.isPresent = isPresent;\n if (drag ||\n prevProps.layoutDependency !== layoutDependency ||\n layoutDependency === undefined) {\n projection.willUpdate();\n }\n else {\n this.safeToRemove();\n }\n if (prevProps.isPresent !== isPresent) {\n if (isPresent) {\n projection.promote();\n }\n else if (!projection.relegate()) {\n /**\n * If there's another stack member taking over from this one,\n * it's in charge of the exit animation and therefore should\n * be in charge of the safe to remove. Otherwise we call it here.\n */\n frame.postRender(() => {\n const stack = projection.getStack();\n if (!stack || !stack.members.length) {\n this.safeToRemove();\n }\n });\n }\n }\n return null;\n }\n componentDidUpdate() {\n const { projection } = this.props.visualElement;\n if (projection) {\n projection.root.didUpdate();\n microtask.postRender(() => {\n if (!projection.currentAnimation && projection.isLead()) {\n this.safeToRemove();\n }\n });\n }\n }\n componentWillUnmount() {\n const { visualElement, layoutGroup, switchLayoutGroup: promoteContext, } = this.props;\n const { projection } = visualElement;\n if (projection) {\n projection.scheduleCheckAfterUnmount();\n if (layoutGroup && layoutGroup.group)\n layoutGroup.group.remove(projection);\n if (promoteContext && promoteContext.deregister)\n promoteContext.deregister(projection);\n }\n }\n safeToRemove() {\n const { safeToRemove } = this.props;\n safeToRemove && safeToRemove();\n }\n render() {\n return null;\n }\n}\nfunction MeasureLayout(props) {\n const [isPresent, safeToRemove] = usePresence();\n const layoutGroup = useContext(LayoutGroupContext);\n return (jsx(MeasureLayoutWithContext, { ...props, layoutGroup: layoutGroup, switchLayoutGroup: useContext(SwitchLayoutGroupContext), isPresent: isPresent, safeToRemove: safeToRemove }));\n}\nconst defaultScaleCorrectors = {\n borderRadius: {\n ...correctBorderRadius,\n applyTo: [\n \"borderTopLeftRadius\",\n \"borderTopRightRadius\",\n \"borderBottomLeftRadius\",\n \"borderBottomRightRadius\",\n ],\n },\n borderTopLeftRadius: correctBorderRadius,\n borderTopRightRadius: correctBorderRadius,\n borderBottomLeftRadius: correctBorderRadius,\n borderBottomRightRadius: correctBorderRadius,\n boxShadow: correctBoxShadow,\n};\n\nexport { MeasureLayout };\n","import { featureDefinitions } from './definitions.mjs';\n\nfunction loadFeatures(features) {\n for (const key in features) {\n featureDefinitions[key] = {\n ...featureDefinitions[key],\n ...features[key],\n };\n }\n}\n\nexport { loadFeatures };\n","import { Feature } from '../Feature.mjs';\nimport { observeIntersection } from './observers.mjs';\n\nconst thresholdNames = {\n some: 0,\n all: 1,\n};\nclass InViewFeature extends Feature {\n constructor() {\n super(...arguments);\n this.hasEnteredView = false;\n this.isInView = false;\n }\n startObserver() {\n this.unmount();\n const { viewport = {} } = this.node.getProps();\n const { root, margin: rootMargin, amount = \"some\", once } = viewport;\n const options = {\n root: root ? root.current : undefined,\n rootMargin,\n threshold: typeof amount === \"number\" ? amount : thresholdNames[amount],\n };\n const onIntersectionUpdate = (entry) => {\n const { isIntersecting } = entry;\n /**\n * If there's been no change in the viewport state, early return.\n */\n if (this.isInView === isIntersecting)\n return;\n this.isInView = isIntersecting;\n /**\n * Handle hasEnteredView. If this is only meant to run once, and\n * element isn't visible, early return. Otherwise set hasEnteredView to true.\n */\n if (once && !isIntersecting && this.hasEnteredView) {\n return;\n }\n else if (isIntersecting) {\n this.hasEnteredView = true;\n }\n if (this.node.animationState) {\n this.node.animationState.setActive(\"whileInView\", isIntersecting);\n }\n /**\n * Use the latest committed props rather than the ones in scope\n * when this observer is created\n */\n const { onViewportEnter, onViewportLeave } = this.node.getProps();\n const callback = isIntersecting ? onViewportEnter : onViewportLeave;\n callback && callback(entry);\n };\n return observeIntersection(this.node.current, options, onIntersectionUpdate);\n }\n mount() {\n this.startObserver();\n }\n update() {\n if (typeof IntersectionObserver === \"undefined\")\n return;\n const { props, prevProps } = this.node;\n const hasOptionsChanged = [\"amount\", \"margin\", \"root\"].some(hasViewportOptionChanged(props, prevProps));\n if (hasOptionsChanged) {\n this.startObserver();\n }\n }\n unmount() { }\n}\nfunction hasViewportOptionChanged({ viewport = {} }, { viewport: prevViewport = {} } = {}) {\n return (name) => viewport[name] !== prevViewport[name];\n}\n\nexport { InViewFeature };\n","/**\n * Map an IntersectionHandler callback to an element. We only ever make one handler for one\n * element, so even though these handlers might all be triggered by different\n * observers, we can keep them in the same map.\n */\nconst observerCallbacks = new WeakMap();\n/**\n * Multiple observers can be created for multiple element/document roots. Each with\n * different settings. So here we store dictionaries of observers to each root,\n * using serialised settings (threshold/margin) as lookup keys.\n */\nconst observers = new WeakMap();\nconst fireObserverCallback = (entry) => {\n const callback = observerCallbacks.get(entry.target);\n callback && callback(entry);\n};\nconst fireAllObserverCallbacks = (entries) => {\n entries.forEach(fireObserverCallback);\n};\nfunction initIntersectionObserver({ root, ...options }) {\n const lookupRoot = root || document;\n /**\n * If we don't have an observer lookup map for this root, create one.\n */\n if (!observers.has(lookupRoot)) {\n observers.set(lookupRoot, {});\n }\n const rootObservers = observers.get(lookupRoot);\n const key = JSON.stringify(options);\n /**\n * If we don't have an observer for this combination of root and settings,\n * create one.\n */\n if (!rootObservers[key]) {\n rootObservers[key] = new IntersectionObserver(fireAllObserverCallbacks, { root, ...options });\n }\n return rootObservers[key];\n}\nfunction observeIntersection(element, options, callback) {\n const rootInteresectionObserver = initIntersectionObserver(options);\n observerCallbacks.set(element, callback);\n rootInteresectionObserver.observe(element);\n return () => {\n observerCallbacks.delete(element);\n rootInteresectionObserver.unobserve(element);\n };\n}\n\nexport { observeIntersection };\n","\"use client\";\nimport { jsxs, jsx } from 'react/jsx-runtime';\nimport { forwardRef, useContext } from 'react';\nimport { MotionConfigContext } from '../context/MotionConfigContext.mjs';\nimport { MotionContext } from '../context/MotionContext/index.mjs';\nimport { useVisualElement } from './utils/use-visual-element.mjs';\nimport { useMotionRef } from './utils/use-motion-ref.mjs';\nimport { useCreateMotionContext } from '../context/MotionContext/create.mjs';\nimport { loadFeatures } from './features/load-features.mjs';\nimport { isBrowser } from '../utils/is-browser.mjs';\nimport { LayoutGroupContext } from '../context/LayoutGroupContext.mjs';\nimport { LazyContext } from '../context/LazyContext.mjs';\nimport { motionComponentSymbol } from './utils/symbol.mjs';\nimport { warning, invariant } from '../utils/errors.mjs';\nimport { featureDefinitions } from './features/definitions.mjs';\n\n/**\n * Create a `motion` component.\n *\n * This function accepts a Component argument, which can be either a string (ie \"div\"\n * for `motion.div`), or an actual React component.\n *\n * Alongside this is a config option which provides a way of rendering the provided\n * component \"offline\", or outside the React render cycle.\n */\nfunction createRendererMotionComponent({ preloadedFeatures, createVisualElement, useRender, useVisualState, Component, }) {\n preloadedFeatures && loadFeatures(preloadedFeatures);\n function MotionComponent(props, externalRef) {\n /**\n * If we need to measure the element we load this functionality in a\n * separate class component in order to gain access to getSnapshotBeforeUpdate.\n */\n let MeasureLayout;\n const configAndProps = {\n ...useContext(MotionConfigContext),\n ...props,\n layoutId: useLayoutId(props),\n };\n const { isStatic } = configAndProps;\n const context = useCreateMotionContext(props);\n const visualState = useVisualState(props, isStatic);\n if (!isStatic && isBrowser) {\n useStrictMode(configAndProps, preloadedFeatures);\n const layoutProjection = getProjectionFunctionality(configAndProps);\n MeasureLayout = layoutProjection.MeasureLayout;\n /**\n * Create a VisualElement for this component. A VisualElement provides a common\n * interface to renderer-specific APIs (ie DOM/Three.js etc) as well as\n * providing a way of rendering to these APIs outside of the React render loop\n * for more performant animations and interactions\n */\n context.visualElement = useVisualElement(Component, visualState, configAndProps, createVisualElement, layoutProjection.ProjectionNode);\n }\n /**\n * The mount order and hierarchy is specific to ensure our element ref\n * is hydrated by the time features fire their effects.\n */\n return (jsxs(MotionContext.Provider, { value: context, children: [MeasureLayout && context.visualElement ? (jsx(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null, useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, context.visualElement)] }));\n }\n const ForwardRefMotionComponent = forwardRef(MotionComponent);\n ForwardRefMotionComponent[motionComponentSymbol] = Component;\n return ForwardRefMotionComponent;\n}\nfunction useLayoutId({ layoutId }) {\n const layoutGroupId = useContext(LayoutGroupContext).id;\n return layoutGroupId && layoutId !== undefined\n ? layoutGroupId + \"-\" + layoutId\n : layoutId;\n}\nfunction useStrictMode(configAndProps, preloadedFeatures) {\n const isStrict = useContext(LazyContext).strict;\n /**\n * If we're in development mode, check to make sure we're not rendering a motion component\n * as a child of LazyMotion, as this will break the file-size benefits of using it.\n */\n if (process.env.NODE_ENV !== \"production\" &&\n preloadedFeatures &&\n isStrict) {\n const strictMessage = \"You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead.\";\n configAndProps.ignoreStrict\n ? warning(false, strictMessage)\n : invariant(false, strictMessage);\n }\n}\nfunction getProjectionFunctionality(props) {\n const { drag, layout } = featureDefinitions;\n if (!drag && !layout)\n return {};\n const combined = { ...drag, ...layout };\n return {\n MeasureLayout: (drag === null || drag === void 0 ? void 0 : drag.isEnabled(props)) || (layout === null || layout === void 0 ? void 0 : layout.isEnabled(props))\n ? combined.MeasureLayout\n : undefined,\n ProjectionNode: combined.ProjectionNode,\n };\n}\n\nexport { createRendererMotionComponent };\n","import { scaleCorrectors } from '../../projection/styles/scale-correction.mjs';\nimport { transformProps } from '../../render/html/utils/transform.mjs';\n\nfunction isForcedMotionValue(key, { layout, layoutId }) {\n return (transformProps.has(key) ||\n key.startsWith(\"origin\") ||\n ((layout || layoutId !== undefined) &&\n (!!scaleCorrectors[key] || key === \"opacity\")));\n}\n\nexport { isForcedMotionValue };\n","const motionComponentSymbol = Symbol.for(\"motionComponentSymbol\");\n\nexport { motionComponentSymbol };\n","import { useCallback } from 'react';\nimport { isRefObject } from '../../utils/is-ref-object.mjs';\n\n/**\n * Creates a ref function that, when called, hydrates the provided\n * external ref and VisualElement.\n */\nfunction useMotionRef(visualState, visualElement, externalRef) {\n return useCallback((instance) => {\n instance && visualState.mount && visualState.mount(instance);\n if (visualElement) {\n if (instance) {\n visualElement.mount(instance);\n }\n else {\n visualElement.unmount();\n }\n }\n if (externalRef) {\n if (typeof externalRef === \"function\") {\n externalRef(instance);\n }\n else if (isRefObject(externalRef)) {\n externalRef.current = instance;\n }\n }\n }, \n /**\n * Only pass a new ref callback to React if we've received a visual element\n * factory. Otherwise we'll be mounting/remounting every time externalRef\n * or other dependencies change.\n */\n [visualElement]);\n}\n\nexport { useMotionRef };\n","import { useContext, useRef, useInsertionEffect, useEffect } from 'react';\nimport { PresenceContext } from '../../context/PresenceContext.mjs';\nimport { MotionContext } from '../../context/MotionContext/index.mjs';\nimport { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';\nimport { LazyContext } from '../../context/LazyContext.mjs';\nimport { MotionConfigContext } from '../../context/MotionConfigContext.mjs';\nimport { optimizedAppearDataAttribute } from '../../animation/optimized-appear/data-id.mjs';\nimport { microtask } from '../../frameloop/microtask.mjs';\nimport { isRefObject } from '../../utils/is-ref-object.mjs';\nimport { SwitchLayoutGroupContext } from '../../context/SwitchLayoutGroupContext.mjs';\n\nlet scheduleHandoffComplete = false;\nfunction useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor) {\n var _a;\n const { visualElement: parent } = useContext(MotionContext);\n const lazyContext = useContext(LazyContext);\n const presenceContext = useContext(PresenceContext);\n const reducedMotionConfig = useContext(MotionConfigContext).reducedMotion;\n const visualElementRef = useRef();\n /**\n * If we haven't preloaded a renderer, check to see if we have one lazy-loaded\n */\n createVisualElement = createVisualElement || lazyContext.renderer;\n if (!visualElementRef.current && createVisualElement) {\n visualElementRef.current = createVisualElement(Component, {\n visualState,\n parent,\n props,\n presenceContext,\n blockInitialAnimation: presenceContext\n ? presenceContext.initial === false\n : false,\n reducedMotionConfig,\n });\n }\n const visualElement = visualElementRef.current;\n /**\n * Load Motion gesture and animation features. These are rendered as renderless\n * components so each feature can optionally make use of React lifecycle methods.\n */\n const initialLayoutGroupConfig = useContext(SwitchLayoutGroupContext);\n if (visualElement &&\n !visualElement.projection &&\n ProjectionNodeConstructor &&\n (visualElement.type === \"html\" || visualElement.type === \"svg\")) {\n createProjectionNode(visualElementRef.current, props, ProjectionNodeConstructor, initialLayoutGroupConfig);\n }\n useInsertionEffect(() => {\n visualElement && visualElement.update(props, presenceContext);\n });\n /**\n * Cache this value as we want to know whether HandoffAppearAnimations\n * was present on initial render - it will be deleted after this.\n */\n const optimisedAppearId = props[optimizedAppearDataAttribute];\n const wantsHandoff = useRef(Boolean(optimisedAppearId) &&\n !window.MotionHandoffIsComplete &&\n ((_a = window.MotionHasOptimisedAnimation) === null || _a === void 0 ? void 0 : _a.call(window, optimisedAppearId)));\n useIsomorphicLayoutEffect(() => {\n if (!visualElement)\n return;\n visualElement.updateFeatures();\n microtask.render(visualElement.render);\n /**\n * Ideally this function would always run in a useEffect.\n *\n * However, if we have optimised appear animations to handoff from,\n * it needs to happen synchronously to ensure there's no flash of\n * incorrect styles in the event of a hydration error.\n *\n * So if we detect a situtation where optimised appear animations\n * are running, we use useLayoutEffect to trigger animations.\n */\n if (wantsHandoff.current && visualElement.animationState) {\n visualElement.animationState.animateChanges();\n }\n });\n useEffect(() => {\n if (!visualElement)\n return;\n if (!wantsHandoff.current && visualElement.animationState) {\n visualElement.animationState.animateChanges();\n }\n wantsHandoff.current = false;\n // This ensures all future calls to animateChanges() will run in useEffect\n if (!scheduleHandoffComplete) {\n scheduleHandoffComplete = true;\n queueMicrotask(completeHandoff);\n }\n });\n return visualElement;\n}\nfunction completeHandoff() {\n window.MotionHandoffIsComplete = true;\n}\nfunction createProjectionNode(visualElement, props, ProjectionNodeConstructor, initialPromotionConfig) {\n const { layoutId, layout, drag, dragConstraints, layoutScroll, layoutRoot, } = props;\n visualElement.projection = new ProjectionNodeConstructor(visualElement.latestValues, props[\"data-framer-portal-id\"]\n ? undefined\n : getClosestProjectingNode(visualElement.parent));\n visualElement.projection.setOptions({\n layoutId,\n layout,\n alwaysMeasureLayout: Boolean(drag) || (dragConstraints && isRefObject(dragConstraints)),\n visualElement,\n /**\n * TODO: Update options in an effect. This could be tricky as it'll be too late\n * to update by the time layout animations run.\n * We also need to fix this safeToRemove by linking it up to the one returned by usePresence,\n * ensuring it gets called if there's no potential layout animations.\n *\n */\n animationType: typeof layout === \"string\" ? layout : \"both\",\n initialPromotionConfig,\n layoutScroll,\n layoutRoot,\n });\n}\nfunction getClosestProjectingNode(visualElement) {\n if (!visualElement)\n return undefined;\n return visualElement.options.allowProjection !== false\n ? visualElement.projection\n : getClosestProjectingNode(visualElement.parent);\n}\n\nexport { useVisualElement };\n","import { useContext } from 'react';\nimport { isAnimationControls } from '../../animation/utils/is-animation-controls.mjs';\nimport { PresenceContext } from '../../context/PresenceContext.mjs';\nimport { resolveVariantFromProps } from '../../render/utils/resolve-variants.mjs';\nimport { useConstant } from '../../utils/use-constant.mjs';\nimport { resolveMotionValue } from '../../value/utils/resolve-motion-value.mjs';\nimport { MotionContext } from '../../context/MotionContext/index.mjs';\nimport { isControllingVariants, isVariantNode } from '../../render/utils/is-controlling-variants.mjs';\nimport { getWillChangeName } from '../../value/use-will-change/get-will-change-name.mjs';\nimport { addUniqueItem } from '../../utils/array.mjs';\n\nfunction makeState({ applyWillChange = false, scrapeMotionValuesFromProps, createRenderState, onMount, }, props, context, presenceContext, isStatic) {\n const state = {\n latestValues: makeLatestValues(props, context, presenceContext, isStatic ? false : applyWillChange, scrapeMotionValuesFromProps),\n renderState: createRenderState(),\n };\n if (onMount) {\n state.mount = (instance) => onMount(props, instance, state);\n }\n return state;\n}\nconst makeUseVisualState = (config) => (props, isStatic) => {\n const context = useContext(MotionContext);\n const presenceContext = useContext(PresenceContext);\n const make = () => makeState(config, props, context, presenceContext, isStatic);\n return isStatic ? make() : useConstant(make);\n};\nfunction addWillChange(willChange, name) {\n const memberName = getWillChangeName(name);\n if (memberName) {\n addUniqueItem(willChange, memberName);\n }\n}\nfunction forEachDefinition(props, definition, callback) {\n const list = Array.isArray(definition) ? definition : [definition];\n for (let i = 0; i < list.length; i++) {\n const resolved = resolveVariantFromProps(props, list[i]);\n if (resolved) {\n const { transitionEnd, transition, ...target } = resolved;\n callback(target, transitionEnd);\n }\n }\n}\nfunction makeLatestValues(props, context, presenceContext, shouldApplyWillChange, scrapeMotionValues) {\n var _a;\n const values = {};\n const willChange = [];\n const applyWillChange = shouldApplyWillChange && ((_a = props.style) === null || _a === void 0 ? void 0 : _a.willChange) === undefined;\n const motionValues = scrapeMotionValues(props, {});\n for (const key in motionValues) {\n values[key] = resolveMotionValue(motionValues[key]);\n }\n let { initial, animate } = props;\n const isControllingVariants$1 = isControllingVariants(props);\n const isVariantNode$1 = isVariantNode(props);\n if (context &&\n isVariantNode$1 &&\n !isControllingVariants$1 &&\n props.inherit !== false) {\n if (initial === undefined)\n initial = context.initial;\n if (animate === undefined)\n animate = context.animate;\n }\n let isInitialAnimationBlocked = presenceContext\n ? presenceContext.initial === false\n : false;\n isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;\n const variantToSet = isInitialAnimationBlocked ? animate : initial;\n if (variantToSet &&\n typeof variantToSet !== \"boolean\" &&\n !isAnimationControls(variantToSet)) {\n forEachDefinition(props, variantToSet, (target, transitionEnd) => {\n for (const key in target) {\n let valueTarget = target[key];\n if (Array.isArray(valueTarget)) {\n /**\n * Take final keyframe if the initial animation is blocked because\n * we want to initialise at the end of that blocked animation.\n */\n const index = isInitialAnimationBlocked\n ? valueTarget.length - 1\n : 0;\n valueTarget = valueTarget[index];\n }\n if (valueTarget !== null) {\n values[key] = valueTarget;\n }\n }\n for (const key in transitionEnd) {\n values[key] = transitionEnd[key];\n }\n });\n }\n // Add animating values to will-change\n if (applyWillChange) {\n if (animate && initial !== false && !isAnimationControls(animate)) {\n forEachDefinition(props, animate, (target) => {\n for (const key in target) {\n addWillChange(willChange, key);\n }\n });\n }\n if (willChange.length) {\n values.willChange = willChange.join(\",\");\n }\n }\n return values;\n}\n\nexport { makeUseVisualState };\n","/**\n * A list of all valid MotionProps.\n *\n * @privateRemarks\n * This doesn't throw if a `MotionProp` name is missing - it should.\n */\nconst validMotionProps = new Set([\n \"animate\",\n \"exit\",\n \"variants\",\n \"initial\",\n \"style\",\n \"values\",\n \"variants\",\n \"transition\",\n \"transformTemplate\",\n \"custom\",\n \"inherit\",\n \"onBeforeLayoutMeasure\",\n \"onAnimationStart\",\n \"onAnimationComplete\",\n \"onUpdate\",\n \"onDragStart\",\n \"onDrag\",\n \"onDragEnd\",\n \"onMeasureDragConstraints\",\n \"onDirectionLock\",\n \"onDragTransitionEnd\",\n \"_dragX\",\n \"_dragY\",\n \"onHoverStart\",\n \"onHoverEnd\",\n \"onViewportEnter\",\n \"onViewportLeave\",\n \"globalTapTarget\",\n \"ignoreStrict\",\n \"viewport\",\n]);\n/**\n * Check whether a prop name is a valid `MotionProp` key.\n *\n * @param key - Name of the property to check\n * @returns `true` is key is a valid `MotionProp`.\n *\n * @public\n */\nfunction isValidMotionProp(key) {\n return (key.startsWith(\"while\") ||\n (key.startsWith(\"drag\") && key !== \"draggable\") ||\n key.startsWith(\"layout\") ||\n key.startsWith(\"onTap\") ||\n key.startsWith(\"onPan\") ||\n key.startsWith(\"onLayout\") ||\n validMotionProps.has(key));\n}\n\nexport { isValidMotionProp };\n","import { circOut } from '../../easing/circ.mjs';\nimport { progress } from '../../utils/progress.mjs';\nimport { mixNumber } from '../../utils/mix/number.mjs';\nimport { noop } from '../../utils/noop.mjs';\nimport { percent, px } from '../../value/types/numbers/units.mjs';\n\nconst borders = [\"TopLeft\", \"TopRight\", \"BottomLeft\", \"BottomRight\"];\nconst numBorders = borders.length;\nconst asNumber = (value) => typeof value === \"string\" ? parseFloat(value) : value;\nconst isPx = (value) => typeof value === \"number\" || px.test(value);\nfunction mixValues(target, follow, lead, progress, shouldCrossfadeOpacity, isOnlyMember) {\n if (shouldCrossfadeOpacity) {\n target.opacity = mixNumber(0, \n // TODO Reinstate this if only child\n lead.opacity !== undefined ? lead.opacity : 1, easeCrossfadeIn(progress));\n target.opacityExit = mixNumber(follow.opacity !== undefined ? follow.opacity : 1, 0, easeCrossfadeOut(progress));\n }\n else if (isOnlyMember) {\n target.opacity = mixNumber(follow.opacity !== undefined ? follow.opacity : 1, lead.opacity !== undefined ? lead.opacity : 1, progress);\n }\n /**\n * Mix border radius\n */\n for (let i = 0; i < numBorders; i++) {\n const borderLabel = `border${borders[i]}Radius`;\n let followRadius = getRadius(follow, borderLabel);\n let leadRadius = getRadius(lead, borderLabel);\n if (followRadius === undefined && leadRadius === undefined)\n continue;\n followRadius || (followRadius = 0);\n leadRadius || (leadRadius = 0);\n const canMix = followRadius === 0 ||\n leadRadius === 0 ||\n isPx(followRadius) === isPx(leadRadius);\n if (canMix) {\n target[borderLabel] = Math.max(mixNumber(asNumber(followRadius), asNumber(leadRadius), progress), 0);\n if (percent.test(leadRadius) || percent.test(followRadius)) {\n target[borderLabel] += \"%\";\n }\n }\n else {\n target[borderLabel] = leadRadius;\n }\n }\n /**\n * Mix rotation\n */\n if (follow.rotate || lead.rotate) {\n target.rotate = mixNumber(follow.rotate || 0, lead.rotate || 0, progress);\n }\n}\nfunction getRadius(values, radiusName) {\n return values[radiusName] !== undefined\n ? values[radiusName]\n : values.borderRadius;\n}\n// /**\n// * We only want to mix the background color if there's a follow element\n// * that we're not crossfading opacity between. For instance with switch\n// * AnimateSharedLayout animations, this helps the illusion of a continuous\n// * element being animated but also cuts down on the number of paints triggered\n// * for elements where opacity is doing that work for us.\n// */\n// if (\n// !hasFollowElement &&\n// latestLeadValues.backgroundColor &&\n// latestFollowValues.backgroundColor\n// ) {\n// /**\n// * This isn't ideal performance-wise as mixColor is creating a new function every frame.\n// * We could probably create a mixer that runs at the start of the animation but\n// * the idea behind the crossfader is that it runs dynamically between two potentially\n// * changing targets (ie opacity or borderRadius may be animating independently via variants)\n// */\n// leadState.backgroundColor = followState.backgroundColor = mixColor(\n// latestFollowValues.backgroundColor as string,\n// latestLeadValues.backgroundColor as string\n// )(p)\n// }\nconst easeCrossfadeIn = compress(0, 0.5, circOut);\nconst easeCrossfadeOut = compress(0.5, 0.95, noop);\nfunction compress(min, max, easing) {\n return (p) => {\n // Could replace ifs with clamp\n if (p < min)\n return 0;\n if (p > max)\n return 1;\n return easing(progress(min, max, p));\n };\n}\n\nexport { mixValues };\n","/**\n * Bounding boxes tend to be defined as top, left, right, bottom. For various operations\n * it's easier to consider each axis individually. This function returns a bounding box\n * as a map of single-axis min/max values.\n */\nfunction convertBoundingBoxToBox({ top, left, right, bottom, }) {\n return {\n x: { min: left, max: right },\n y: { min: top, max: bottom },\n };\n}\nfunction convertBoxToBoundingBox({ x, y }) {\n return { top: y.min, right: x.max, bottom: y.max, left: x.min };\n}\n/**\n * Applies a TransformPoint function to a bounding box. TransformPoint is usually a function\n * provided by Framer to allow measured points to be corrected for device scaling. This is used\n * when measuring DOM elements and DOM event points.\n */\nfunction transformBoxPoints(point, transformPoint) {\n if (!transformPoint)\n return point;\n const topLeft = transformPoint({ x: point.left, y: point.top });\n const bottomRight = transformPoint({ x: point.right, y: point.bottom });\n return {\n top: topLeft.y,\n left: topLeft.x,\n bottom: bottomRight.y,\n right: bottomRight.x,\n };\n}\n\nexport { convertBoundingBoxToBox, convertBoxToBoundingBox, transformBoxPoints };\n","/**\n * Reset an axis to the provided origin box.\n *\n * This is a mutative operation.\n */\nfunction copyAxisInto(axis, originAxis) {\n axis.min = originAxis.min;\n axis.max = originAxis.max;\n}\n/**\n * Reset a box to the provided origin box.\n *\n * This is a mutative operation.\n */\nfunction copyBoxInto(box, originBox) {\n copyAxisInto(box.x, originBox.x);\n copyAxisInto(box.y, originBox.y);\n}\n/**\n * Reset a delta to the provided origin box.\n *\n * This is a mutative operation.\n */\nfunction copyAxisDeltaInto(delta, originDelta) {\n delta.translate = originDelta.translate;\n delta.scale = originDelta.scale;\n delta.originPoint = originDelta.originPoint;\n delta.origin = originDelta.origin;\n}\n\nexport { copyAxisDeltaInto, copyAxisInto, copyBoxInto };\n","import { mixNumber } from '../../utils/mix/number.mjs';\nimport { hasTransform } from '../utils/has-transform.mjs';\n\n/**\n * Scales a point based on a factor and an originPoint\n */\nfunction scalePoint(point, scale, originPoint) {\n const distanceFromOrigin = point - originPoint;\n const scaled = scale * distanceFromOrigin;\n return originPoint + scaled;\n}\n/**\n * Applies a translate/scale delta to a point\n */\nfunction applyPointDelta(point, translate, scale, originPoint, boxScale) {\n if (boxScale !== undefined) {\n point = scalePoint(point, boxScale, originPoint);\n }\n return scalePoint(point, scale, originPoint) + translate;\n}\n/**\n * Applies a translate/scale delta to an axis\n */\nfunction applyAxisDelta(axis, translate = 0, scale = 1, originPoint, boxScale) {\n axis.min = applyPointDelta(axis.min, translate, scale, originPoint, boxScale);\n axis.max = applyPointDelta(axis.max, translate, scale, originPoint, boxScale);\n}\n/**\n * Applies a translate/scale delta to a box\n */\nfunction applyBoxDelta(box, { x, y }) {\n applyAxisDelta(box.x, x.translate, x.scale, x.originPoint);\n applyAxisDelta(box.y, y.translate, y.scale, y.originPoint);\n}\nconst TREE_SCALE_SNAP_MIN = 0.999999999999;\nconst TREE_SCALE_SNAP_MAX = 1.0000000000001;\n/**\n * Apply a tree of deltas to a box. We do this to calculate the effect of all the transforms\n * in a tree upon our box before then calculating how to project it into our desired viewport-relative box\n *\n * This is the final nested loop within updateLayoutDelta for future refactoring\n */\nfunction applyTreeDeltas(box, treeScale, treePath, isSharedTransition = false) {\n const treeLength = treePath.length;\n if (!treeLength)\n return;\n // Reset the treeScale\n treeScale.x = treeScale.y = 1;\n let node;\n let delta;\n for (let i = 0; i < treeLength; i++) {\n node = treePath[i];\n delta = node.projectionDelta;\n /**\n * TODO: Prefer to remove this, but currently we have motion components with\n * display: contents in Framer.\n */\n const { visualElement } = node.options;\n if (visualElement &&\n visualElement.props.style &&\n visualElement.props.style.display === \"contents\") {\n continue;\n }\n if (isSharedTransition &&\n node.options.layoutScroll &&\n node.scroll &&\n node !== node.root) {\n transformBox(box, {\n x: -node.scroll.offset.x,\n y: -node.scroll.offset.y,\n });\n }\n if (delta) {\n // Incoporate each ancestor's scale into a culmulative treeScale for this component\n treeScale.x *= delta.x.scale;\n treeScale.y *= delta.y.scale;\n // Apply each ancestor's calculated delta into this component's recorded layout box\n applyBoxDelta(box, delta);\n }\n if (isSharedTransition && hasTransform(node.latestValues)) {\n transformBox(box, node.latestValues);\n }\n }\n /**\n * Snap tree scale back to 1 if it's within a non-perceivable threshold.\n * This will help reduce useless scales getting rendered.\n */\n if (treeScale.x < TREE_SCALE_SNAP_MAX &&\n treeScale.x > TREE_SCALE_SNAP_MIN) {\n treeScale.x = 1.0;\n }\n if (treeScale.y < TREE_SCALE_SNAP_MAX &&\n treeScale.y > TREE_SCALE_SNAP_MIN) {\n treeScale.y = 1.0;\n }\n}\nfunction translateAxis(axis, distance) {\n axis.min = axis.min + distance;\n axis.max = axis.max + distance;\n}\n/**\n * Apply a transform to an axis from the latest resolved motion values.\n * This function basically acts as a bridge between a flat motion value map\n * and applyAxisDelta\n */\nfunction transformAxis(axis, axisTranslate, axisScale, boxScale, axisOrigin = 0.5) {\n const originPoint = mixNumber(axis.min, axis.max, axisOrigin);\n // Apply the axis delta to the final axis\n applyAxisDelta(axis, axisTranslate, axisScale, originPoint, boxScale);\n}\n/**\n * Apply a transform to a box from the latest resolved motion values.\n */\nfunction transformBox(box, transform) {\n transformAxis(box.x, transform.x, transform.scaleX, transform.scale, transform.originX);\n transformAxis(box.y, transform.y, transform.scaleY, transform.scale, transform.originY);\n}\n\nexport { applyAxisDelta, applyBoxDelta, applyPointDelta, applyTreeDeltas, scalePoint, transformAxis, transformBox, translateAxis };\n","import { mixNumber } from '../../utils/mix/number.mjs';\n\nconst SCALE_PRECISION = 0.0001;\nconst SCALE_MIN = 1 - SCALE_PRECISION;\nconst SCALE_MAX = 1 + SCALE_PRECISION;\nconst TRANSLATE_PRECISION = 0.01;\nconst TRANSLATE_MIN = 0 - TRANSLATE_PRECISION;\nconst TRANSLATE_MAX = 0 + TRANSLATE_PRECISION;\nfunction calcLength(axis) {\n return axis.max - axis.min;\n}\nfunction isNear(value, target, maxDistance) {\n return Math.abs(value - target) <= maxDistance;\n}\nfunction calcAxisDelta(delta, source, target, origin = 0.5) {\n delta.origin = origin;\n delta.originPoint = mixNumber(source.min, source.max, delta.origin);\n delta.scale = calcLength(target) / calcLength(source);\n delta.translate =\n mixNumber(target.min, target.max, delta.origin) - delta.originPoint;\n if ((delta.scale >= SCALE_MIN && delta.scale <= SCALE_MAX) ||\n isNaN(delta.scale)) {\n delta.scale = 1.0;\n }\n if ((delta.translate >= TRANSLATE_MIN &&\n delta.translate <= TRANSLATE_MAX) ||\n isNaN(delta.translate)) {\n delta.translate = 0.0;\n }\n}\nfunction calcBoxDelta(delta, source, target, origin) {\n calcAxisDelta(delta.x, source.x, target.x, origin ? origin.originX : undefined);\n calcAxisDelta(delta.y, source.y, target.y, origin ? origin.originY : undefined);\n}\nfunction calcRelativeAxis(target, relative, parent) {\n target.min = parent.min + relative.min;\n target.max = target.min + calcLength(relative);\n}\nfunction calcRelativeBox(target, relative, parent) {\n calcRelativeAxis(target.x, relative.x, parent.x);\n calcRelativeAxis(target.y, relative.y, parent.y);\n}\nfunction calcRelativeAxisPosition(target, layout, parent) {\n target.min = layout.min - parent.min;\n target.max = target.min + calcLength(layout);\n}\nfunction calcRelativePosition(target, layout, parent) {\n calcRelativeAxisPosition(target.x, layout.x, parent.x);\n calcRelativeAxisPosition(target.y, layout.y, parent.y);\n}\n\nexport { calcAxisDelta, calcBoxDelta, calcLength, calcRelativeAxis, calcRelativeAxisPosition, calcRelativeBox, calcRelativePosition, isNear };\n","import { mixNumber } from '../../utils/mix/number.mjs';\nimport { percent } from '../../value/types/numbers/units.mjs';\nimport { scalePoint } from './delta-apply.mjs';\n\n/**\n * Remove a delta from a point. This is essentially the steps of applyPointDelta in reverse\n */\nfunction removePointDelta(point, translate, scale, originPoint, boxScale) {\n point -= translate;\n point = scalePoint(point, 1 / scale, originPoint);\n if (boxScale !== undefined) {\n point = scalePoint(point, 1 / boxScale, originPoint);\n }\n return point;\n}\n/**\n * Remove a delta from an axis. This is essentially the steps of applyAxisDelta in reverse\n */\nfunction removeAxisDelta(axis, translate = 0, scale = 1, origin = 0.5, boxScale, originAxis = axis, sourceAxis = axis) {\n if (percent.test(translate)) {\n translate = parseFloat(translate);\n const relativeProgress = mixNumber(sourceAxis.min, sourceAxis.max, translate / 100);\n translate = relativeProgress - sourceAxis.min;\n }\n if (typeof translate !== \"number\")\n return;\n let originPoint = mixNumber(originAxis.min, originAxis.max, origin);\n if (axis === originAxis)\n originPoint -= translate;\n axis.min = removePointDelta(axis.min, translate, scale, originPoint, boxScale);\n axis.max = removePointDelta(axis.max, translate, scale, originPoint, boxScale);\n}\n/**\n * Remove a transforms from an axis. This is essentially the steps of applyAxisTransforms in reverse\n * and acts as a bridge between motion values and removeAxisDelta\n */\nfunction removeAxisTransforms(axis, transforms, [key, scaleKey, originKey], origin, sourceAxis) {\n removeAxisDelta(axis, transforms[key], transforms[scaleKey], transforms[originKey], transforms.scale, origin, sourceAxis);\n}\n/**\n * The names of the motion values we want to apply as translation, scale and origin.\n */\nconst xKeys = [\"x\", \"scaleX\", \"originX\"];\nconst yKeys = [\"y\", \"scaleY\", \"originY\"];\n/**\n * Remove a transforms from an box. This is essentially the steps of applyAxisBox in reverse\n * and acts as a bridge between motion values and removeAxisDelta\n */\nfunction removeBoxTransforms(box, transforms, originBox, sourceBox) {\n removeAxisTransforms(box.x, transforms, xKeys, originBox ? originBox.x : undefined, sourceBox ? sourceBox.x : undefined);\n removeAxisTransforms(box.y, transforms, yKeys, originBox ? originBox.y : undefined, sourceBox ? sourceBox.y : undefined);\n}\n\nexport { removeAxisDelta, removeAxisTransforms, removeBoxTransforms, removePointDelta };\n","const createAxisDelta = () => ({\n translate: 0,\n scale: 1,\n origin: 0,\n originPoint: 0,\n});\nconst createDelta = () => ({\n x: createAxisDelta(),\n y: createAxisDelta(),\n});\nconst createAxis = () => ({ min: 0, max: 0 });\nconst createBox = () => ({\n x: createAxis(),\n y: createAxis(),\n});\n\nexport { createAxis, createAxisDelta, createBox, createDelta };\n","import { calcLength } from './delta-calc.mjs';\n\nfunction isAxisDeltaZero(delta) {\n return delta.translate === 0 && delta.scale === 1;\n}\nfunction isDeltaZero(delta) {\n return isAxisDeltaZero(delta.x) && isAxisDeltaZero(delta.y);\n}\nfunction axisEquals(a, b) {\n return a.min === b.min && a.max === b.max;\n}\nfunction boxEquals(a, b) {\n return axisEquals(a.x, b.x) && axisEquals(a.y, b.y);\n}\nfunction axisEqualsRounded(a, b) {\n return (Math.round(a.min) === Math.round(b.min) &&\n Math.round(a.max) === Math.round(b.max));\n}\nfunction boxEqualsRounded(a, b) {\n return axisEqualsRounded(a.x, b.x) && axisEqualsRounded(a.y, b.y);\n}\nfunction aspectRatio(box) {\n return calcLength(box.x) / calcLength(box.y);\n}\nfunction axisDeltaEquals(a, b) {\n return (a.translate === b.translate &&\n a.scale === b.scale &&\n a.originPoint === b.originPoint);\n}\n\nexport { aspectRatio, axisDeltaEquals, axisEquals, axisEqualsRounded, boxEquals, boxEqualsRounded, isDeltaZero };\n","import { createProjectionNode } from './create-projection-node.mjs';\nimport { addDomEvent } from '../../events/add-dom-event.mjs';\n\nconst DocumentProjectionNode = createProjectionNode({\n attachResizeListener: (ref, notify) => addDomEvent(ref, \"resize\", notify),\n measureScroll: () => ({\n x: document.documentElement.scrollLeft || document.body.scrollLeft,\n y: document.documentElement.scrollTop || document.body.scrollTop,\n }),\n checkIsScrollRoot: () => true,\n});\n\nexport { DocumentProjectionNode };\n","import { createProjectionNode } from './create-projection-node.mjs';\nimport { DocumentProjectionNode } from './DocumentProjectionNode.mjs';\n\nconst rootProjectionNode = {\n current: undefined,\n};\nconst HTMLProjectionNode = createProjectionNode({\n measureScroll: (instance) => ({\n x: instance.scrollLeft,\n y: instance.scrollTop,\n }),\n defaultParent: () => {\n if (!rootProjectionNode.current) {\n const documentNode = new DocumentProjectionNode({});\n documentNode.mount(window);\n documentNode.setOptions({ layoutScroll: true });\n rootProjectionNode.current = documentNode;\n }\n return rootProjectionNode.current;\n },\n resetTransform: (instance, value) => {\n instance.style.transform = value !== undefined ? value : \"none\";\n },\n checkIsScrollRoot: (instance) => Boolean(window.getComputedStyle(instance).position === \"fixed\"),\n});\n\nexport { HTMLProjectionNode, rootProjectionNode };\n","import { SubscriptionManager } from '../../utils/subscription-manager.mjs';\nimport { mixValues } from '../animation/mix-values.mjs';\nimport { copyBoxInto, copyAxisDeltaInto } from '../geometry/copy.mjs';\nimport { translateAxis, transformBox, applyBoxDelta, applyTreeDeltas } from '../geometry/delta-apply.mjs';\nimport { calcRelativePosition, calcRelativeBox, calcBoxDelta, calcLength, isNear } from '../geometry/delta-calc.mjs';\nimport { removeBoxTransforms } from '../geometry/delta-remove.mjs';\nimport { getValueTransition } from '../../animation/utils/transitions.mjs';\nimport { boxEqualsRounded, isDeltaZero, axisDeltaEquals, aspectRatio, boxEquals } from '../geometry/utils.mjs';\nimport { NodeStack } from '../shared/stack.mjs';\nimport { scaleCorrectors } from '../styles/scale-correction.mjs';\nimport { buildProjectionTransform } from '../styles/transform.mjs';\nimport { eachAxis } from '../utils/each-axis.mjs';\nimport { hasTransform, hasScale, has2DTranslate } from '../utils/has-transform.mjs';\nimport { FlatTree } from '../../render/utils/flat-tree.mjs';\nimport { resolveMotionValue } from '../../value/utils/resolve-motion-value.mjs';\nimport { globalProjectionState } from './state.mjs';\nimport { delay } from '../../utils/delay.mjs';\nimport { mixNumber } from '../../utils/mix/number.mjs';\nimport { isSVGElement } from '../../render/dom/utils/is-svg-element.mjs';\nimport { animateSingleValue } from '../../animation/interfaces/single-value.mjs';\nimport { clamp } from '../../utils/clamp.mjs';\nimport { cancelFrame, frameData, steps, frame } from '../../frameloop/frame.mjs';\nimport { noop } from '../../utils/noop.mjs';\nimport { time } from '../../frameloop/sync-time.mjs';\nimport { microtask } from '../../frameloop/microtask.mjs';\nimport { getOptimisedAppearId } from '../../animation/optimized-appear/get-appear-id.mjs';\nimport { createBox, createDelta } from '../geometry/models.mjs';\n\nconst metrics = {\n type: \"projectionFrame\",\n totalNodes: 0,\n resolvedTargetDeltas: 0,\n recalculatedProjection: 0,\n};\nconst isDebug = typeof window !== \"undefined\" && window.MotionDebug !== undefined;\nconst transformAxes = [\"\", \"X\", \"Y\", \"Z\"];\nconst hiddenVisibility = { visibility: \"hidden\" };\n/**\n * We use 1000 as the animation target as 0-1000 maps better to pixels than 0-1\n * which has a noticeable difference in spring animations\n */\nconst animationTarget = 1000;\nlet id = 0;\nfunction resetDistortingTransform(key, visualElement, values, sharedAnimationValues) {\n const { latestValues } = visualElement;\n // Record the distorting transform and then temporarily set it to 0\n if (latestValues[key]) {\n values[key] = latestValues[key];\n visualElement.setStaticValue(key, 0);\n if (sharedAnimationValues) {\n sharedAnimationValues[key] = 0;\n }\n }\n}\nfunction cancelTreeOptimisedTransformAnimations(projectionNode) {\n projectionNode.hasCheckedOptimisedAppear = true;\n if (projectionNode.root === projectionNode)\n return;\n const { visualElement } = projectionNode.options;\n if (!visualElement)\n return;\n const appearId = getOptimisedAppearId(visualElement);\n if (window.MotionHasOptimisedAnimation(appearId, \"transform\")) {\n const { layout, layoutId } = projectionNode.options;\n window.MotionCancelOptimisedAnimation(appearId, \"transform\", frame, !(layout || layoutId));\n }\n const { parent } = projectionNode;\n if (parent && !parent.hasCheckedOptimisedAppear) {\n cancelTreeOptimisedTransformAnimations(parent);\n }\n}\nfunction createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {\n return class ProjectionNode {\n constructor(latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {\n /**\n * A unique ID generated for every projection node.\n */\n this.id = id++;\n /**\n * An id that represents a unique session instigated by startUpdate.\n */\n this.animationId = 0;\n /**\n * A Set containing all this component's children. This is used to iterate\n * through the children.\n *\n * TODO: This could be faster to iterate as a flat array stored on the root node.\n */\n this.children = new Set();\n /**\n * Options for the node. We use this to configure what kind of layout animations\n * we should perform (if any).\n */\n this.options = {};\n /**\n * We use this to detect when its safe to shut down part of a projection tree.\n * We have to keep projecting children for scale correction and relative projection\n * until all their parents stop performing layout animations.\n */\n this.isTreeAnimating = false;\n this.isAnimationBlocked = false;\n /**\n * Flag to true if we think this layout has been changed. We can't always know this,\n * currently we set it to true every time a component renders, or if it has a layoutDependency\n * if that has changed between renders. Additionally, components can be grouped by LayoutGroup\n * and if one node is dirtied, they all are.\n */\n this.isLayoutDirty = false;\n /**\n * Flag to true if we think the projection calculations for this node needs\n * recalculating as a result of an updated transform or layout animation.\n */\n this.isProjectionDirty = false;\n /**\n * Flag to true if the layout *or* transform has changed. This then gets propagated\n * throughout the projection tree, forcing any element below to recalculate on the next frame.\n */\n this.isSharedProjectionDirty = false;\n /**\n * Flag transform dirty. This gets propagated throughout the whole tree but is only\n * respected by shared nodes.\n */\n this.isTransformDirty = false;\n /**\n * Block layout updates for instant layout transitions throughout the tree.\n */\n this.updateManuallyBlocked = false;\n this.updateBlockedByResize = false;\n /**\n * Set to true between the start of the first `willUpdate` call and the end of the `didUpdate`\n * call.\n */\n this.isUpdating = false;\n /**\n * If this is an SVG element we currently disable projection transforms\n */\n this.isSVG = false;\n /**\n * Flag to true (during promotion) if a node doing an instant layout transition needs to reset\n * its projection styles.\n */\n this.needsReset = false;\n /**\n * Flags whether this node should have its transform reset prior to measuring.\n */\n this.shouldResetTransform = false;\n /**\n * Store whether this node has been checked for optimised appear animations. As\n * effects fire bottom-up, and we want to look up the tree for appear animations,\n * this makes sure we only check each path once, stopping at nodes that\n * have already been checked.\n */\n this.hasCheckedOptimisedAppear = false;\n /**\n * An object representing the calculated contextual/accumulated/tree scale.\n * This will be used to scale calculcated projection transforms, as these are\n * calculated in screen-space but need to be scaled for elements to layoutly\n * make it to their calculated destinations.\n *\n * TODO: Lazy-init\n */\n this.treeScale = { x: 1, y: 1 };\n /**\n *\n */\n this.eventHandlers = new Map();\n this.hasTreeAnimated = false;\n // Note: Currently only running on root node\n this.updateScheduled = false;\n this.scheduleUpdate = () => this.update();\n this.projectionUpdateScheduled = false;\n this.checkUpdateFailed = () => {\n if (this.isUpdating) {\n this.isUpdating = false;\n this.clearAllSnapshots();\n }\n };\n /**\n * This is a multi-step process as shared nodes might be of different depths. Nodes\n * are sorted by depth order, so we need to resolve the entire tree before moving to\n * the next step.\n */\n this.updateProjection = () => {\n this.projectionUpdateScheduled = false;\n /**\n * Reset debug counts. Manually resetting rather than creating a new\n * object each frame.\n */\n if (isDebug) {\n metrics.totalNodes =\n metrics.resolvedTargetDeltas =\n metrics.recalculatedProjection =\n 0;\n }\n this.nodes.forEach(propagateDirtyNodes);\n this.nodes.forEach(resolveTargetDelta);\n this.nodes.forEach(calcProjection);\n this.nodes.forEach(cleanDirtyNodes);\n if (isDebug) {\n window.MotionDebug.record(metrics);\n }\n };\n /**\n * Frame calculations\n */\n this.resolvedRelativeTargetAt = 0.0;\n this.hasProjected = false;\n this.isVisible = true;\n this.animationProgress = 0;\n /**\n * Shared layout\n */\n // TODO Only running on root node\n this.sharedNodes = new Map();\n this.latestValues = latestValues;\n this.root = parent ? parent.root || parent : this;\n this.path = parent ? [...parent.path, parent] : [];\n this.parent = parent;\n this.depth = parent ? parent.depth + 1 : 0;\n for (let i = 0; i < this.path.length; i++) {\n this.path[i].shouldResetTransform = true;\n }\n if (this.root === this)\n this.nodes = new FlatTree();\n }\n addEventListener(name, handler) {\n if (!this.eventHandlers.has(name)) {\n this.eventHandlers.set(name, new SubscriptionManager());\n }\n return this.eventHandlers.get(name).add(handler);\n }\n notifyListeners(name, ...args) {\n const subscriptionManager = this.eventHandlers.get(name);\n subscriptionManager && subscriptionManager.notify(...args);\n }\n hasListeners(name) {\n return this.eventHandlers.has(name);\n }\n /**\n * Lifecycles\n */\n mount(instance, isLayoutDirty = this.root.hasTreeAnimated) {\n if (this.instance)\n return;\n this.isSVG = isSVGElement(instance);\n this.instance = instance;\n const { layoutId, layout, visualElement } = this.options;\n if (visualElement && !visualElement.current) {\n visualElement.mount(instance);\n }\n this.root.nodes.add(this);\n this.parent && this.parent.children.add(this);\n if (isLayoutDirty && (layout || layoutId)) {\n this.isLayoutDirty = true;\n }\n if (attachResizeListener) {\n let cancelDelay;\n const resizeUnblockUpdate = () => (this.root.updateBlockedByResize = false);\n attachResizeListener(instance, () => {\n this.root.updateBlockedByResize = true;\n cancelDelay && cancelDelay();\n cancelDelay = delay(resizeUnblockUpdate, 250);\n if (globalProjectionState.hasAnimatedSinceResize) {\n globalProjectionState.hasAnimatedSinceResize = false;\n this.nodes.forEach(finishAnimation);\n }\n });\n }\n if (layoutId) {\n this.root.registerSharedNode(layoutId, this);\n }\n // Only register the handler if it requires layout animation\n if (this.options.animate !== false &&\n visualElement &&\n (layoutId || layout)) {\n this.addEventListener(\"didUpdate\", ({ delta, hasLayoutChanged, hasRelativeTargetChanged, layout: newLayout, }) => {\n if (this.isTreeAnimationBlocked()) {\n this.target = undefined;\n this.relativeTarget = undefined;\n return;\n }\n // TODO: Check here if an animation exists\n const layoutTransition = this.options.transition ||\n visualElement.getDefaultTransition() ||\n defaultLayoutTransition;\n const { onLayoutAnimationStart, onLayoutAnimationComplete, } = visualElement.getProps();\n /**\n * The target layout of the element might stay the same,\n * but its position relative to its parent has changed.\n */\n const targetChanged = !this.targetLayout ||\n !boxEqualsRounded(this.targetLayout, newLayout) ||\n hasRelativeTargetChanged;\n /**\n * If the layout hasn't seemed to have changed, it might be that the\n * element is visually in the same place in the document but its position\n * relative to its parent has indeed changed. So here we check for that.\n */\n const hasOnlyRelativeTargetChanged = !hasLayoutChanged && hasRelativeTargetChanged;\n if (this.options.layoutRoot ||\n (this.resumeFrom && this.resumeFrom.instance) ||\n hasOnlyRelativeTargetChanged ||\n (hasLayoutChanged &&\n (targetChanged || !this.currentAnimation))) {\n if (this.resumeFrom) {\n this.resumingFrom = this.resumeFrom;\n this.resumingFrom.resumingFrom = undefined;\n }\n this.setAnimationOrigin(delta, hasOnlyRelativeTargetChanged);\n const animationOptions = {\n ...getValueTransition(layoutTransition, \"layout\"),\n onPlay: onLayoutAnimationStart,\n onComplete: onLayoutAnimationComplete,\n };\n if (visualElement.shouldReduceMotion ||\n this.options.layoutRoot) {\n animationOptions.delay = 0;\n animationOptions.type = false;\n }\n this.startAnimation(animationOptions);\n }\n else {\n /**\n * If the layout hasn't changed and we have an animation that hasn't started yet,\n * finish it immediately. Otherwise it will be animating from a location\n * that was probably never commited to screen and look like a jumpy box.\n */\n if (!hasLayoutChanged) {\n finishAnimation(this);\n }\n if (this.isLead() && this.options.onExitComplete) {\n this.options.onExitComplete();\n }\n }\n this.targetLayout = newLayout;\n });\n }\n }\n unmount() {\n this.options.layoutId && this.willUpdate();\n this.root.nodes.remove(this);\n const stack = this.getStack();\n stack && stack.remove(this);\n this.parent && this.parent.children.delete(this);\n this.instance = undefined;\n cancelFrame(this.updateProjection);\n }\n // only on the root\n blockUpdate() {\n this.updateManuallyBlocked = true;\n }\n unblockUpdate() {\n this.updateManuallyBlocked = false;\n }\n isUpdateBlocked() {\n return this.updateManuallyBlocked || this.updateBlockedByResize;\n }\n isTreeAnimationBlocked() {\n return (this.isAnimationBlocked ||\n (this.parent && this.parent.isTreeAnimationBlocked()) ||\n false);\n }\n // Note: currently only running on root node\n startUpdate() {\n if (this.isUpdateBlocked())\n return;\n this.isUpdating = true;\n this.nodes && this.nodes.forEach(resetSkewAndRotation);\n this.animationId++;\n }\n getTransformTemplate() {\n const { visualElement } = this.options;\n return visualElement && visualElement.getProps().transformTemplate;\n }\n willUpdate(shouldNotifyListeners = true) {\n this.root.hasTreeAnimated = true;\n if (this.root.isUpdateBlocked()) {\n this.options.onExitComplete && this.options.onExitComplete();\n return;\n }\n /**\n * If we're running optimised appear animations then these must be\n * cancelled before measuring the DOM. This is so we can measure\n * the true layout of the element rather than the WAAPI animation\n * which will be unaffected by the resetSkewAndRotate step.\n *\n * Note: This is a DOM write. Worst case scenario is this is sandwiched\n * between other snapshot reads which will cause unnecessary style recalculations.\n * This has to happen here though, as we don't yet know which nodes will need\n * snapshots in startUpdate(), but we only want to cancel optimised animations\n * if a layout animation measurement is actually going to be affected by them.\n */\n if (window.MotionCancelOptimisedAnimation &&\n !this.hasCheckedOptimisedAppear) {\n cancelTreeOptimisedTransformAnimations(this);\n }\n !this.root.isUpdating && this.root.startUpdate();\n if (this.isLayoutDirty)\n return;\n this.isLayoutDirty = true;\n for (let i = 0; i < this.path.length; i++) {\n const node = this.path[i];\n node.shouldResetTransform = true;\n node.updateScroll(\"snapshot\");\n if (node.options.layoutRoot) {\n node.willUpdate(false);\n }\n }\n const { layoutId, layout } = this.options;\n if (layoutId === undefined && !layout)\n return;\n const transformTemplate = this.getTransformTemplate();\n this.prevTransformTemplateValue = transformTemplate\n ? transformTemplate(this.latestValues, \"\")\n : undefined;\n this.updateSnapshot();\n shouldNotifyListeners && this.notifyListeners(\"willUpdate\");\n }\n update() {\n this.updateScheduled = false;\n const updateWasBlocked = this.isUpdateBlocked();\n // When doing an instant transition, we skip the layout update,\n // but should still clean up the measurements so that the next\n // snapshot could be taken correctly.\n if (updateWasBlocked) {\n this.unblockUpdate();\n this.clearAllSnapshots();\n this.nodes.forEach(clearMeasurements);\n return;\n }\n if (!this.isUpdating) {\n this.nodes.forEach(clearIsLayoutDirty);\n }\n this.isUpdating = false;\n /**\n * Write\n */\n this.nodes.forEach(resetTransformStyle);\n /**\n * Read ==================\n */\n // Update layout measurements of updated children\n this.nodes.forEach(updateLayout);\n /**\n * Write\n */\n // Notify listeners that the layout is updated\n this.nodes.forEach(notifyLayoutUpdate);\n this.clearAllSnapshots();\n /**\n * Manually flush any pending updates. Ideally\n * we could leave this to the following requestAnimationFrame but this seems\n * to leave a flash of incorrectly styled content.\n */\n const now = time.now();\n frameData.delta = clamp(0, 1000 / 60, now - frameData.timestamp);\n frameData.timestamp = now;\n frameData.isProcessing = true;\n steps.update.process(frameData);\n steps.preRender.process(frameData);\n steps.render.process(frameData);\n frameData.isProcessing = false;\n }\n didUpdate() {\n if (!this.updateScheduled) {\n this.updateScheduled = true;\n microtask.read(this.scheduleUpdate);\n }\n }\n clearAllSnapshots() {\n this.nodes.forEach(clearSnapshot);\n this.sharedNodes.forEach(removeLeadSnapshots);\n }\n scheduleUpdateProjection() {\n if (!this.projectionUpdateScheduled) {\n this.projectionUpdateScheduled = true;\n frame.preRender(this.updateProjection, false, true);\n }\n }\n scheduleCheckAfterUnmount() {\n /**\n * If the unmounting node is in a layoutGroup and did trigger a willUpdate,\n * we manually call didUpdate to give a chance to the siblings to animate.\n * Otherwise, cleanup all snapshots to prevents future nodes from reusing them.\n */\n frame.postRender(() => {\n if (this.isLayoutDirty) {\n this.root.didUpdate();\n }\n else {\n this.root.checkUpdateFailed();\n }\n });\n }\n /**\n * Update measurements\n */\n updateSnapshot() {\n if (this.snapshot || !this.instance)\n return;\n this.snapshot = this.measure();\n }\n updateLayout() {\n if (!this.instance)\n return;\n // TODO: Incorporate into a forwarded scroll offset\n this.updateScroll();\n if (!(this.options.alwaysMeasureLayout && this.isLead()) &&\n !this.isLayoutDirty) {\n return;\n }\n /**\n * When a node is mounted, it simply resumes from the prevLead's\n * snapshot instead of taking a new one, but the ancestors scroll\n * might have updated while the prevLead is unmounted. We need to\n * update the scroll again to make sure the layout we measure is\n * up to date.\n */\n if (this.resumeFrom && !this.resumeFrom.instance) {\n for (let i = 0; i < this.path.length; i++) {\n const node = this.path[i];\n node.updateScroll();\n }\n }\n const prevLayout = this.layout;\n this.layout = this.measure(false);\n this.layoutCorrected = createBox();\n this.isLayoutDirty = false;\n this.projectionDelta = undefined;\n this.notifyListeners(\"measure\", this.layout.layoutBox);\n const { visualElement } = this.options;\n visualElement &&\n visualElement.notify(\"LayoutMeasure\", this.layout.layoutBox, prevLayout ? prevLayout.layoutBox : undefined);\n }\n updateScroll(phase = \"measure\") {\n let needsMeasurement = Boolean(this.options.layoutScroll && this.instance);\n if (this.scroll &&\n this.scroll.animationId === this.root.animationId &&\n this.scroll.phase === phase) {\n needsMeasurement = false;\n }\n if (needsMeasurement) {\n const isRoot = checkIsScrollRoot(this.instance);\n this.scroll = {\n animationId: this.root.animationId,\n phase,\n isRoot,\n offset: measureScroll(this.instance),\n wasRoot: this.scroll ? this.scroll.isRoot : isRoot,\n };\n }\n }\n resetTransform() {\n if (!resetTransform)\n return;\n const isResetRequested = this.isLayoutDirty ||\n this.shouldResetTransform ||\n this.options.alwaysMeasureLayout;\n const hasProjection = this.projectionDelta && !isDeltaZero(this.projectionDelta);\n const transformTemplate = this.getTransformTemplate();\n const transformTemplateValue = transformTemplate\n ? transformTemplate(this.latestValues, \"\")\n : undefined;\n const transformTemplateHasChanged = transformTemplateValue !== this.prevTransformTemplateValue;\n if (isResetRequested &&\n (hasProjection ||\n hasTransform(this.latestValues) ||\n transformTemplateHasChanged)) {\n resetTransform(this.instance, transformTemplateValue);\n this.shouldResetTransform = false;\n this.scheduleRender();\n }\n }\n measure(removeTransform = true) {\n const pageBox = this.measurePageBox();\n let layoutBox = this.removeElementScroll(pageBox);\n /**\n * Measurements taken during the pre-render stage\n * still have transforms applied so we remove them\n * via calculation.\n */\n if (removeTransform) {\n layoutBox = this.removeTransform(layoutBox);\n }\n roundBox(layoutBox);\n return {\n animationId: this.root.animationId,\n measuredBox: pageBox,\n layoutBox,\n latestValues: {},\n source: this.id,\n };\n }\n measurePageBox() {\n var _a;\n const { visualElement } = this.options;\n if (!visualElement)\n return createBox();\n const box = visualElement.measureViewportBox();\n const wasInScrollRoot = ((_a = this.scroll) === null || _a === void 0 ? void 0 : _a.wasRoot) || this.path.some(checkNodeWasScrollRoot);\n if (!wasInScrollRoot) {\n // Remove viewport scroll to give page-relative coordinates\n const { scroll } = this.root;\n if (scroll) {\n translateAxis(box.x, scroll.offset.x);\n translateAxis(box.y, scroll.offset.y);\n }\n }\n return box;\n }\n removeElementScroll(box) {\n var _a;\n const boxWithoutScroll = createBox();\n copyBoxInto(boxWithoutScroll, box);\n if ((_a = this.scroll) === null || _a === void 0 ? void 0 : _a.wasRoot) {\n return boxWithoutScroll;\n }\n /**\n * Performance TODO: Keep a cumulative scroll offset down the tree\n * rather than loop back up the path.\n */\n for (let i = 0; i < this.path.length; i++) {\n const node = this.path[i];\n const { scroll, options } = node;\n if (node !== this.root && scroll && options.layoutScroll) {\n /**\n * If this is a new scroll root, we want to remove all previous scrolls\n * from the viewport box.\n */\n if (scroll.wasRoot) {\n copyBoxInto(boxWithoutScroll, box);\n }\n translateAxis(boxWithoutScroll.x, scroll.offset.x);\n translateAxis(boxWithoutScroll.y, scroll.offset.y);\n }\n }\n return boxWithoutScroll;\n }\n applyTransform(box, transformOnly = false) {\n const withTransforms = createBox();\n copyBoxInto(withTransforms, box);\n for (let i = 0; i < this.path.length; i++) {\n const node = this.path[i];\n if (!transformOnly &&\n node.options.layoutScroll &&\n node.scroll &&\n node !== node.root) {\n transformBox(withTransforms, {\n x: -node.scroll.offset.x,\n y: -node.scroll.offset.y,\n });\n }\n if (!hasTransform(node.latestValues))\n continue;\n transformBox(withTransforms, node.latestValues);\n }\n if (hasTransform(this.latestValues)) {\n transformBox(withTransforms, this.latestValues);\n }\n return withTransforms;\n }\n removeTransform(box) {\n const boxWithoutTransform = createBox();\n copyBoxInto(boxWithoutTransform, box);\n for (let i = 0; i < this.path.length; i++) {\n const node = this.path[i];\n if (!node.instance)\n continue;\n if (!hasTransform(node.latestValues))\n continue;\n hasScale(node.latestValues) && node.updateSnapshot();\n const sourceBox = createBox();\n const nodeBox = node.measurePageBox();\n copyBoxInto(sourceBox, nodeBox);\n removeBoxTransforms(boxWithoutTransform, node.latestValues, node.snapshot ? node.snapshot.layoutBox : undefined, sourceBox);\n }\n if (hasTransform(this.latestValues)) {\n removeBoxTransforms(boxWithoutTransform, this.latestValues);\n }\n return boxWithoutTransform;\n }\n setTargetDelta(delta) {\n this.targetDelta = delta;\n this.root.scheduleUpdateProjection();\n this.isProjectionDirty = true;\n }\n setOptions(options) {\n this.options = {\n ...this.options,\n ...options,\n crossfade: options.crossfade !== undefined ? options.crossfade : true,\n };\n }\n clearMeasurements() {\n this.scroll = undefined;\n this.layout = undefined;\n this.snapshot = undefined;\n this.prevTransformTemplateValue = undefined;\n this.targetDelta = undefined;\n this.target = undefined;\n this.isLayoutDirty = false;\n }\n forceRelativeParentToResolveTarget() {\n if (!this.relativeParent)\n return;\n /**\n * If the parent target isn't up-to-date, force it to update.\n * This is an unfortunate de-optimisation as it means any updating relative\n * projection will cause all the relative parents to recalculate back\n * up the tree.\n */\n if (this.relativeParent.resolvedRelativeTargetAt !==\n frameData.timestamp) {\n this.relativeParent.resolveTargetDelta(true);\n }\n }\n resolveTargetDelta(forceRecalculation = false) {\n var _a;\n /**\n * Once the dirty status of nodes has been spread through the tree, we also\n * need to check if we have a shared node of a different depth that has itself\n * been dirtied.\n */\n const lead = this.getLead();\n this.isProjectionDirty || (this.isProjectionDirty = lead.isProjectionDirty);\n this.isTransformDirty || (this.isTransformDirty = lead.isTransformDirty);\n this.isSharedProjectionDirty || (this.isSharedProjectionDirty = lead.isSharedProjectionDirty);\n const isShared = Boolean(this.resumingFrom) || this !== lead;\n /**\n * We don't use transform for this step of processing so we don't\n * need to check whether any nodes have changed transform.\n */\n const canSkip = !(forceRecalculation ||\n (isShared && this.isSharedProjectionDirty) ||\n this.isProjectionDirty ||\n ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.isProjectionDirty) ||\n this.attemptToResolveRelativeTarget ||\n this.root.updateBlockedByResize);\n if (canSkip)\n return;\n const { layout, layoutId } = this.options;\n /**\n * If we have no layout, we can't perform projection, so early return\n */\n if (!this.layout || !(layout || layoutId))\n return;\n this.resolvedRelativeTargetAt = frameData.timestamp;\n /**\n * If we don't have a targetDelta but do have a layout, we can attempt to resolve\n * a relativeParent. This will allow a component to perform scale correction\n * even if no animation has started.\n */\n if (!this.targetDelta && !this.relativeTarget) {\n const relativeParent = this.getClosestProjectingParent();\n if (relativeParent &&\n relativeParent.layout &&\n this.animationProgress !== 1) {\n this.relativeParent = relativeParent;\n this.forceRelativeParentToResolveTarget();\n this.relativeTarget = createBox();\n this.relativeTargetOrigin = createBox();\n calcRelativePosition(this.relativeTargetOrigin, this.layout.layoutBox, relativeParent.layout.layoutBox);\n copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);\n }\n else {\n this.relativeParent = this.relativeTarget = undefined;\n }\n }\n /**\n * If we have no relative target or no target delta our target isn't valid\n * for this frame.\n */\n if (!this.relativeTarget && !this.targetDelta)\n return;\n /**\n * Lazy-init target data structure\n */\n if (!this.target) {\n this.target = createBox();\n this.targetWithTransforms = createBox();\n }\n /**\n * If we've got a relative box for this component, resolve it into a target relative to the parent.\n */\n if (this.relativeTarget &&\n this.relativeTargetOrigin &&\n this.relativeParent &&\n this.relativeParent.target) {\n this.forceRelativeParentToResolveTarget();\n calcRelativeBox(this.target, this.relativeTarget, this.relativeParent.target);\n /**\n * If we've only got a targetDelta, resolve it into a target\n */\n }\n else if (this.targetDelta) {\n if (Boolean(this.resumingFrom)) {\n // TODO: This is creating a new object every frame\n this.target = this.applyTransform(this.layout.layoutBox);\n }\n else {\n copyBoxInto(this.target, this.layout.layoutBox);\n }\n applyBoxDelta(this.target, this.targetDelta);\n }\n else {\n /**\n * If no target, use own layout as target\n */\n copyBoxInto(this.target, this.layout.layoutBox);\n }\n /**\n * If we've been told to attempt to resolve a relative target, do so.\n */\n if (this.attemptToResolveRelativeTarget) {\n this.attemptToResolveRelativeTarget = false;\n const relativeParent = this.getClosestProjectingParent();\n if (relativeParent &&\n Boolean(relativeParent.resumingFrom) ===\n Boolean(this.resumingFrom) &&\n !relativeParent.options.layoutScroll &&\n relativeParent.target &&\n this.animationProgress !== 1) {\n this.relativeParent = relativeParent;\n this.forceRelativeParentToResolveTarget();\n this.relativeTarget = createBox();\n this.relativeTargetOrigin = createBox();\n calcRelativePosition(this.relativeTargetOrigin, this.target, relativeParent.target);\n copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);\n }\n else {\n this.relativeParent = this.relativeTarget = undefined;\n }\n }\n /**\n * Increase debug counter for resolved target deltas\n */\n if (isDebug) {\n metrics.resolvedTargetDeltas++;\n }\n }\n getClosestProjectingParent() {\n if (!this.parent ||\n hasScale(this.parent.latestValues) ||\n has2DTranslate(this.parent.latestValues)) {\n return undefined;\n }\n if (this.parent.isProjecting()) {\n return this.parent;\n }\n else {\n return this.parent.getClosestProjectingParent();\n }\n }\n isProjecting() {\n return Boolean((this.relativeTarget ||\n this.targetDelta ||\n this.options.layoutRoot) &&\n this.layout);\n }\n calcProjection() {\n var _a;\n const lead = this.getLead();\n const isShared = Boolean(this.resumingFrom) || this !== lead;\n let canSkip = true;\n /**\n * If this is a normal layout animation and neither this node nor its nearest projecting\n * is dirty then we can't skip.\n */\n if (this.isProjectionDirty || ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.isProjectionDirty)) {\n canSkip = false;\n }\n /**\n * If this is a shared layout animation and this node's shared projection is dirty then\n * we can't skip.\n */\n if (isShared &&\n (this.isSharedProjectionDirty || this.isTransformDirty)) {\n canSkip = false;\n }\n /**\n * If we have resolved the target this frame we must recalculate the\n * projection to ensure it visually represents the internal calculations.\n */\n if (this.resolvedRelativeTargetAt === frameData.timestamp) {\n canSkip = false;\n }\n if (canSkip)\n return;\n const { layout, layoutId } = this.options;\n /**\n * If this section of the tree isn't animating we can\n * delete our target sources for the following frame.\n */\n this.isTreeAnimating = Boolean((this.parent && this.parent.isTreeAnimating) ||\n this.currentAnimation ||\n this.pendingAnimation);\n if (!this.isTreeAnimating) {\n this.targetDelta = this.relativeTarget = undefined;\n }\n if (!this.layout || !(layout || layoutId))\n return;\n /**\n * Reset the corrected box with the latest values from box, as we're then going\n * to perform mutative operations on it.\n */\n copyBoxInto(this.layoutCorrected, this.layout.layoutBox);\n /**\n * Record previous tree scales before updating.\n */\n const prevTreeScaleX = this.treeScale.x;\n const prevTreeScaleY = this.treeScale.y;\n /**\n * Apply all the parent deltas to this box to produce the corrected box. This\n * is the layout box, as it will appear on screen as a result of the transforms of its parents.\n */\n applyTreeDeltas(this.layoutCorrected, this.treeScale, this.path, isShared);\n /**\n * If this layer needs to perform scale correction but doesn't have a target,\n * use the layout as the target.\n */\n if (lead.layout &&\n !lead.target &&\n (this.treeScale.x !== 1 || this.treeScale.y !== 1)) {\n lead.target = lead.layout.layoutBox;\n lead.targetWithTransforms = createBox();\n }\n const { target } = lead;\n if (!target) {\n /**\n * If we don't have a target to project into, but we were previously\n * projecting, we want to remove the stored transform and schedule\n * a render to ensure the elements reflect the removed transform.\n */\n if (this.prevProjectionDelta) {\n this.createProjectionDeltas();\n this.scheduleRender();\n }\n return;\n }\n if (!this.projectionDelta || !this.prevProjectionDelta) {\n this.createProjectionDeltas();\n }\n else {\n copyAxisDeltaInto(this.prevProjectionDelta.x, this.projectionDelta.x);\n copyAxisDeltaInto(this.prevProjectionDelta.y, this.projectionDelta.y);\n }\n /**\n * Update the delta between the corrected box and the target box before user-set transforms were applied.\n * This will allow us to calculate the corrected borderRadius and boxShadow to compensate\n * for our layout reprojection, but still allow them to be scaled correctly by the user.\n * It might be that to simplify this we may want to accept that user-set scale is also corrected\n * and we wouldn't have to keep and calc both deltas, OR we could support a user setting\n * to allow people to choose whether these styles are corrected based on just the\n * layout reprojection or the final bounding box.\n */\n calcBoxDelta(this.projectionDelta, this.layoutCorrected, target, this.latestValues);\n if (this.treeScale.x !== prevTreeScaleX ||\n this.treeScale.y !== prevTreeScaleY ||\n !axisDeltaEquals(this.projectionDelta.x, this.prevProjectionDelta.x) ||\n !axisDeltaEquals(this.projectionDelta.y, this.prevProjectionDelta.y)) {\n this.hasProjected = true;\n this.scheduleRender();\n this.notifyListeners(\"projectionUpdate\", target);\n }\n /**\n * Increase debug counter for recalculated projections\n */\n if (isDebug) {\n metrics.recalculatedProjection++;\n }\n }\n hide() {\n this.isVisible = false;\n // TODO: Schedule render\n }\n show() {\n this.isVisible = true;\n // TODO: Schedule render\n }\n scheduleRender(notifyAll = true) {\n var _a;\n (_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.scheduleRender();\n if (notifyAll) {\n const stack = this.getStack();\n stack && stack.scheduleRender();\n }\n if (this.resumingFrom && !this.resumingFrom.instance) {\n this.resumingFrom = undefined;\n }\n }\n createProjectionDeltas() {\n this.prevProjectionDelta = createDelta();\n this.projectionDelta = createDelta();\n this.projectionDeltaWithTransform = createDelta();\n }\n setAnimationOrigin(delta, hasOnlyRelativeTargetChanged = false) {\n const snapshot = this.snapshot;\n const snapshotLatestValues = snapshot\n ? snapshot.latestValues\n : {};\n const mixedValues = { ...this.latestValues };\n const targetDelta = createDelta();\n if (!this.relativeParent ||\n !this.relativeParent.options.layoutRoot) {\n this.relativeTarget = this.relativeTargetOrigin = undefined;\n }\n this.attemptToResolveRelativeTarget = !hasOnlyRelativeTargetChanged;\n const relativeLayout = createBox();\n const snapshotSource = snapshot ? snapshot.source : undefined;\n const layoutSource = this.layout ? this.layout.source : undefined;\n const isSharedLayoutAnimation = snapshotSource !== layoutSource;\n const stack = this.getStack();\n const isOnlyMember = !stack || stack.members.length <= 1;\n const shouldCrossfadeOpacity = Boolean(isSharedLayoutAnimation &&\n !isOnlyMember &&\n this.options.crossfade === true &&\n !this.path.some(hasOpacityCrossfade));\n this.animationProgress = 0;\n let prevRelativeTarget;\n this.mixTargetDelta = (latest) => {\n const progress = latest / 1000;\n mixAxisDelta(targetDelta.x, delta.x, progress);\n mixAxisDelta(targetDelta.y, delta.y, progress);\n this.setTargetDelta(targetDelta);\n if (this.relativeTarget &&\n this.relativeTargetOrigin &&\n this.layout &&\n this.relativeParent &&\n this.relativeParent.layout) {\n calcRelativePosition(relativeLayout, this.layout.layoutBox, this.relativeParent.layout.layoutBox);\n mixBox(this.relativeTarget, this.relativeTargetOrigin, relativeLayout, progress);\n /**\n * If this is an unchanged relative target we can consider the\n * projection not dirty.\n */\n if (prevRelativeTarget &&\n boxEquals(this.relativeTarget, prevRelativeTarget)) {\n this.isProjectionDirty = false;\n }\n if (!prevRelativeTarget)\n prevRelativeTarget = createBox();\n copyBoxInto(prevRelativeTarget, this.relativeTarget);\n }\n if (isSharedLayoutAnimation) {\n this.animationValues = mixedValues;\n mixValues(mixedValues, snapshotLatestValues, this.latestValues, progress, shouldCrossfadeOpacity, isOnlyMember);\n }\n this.root.scheduleUpdateProjection();\n this.scheduleRender();\n this.animationProgress = progress;\n };\n this.mixTargetDelta(this.options.layoutRoot ? 1000 : 0);\n }\n startAnimation(options) {\n this.notifyListeners(\"animationStart\");\n this.currentAnimation && this.currentAnimation.stop();\n if (this.resumingFrom && this.resumingFrom.currentAnimation) {\n this.resumingFrom.currentAnimation.stop();\n }\n if (this.pendingAnimation) {\n cancelFrame(this.pendingAnimation);\n this.pendingAnimation = undefined;\n }\n /**\n * Start the animation in the next frame to have a frame with progress 0,\n * where the target is the same as when the animation started, so we can\n * calculate the relative positions correctly for instant transitions.\n */\n this.pendingAnimation = frame.update(() => {\n globalProjectionState.hasAnimatedSinceResize = true;\n this.currentAnimation = animateSingleValue(0, animationTarget, {\n ...options,\n onUpdate: (latest) => {\n this.mixTargetDelta(latest);\n options.onUpdate && options.onUpdate(latest);\n },\n onComplete: () => {\n options.onComplete && options.onComplete();\n this.completeAnimation();\n },\n });\n if (this.resumingFrom) {\n this.resumingFrom.currentAnimation = this.currentAnimation;\n }\n this.pendingAnimation = undefined;\n });\n }\n completeAnimation() {\n if (this.resumingFrom) {\n this.resumingFrom.currentAnimation = undefined;\n this.resumingFrom.preserveOpacity = undefined;\n }\n const stack = this.getStack();\n stack && stack.exitAnimationComplete();\n this.resumingFrom =\n this.currentAnimation =\n this.animationValues =\n undefined;\n this.notifyListeners(\"animationComplete\");\n }\n finishAnimation() {\n if (this.currentAnimation) {\n this.mixTargetDelta && this.mixTargetDelta(animationTarget);\n this.currentAnimation.stop();\n }\n this.completeAnimation();\n }\n applyTransformsToTarget() {\n const lead = this.getLead();\n let { targetWithTransforms, target, layout, latestValues } = lead;\n if (!targetWithTransforms || !target || !layout)\n return;\n /**\n * If we're only animating position, and this element isn't the lead element,\n * then instead of projecting into the lead box we instead want to calculate\n * a new target that aligns the two boxes but maintains the layout shape.\n */\n if (this !== lead &&\n this.layout &&\n layout &&\n shouldAnimatePositionOnly(this.options.animationType, this.layout.layoutBox, layout.layoutBox)) {\n target = this.target || createBox();\n const xLength = calcLength(this.layout.layoutBox.x);\n target.x.min = lead.target.x.min;\n target.x.max = target.x.min + xLength;\n const yLength = calcLength(this.layout.layoutBox.y);\n target.y.min = lead.target.y.min;\n target.y.max = target.y.min + yLength;\n }\n copyBoxInto(targetWithTransforms, target);\n /**\n * Apply the latest user-set transforms to the targetBox to produce the targetBoxFinal.\n * This is the final box that we will then project into by calculating a transform delta and\n * applying it to the corrected box.\n */\n transformBox(targetWithTransforms, latestValues);\n /**\n * Update the delta between the corrected box and the final target box, after\n * user-set transforms are applied to it. This will be used by the renderer to\n * create a transform style that will reproject the element from its layout layout\n * into the desired bounding box.\n */\n calcBoxDelta(this.projectionDeltaWithTransform, this.layoutCorrected, targetWithTransforms, latestValues);\n }\n registerSharedNode(layoutId, node) {\n if (!this.sharedNodes.has(layoutId)) {\n this.sharedNodes.set(layoutId, new NodeStack());\n }\n const stack = this.sharedNodes.get(layoutId);\n stack.add(node);\n const config = node.options.initialPromotionConfig;\n node.promote({\n transition: config ? config.transition : undefined,\n preserveFollowOpacity: config && config.shouldPreserveFollowOpacity\n ? config.shouldPreserveFollowOpacity(node)\n : undefined,\n });\n }\n isLead() {\n const stack = this.getStack();\n return stack ? stack.lead === this : true;\n }\n getLead() {\n var _a;\n const { layoutId } = this.options;\n return layoutId ? ((_a = this.getStack()) === null || _a === void 0 ? void 0 : _a.lead) || this : this;\n }\n getPrevLead() {\n var _a;\n const { layoutId } = this.options;\n return layoutId ? (_a = this.getStack()) === null || _a === void 0 ? void 0 : _a.prevLead : undefined;\n }\n getStack() {\n const { layoutId } = this.options;\n if (layoutId)\n return this.root.sharedNodes.get(layoutId);\n }\n promote({ needsReset, transition, preserveFollowOpacity, } = {}) {\n const stack = this.getStack();\n if (stack)\n stack.promote(this, preserveFollowOpacity);\n if (needsReset) {\n this.projectionDelta = undefined;\n this.needsReset = true;\n }\n if (transition)\n this.setOptions({ transition });\n }\n relegate() {\n const stack = this.getStack();\n if (stack) {\n return stack.relegate(this);\n }\n else {\n return false;\n }\n }\n resetSkewAndRotation() {\n const { visualElement } = this.options;\n if (!visualElement)\n return;\n // If there's no detected skew or rotation values, we can early return without a forced render.\n let hasDistortingTransform = false;\n /**\n * An unrolled check for rotation values. Most elements don't have any rotation and\n * skipping the nested loop and new object creation is 50% faster.\n */\n const { latestValues } = visualElement;\n if (latestValues.z ||\n latestValues.rotate ||\n latestValues.rotateX ||\n latestValues.rotateY ||\n latestValues.rotateZ ||\n latestValues.skewX ||\n latestValues.skewY) {\n hasDistortingTransform = true;\n }\n // If there's no distorting values, we don't need to do any more.\n if (!hasDistortingTransform)\n return;\n const resetValues = {};\n if (latestValues.z) {\n resetDistortingTransform(\"z\", visualElement, resetValues, this.animationValues);\n }\n // Check the skew and rotate value of all axes and reset to 0\n for (let i = 0; i < transformAxes.length; i++) {\n resetDistortingTransform(`rotate${transformAxes[i]}`, visualElement, resetValues, this.animationValues);\n resetDistortingTransform(`skew${transformAxes[i]}`, visualElement, resetValues, this.animationValues);\n }\n // Force a render of this element to apply the transform with all skews and rotations\n // set to 0.\n visualElement.render();\n // Put back all the values we reset\n for (const key in resetValues) {\n visualElement.setStaticValue(key, resetValues[key]);\n if (this.animationValues) {\n this.animationValues[key] = resetValues[key];\n }\n }\n // Schedule a render for the next frame. This ensures we won't visually\n // see the element with the reset rotate value applied.\n visualElement.scheduleRender();\n }\n getProjectionStyles(styleProp) {\n var _a, _b;\n if (!this.instance || this.isSVG)\n return undefined;\n if (!this.isVisible) {\n return hiddenVisibility;\n }\n const styles = {\n visibility: \"\",\n };\n const transformTemplate = this.getTransformTemplate();\n if (this.needsReset) {\n this.needsReset = false;\n styles.opacity = \"\";\n styles.pointerEvents =\n resolveMotionValue(styleProp === null || styleProp === void 0 ? void 0 : styleProp.pointerEvents) || \"\";\n styles.transform = transformTemplate\n ? transformTemplate(this.latestValues, \"\")\n : \"none\";\n return styles;\n }\n const lead = this.getLead();\n if (!this.projectionDelta || !this.layout || !lead.target) {\n const emptyStyles = {};\n if (this.options.layoutId) {\n emptyStyles.opacity =\n this.latestValues.opacity !== undefined\n ? this.latestValues.opacity\n : 1;\n emptyStyles.pointerEvents =\n resolveMotionValue(styleProp === null || styleProp === void 0 ? void 0 : styleProp.pointerEvents) || \"\";\n }\n if (this.hasProjected && !hasTransform(this.latestValues)) {\n emptyStyles.transform = transformTemplate\n ? transformTemplate({}, \"\")\n : \"none\";\n this.hasProjected = false;\n }\n return emptyStyles;\n }\n const valuesToRender = lead.animationValues || lead.latestValues;\n this.applyTransformsToTarget();\n styles.transform = buildProjectionTransform(this.projectionDeltaWithTransform, this.treeScale, valuesToRender);\n if (transformTemplate) {\n styles.transform = transformTemplate(valuesToRender, styles.transform);\n }\n const { x, y } = this.projectionDelta;\n styles.transformOrigin = `${x.origin * 100}% ${y.origin * 100}% 0`;\n if (lead.animationValues) {\n /**\n * If the lead component is animating, assign this either the entering/leaving\n * opacity\n */\n styles.opacity =\n lead === this\n ? (_b = (_a = valuesToRender.opacity) !== null && _a !== void 0 ? _a : this.latestValues.opacity) !== null && _b !== void 0 ? _b : 1\n : this.preserveOpacity\n ? this.latestValues.opacity\n : valuesToRender.opacityExit;\n }\n else {\n /**\n * Or we're not animating at all, set the lead component to its layout\n * opacity and other components to hidden.\n */\n styles.opacity =\n lead === this\n ? valuesToRender.opacity !== undefined\n ? valuesToRender.opacity\n : \"\"\n : valuesToRender.opacityExit !== undefined\n ? valuesToRender.opacityExit\n : 0;\n }\n /**\n * Apply scale correction\n */\n for (const key in scaleCorrectors) {\n if (valuesToRender[key] === undefined)\n continue;\n const { correct, applyTo } = scaleCorrectors[key];\n /**\n * Only apply scale correction to the value if we have an\n * active projection transform. Otherwise these values become\n * vulnerable to distortion if the element changes size without\n * a corresponding layout animation.\n */\n const corrected = styles.transform === \"none\"\n ? valuesToRender[key]\n : correct(valuesToRender[key], lead);\n if (applyTo) {\n const num = applyTo.length;\n for (let i = 0; i < num; i++) {\n styles[applyTo[i]] = corrected;\n }\n }\n else {\n styles[key] = corrected;\n }\n }\n /**\n * Disable pointer events on follow components. This is to ensure\n * that if a follow component covers a lead component it doesn't block\n * pointer events on the lead.\n */\n if (this.options.layoutId) {\n styles.pointerEvents =\n lead === this\n ? resolveMotionValue(styleProp === null || styleProp === void 0 ? void 0 : styleProp.pointerEvents) || \"\"\n : \"none\";\n }\n return styles;\n }\n clearSnapshot() {\n this.resumeFrom = this.snapshot = undefined;\n }\n // Only run on root\n resetTree() {\n this.root.nodes.forEach((node) => { var _a; return (_a = node.currentAnimation) === null || _a === void 0 ? void 0 : _a.stop(); });\n this.root.nodes.forEach(clearMeasurements);\n this.root.sharedNodes.clear();\n }\n };\n}\nfunction updateLayout(node) {\n node.updateLayout();\n}\nfunction notifyLayoutUpdate(node) {\n var _a;\n const snapshot = ((_a = node.resumeFrom) === null || _a === void 0 ? void 0 : _a.snapshot) || node.snapshot;\n if (node.isLead() &&\n node.layout &&\n snapshot &&\n node.hasListeners(\"didUpdate\")) {\n const { layoutBox: layout, measuredBox: measuredLayout } = node.layout;\n const { animationType } = node.options;\n const isShared = snapshot.source !== node.layout.source;\n // TODO Maybe we want to also resize the layout snapshot so we don't trigger\n // animations for instance if layout=\"size\" and an element has only changed position\n if (animationType === \"size\") {\n eachAxis((axis) => {\n const axisSnapshot = isShared\n ? snapshot.measuredBox[axis]\n : snapshot.layoutBox[axis];\n const length = calcLength(axisSnapshot);\n axisSnapshot.min = layout[axis].min;\n axisSnapshot.max = axisSnapshot.min + length;\n });\n }\n else if (shouldAnimatePositionOnly(animationType, snapshot.layoutBox, layout)) {\n eachAxis((axis) => {\n const axisSnapshot = isShared\n ? snapshot.measuredBox[axis]\n : snapshot.layoutBox[axis];\n const length = calcLength(layout[axis]);\n axisSnapshot.max = axisSnapshot.min + length;\n /**\n * Ensure relative target gets resized and rerendererd\n */\n if (node.relativeTarget && !node.currentAnimation) {\n node.isProjectionDirty = true;\n node.relativeTarget[axis].max =\n node.relativeTarget[axis].min + length;\n }\n });\n }\n const layoutDelta = createDelta();\n calcBoxDelta(layoutDelta, layout, snapshot.layoutBox);\n const visualDelta = createDelta();\n if (isShared) {\n calcBoxDelta(visualDelta, node.applyTransform(measuredLayout, true), snapshot.measuredBox);\n }\n else {\n calcBoxDelta(visualDelta, layout, snapshot.layoutBox);\n }\n const hasLayoutChanged = !isDeltaZero(layoutDelta);\n let hasRelativeTargetChanged = false;\n if (!node.resumeFrom) {\n const relativeParent = node.getClosestProjectingParent();\n /**\n * If the relativeParent is itself resuming from a different element then\n * the relative snapshot is not relavent\n */\n if (relativeParent && !relativeParent.resumeFrom) {\n const { snapshot: parentSnapshot, layout: parentLayout } = relativeParent;\n if (parentSnapshot && parentLayout) {\n const relativeSnapshot = createBox();\n calcRelativePosition(relativeSnapshot, snapshot.layoutBox, parentSnapshot.layoutBox);\n const relativeLayout = createBox();\n calcRelativePosition(relativeLayout, layout, parentLayout.layoutBox);\n if (!boxEqualsRounded(relativeSnapshot, relativeLayout)) {\n hasRelativeTargetChanged = true;\n }\n if (relativeParent.options.layoutRoot) {\n node.relativeTarget = relativeLayout;\n node.relativeTargetOrigin = relativeSnapshot;\n node.relativeParent = relativeParent;\n }\n }\n }\n }\n node.notifyListeners(\"didUpdate\", {\n layout,\n snapshot,\n delta: visualDelta,\n layoutDelta,\n hasLayoutChanged,\n hasRelativeTargetChanged,\n });\n }\n else if (node.isLead()) {\n const { onExitComplete } = node.options;\n onExitComplete && onExitComplete();\n }\n /**\n * Clearing transition\n * TODO: Investigate why this transition is being passed in as {type: false } from Framer\n * and why we need it at all\n */\n node.options.transition = undefined;\n}\nfunction propagateDirtyNodes(node) {\n /**\n * Increase debug counter for nodes encountered this frame\n */\n if (isDebug) {\n metrics.totalNodes++;\n }\n if (!node.parent)\n return;\n /**\n * If this node isn't projecting, propagate isProjectionDirty. It will have\n * no performance impact but it will allow the next child that *is* projecting\n * but *isn't* dirty to just check its parent to see if *any* ancestor needs\n * correcting.\n */\n if (!node.isProjecting()) {\n node.isProjectionDirty = node.parent.isProjectionDirty;\n }\n /**\n * Propagate isSharedProjectionDirty and isTransformDirty\n * throughout the whole tree. A future revision can take another look at\n * this but for safety we still recalcualte shared nodes.\n */\n node.isSharedProjectionDirty || (node.isSharedProjectionDirty = Boolean(node.isProjectionDirty ||\n node.parent.isProjectionDirty ||\n node.parent.isSharedProjectionDirty));\n node.isTransformDirty || (node.isTransformDirty = node.parent.isTransformDirty);\n}\nfunction cleanDirtyNodes(node) {\n node.isProjectionDirty =\n node.isSharedProjectionDirty =\n node.isTransformDirty =\n false;\n}\nfunction clearSnapshot(node) {\n node.clearSnapshot();\n}\nfunction clearMeasurements(node) {\n node.clearMeasurements();\n}\nfunction clearIsLayoutDirty(node) {\n node.isLayoutDirty = false;\n}\nfunction resetTransformStyle(node) {\n const { visualElement } = node.options;\n if (visualElement && visualElement.getProps().onBeforeLayoutMeasure) {\n visualElement.notify(\"BeforeLayoutMeasure\");\n }\n node.resetTransform();\n}\nfunction finishAnimation(node) {\n node.finishAnimation();\n node.targetDelta = node.relativeTarget = node.target = undefined;\n node.isProjectionDirty = true;\n}\nfunction resolveTargetDelta(node) {\n node.resolveTargetDelta();\n}\nfunction calcProjection(node) {\n node.calcProjection();\n}\nfunction resetSkewAndRotation(node) {\n node.resetSkewAndRotation();\n}\nfunction removeLeadSnapshots(stack) {\n stack.removeLeadSnapshot();\n}\nfunction mixAxisDelta(output, delta, p) {\n output.translate = mixNumber(delta.translate, 0, p);\n output.scale = mixNumber(delta.scale, 1, p);\n output.origin = delta.origin;\n output.originPoint = delta.originPoint;\n}\nfunction mixAxis(output, from, to, p) {\n output.min = mixNumber(from.min, to.min, p);\n output.max = mixNumber(from.max, to.max, p);\n}\nfunction mixBox(output, from, to, p) {\n mixAxis(output.x, from.x, to.x, p);\n mixAxis(output.y, from.y, to.y, p);\n}\nfunction hasOpacityCrossfade(node) {\n return (node.animationValues && node.animationValues.opacityExit !== undefined);\n}\nconst defaultLayoutTransition = {\n duration: 0.45,\n ease: [0.4, 0, 0.1, 1],\n};\nconst userAgentContains = (string) => typeof navigator !== \"undefined\" &&\n navigator.userAgent &&\n navigator.userAgent.toLowerCase().includes(string);\n/**\n * Measured bounding boxes must be rounded in Safari and\n * left untouched in Chrome, otherwise non-integer layouts within scaled-up elements\n * can appear to jump.\n */\nconst roundPoint = userAgentContains(\"applewebkit/\") && !userAgentContains(\"chrome/\")\n ? Math.round\n : noop;\nfunction roundAxis(axis) {\n // Round to the nearest .5 pixels to support subpixel layouts\n axis.min = roundPoint(axis.min);\n axis.max = roundPoint(axis.max);\n}\nfunction roundBox(box) {\n roundAxis(box.x);\n roundAxis(box.y);\n}\nfunction shouldAnimatePositionOnly(animationType, snapshot, layout) {\n return (animationType === \"position\" ||\n (animationType === \"preserve-aspect\" &&\n !isNear(aspectRatio(snapshot), aspectRatio(layout), 0.2)));\n}\nfunction checkNodeWasScrollRoot(node) {\n var _a;\n return node !== node.root && ((_a = node.scroll) === null || _a === void 0 ? void 0 : _a.wasRoot);\n}\n\nexport { cleanDirtyNodes, createProjectionNode, mixAxis, mixAxisDelta, mixBox, propagateDirtyNodes };\n","/**\n * This should only ever be modified on the client otherwise it'll\n * persist through server requests. If we need instanced states we\n * could lazy-init via root.\n */\nconst globalProjectionState = {\n /**\n * Global flag as to whether the tree has animated since the last time\n * we resized the window\n */\n hasAnimatedSinceResize: true,\n /**\n * We set this to true once, on the first update. Any nodes added to the tree beyond that\n * update will be given a `data-projection-id` attribute.\n */\n hasEverUpdated: false,\n};\n\nexport { globalProjectionState };\n","import { addUniqueItem, removeItem } from '../../utils/array.mjs';\n\nclass NodeStack {\n constructor() {\n this.members = [];\n }\n add(node) {\n addUniqueItem(this.members, node);\n node.scheduleRender();\n }\n remove(node) {\n removeItem(this.members, node);\n if (node === this.prevLead) {\n this.prevLead = undefined;\n }\n if (node === this.lead) {\n const prevLead = this.members[this.members.length - 1];\n if (prevLead) {\n this.promote(prevLead);\n }\n }\n }\n relegate(node) {\n const indexOfNode = this.members.findIndex((member) => node === member);\n if (indexOfNode === 0)\n return false;\n /**\n * Find the next projection node that is present\n */\n let prevLead;\n for (let i = indexOfNode; i >= 0; i--) {\n const member = this.members[i];\n if (member.isPresent !== false) {\n prevLead = member;\n break;\n }\n }\n if (prevLead) {\n this.promote(prevLead);\n return true;\n }\n else {\n return false;\n }\n }\n promote(node, preserveFollowOpacity) {\n const prevLead = this.lead;\n if (node === prevLead)\n return;\n this.prevLead = prevLead;\n this.lead = node;\n node.show();\n if (prevLead) {\n prevLead.instance && prevLead.scheduleRender();\n node.scheduleRender();\n node.resumeFrom = prevLead;\n if (preserveFollowOpacity) {\n node.resumeFrom.preserveOpacity = true;\n }\n if (prevLead.snapshot) {\n node.snapshot = prevLead.snapshot;\n node.snapshot.latestValues =\n prevLead.animationValues || prevLead.latestValues;\n }\n if (node.root && node.root.isUpdating) {\n node.isLayoutDirty = true;\n }\n const { crossfade } = node.options;\n if (crossfade === false) {\n prevLead.hide();\n }\n /**\n * TODO:\n * - Test border radius when previous node was deleted\n * - boxShadow mixing\n * - Shared between element A in scrolled container and element B (scroll stays the same or changes)\n * - Shared between element A in transformed container and element B (transform stays the same or changes)\n * - Shared between element A in scrolled page and element B (scroll stays the same or changes)\n * ---\n * - Crossfade opacity of root nodes\n * - layoutId changes after animation\n * - layoutId changes mid animation\n */\n }\n }\n exitAnimationComplete() {\n this.members.forEach((node) => {\n const { options, resumingFrom } = node;\n options.onExitComplete && options.onExitComplete();\n if (resumingFrom) {\n resumingFrom.options.onExitComplete &&\n resumingFrom.options.onExitComplete();\n }\n });\n }\n scheduleRender() {\n this.members.forEach((node) => {\n node.instance && node.scheduleRender(false);\n });\n }\n /**\n * Clear any leads that have been removed this render to prevent them from being\n * used in future animations and to prevent memory leaks\n */\n removeLeadSnapshot() {\n if (this.lead && this.lead.snapshot) {\n this.lead.snapshot = undefined;\n }\n }\n}\n\nexport { NodeStack };\n","import { px } from '../../value/types/numbers/units.mjs';\n\nfunction pixelsToPercent(pixels, axis) {\n if (axis.max === axis.min)\n return 0;\n return (pixels / (axis.max - axis.min)) * 100;\n}\n/**\n * We always correct borderRadius as a percentage rather than pixels to reduce paints.\n * For example, if you are projecting a box that is 100px wide with a 10px borderRadius\n * into a box that is 200px wide with a 20px borderRadius, that is actually a 10%\n * borderRadius in both states. If we animate between the two in pixels that will trigger\n * a paint each time. If we animate between the two in percentage we'll avoid a paint.\n */\nconst correctBorderRadius = {\n correct: (latest, node) => {\n if (!node.target)\n return latest;\n /**\n * If latest is a string, if it's a percentage we can return immediately as it's\n * going to be stretched appropriately. Otherwise, if it's a pixel, convert it to a number.\n */\n if (typeof latest === \"string\") {\n if (px.test(latest)) {\n latest = parseFloat(latest);\n }\n else {\n return latest;\n }\n }\n /**\n * If latest is a number, it's a pixel value. We use the current viewportBox to calculate that\n * pixel value as a percentage of each axis\n */\n const x = pixelsToPercent(latest, node.target.x);\n const y = pixelsToPercent(latest, node.target.y);\n return `${x}% ${y}%`;\n },\n};\n\nexport { correctBorderRadius, pixelsToPercent };\n","import { mixNumber } from '../../utils/mix/number.mjs';\nimport { complex } from '../../value/types/complex/index.mjs';\n\nconst correctBoxShadow = {\n correct: (latest, { treeScale, projectionDelta }) => {\n const original = latest;\n const shadow = complex.parse(latest);\n // TODO: Doesn't support multiple shadows\n if (shadow.length > 5)\n return original;\n const template = complex.createTransformer(latest);\n const offset = typeof shadow[0] !== \"number\" ? 1 : 0;\n // Calculate the overall context scale\n const xScale = projectionDelta.x.scale * treeScale.x;\n const yScale = projectionDelta.y.scale * treeScale.y;\n shadow[0 + offset] /= xScale;\n shadow[1 + offset] /= yScale;\n /**\n * Ideally we'd correct x and y scales individually, but because blur and\n * spread apply to both we have to take a scale average and apply that instead.\n * We could potentially improve the outcome of this by incorporating the ratio between\n * the two scales.\n */\n const averageScale = mixNumber(xScale, yScale, 0.5);\n // Blur\n if (typeof shadow[2 + offset] === \"number\")\n shadow[2 + offset] /= averageScale;\n // Spread\n if (typeof shadow[3 + offset] === \"number\")\n shadow[3 + offset] /= averageScale;\n return template(shadow);\n },\n};\n\nexport { correctBoxShadow };\n","const scaleCorrectors = {};\nfunction addScaleCorrector(correctors) {\n Object.assign(scaleCorrectors, correctors);\n}\n\nexport { addScaleCorrector, scaleCorrectors };\n","function buildProjectionTransform(delta, treeScale, latestTransform) {\n let transform = \"\";\n /**\n * The translations we use to calculate are always relative to the viewport coordinate space.\n * But when we apply scales, we also scale the coordinate space of an element and its children.\n * For instance if we have a treeScale (the culmination of all parent scales) of 0.5 and we need\n * to move an element 100 pixels, we actually need to move it 200 in within that scaled space.\n */\n const xTranslate = delta.x.translate / treeScale.x;\n const yTranslate = delta.y.translate / treeScale.y;\n const zTranslate = (latestTransform === null || latestTransform === void 0 ? void 0 : latestTransform.z) || 0;\n if (xTranslate || yTranslate || zTranslate) {\n transform = `translate3d(${xTranslate}px, ${yTranslate}px, ${zTranslate}px) `;\n }\n /**\n * Apply scale correction for the tree transform.\n * This will apply scale to the screen-orientated axes.\n */\n if (treeScale.x !== 1 || treeScale.y !== 1) {\n transform += `scale(${1 / treeScale.x}, ${1 / treeScale.y}) `;\n }\n if (latestTransform) {\n const { transformPerspective, rotate, rotateX, rotateY, skewX, skewY } = latestTransform;\n if (transformPerspective)\n transform = `perspective(${transformPerspective}px) ${transform}`;\n if (rotate)\n transform += `rotate(${rotate}deg) `;\n if (rotateX)\n transform += `rotateX(${rotateX}deg) `;\n if (rotateY)\n transform += `rotateY(${rotateY}deg) `;\n if (skewX)\n transform += `skewX(${skewX}deg) `;\n if (skewY)\n transform += `skewY(${skewY}deg) `;\n }\n /**\n * Apply scale to match the size of the element to the size we want it.\n * This will apply scale to the element-orientated axes.\n */\n const elementScaleX = delta.x.scale * treeScale.x;\n const elementScaleY = delta.y.scale * treeScale.y;\n if (elementScaleX !== 1 || elementScaleY !== 1) {\n transform += `scale(${elementScaleX}, ${elementScaleY})`;\n }\n return transform || \"none\";\n}\n\nexport { buildProjectionTransform };\n","function eachAxis(callback) {\n return [callback(\"x\"), callback(\"y\")];\n}\n\nexport { eachAxis };\n","function isIdentityScale(scale) {\n return scale === undefined || scale === 1;\n}\nfunction hasScale({ scale, scaleX, scaleY }) {\n return (!isIdentityScale(scale) ||\n !isIdentityScale(scaleX) ||\n !isIdentityScale(scaleY));\n}\nfunction hasTransform(values) {\n return (hasScale(values) ||\n has2DTranslate(values) ||\n values.z ||\n values.rotate ||\n values.rotateX ||\n values.rotateY ||\n values.skewX ||\n values.skewY);\n}\nfunction has2DTranslate(values) {\n return is2DTranslate(values.x) || is2DTranslate(values.y);\n}\nfunction is2DTranslate(value) {\n return value && value !== \"0%\";\n}\n\nexport { has2DTranslate, hasScale, hasTransform };\n","import { convertBoundingBoxToBox, transformBoxPoints } from '../geometry/conversion.mjs';\nimport { translateAxis } from '../geometry/delta-apply.mjs';\n\nfunction measureViewportBox(instance, transformPoint) {\n return convertBoundingBoxToBox(transformBoxPoints(instance.getBoundingClientRect(), transformPoint));\n}\nfunction measurePageBox(element, rootProjectionNode, transformPagePoint) {\n const viewportBox = measureViewportBox(element, transformPagePoint);\n const { scroll } = rootProjectionNode;\n if (scroll) {\n translateAxis(viewportBox.x, scroll.offset.x);\n translateAxis(viewportBox.y, scroll.offset.y);\n }\n return viewportBox;\n}\n\nexport { measurePageBox, measureViewportBox };\n","import { initPrefersReducedMotion } from '../utils/reduced-motion/index.mjs';\nimport { hasReducedMotionListener, prefersReducedMotion } from '../utils/reduced-motion/state.mjs';\nimport { SubscriptionManager } from '../utils/subscription-manager.mjs';\nimport { motionValue } from '../value/index.mjs';\nimport { isMotionValue } from '../value/utils/is-motion-value.mjs';\nimport { transformProps } from './html/utils/transform.mjs';\nimport { isControllingVariants, isVariantNode } from './utils/is-controlling-variants.mjs';\nimport { isVariantLabel } from './utils/is-variant-label.mjs';\nimport { updateMotionValuesFromProps } from './utils/motion-values.mjs';\nimport { resolveVariantFromProps } from './utils/resolve-variants.mjs';\nimport { warnOnce } from '../utils/warn-once.mjs';\nimport { featureDefinitions } from '../motion/features/definitions.mjs';\nimport { variantProps } from './utils/variant-props.mjs';\nimport { visualElementStore } from './store.mjs';\nimport { KeyframeResolver } from './utils/KeyframesResolver.mjs';\nimport { isNumericalString } from '../utils/is-numerical-string.mjs';\nimport { isZeroValueString } from '../utils/is-zero-value-string.mjs';\nimport { findValueType } from './dom/value-types/find.mjs';\nimport { complex } from '../value/types/complex/index.mjs';\nimport { getAnimatableNone } from './dom/value-types/animatable-none.mjs';\nimport { createBox } from '../projection/geometry/models.mjs';\nimport { frame, cancelFrame } from '../frameloop/frame.mjs';\n\nconst propEventHandlers = [\n \"AnimationStart\",\n \"AnimationComplete\",\n \"Update\",\n \"BeforeLayoutMeasure\",\n \"LayoutMeasure\",\n \"LayoutAnimationStart\",\n \"LayoutAnimationComplete\",\n];\nconst numVariantProps = variantProps.length;\n/**\n * A VisualElement is an imperative abstraction around UI elements such as\n * HTMLElement, SVGElement, Three.Object3D etc.\n */\nclass VisualElement {\n /**\n * This method takes React props and returns found MotionValues. For example, HTML\n * MotionValues will be found within the style prop, whereas for Three.js within attribute arrays.\n *\n * This isn't an abstract method as it needs calling in the constructor, but it is\n * intended to be one.\n */\n scrapeMotionValuesFromProps(_props, _prevProps, _visualElement) {\n return {};\n }\n constructor({ parent, props, presenceContext, reducedMotionConfig, blockInitialAnimation, visualState, }, options = {}) {\n /**\n * If true, will-change will be applied to the element. Only HTMLVisualElements\n * currently support this.\n */\n this.applyWillChange = false;\n /**\n * A reference to the current underlying Instance, e.g. a HTMLElement\n * or Three.Mesh etc.\n */\n this.current = null;\n /**\n * A set containing references to this VisualElement's children.\n */\n this.children = new Set();\n /**\n * Determine what role this visual element should take in the variant tree.\n */\n this.isVariantNode = false;\n this.isControllingVariants = false;\n /**\n * Decides whether this VisualElement should animate in reduced motion\n * mode.\n *\n * TODO: This is currently set on every individual VisualElement but feels\n * like it could be set globally.\n */\n this.shouldReduceMotion = null;\n /**\n * A map of all motion values attached to this visual element. Motion\n * values are source of truth for any given animated value. A motion\n * value might be provided externally by the component via props.\n */\n this.values = new Map();\n this.KeyframeResolver = KeyframeResolver;\n /**\n * Cleanup functions for active features (hover/tap/exit etc)\n */\n this.features = {};\n /**\n * A map of every subscription that binds the provided or generated\n * motion values onChange listeners to this visual element.\n */\n this.valueSubscriptions = new Map();\n /**\n * A reference to the previously-provided motion values as returned\n * from scrapeMotionValuesFromProps. We use the keys in here to determine\n * if any motion values need to be removed after props are updated.\n */\n this.prevMotionValues = {};\n /**\n * An object containing a SubscriptionManager for each active event.\n */\n this.events = {};\n /**\n * An object containing an unsubscribe function for each prop event subscription.\n * For example, every \"Update\" event can have multiple subscribers via\n * VisualElement.on(), but only one of those can be defined via the onUpdate prop.\n */\n this.propEventSubscriptions = {};\n this.notifyUpdate = () => this.notify(\"Update\", this.latestValues);\n this.render = () => {\n this.isRenderScheduled = false;\n if (!this.current)\n return;\n this.triggerBuild();\n this.renderInstance(this.current, this.renderState, this.props.style, this.projection);\n };\n this.isRenderScheduled = false;\n this.scheduleRender = () => {\n if (!this.isRenderScheduled) {\n this.isRenderScheduled = true;\n frame.render(this.render, false, true);\n }\n };\n const { latestValues, renderState } = visualState;\n this.latestValues = latestValues;\n this.baseTarget = { ...latestValues };\n this.initialValues = props.initial ? { ...latestValues } : {};\n this.renderState = renderState;\n this.parent = parent;\n this.props = props;\n this.presenceContext = presenceContext;\n this.depth = parent ? parent.depth + 1 : 0;\n this.reducedMotionConfig = reducedMotionConfig;\n this.options = options;\n this.blockInitialAnimation = Boolean(blockInitialAnimation);\n this.isControllingVariants = isControllingVariants(props);\n this.isVariantNode = isVariantNode(props);\n if (this.isVariantNode) {\n this.variantChildren = new Set();\n }\n this.manuallyAnimateOnMount = Boolean(parent && parent.current);\n /**\n * Any motion values that are provided to the element when created\n * aren't yet bound to the element, as this would technically be impure.\n * However, we iterate through the motion values and set them to the\n * initial values for this component.\n *\n * TODO: This is impure and we should look at changing this to run on mount.\n * Doing so will break some tests but this isn't necessarily a breaking change,\n * more a reflection of the test.\n */\n const { willChange, ...initialMotionValues } = this.scrapeMotionValuesFromProps(props, {}, this);\n for (const key in initialMotionValues) {\n const value = initialMotionValues[key];\n if (latestValues[key] !== undefined && isMotionValue(value)) {\n value.set(latestValues[key], false);\n }\n }\n }\n mount(instance) {\n this.current = instance;\n visualElementStore.set(instance, this);\n if (this.projection && !this.projection.instance) {\n this.projection.mount(instance);\n }\n if (this.parent && this.isVariantNode && !this.isControllingVariants) {\n this.removeFromVariantTree = this.parent.addVariantChild(this);\n }\n this.values.forEach((value, key) => this.bindToMotionValue(key, value));\n if (!hasReducedMotionListener.current) {\n initPrefersReducedMotion();\n }\n this.shouldReduceMotion =\n this.reducedMotionConfig === \"never\"\n ? false\n : this.reducedMotionConfig === \"always\"\n ? true\n : prefersReducedMotion.current;\n if (process.env.NODE_ENV !== \"production\") {\n warnOnce(this.shouldReduceMotion !== true, \"You have Reduced Motion enabled on your device. Animations may not appear as expected.\");\n }\n if (this.parent)\n this.parent.children.add(this);\n this.update(this.props, this.presenceContext);\n }\n unmount() {\n visualElementStore.delete(this.current);\n this.projection && this.projection.unmount();\n cancelFrame(this.notifyUpdate);\n cancelFrame(this.render);\n this.valueSubscriptions.forEach((remove) => remove());\n this.valueSubscriptions.clear();\n this.removeFromVariantTree && this.removeFromVariantTree();\n this.parent && this.parent.children.delete(this);\n for (const key in this.events) {\n this.events[key].clear();\n }\n for (const key in this.features) {\n const feature = this.features[key];\n if (feature) {\n feature.unmount();\n feature.isMounted = false;\n }\n }\n this.current = null;\n }\n bindToMotionValue(key, value) {\n if (this.valueSubscriptions.has(key)) {\n this.valueSubscriptions.get(key)();\n }\n const valueIsTransform = transformProps.has(key);\n const removeOnChange = value.on(\"change\", (latestValue) => {\n this.latestValues[key] = latestValue;\n this.props.onUpdate && frame.preRender(this.notifyUpdate);\n if (valueIsTransform && this.projection) {\n this.projection.isTransformDirty = true;\n }\n });\n const removeOnRenderRequest = value.on(\"renderRequest\", this.scheduleRender);\n let removeSyncCheck;\n if (window.MotionCheckAppearSync) {\n removeSyncCheck = window.MotionCheckAppearSync(this, key, value);\n }\n this.valueSubscriptions.set(key, () => {\n removeOnChange();\n removeOnRenderRequest();\n if (removeSyncCheck)\n removeSyncCheck();\n if (value.owner)\n value.stop();\n });\n }\n sortNodePosition(other) {\n /**\n * If these nodes aren't even of the same type we can't compare their depth.\n */\n if (!this.current ||\n !this.sortInstanceNodePosition ||\n this.type !== other.type) {\n return 0;\n }\n return this.sortInstanceNodePosition(this.current, other.current);\n }\n updateFeatures() {\n let key = \"animation\";\n for (key in featureDefinitions) {\n const featureDefinition = featureDefinitions[key];\n if (!featureDefinition)\n continue;\n const { isEnabled, Feature: FeatureConstructor } = featureDefinition;\n /**\n * If this feature is enabled but not active, make a new instance.\n */\n if (!this.features[key] &&\n FeatureConstructor &&\n isEnabled(this.props)) {\n this.features[key] = new FeatureConstructor(this);\n }\n /**\n * If we have a feature, mount or update it.\n */\n if (this.features[key]) {\n const feature = this.features[key];\n if (feature.isMounted) {\n feature.update();\n }\n else {\n feature.mount();\n feature.isMounted = true;\n }\n }\n }\n }\n triggerBuild() {\n this.build(this.renderState, this.latestValues, this.props);\n }\n /**\n * Measure the current viewport box with or without transforms.\n * Only measures axis-aligned boxes, rotate and skew must be manually\n * removed with a re-render to work.\n */\n measureViewportBox() {\n return this.current\n ? this.measureInstanceViewportBox(this.current, this.props)\n : createBox();\n }\n getStaticValue(key) {\n return this.latestValues[key];\n }\n setStaticValue(key, value) {\n this.latestValues[key] = value;\n }\n /**\n * Update the provided props. Ensure any newly-added motion values are\n * added to our map, old ones removed, and listeners updated.\n */\n update(props, presenceContext) {\n if (props.transformTemplate || this.props.transformTemplate) {\n this.scheduleRender();\n }\n this.prevProps = this.props;\n this.props = props;\n this.prevPresenceContext = this.presenceContext;\n this.presenceContext = presenceContext;\n /**\n * Update prop event handlers ie onAnimationStart, onAnimationComplete\n */\n for (let i = 0; i < propEventHandlers.length; i++) {\n const key = propEventHandlers[i];\n if (this.propEventSubscriptions[key]) {\n this.propEventSubscriptions[key]();\n delete this.propEventSubscriptions[key];\n }\n const listenerName = (\"on\" + key);\n const listener = props[listenerName];\n if (listener) {\n this.propEventSubscriptions[key] = this.on(key, listener);\n }\n }\n this.prevMotionValues = updateMotionValuesFromProps(this, this.scrapeMotionValuesFromProps(props, this.prevProps, this), this.prevMotionValues);\n if (this.handleChildMotionValue) {\n this.handleChildMotionValue();\n }\n }\n getProps() {\n return this.props;\n }\n /**\n * Returns the variant definition with a given name.\n */\n getVariant(name) {\n return this.props.variants ? this.props.variants[name] : undefined;\n }\n /**\n * Returns the defined default transition on this component.\n */\n getDefaultTransition() {\n return this.props.transition;\n }\n getTransformPagePoint() {\n return this.props.transformPagePoint;\n }\n getClosestVariantNode() {\n return this.isVariantNode\n ? this\n : this.parent\n ? this.parent.getClosestVariantNode()\n : undefined;\n }\n getVariantContext(startAtParent = false) {\n if (startAtParent) {\n return this.parent ? this.parent.getVariantContext() : undefined;\n }\n if (!this.isControllingVariants) {\n const context = this.parent\n ? this.parent.getVariantContext() || {}\n : {};\n if (this.props.initial !== undefined) {\n context.initial = this.props.initial;\n }\n return context;\n }\n const context = {};\n for (let i = 0; i < numVariantProps; i++) {\n const name = variantProps[i];\n const prop = this.props[name];\n if (isVariantLabel(prop) || prop === false) {\n context[name] = prop;\n }\n }\n return context;\n }\n /**\n * Add a child visual element to our set of children.\n */\n addVariantChild(child) {\n const closestVariantNode = this.getClosestVariantNode();\n if (closestVariantNode) {\n closestVariantNode.variantChildren &&\n closestVariantNode.variantChildren.add(child);\n return () => closestVariantNode.variantChildren.delete(child);\n }\n }\n /**\n * Add a motion value and bind it to this visual element.\n */\n addValue(key, value) {\n // Remove existing value if it exists\n const existingValue = this.values.get(key);\n if (value !== existingValue) {\n if (existingValue)\n this.removeValue(key);\n this.bindToMotionValue(key, value);\n this.values.set(key, value);\n this.latestValues[key] = value.get();\n }\n }\n /**\n * Remove a motion value and unbind any active subscriptions.\n */\n removeValue(key) {\n this.values.delete(key);\n const unsubscribe = this.valueSubscriptions.get(key);\n if (unsubscribe) {\n unsubscribe();\n this.valueSubscriptions.delete(key);\n }\n delete this.latestValues[key];\n this.removeValueFromRenderState(key, this.renderState);\n }\n /**\n * Check whether we have a motion value for this key\n */\n hasValue(key) {\n return this.values.has(key);\n }\n getValue(key, defaultValue) {\n if (this.props.values && this.props.values[key]) {\n return this.props.values[key];\n }\n let value = this.values.get(key);\n if (value === undefined && defaultValue !== undefined) {\n value = motionValue(defaultValue === null ? undefined : defaultValue, { owner: this });\n this.addValue(key, value);\n }\n return value;\n }\n /**\n * If we're trying to animate to a previously unencountered value,\n * we need to check for it in our state and as a last resort read it\n * directly from the instance (which might have performance implications).\n */\n readValue(key, target) {\n var _a;\n let value = this.latestValues[key] !== undefined || !this.current\n ? this.latestValues[key]\n : (_a = this.getBaseTargetFromProps(this.props, key)) !== null && _a !== void 0 ? _a : this.readValueFromInstance(this.current, key, this.options);\n if (value !== undefined && value !== null) {\n if (typeof value === \"string\" &&\n (isNumericalString(value) || isZeroValueString(value))) {\n // If this is a number read as a string, ie \"0\" or \"200\", convert it to a number\n value = parseFloat(value);\n }\n else if (!findValueType(value) && complex.test(target)) {\n value = getAnimatableNone(key, target);\n }\n this.setBaseTarget(key, isMotionValue(value) ? value.get() : value);\n }\n return isMotionValue(value) ? value.get() : value;\n }\n /**\n * Set the base target to later animate back to. This is currently\n * only hydrated on creation and when we first read a value.\n */\n setBaseTarget(key, value) {\n this.baseTarget[key] = value;\n }\n /**\n * Find the base target for a value thats been removed from all animation\n * props.\n */\n getBaseTarget(key) {\n var _a;\n const { initial } = this.props;\n let valueFromInitial;\n if (typeof initial === \"string\" || typeof initial === \"object\") {\n const variant = resolveVariantFromProps(this.props, initial, (_a = this.presenceContext) === null || _a === void 0 ? void 0 : _a.custom);\n if (variant) {\n valueFromInitial = variant[key];\n }\n }\n /**\n * If this value still exists in the current initial variant, read that.\n */\n if (initial && valueFromInitial !== undefined) {\n return valueFromInitial;\n }\n /**\n * Alternatively, if this VisualElement config has defined a getBaseTarget\n * so we can read the value from an alternative source, try that.\n */\n const target = this.getBaseTargetFromProps(this.props, key);\n if (target !== undefined && !isMotionValue(target))\n return target;\n /**\n * If the value was initially defined on initial, but it doesn't any more,\n * return undefined. Otherwise return the value as initially read from the DOM.\n */\n return this.initialValues[key] !== undefined &&\n valueFromInitial === undefined\n ? undefined\n : this.baseTarget[key];\n }\n on(eventName, callback) {\n if (!this.events[eventName]) {\n this.events[eventName] = new SubscriptionManager();\n }\n return this.events[eventName].add(callback);\n }\n notify(eventName, ...args) {\n if (this.events[eventName]) {\n this.events[eventName].notify(...args);\n }\n }\n}\n\nexport { VisualElement };\n","import { createRendererMotionComponent } from '../../motion/index.mjs';\nimport { isSVGComponent } from '../dom/utils/is-svg-component.mjs';\nimport { svgMotionConfig } from '../svg/config-motion.mjs';\nimport { htmlMotionConfig } from '../html/config-motion.mjs';\nimport { createUseRender } from '../dom/use-render.mjs';\n\nfunction createMotionComponentFactory(preloadedFeatures, createVisualElement) {\n return function createMotionComponent(Component, { forwardMotionProps } = { forwardMotionProps: false }) {\n const baseConfig = isSVGComponent(Component)\n ? svgMotionConfig\n : htmlMotionConfig;\n const config = {\n ...baseConfig,\n preloadedFeatures,\n useRender: createUseRender(forwardMotionProps),\n createVisualElement,\n Component,\n };\n return createRendererMotionComponent(config);\n };\n}\n\nexport { createMotionComponentFactory };\n","function createDOMMotionComponentProxy(componentFactory) {\n if (typeof Proxy === \"undefined\") {\n return componentFactory;\n }\n /**\n * A cache of generated `motion` components, e.g `motion.div`, `motion.input` etc.\n * Rather than generating them anew every render.\n */\n const componentCache = new Map();\n return new Proxy(componentFactory, {\n /**\n * Called when `motion` is referenced with a prop: `motion.div`, `motion.input` etc.\n * The prop name is passed through as `key` and we can use that to generate a `motion`\n * DOM component with that name.\n */\n get: (_target, key) => {\n /**\n * If this element doesn't exist in the component cache, create it and cache.\n */\n if (!componentCache.has(key)) {\n componentCache.set(key, componentFactory(key));\n }\n return componentCache.get(key);\n },\n });\n}\n\nexport { createDOMMotionComponentProxy };\n","import { animations } from '../../../motion/features/animations.mjs';\nimport { drag } from '../../../motion/features/drag.mjs';\nimport { gestureAnimations } from '../../../motion/features/gestures.mjs';\nimport { layout } from '../../../motion/features/layout.mjs';\nimport { createMotionComponentFactory } from '../create-factory.mjs';\nimport { createDomVisualElement } from '../../dom/create-visual-element.mjs';\n\nconst createMotionComponent = /*@__PURE__*/ createMotionComponentFactory({\n ...animations,\n ...gestureAnimations,\n ...drag,\n ...layout,\n}, createDomVisualElement);\n\nexport { createMotionComponent };\n","import { createDOMMotionComponentProxy } from '../create-proxy.mjs';\nimport { createMotionComponent } from './create.mjs';\n\nconst motion = /*@__PURE__*/ createDOMMotionComponentProxy(createMotionComponent);\n\nexport { motion };\n","import { isNone } from '../../animation/utils/is-none.mjs';\nimport { getVariableValue } from './utils/css-variables-conversion.mjs';\nimport { isCSSVariableToken } from './utils/is-css-variable.mjs';\nimport { positionalKeys, isNumOrPxType, positionalValues } from './utils/unit-conversion.mjs';\nimport { findDimensionValueType } from './value-types/dimensions.mjs';\nimport { KeyframeResolver } from '../utils/KeyframesResolver.mjs';\nimport { makeNoneKeyframesAnimatable } from '../html/utils/make-none-animatable.mjs';\n\nclass DOMKeyframesResolver extends KeyframeResolver {\n constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {\n super(unresolvedKeyframes, onComplete, name, motionValue, element, true);\n }\n readKeyframes() {\n const { unresolvedKeyframes, element, name } = this;\n if (!element || !element.current)\n return;\n super.readKeyframes();\n /**\n * If any keyframe is a CSS variable, we need to find its value by sampling the element\n */\n for (let i = 0; i < unresolvedKeyframes.length; i++) {\n let keyframe = unresolvedKeyframes[i];\n if (typeof keyframe === \"string\") {\n keyframe = keyframe.trim();\n if (isCSSVariableToken(keyframe)) {\n const resolved = getVariableValue(keyframe, element.current);\n if (resolved !== undefined) {\n unresolvedKeyframes[i] = resolved;\n }\n if (i === unresolvedKeyframes.length - 1) {\n this.finalKeyframe = keyframe;\n }\n }\n }\n }\n /**\n * Resolve \"none\" values. We do this potentially twice - once before and once after measuring keyframes.\n * This could be seen as inefficient but it's a trade-off to avoid measurements in more situations, which\n * have a far bigger performance impact.\n */\n this.resolveNoneKeyframes();\n /**\n * Check to see if unit type has changed. If so schedule jobs that will\n * temporarily set styles to the destination keyframes.\n * Skip if we have more than two keyframes or this isn't a positional value.\n * TODO: We can throw if there are multiple keyframes and the value type changes.\n */\n if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {\n return;\n }\n const [origin, target] = unresolvedKeyframes;\n const originType = findDimensionValueType(origin);\n const targetType = findDimensionValueType(target);\n /**\n * Either we don't recognise these value types or we can animate between them.\n */\n if (originType === targetType)\n return;\n /**\n * If both values are numbers or pixels, we can animate between them by\n * converting them to numbers.\n */\n if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {\n for (let i = 0; i < unresolvedKeyframes.length; i++) {\n const value = unresolvedKeyframes[i];\n if (typeof value === \"string\") {\n unresolvedKeyframes[i] = parseFloat(value);\n }\n }\n }\n else {\n /**\n * Else, the only way to resolve this is by measuring the element.\n */\n this.needsMeasurement = true;\n }\n }\n resolveNoneKeyframes() {\n const { unresolvedKeyframes, name } = this;\n const noneKeyframeIndexes = [];\n for (let i = 0; i < unresolvedKeyframes.length; i++) {\n if (isNone(unresolvedKeyframes[i])) {\n noneKeyframeIndexes.push(i);\n }\n }\n if (noneKeyframeIndexes.length) {\n makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);\n }\n }\n measureInitialState() {\n const { element, unresolvedKeyframes, name } = this;\n if (!element || !element.current)\n return;\n if (name === \"height\") {\n this.suspendedScrollY = window.pageYOffset;\n }\n this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));\n unresolvedKeyframes[0] = this.measuredOrigin;\n // Set final key frame to measure after next render\n const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];\n if (measureKeyframe !== undefined) {\n element.getValue(name, measureKeyframe).jump(measureKeyframe, false);\n }\n }\n measureEndState() {\n var _a;\n const { element, name, unresolvedKeyframes } = this;\n if (!element || !element.current)\n return;\n const value = element.getValue(name);\n value && value.jump(this.measuredOrigin, false);\n const finalKeyframeIndex = unresolvedKeyframes.length - 1;\n const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];\n unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));\n if (finalKeyframe !== null && this.finalKeyframe === undefined) {\n this.finalKeyframe = finalKeyframe;\n }\n // If we removed transform values, reapply them before the next render\n if ((_a = this.removedTransforms) === null || _a === void 0 ? void 0 : _a.length) {\n this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {\n element\n .getValue(unsetTransformName)\n .set(unsetTransformValue);\n });\n }\n this.resolveNoneKeyframes();\n }\n}\n\nexport { DOMKeyframesResolver };\n","import { VisualElement } from '../VisualElement.mjs';\nimport { DOMKeyframesResolver } from './DOMKeyframesResolver.mjs';\n\nclass DOMVisualElement extends VisualElement {\n constructor() {\n super(...arguments);\n this.KeyframeResolver = DOMKeyframesResolver;\n }\n sortInstanceNodePosition(a, b) {\n /**\n * compareDocumentPosition returns a bitmask, by using the bitwise &\n * we're returning true if 2 in that bitmask is set to true. 2 is set\n * to true if b preceeds a.\n */\n return a.compareDocumentPosition(b) & 2 ? 1 : -1;\n }\n getBaseTargetFromProps(props, key) {\n return props.style\n ? props.style[key]\n : undefined;\n }\n removeValueFromRenderState(key, { vars, style }) {\n delete vars[key];\n delete style[key];\n }\n}\n\nexport { DOMVisualElement };\n","import { Fragment } from 'react';\nimport { HTMLVisualElement } from '../html/HTMLVisualElement.mjs';\nimport { SVGVisualElement } from '../svg/SVGVisualElement.mjs';\nimport { isSVGComponent } from './utils/is-svg-component.mjs';\n\nconst createDomVisualElement = (Component, options) => {\n return isSVGComponent(Component)\n ? new SVGVisualElement(options)\n : new HTMLVisualElement(options, {\n allowProjection: Component !== Fragment,\n });\n};\n\nexport { createDomVisualElement };\n","import { frame, cancelFrame } from '../../../frameloop/frame.mjs';\n\nfunction observeTimeline(update, timeline) {\n let prevProgress;\n const onFrame = () => {\n const { currentTime } = timeline;\n const percentage = currentTime === null ? 0 : currentTime.value;\n const progress = percentage / 100;\n if (prevProgress !== progress) {\n update(progress);\n }\n prevProgress = progress;\n };\n frame.update(onFrame, true);\n return () => cancelFrame(onFrame);\n}\n\nexport { observeTimeline };\n","import { memo } from '../../../utils/memo.mjs';\n\nconst supportsScrollTimeline = memo(() => window.ScrollTimeline !== undefined);\n\nexport { supportsScrollTimeline };\n","import { Fragment, useMemo, createElement } from 'react';\nimport { useHTMLProps } from '../html/use-props.mjs';\nimport { filterProps } from './utils/filter-props.mjs';\nimport { isSVGComponent } from './utils/is-svg-component.mjs';\nimport { useSVGProps } from '../svg/use-props.mjs';\nimport { isMotionValue } from '../../value/utils/is-motion-value.mjs';\n\nfunction createUseRender(forwardMotionProps = false) {\n const useRender = (Component, props, ref, { latestValues }, isStatic) => {\n const useVisualProps = isSVGComponent(Component)\n ? useSVGProps\n : useHTMLProps;\n const visualProps = useVisualProps(props, latestValues, isStatic, Component);\n const filteredProps = filterProps(props, typeof Component === \"string\", forwardMotionProps);\n const elementProps = Component !== Fragment\n ? { ...filteredProps, ...visualProps, ref }\n : {};\n /**\n * If component has been handed a motion value as its child,\n * memoise its initial value and render that. Subsequent updates\n * will be handled by the onChange handler\n */\n const { children } = props;\n const renderedChildren = useMemo(() => (isMotionValue(children) ? children.get() : children), [children]);\n return createElement(Component, {\n ...elementProps,\n children: renderedChildren,\n });\n };\n return useRender;\n}\n\nexport { createUseRender };\n","/**\n * Convert camelCase to dash-case properties.\n */\nconst camelToDash = (str) => str.replace(/([a-z])([A-Z])/gu, \"$1-$2\").toLowerCase();\n\nexport { camelToDash };\n","import { invariant } from '../../../utils/errors.mjs';\nimport { isNumericalString } from '../../../utils/is-numerical-string.mjs';\nimport { isCSSVariableToken } from './is-css-variable.mjs';\n\n/**\n * Parse Framer's special CSS variable format into a CSS token and a fallback.\n *\n * ```\n * `var(--foo, #fff)` => [`--foo`, '#fff']\n * ```\n *\n * @param current\n */\nconst splitCSSVariableRegex = \n// eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words\n/^var\\(--(?:([\\w-]+)|([\\w-]+), ?([a-zA-Z\\d ()%#.,-]+))\\)/u;\nfunction parseCSSVariable(current) {\n const match = splitCSSVariableRegex.exec(current);\n if (!match)\n return [,];\n const [, token1, token2, fallback] = match;\n return [`--${token1 !== null && token1 !== void 0 ? token1 : token2}`, fallback];\n}\nconst maxDepth = 4;\nfunction getVariableValue(current, element, depth = 1) {\n invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property \"${current}\". This may indicate a circular fallback dependency.`);\n const [token, fallback] = parseCSSVariable(current);\n // No CSS variable detected\n if (!token)\n return;\n // Attempt to read this CSS variable off the element\n const resolved = window.getComputedStyle(element).getPropertyValue(token);\n if (resolved) {\n const trimmed = resolved.trim();\n return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;\n }\n return isCSSVariableToken(fallback)\n ? getVariableValue(fallback, element, depth + 1)\n : fallback;\n}\n\nexport { getVariableValue, parseCSSVariable };\n","import { isValidMotionProp } from '../../../motion/utils/valid-prop.mjs';\n\nlet shouldForward = (key) => !isValidMotionProp(key);\nfunction loadExternalIsValidProp(isValidProp) {\n if (!isValidProp)\n return;\n // Explicitly filter our events\n shouldForward = (key) => key.startsWith(\"on\") ? !isValidMotionProp(key) : isValidProp(key);\n}\n/**\n * Emotion and Styled Components both allow users to pass through arbitrary props to their components\n * to dynamically generate CSS. They both use the `@emotion/is-prop-valid` package to determine which\n * of these should be passed to the underlying DOM node.\n *\n * However, when styling a Motion component `styled(motion.div)`, both packages pass through *all* props\n * as it's seen as an arbitrary component rather than a DOM node. Motion only allows arbitrary props\n * passed through the `custom` prop so it doesn't *need* the payload or computational overhead of\n * `@emotion/is-prop-valid`, however to fix this problem we need to use it.\n *\n * By making it an optionalDependency we can offer this functionality only in the situations where it's\n * actually required.\n */\ntry {\n /**\n * We attempt to import this package but require won't be defined in esm environments, in that case\n * isPropValid will have to be provided via `MotionContext`. In a 6.0.0 this should probably be removed\n * in favour of explicit injection.\n */\n loadExternalIsValidProp(require(\"@emotion/is-prop-valid\").default);\n}\ncatch (_a) {\n // We don't need to actually do anything here - the fallback is the existing `isPropValid`.\n}\nfunction filterProps(props, isDom, forwardMotionProps) {\n const filteredProps = {};\n for (const key in props) {\n /**\n * values is considered a valid prop by Emotion, so if it's present\n * this will be rendered out to the DOM unless explicitly filtered.\n *\n * We check the type as it could be used with the `feColorMatrix`\n * element, which we support.\n */\n if (key === \"values\" && typeof props.values === \"object\")\n continue;\n if (shouldForward(key) ||\n (forwardMotionProps === true && isValidMotionProp(key)) ||\n (!isDom && !isValidMotionProp(key)) ||\n // If trying to use native HTML drag events, forward drag listeners\n (props[\"draggable\"] &&\n key.startsWith(\"onDrag\"))) {\n filteredProps[key] =\n props[key];\n }\n }\n return filteredProps;\n}\n\nexport { filterProps, loadExternalIsValidProp };\n","const checkStringStartsWith = (token) => (key) => typeof key === \"string\" && key.startsWith(token);\nconst isCSSVariableName = checkStringStartsWith(\"--\");\nconst startsAsVariableToken = checkStringStartsWith(\"var(--\");\nconst isCSSVariableToken = (value) => {\n const startsWithToken = startsAsVariableToken(value);\n if (!startsWithToken)\n return false;\n // Ensure any comments are stripped from the value as this can harm performance of the regex.\n return singleCssVariableRegex.test(value.split(\"/*\")[0].trim());\n};\nconst singleCssVariableRegex = /var\\(--(?:[\\w-]+\\s*|[\\w-]+\\s*,(?:\\s*[^)(\\s]|\\s*\\((?:[^)(]|\\([^)(]*\\))*\\))+\\s*)\\)$/iu;\n\nexport { isCSSVariableName, isCSSVariableToken };\n","import { lowercaseSVGElements } from '../../svg/lowercase-elements.mjs';\n\nfunction isSVGComponent(Component) {\n if (\n /**\n * If it's not a string, it's a custom React component. Currently we only support\n * HTML custom React components.\n */\n typeof Component !== \"string\" ||\n /**\n * If it contains a dash, the element is a custom HTML webcomponent.\n */\n Component.includes(\"-\")) {\n return false;\n }\n else if (\n /**\n * If it's in our list of lowercase SVG tags, it's an SVG component\n */\n lowercaseSVGElements.indexOf(Component) > -1 ||\n /**\n * If it contains a capital letter, it's an SVG component\n */\n /[A-Z]/u.test(Component)) {\n return true;\n }\n return false;\n}\n\nexport { isSVGComponent };\n","function isSVGElement(element) {\n return element instanceof SVGElement && element.tagName !== \"svg\";\n}\n\nexport { isSVGElement };\n","import { transformPropOrder } from '../../html/utils/transform.mjs';\nimport { number } from '../../../value/types/numbers/index.mjs';\nimport { px } from '../../../value/types/numbers/units.mjs';\n\nconst positionalKeys = new Set([\n \"width\",\n \"height\",\n \"top\",\n \"left\",\n \"right\",\n \"bottom\",\n \"x\",\n \"y\",\n \"translateX\",\n \"translateY\",\n]);\nconst isNumOrPxType = (v) => v === number || v === px;\nconst getPosFromMatrix = (matrix, pos) => parseFloat(matrix.split(\", \")[pos]);\nconst getTranslateFromMatrix = (pos2, pos3) => (_bbox, { transform }) => {\n if (transform === \"none\" || !transform)\n return 0;\n const matrix3d = transform.match(/^matrix3d\\((.+)\\)$/u);\n if (matrix3d) {\n return getPosFromMatrix(matrix3d[1], pos3);\n }\n else {\n const matrix = transform.match(/^matrix\\((.+)\\)$/u);\n if (matrix) {\n return getPosFromMatrix(matrix[1], pos2);\n }\n else {\n return 0;\n }\n }\n};\nconst transformKeys = new Set([\"x\", \"y\", \"z\"]);\nconst nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));\nfunction removeNonTranslationalTransform(visualElement) {\n const removedTransforms = [];\n nonTranslationalTransformKeys.forEach((key) => {\n const value = visualElement.getValue(key);\n if (value !== undefined) {\n removedTransforms.push([key, value.get()]);\n value.set(key.startsWith(\"scale\") ? 1 : 0);\n }\n });\n return removedTransforms;\n}\nconst positionalValues = {\n // Dimensions\n width: ({ x }, { paddingLeft = \"0\", paddingRight = \"0\" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),\n height: ({ y }, { paddingTop = \"0\", paddingBottom = \"0\" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),\n top: (_bbox, { top }) => parseFloat(top),\n left: (_bbox, { left }) => parseFloat(left),\n bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),\n right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),\n // Transform\n x: getTranslateFromMatrix(4, 13),\n y: getTranslateFromMatrix(5, 14),\n};\n// Alias translate longform names\npositionalValues.translateX = positionalValues.x;\npositionalValues.translateY = positionalValues.y;\n\nexport { isNumOrPxType, positionalKeys, positionalValues, removeNonTranslationalTransform };\n","import { complex } from '../../../value/types/complex/index.mjs';\nimport { filter } from '../../../value/types/complex/filter.mjs';\nimport { getDefaultValueType } from './defaults.mjs';\n\nfunction getAnimatableNone(key, value) {\n let defaultValueType = getDefaultValueType(key);\n if (defaultValueType !== filter)\n defaultValueType = complex;\n // If value is not recognised as animatable, ie \"none\", create an animatable version origin based on the target\n return defaultValueType.getAnimatableNone\n ? defaultValueType.getAnimatableNone(value)\n : undefined;\n}\n\nexport { getAnimatableNone };\n","import { color } from '../../../value/types/color/index.mjs';\nimport { filter } from '../../../value/types/complex/filter.mjs';\nimport { numberValueTypes } from './number.mjs';\n\n/**\n * A map of default value types for common values\n */\nconst defaultValueTypes = {\n ...numberValueTypes,\n // Color props\n color,\n backgroundColor: color,\n outlineColor: color,\n fill: color,\n stroke: color,\n // Border props\n borderColor: color,\n borderTopColor: color,\n borderRightColor: color,\n borderBottomColor: color,\n borderLeftColor: color,\n filter,\n WebkitFilter: filter,\n};\n/**\n * Gets the default ValueType for the provided value key\n */\nconst getDefaultValueType = (key) => defaultValueTypes[key];\n\nexport { defaultValueTypes, getDefaultValueType };\n","import { number } from '../../../value/types/numbers/index.mjs';\nimport { px, percent, degrees, vw, vh } from '../../../value/types/numbers/units.mjs';\nimport { testValueType } from './test.mjs';\nimport { auto } from './type-auto.mjs';\n\n/**\n * A list of value types commonly used for dimensions\n */\nconst dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];\n/**\n * Tests a dimensional value against the list of dimension ValueTypes\n */\nconst findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));\n\nexport { dimensionValueTypes, findDimensionValueType };\n","import { color } from '../../../value/types/color/index.mjs';\nimport { complex } from '../../../value/types/complex/index.mjs';\nimport { dimensionValueTypes } from './dimensions.mjs';\nimport { testValueType } from './test.mjs';\n\n/**\n * A list of all ValueTypes\n */\nconst valueTypes = [...dimensionValueTypes, color, complex];\n/**\n * Tests a value against the list of ValueTypes\n */\nconst findValueType = (v) => valueTypes.find(testValueType(v));\n\nexport { findValueType };\n","/**\n * Provided a value and a ValueType, returns the value as that value type.\n */\nconst getValueAsType = (value, type) => {\n return type && typeof value === \"number\"\n ? type.transform(value)\n : value;\n};\n\nexport { getValueAsType };\n","import { scale, alpha } from '../../../value/types/numbers/index.mjs';\nimport { px, degrees, progressPercentage } from '../../../value/types/numbers/units.mjs';\nimport { int } from './type-int.mjs';\n\nconst numberValueTypes = {\n // Border props\n borderWidth: px,\n borderTopWidth: px,\n borderRightWidth: px,\n borderBottomWidth: px,\n borderLeftWidth: px,\n borderRadius: px,\n radius: px,\n borderTopLeftRadius: px,\n borderTopRightRadius: px,\n borderBottomRightRadius: px,\n borderBottomLeftRadius: px,\n // Positioning props\n width: px,\n maxWidth: px,\n height: px,\n maxHeight: px,\n size: px,\n top: px,\n right: px,\n bottom: px,\n left: px,\n // Spacing props\n padding: px,\n paddingTop: px,\n paddingRight: px,\n paddingBottom: px,\n paddingLeft: px,\n margin: px,\n marginTop: px,\n marginRight: px,\n marginBottom: px,\n marginLeft: px,\n // Transform props\n rotate: degrees,\n rotateX: degrees,\n rotateY: degrees,\n rotateZ: degrees,\n scale,\n scaleX: scale,\n scaleY: scale,\n scaleZ: scale,\n skew: degrees,\n skewX: degrees,\n skewY: degrees,\n distance: px,\n translateX: px,\n translateY: px,\n translateZ: px,\n x: px,\n y: px,\n z: px,\n perspective: px,\n transformPerspective: px,\n opacity: alpha,\n originX: progressPercentage,\n originY: progressPercentage,\n originZ: px,\n // Misc\n zIndex: int,\n backgroundPositionX: px,\n backgroundPositionY: px,\n // SVG\n fillOpacity: alpha,\n strokeOpacity: alpha,\n numOctaves: int,\n};\n\nexport { numberValueTypes };\n","/**\n * Tests a provided value against a ValueType\n */\nconst testValueType = (v) => (type) => type.test(v);\n\nexport { testValueType };\n","/**\n * ValueType for \"auto\"\n */\nconst auto = {\n test: (v) => v === \"auto\",\n parse: (v) => v,\n};\n\nexport { auto };\n","import { number } from '../../../value/types/numbers/index.mjs';\n\nconst int = {\n ...number,\n transform: Math.round,\n};\n\nexport { int };\n","import { buildHTMLStyles } from './utils/build-styles.mjs';\nimport { isCSSVariableName } from '../dom/utils/is-css-variable.mjs';\nimport { transformProps } from './utils/transform.mjs';\nimport { scrapeMotionValuesFromProps } from './utils/scrape-motion-values.mjs';\nimport { renderHTML } from './utils/render.mjs';\nimport { getDefaultValueType } from '../dom/value-types/defaults.mjs';\nimport { measureViewportBox } from '../../projection/utils/measure.mjs';\nimport { DOMVisualElement } from '../dom/DOMVisualElement.mjs';\nimport { isMotionValue } from '../../value/utils/is-motion-value.mjs';\n\nfunction getComputedStyle(element) {\n return window.getComputedStyle(element);\n}\nclass HTMLVisualElement extends DOMVisualElement {\n constructor() {\n super(...arguments);\n this.type = \"html\";\n this.applyWillChange = true;\n this.renderInstance = renderHTML;\n }\n readValueFromInstance(instance, key) {\n if (transformProps.has(key)) {\n const defaultType = getDefaultValueType(key);\n return defaultType ? defaultType.default || 0 : 0;\n }\n else {\n const computedStyle = getComputedStyle(instance);\n const value = (isCSSVariableName(key)\n ? computedStyle.getPropertyValue(key)\n : computedStyle[key]) || 0;\n return typeof value === \"string\" ? value.trim() : value;\n }\n }\n measureInstanceViewportBox(instance, { transformPagePoint }) {\n return measureViewportBox(instance, transformPagePoint);\n }\n build(renderState, latestValues, props) {\n buildHTMLStyles(renderState, latestValues, props.transformTemplate);\n }\n scrapeMotionValuesFromProps(props, prevProps, visualElement) {\n return scrapeMotionValuesFromProps(props, prevProps, visualElement);\n }\n handleChildMotionValue() {\n if (this.childSubscription) {\n this.childSubscription();\n delete this.childSubscription;\n }\n const { children } = this.props;\n if (isMotionValue(children)) {\n this.childSubscription = children.on(\"change\", (latest) => {\n if (this.current)\n this.current.textContent = `${latest}`;\n });\n }\n }\n}\n\nexport { HTMLVisualElement, getComputedStyle };\n","import { makeUseVisualState } from '../../motion/utils/use-visual-state.mjs';\nimport { scrapeMotionValuesFromProps } from './utils/scrape-motion-values.mjs';\nimport { createHtmlRenderState } from './utils/create-render-state.mjs';\n\nconst htmlMotionConfig = {\n useVisualState: makeUseVisualState({\n applyWillChange: true,\n scrapeMotionValuesFromProps,\n createRenderState: createHtmlRenderState,\n }),\n};\n\nexport { htmlMotionConfig };\n","import { useMemo } from 'react';\nimport { isForcedMotionValue } from '../../motion/utils/is-forced-motion-value.mjs';\nimport { isMotionValue } from '../../value/utils/is-motion-value.mjs';\nimport { buildHTMLStyles } from './utils/build-styles.mjs';\nimport { createHtmlRenderState } from './utils/create-render-state.mjs';\n\nfunction copyRawValuesOnly(target, source, props) {\n for (const key in source) {\n if (!isMotionValue(source[key]) && !isForcedMotionValue(key, props)) {\n target[key] = source[key];\n }\n }\n}\nfunction useInitialMotionValues({ transformTemplate }, visualState) {\n return useMemo(() => {\n const state = createHtmlRenderState();\n buildHTMLStyles(state, visualState, transformTemplate);\n return Object.assign({}, state.vars, state.style);\n }, [visualState]);\n}\nfunction useStyle(props, visualState) {\n const styleProp = props.style || {};\n const style = {};\n /**\n * Copy non-Motion Values straight into style\n */\n copyRawValuesOnly(style, styleProp, props);\n Object.assign(style, useInitialMotionValues(props, visualState));\n return style;\n}\nfunction useHTMLProps(props, visualState) {\n // The `any` isn't ideal but it is the type of createElement props argument\n const htmlProps = {};\n const style = useStyle(props, visualState);\n if (props.drag && props.dragListener !== false) {\n // Disable the ghost element when a user drags\n htmlProps.draggable = false;\n // Disable text selection\n style.userSelect =\n style.WebkitUserSelect =\n style.WebkitTouchCallout =\n \"none\";\n // Disable scrolling on the draggable direction\n style.touchAction =\n props.drag === true\n ? \"none\"\n : `pan-${props.drag === \"x\" ? \"y\" : \"x\"}`;\n }\n if (props.tabIndex === undefined &&\n (props.onTap || props.onTapStart || props.whileTap)) {\n htmlProps.tabIndex = 0;\n }\n htmlProps.style = style;\n return htmlProps;\n}\n\nexport { copyRawValuesOnly, useHTMLProps };\n","import { buildTransform } from './build-transform.mjs';\nimport { isCSSVariableName } from '../../dom/utils/is-css-variable.mjs';\nimport { transformProps } from './transform.mjs';\nimport { getValueAsType } from '../../dom/value-types/get-as-type.mjs';\nimport { numberValueTypes } from '../../dom/value-types/number.mjs';\n\nfunction buildHTMLStyles(state, latestValues, transformTemplate) {\n const { style, vars, transformOrigin } = state;\n // Track whether we encounter any transform or transformOrigin values.\n let hasTransform = false;\n let hasTransformOrigin = false;\n /**\n * Loop over all our latest animated values and decide whether to handle them\n * as a style or CSS variable.\n *\n * Transforms and transform origins are kept separately for further processing.\n */\n for (const key in latestValues) {\n const value = latestValues[key];\n if (transformProps.has(key)) {\n // If this is a transform, flag to enable further transform processing\n hasTransform = true;\n continue;\n }\n else if (isCSSVariableName(key)) {\n vars[key] = value;\n continue;\n }\n else {\n // Convert the value to its default value type, ie 0 -> \"0px\"\n const valueAsType = getValueAsType(value, numberValueTypes[key]);\n if (key.startsWith(\"origin\")) {\n // If this is a transform origin, flag and enable further transform-origin processing\n hasTransformOrigin = true;\n transformOrigin[key] =\n valueAsType;\n }\n else {\n style[key] = valueAsType;\n }\n }\n }\n if (!latestValues.transform) {\n if (hasTransform || transformTemplate) {\n style.transform = buildTransform(latestValues, state.transform, transformTemplate);\n }\n else if (style.transform) {\n /**\n * If we have previously created a transform but currently don't have any,\n * reset transform style to none.\n */\n style.transform = \"none\";\n }\n }\n /**\n * Build a transformOrigin style. Uses the same defaults as the browser for\n * undefined origins.\n */\n if (hasTransformOrigin) {\n const { originX = \"50%\", originY = \"50%\", originZ = 0, } = transformOrigin;\n style.transformOrigin = `${originX} ${originY} ${originZ}`;\n }\n}\n\nexport { buildHTMLStyles };\n","import { transformPropOrder } from './transform.mjs';\nimport { getValueAsType } from '../../dom/value-types/get-as-type.mjs';\nimport { numberValueTypes } from '../../dom/value-types/number.mjs';\n\nconst translateAlias = {\n x: \"translateX\",\n y: \"translateY\",\n z: \"translateZ\",\n transformPerspective: \"perspective\",\n};\nconst numTransforms = transformPropOrder.length;\n/**\n * Build a CSS transform style from individual x/y/scale etc properties.\n *\n * This outputs with a default order of transforms/scales/rotations, this can be customised by\n * providing a transformTemplate function.\n */\nfunction buildTransform(latestValues, transform, transformTemplate) {\n // The transform string we're going to build into.\n let transformString = \"\";\n let transformIsDefault = true;\n /**\n * Loop over all possible transforms in order, adding the ones that\n * are present to the transform string.\n */\n for (let i = 0; i < numTransforms; i++) {\n const key = transformPropOrder[i];\n const value = latestValues[key];\n if (value === undefined)\n continue;\n let valueIsDefault = true;\n if (typeof value === \"number\") {\n valueIsDefault = value === (key.startsWith(\"scale\") ? 1 : 0);\n }\n else {\n valueIsDefault = parseFloat(value) === 0;\n }\n if (!valueIsDefault || transformTemplate) {\n const valueAsType = getValueAsType(value, numberValueTypes[key]);\n if (!valueIsDefault) {\n transformIsDefault = false;\n const transformName = translateAlias[key] || key;\n transformString += `${transformName}(${valueAsType}) `;\n }\n if (transformTemplate) {\n transform[key] = valueAsType;\n }\n }\n }\n transformString = transformString.trim();\n // If we have a custom `transform` template, pass our transform values and\n // generated transformString to that before returning\n if (transformTemplate) {\n transformString = transformTemplate(transform, transformIsDefault ? \"\" : transformString);\n }\n else if (transformIsDefault) {\n transformString = \"none\";\n }\n return transformString;\n}\n\nexport { buildTransform };\n","const createHtmlRenderState = () => ({\n style: {},\n transform: {},\n transformOrigin: {},\n vars: {},\n});\n\nexport { createHtmlRenderState };\n","import { analyseComplexValue } from '../../../value/types/complex/index.mjs';\nimport { getAnimatableNone } from '../../dom/value-types/animatable-none.mjs';\n\n/**\n * If we encounter keyframes like \"none\" or \"0\" and we also have keyframes like\n * \"#fff\" or \"200px 200px\" we want to find a keyframe to serve as a template for\n * the \"none\" keyframes. In this case \"#fff\" or \"200px 200px\" - then these get turned into\n * zero equivalents, i.e. \"#fff0\" or \"0px 0px\".\n */\nconst invalidTemplates = new Set([\"auto\", \"none\", \"0\"]);\nfunction makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {\n let i = 0;\n let animatableTemplate = undefined;\n while (i < unresolvedKeyframes.length && !animatableTemplate) {\n const keyframe = unresolvedKeyframes[i];\n if (typeof keyframe === \"string\" &&\n !invalidTemplates.has(keyframe) &&\n analyseComplexValue(keyframe).values.length) {\n animatableTemplate = unresolvedKeyframes[i];\n }\n i++;\n }\n if (animatableTemplate && name) {\n for (const noneIndex of noneKeyframeIndexes) {\n unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);\n }\n }\n}\n\nexport { makeNoneKeyframesAnimatable };\n","function renderHTML(element, { style, vars }, styleProp, projection) {\n Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));\n // Loop over any CSS variables and assign those.\n for (const key in vars) {\n element.style.setProperty(key, vars[key]);\n }\n}\n\nexport { renderHTML };\n","import { isForcedMotionValue } from '../../../motion/utils/is-forced-motion-value.mjs';\nimport { isMotionValue } from '../../../value/utils/is-motion-value.mjs';\n\nfunction scrapeMotionValuesFromProps(props, prevProps, visualElement) {\n var _a;\n const { style } = props;\n const newValues = {};\n for (const key in style) {\n if (isMotionValue(style[key]) ||\n (prevProps.style &&\n isMotionValue(prevProps.style[key])) ||\n isForcedMotionValue(key, props) ||\n ((_a = visualElement === null || visualElement === void 0 ? void 0 : visualElement.getValue(key)) === null || _a === void 0 ? void 0 : _a.liveStyle) !== undefined) {\n newValues[key] = style[key];\n }\n }\n /**\n * If the willChange style has been manually set as a string, set\n * applyWillChange to false to prevent it from automatically being applied.\n */\n if (visualElement && style && typeof style.willChange === \"string\") {\n visualElement.applyWillChange = false;\n }\n return newValues;\n}\n\nexport { scrapeMotionValuesFromProps };\n","/**\n * Generate a list of every possible transform key.\n */\nconst transformPropOrder = [\n \"transformPerspective\",\n \"x\",\n \"y\",\n \"z\",\n \"translateX\",\n \"translateY\",\n \"translateZ\",\n \"scale\",\n \"scaleX\",\n \"scaleY\",\n \"rotate\",\n \"rotateX\",\n \"rotateY\",\n \"rotateZ\",\n \"skew\",\n \"skewX\",\n \"skewY\",\n];\n/**\n * A quick lookup for transform props.\n */\nconst transformProps = new Set(transformPropOrder);\n\nexport { transformPropOrder, transformProps };\n","const visualElementStore = new WeakMap();\n\nexport { visualElementStore };\n","import { scrapeMotionValuesFromProps } from './utils/scrape-motion-values.mjs';\nimport { DOMVisualElement } from '../dom/DOMVisualElement.mjs';\nimport { buildSVGAttrs } from './utils/build-attrs.mjs';\nimport { camelToDash } from '../dom/utils/camel-to-dash.mjs';\nimport { camelCaseAttributes } from './utils/camel-case-attrs.mjs';\nimport { transformProps } from '../html/utils/transform.mjs';\nimport { renderSVG } from './utils/render.mjs';\nimport { getDefaultValueType } from '../dom/value-types/defaults.mjs';\nimport { createBox } from '../../projection/geometry/models.mjs';\nimport { isSVGTag } from './utils/is-svg-tag.mjs';\n\nclass SVGVisualElement extends DOMVisualElement {\n constructor() {\n super(...arguments);\n this.type = \"svg\";\n this.isSVGTag = false;\n this.measureInstanceViewportBox = createBox;\n }\n getBaseTargetFromProps(props, key) {\n return props[key];\n }\n readValueFromInstance(instance, key) {\n if (transformProps.has(key)) {\n const defaultType = getDefaultValueType(key);\n return defaultType ? defaultType.default || 0 : 0;\n }\n key = !camelCaseAttributes.has(key) ? camelToDash(key) : key;\n return instance.getAttribute(key);\n }\n scrapeMotionValuesFromProps(props, prevProps, visualElement) {\n return scrapeMotionValuesFromProps(props, prevProps, visualElement);\n }\n build(renderState, latestValues, props) {\n buildSVGAttrs(renderState, latestValues, this.isSVGTag, props.transformTemplate);\n }\n renderInstance(instance, renderState, styleProp, projection) {\n renderSVG(instance, renderState, styleProp, projection);\n }\n mount(instance) {\n this.isSVGTag = isSVGTag(instance.tagName);\n super.mount(instance);\n }\n}\n\nexport { SVGVisualElement };\n","import { renderSVG } from './utils/render.mjs';\nimport { scrapeMotionValuesFromProps } from './utils/scrape-motion-values.mjs';\nimport { makeUseVisualState } from '../../motion/utils/use-visual-state.mjs';\nimport { createSvgRenderState } from './utils/create-render-state.mjs';\nimport { buildSVGAttrs } from './utils/build-attrs.mjs';\nimport { isSVGTag } from './utils/is-svg-tag.mjs';\nimport { frame } from '../../frameloop/frame.mjs';\n\nconst svgMotionConfig = {\n useVisualState: makeUseVisualState({\n scrapeMotionValuesFromProps: scrapeMotionValuesFromProps,\n createRenderState: createSvgRenderState,\n onMount: (props, instance, { renderState, latestValues }) => {\n frame.read(() => {\n try {\n renderState.dimensions =\n typeof instance.getBBox ===\n \"function\"\n ? instance.getBBox()\n : instance.getBoundingClientRect();\n }\n catch (e) {\n // Most likely trying to measure an unrendered element under Firefox\n renderState.dimensions = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n }\n });\n frame.render(() => {\n buildSVGAttrs(renderState, latestValues, isSVGTag(instance.tagName), props.transformTemplate);\n renderSVG(instance, renderState);\n });\n },\n }),\n};\n\nexport { svgMotionConfig };\n","/**\n * We keep these listed separately as we use the lowercase tag names as part\n * of the runtime bundle to detect SVG components\n */\nconst lowercaseSVGElements = [\n \"animate\",\n \"circle\",\n \"defs\",\n \"desc\",\n \"ellipse\",\n \"g\",\n \"image\",\n \"line\",\n \"filter\",\n \"marker\",\n \"mask\",\n \"metadata\",\n \"path\",\n \"pattern\",\n \"polygon\",\n \"polyline\",\n \"rect\",\n \"stop\",\n \"switch\",\n \"symbol\",\n \"svg\",\n \"text\",\n \"tspan\",\n \"use\",\n \"view\",\n];\n\nexport { lowercaseSVGElements };\n","import { useMemo } from 'react';\nimport { copyRawValuesOnly } from '../html/use-props.mjs';\nimport { buildSVGAttrs } from './utils/build-attrs.mjs';\nimport { createSvgRenderState } from './utils/create-render-state.mjs';\nimport { isSVGTag } from './utils/is-svg-tag.mjs';\n\nfunction useSVGProps(props, visualState, _isStatic, Component) {\n const visualProps = useMemo(() => {\n const state = createSvgRenderState();\n buildSVGAttrs(state, visualState, isSVGTag(Component), props.transformTemplate);\n return {\n ...state.attrs,\n style: { ...state.style },\n };\n }, [visualState]);\n if (props.style) {\n const rawStyles = {};\n copyRawValuesOnly(rawStyles, props.style, props);\n visualProps.style = { ...rawStyles, ...visualProps.style };\n }\n return visualProps;\n}\n\nexport { useSVGProps };\n","import { buildHTMLStyles } from '../../html/utils/build-styles.mjs';\nimport { calcSVGTransformOrigin } from './transform-origin.mjs';\nimport { buildSVGPath } from './path.mjs';\n\n/**\n * Build SVG visual attrbutes, like cx and style.transform\n */\nfunction buildSVGAttrs(state, { attrX, attrY, attrScale, originX, originY, pathLength, pathSpacing = 1, pathOffset = 0, \n// This is object creation, which we try to avoid per-frame.\n...latest }, isSVGTag, transformTemplate) {\n buildHTMLStyles(state, latest, transformTemplate);\n /**\n * For svg tags we just want to make sure viewBox is animatable and treat all the styles\n * as normal HTML tags.\n */\n if (isSVGTag) {\n if (state.style.viewBox) {\n state.attrs.viewBox = state.style.viewBox;\n }\n return;\n }\n state.attrs = state.style;\n state.style = {};\n const { attrs, style, dimensions } = state;\n /**\n * However, we apply transforms as CSS transforms. So if we detect a transform we take it from attrs\n * and copy it into style.\n */\n if (attrs.transform) {\n if (dimensions)\n style.transform = attrs.transform;\n delete attrs.transform;\n }\n // Parse transformOrigin\n if (dimensions &&\n (originX !== undefined || originY !== undefined || style.transform)) {\n style.transformOrigin = calcSVGTransformOrigin(dimensions, originX !== undefined ? originX : 0.5, originY !== undefined ? originY : 0.5);\n }\n // Render attrX/attrY/attrScale as attributes\n if (attrX !== undefined)\n attrs.x = attrX;\n if (attrY !== undefined)\n attrs.y = attrY;\n if (attrScale !== undefined)\n attrs.scale = attrScale;\n // Build SVG path if one has been defined\n if (pathLength !== undefined) {\n buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false);\n }\n}\n\nexport { buildSVGAttrs };\n","/**\n * A set of attribute names that are always read/written as camel case.\n */\nconst camelCaseAttributes = new Set([\n \"baseFrequency\",\n \"diffuseConstant\",\n \"kernelMatrix\",\n \"kernelUnitLength\",\n \"keySplines\",\n \"keyTimes\",\n \"limitingConeAngle\",\n \"markerHeight\",\n \"markerWidth\",\n \"numOctaves\",\n \"targetX\",\n \"targetY\",\n \"surfaceScale\",\n \"specularConstant\",\n \"specularExponent\",\n \"stdDeviation\",\n \"tableValues\",\n \"viewBox\",\n \"gradientTransform\",\n \"pathLength\",\n \"startOffset\",\n \"textLength\",\n \"lengthAdjust\",\n]);\n\nexport { camelCaseAttributes };\n","import { createHtmlRenderState } from '../../html/utils/create-render-state.mjs';\n\nconst createSvgRenderState = () => ({\n ...createHtmlRenderState(),\n attrs: {},\n});\n\nexport { createSvgRenderState };\n","const isSVGTag = (tag) => typeof tag === \"string\" && tag.toLowerCase() === \"svg\";\n\nexport { isSVGTag };\n","import { px } from '../../../value/types/numbers/units.mjs';\n\nconst dashKeys = {\n offset: \"stroke-dashoffset\",\n array: \"stroke-dasharray\",\n};\nconst camelKeys = {\n offset: \"strokeDashoffset\",\n array: \"strokeDasharray\",\n};\n/**\n * Build SVG path properties. Uses the path's measured length to convert\n * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset\n * and stroke-dasharray attributes.\n *\n * This function is mutative to reduce per-frame GC.\n */\nfunction buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true) {\n // Normalise path length by setting SVG attribute pathLength to 1\n attrs.pathLength = 1;\n // We use dash case when setting attributes directly to the DOM node and camel case\n // when defining props on a React component.\n const keys = useDashCase ? dashKeys : camelKeys;\n // Build the dash offset\n attrs[keys.offset] = px.transform(-offset);\n // Build the dash array\n const pathLength = px.transform(length);\n const pathSpacing = px.transform(spacing);\n attrs[keys.array] = `${pathLength} ${pathSpacing}`;\n}\n\nexport { buildSVGPath };\n","import { camelToDash } from '../../dom/utils/camel-to-dash.mjs';\nimport { renderHTML } from '../../html/utils/render.mjs';\nimport { camelCaseAttributes } from './camel-case-attrs.mjs';\n\nfunction renderSVG(element, renderState, _styleProp, projection) {\n renderHTML(element, renderState, undefined, projection);\n for (const key in renderState.attrs) {\n element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);\n }\n}\n\nexport { renderSVG };\n","import { isMotionValue } from '../../../value/utils/is-motion-value.mjs';\nimport { scrapeMotionValuesFromProps as scrapeMotionValuesFromProps$1 } from '../../html/utils/scrape-motion-values.mjs';\nimport { transformPropOrder } from '../../html/utils/transform.mjs';\n\nfunction scrapeMotionValuesFromProps(props, prevProps, visualElement) {\n const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);\n for (const key in props) {\n if (isMotionValue(props[key]) ||\n isMotionValue(prevProps[key])) {\n const targetKey = transformPropOrder.indexOf(key) !== -1\n ? \"attr\" + key.charAt(0).toUpperCase() + key.substring(1)\n : key;\n newValues[targetKey] = props[key];\n }\n }\n return newValues;\n}\n\nexport { scrapeMotionValuesFromProps };\n","import { px } from '../../../value/types/numbers/units.mjs';\n\nfunction calcOrigin(origin, offset, size) {\n return typeof origin === \"string\"\n ? origin\n : px.transform(offset + size * origin);\n}\n/**\n * The SVG transform origin defaults are different to CSS and is less intuitive,\n * so we use the measured dimensions of the SVG to reconcile these.\n */\nfunction calcSVGTransformOrigin(dimensions, originX, originY) {\n const pxOriginX = calcOrigin(originX, dimensions.x, dimensions.width);\n const pxOriginY = calcOrigin(originY, dimensions.y, dimensions.height);\n return `${pxOriginX} ${pxOriginY}`;\n}\n\nexport { calcSVGTransformOrigin };\n","import { removeNonTranslationalTransform } from '../dom/utils/unit-conversion.mjs';\nimport { frame } from '../../frameloop/frame.mjs';\n\nconst toResolve = new Set();\nlet isScheduled = false;\nlet anyNeedsMeasurement = false;\nfunction measureAllKeyframes() {\n if (anyNeedsMeasurement) {\n const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);\n const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));\n const transformsToRestore = new Map();\n /**\n * Write pass\n * If we're measuring elements we want to remove bounding box-changing transforms.\n */\n elementsToMeasure.forEach((element) => {\n const removedTransforms = removeNonTranslationalTransform(element);\n if (!removedTransforms.length)\n return;\n transformsToRestore.set(element, removedTransforms);\n element.render();\n });\n // Read\n resolversToMeasure.forEach((resolver) => resolver.measureInitialState());\n // Write\n elementsToMeasure.forEach((element) => {\n element.render();\n const restore = transformsToRestore.get(element);\n if (restore) {\n restore.forEach(([key, value]) => {\n var _a;\n (_a = element.getValue(key)) === null || _a === void 0 ? void 0 : _a.set(value);\n });\n }\n });\n // Read\n resolversToMeasure.forEach((resolver) => resolver.measureEndState());\n // Write\n resolversToMeasure.forEach((resolver) => {\n if (resolver.suspendedScrollY !== undefined) {\n window.scrollTo(0, resolver.suspendedScrollY);\n }\n });\n }\n anyNeedsMeasurement = false;\n isScheduled = false;\n toResolve.forEach((resolver) => resolver.complete());\n toResolve.clear();\n}\nfunction readAllKeyframes() {\n toResolve.forEach((resolver) => {\n resolver.readKeyframes();\n if (resolver.needsMeasurement) {\n anyNeedsMeasurement = true;\n }\n });\n}\nfunction flushKeyframeResolvers() {\n readAllKeyframes();\n measureAllKeyframes();\n}\nclass KeyframeResolver {\n constructor(unresolvedKeyframes, onComplete, name, motionValue, element, isAsync = false) {\n /**\n * Track whether this resolver has completed. Once complete, it never\n * needs to attempt keyframe resolution again.\n */\n this.isComplete = false;\n /**\n * Track whether this resolver is async. If it is, it'll be added to the\n * resolver queue and flushed in the next frame. Resolvers that aren't going\n * to trigger read/write thrashing don't need to be async.\n */\n this.isAsync = false;\n /**\n * Track whether this resolver needs to perform a measurement\n * to resolve its keyframes.\n */\n this.needsMeasurement = false;\n /**\n * Track whether this resolver is currently scheduled to resolve\n * to allow it to be cancelled and resumed externally.\n */\n this.isScheduled = false;\n this.unresolvedKeyframes = [...unresolvedKeyframes];\n this.onComplete = onComplete;\n this.name = name;\n this.motionValue = motionValue;\n this.element = element;\n this.isAsync = isAsync;\n }\n scheduleResolve() {\n this.isScheduled = true;\n if (this.isAsync) {\n toResolve.add(this);\n if (!isScheduled) {\n isScheduled = true;\n frame.read(readAllKeyframes);\n frame.resolveKeyframes(measureAllKeyframes);\n }\n }\n else {\n this.readKeyframes();\n this.complete();\n }\n }\n readKeyframes() {\n const { unresolvedKeyframes, name, element, motionValue } = this;\n /**\n * If a keyframe is null, we hydrate it either by reading it from\n * the instance, or propagating from previous keyframes.\n */\n for (let i = 0; i < unresolvedKeyframes.length; i++) {\n if (unresolvedKeyframes[i] === null) {\n /**\n * If the first keyframe is null, we need to find its value by sampling the element\n */\n if (i === 0) {\n const currentValue = motionValue === null || motionValue === void 0 ? void 0 : motionValue.get();\n const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];\n if (currentValue !== undefined) {\n unresolvedKeyframes[0] = currentValue;\n }\n else if (element && name) {\n const valueAsRead = element.readValue(name, finalKeyframe);\n if (valueAsRead !== undefined && valueAsRead !== null) {\n unresolvedKeyframes[0] = valueAsRead;\n }\n }\n if (unresolvedKeyframes[0] === undefined) {\n unresolvedKeyframes[0] = finalKeyframe;\n }\n if (motionValue && currentValue === undefined) {\n motionValue.set(unresolvedKeyframes[0]);\n }\n }\n else {\n unresolvedKeyframes[i] = unresolvedKeyframes[i - 1];\n }\n }\n }\n }\n setFinalKeyframe() { }\n measureInitialState() { }\n renderEndStyles() { }\n measureEndState() { }\n complete() {\n this.isComplete = true;\n this.onComplete(this.unresolvedKeyframes, this.finalKeyframe);\n toResolve.delete(this);\n }\n cancel() {\n if (!this.isComplete) {\n this.isScheduled = false;\n toResolve.delete(this);\n }\n }\n resume() {\n if (!this.isComplete)\n this.scheduleResolve();\n }\n}\n\nexport { KeyframeResolver, flushKeyframeResolvers };\n","import { isAnimationControls } from '../../animation/utils/is-animation-controls.mjs';\nimport { isKeyframesTarget } from '../../animation/utils/is-keyframes-target.mjs';\nimport { shallowCompare } from '../../utils/shallow-compare.mjs';\nimport { isVariantLabel } from './is-variant-label.mjs';\nimport { resolveVariant } from './resolve-dynamic-variants.mjs';\nimport { variantPriorityOrder } from './variant-props.mjs';\nimport { animateVisualElement } from '../../animation/interfaces/visual-element.mjs';\n\nconst reversePriorityOrder = [...variantPriorityOrder].reverse();\nconst numAnimationTypes = variantPriorityOrder.length;\nfunction animateList(visualElement) {\n return (animations) => Promise.all(animations.map(({ animation, options }) => animateVisualElement(visualElement, animation, options)));\n}\nfunction createAnimationState(visualElement) {\n let animate = animateList(visualElement);\n let state = createState();\n let isInitialRender = true;\n /**\n * This function will be used to reduce the animation definitions for\n * each active animation type into an object of resolved values for it.\n */\n const buildResolvedTypeValues = (type) => (acc, definition) => {\n var _a;\n const resolved = resolveVariant(visualElement, definition, type === \"exit\"\n ? (_a = visualElement.presenceContext) === null || _a === void 0 ? void 0 : _a.custom\n : undefined);\n if (resolved) {\n const { transition, transitionEnd, ...target } = resolved;\n acc = { ...acc, ...target, ...transitionEnd };\n }\n return acc;\n };\n /**\n * This just allows us to inject mocked animation functions\n * @internal\n */\n function setAnimateFunction(makeAnimator) {\n animate = makeAnimator(visualElement);\n }\n /**\n * When we receive new props, we need to:\n * 1. Create a list of protected keys for each type. This is a directory of\n * value keys that are currently being \"handled\" by types of a higher priority\n * so that whenever an animation is played of a given type, these values are\n * protected from being animated.\n * 2. Determine if an animation type needs animating.\n * 3. Determine if any values have been removed from a type and figure out\n * what to animate those to.\n */\n function animateChanges(changedActiveType) {\n const props = visualElement.getProps();\n const context = visualElement.getVariantContext(true) || {};\n /**\n * A list of animations that we'll build into as we iterate through the animation\n * types. This will get executed at the end of the function.\n */\n const animations = [];\n /**\n * Keep track of which values have been removed. Then, as we hit lower priority\n * animation types, we can check if they contain removed values and animate to that.\n */\n const removedKeys = new Set();\n /**\n * A dictionary of all encountered keys. This is an object to let us build into and\n * copy it without iteration. Each time we hit an animation type we set its protected\n * keys - the keys its not allowed to animate - to the latest version of this object.\n */\n let encounteredKeys = {};\n /**\n * If a variant has been removed at a given index, and this component is controlling\n * variant animations, we want to ensure lower-priority variants are forced to animate.\n */\n let removedVariantIndex = Infinity;\n /**\n * Iterate through all animation types in reverse priority order. For each, we want to\n * detect which values it's handling and whether or not they've changed (and therefore\n * need to be animated). If any values have been removed, we want to detect those in\n * lower priority props and flag for animation.\n */\n for (let i = 0; i < numAnimationTypes; i++) {\n const type = reversePriorityOrder[i];\n const typeState = state[type];\n const prop = props[type] !== undefined\n ? props[type]\n : context[type];\n const propIsVariant = isVariantLabel(prop);\n /**\n * If this type has *just* changed isActive status, set activeDelta\n * to that status. Otherwise set to null.\n */\n const activeDelta = type === changedActiveType ? typeState.isActive : null;\n if (activeDelta === false)\n removedVariantIndex = i;\n /**\n * If this prop is an inherited variant, rather than been set directly on the\n * component itself, we want to make sure we allow the parent to trigger animations.\n *\n * TODO: Can probably change this to a !isControllingVariants check\n */\n let isInherited = prop === context[type] &&\n prop !== props[type] &&\n propIsVariant;\n /**\n *\n */\n if (isInherited &&\n isInitialRender &&\n visualElement.manuallyAnimateOnMount) {\n isInherited = false;\n }\n /**\n * Set all encountered keys so far as the protected keys for this type. This will\n * be any key that has been animated or otherwise handled by active, higher-priortiy types.\n */\n typeState.protectedKeys = { ...encounteredKeys };\n // Check if we can skip analysing this prop early\n if (\n // If it isn't active and hasn't *just* been set as inactive\n (!typeState.isActive && activeDelta === null) ||\n // If we didn't and don't have any defined prop for this animation type\n (!prop && !typeState.prevProp) ||\n // Or if the prop doesn't define an animation\n isAnimationControls(prop) ||\n typeof prop === \"boolean\") {\n continue;\n }\n /**\n * As we go look through the values defined on this type, if we detect\n * a changed value or a value that was removed in a higher priority, we set\n * this to true and add this prop to the animation list.\n */\n const variantDidChange = checkVariantsDidChange(typeState.prevProp, prop);\n let shouldAnimateType = variantDidChange ||\n // If we're making this variant active, we want to always make it active\n (type === changedActiveType &&\n typeState.isActive &&\n !isInherited &&\n propIsVariant) ||\n // If we removed a higher-priority variant (i is in reverse order)\n (i > removedVariantIndex && propIsVariant);\n let handledRemovedValues = false;\n /**\n * As animations can be set as variant lists, variants or target objects, we\n * coerce everything to an array if it isn't one already\n */\n const definitionList = Array.isArray(prop) ? prop : [prop];\n /**\n * Build an object of all the resolved values. We'll use this in the subsequent\n * animateChanges calls to determine whether a value has changed.\n */\n let resolvedValues = definitionList.reduce(buildResolvedTypeValues(type), {});\n if (activeDelta === false)\n resolvedValues = {};\n /**\n * Now we need to loop through all the keys in the prev prop and this prop,\n * and decide:\n * 1. If the value has changed, and needs animating\n * 2. If it has been removed, and needs adding to the removedKeys set\n * 3. If it has been removed in a higher priority type and needs animating\n * 4. If it hasn't been removed in a higher priority but hasn't changed, and\n * needs adding to the type's protectedKeys list.\n */\n const { prevResolvedValues = {} } = typeState;\n const allKeys = {\n ...prevResolvedValues,\n ...resolvedValues,\n };\n const markToAnimate = (key) => {\n shouldAnimateType = true;\n if (removedKeys.has(key)) {\n handledRemovedValues = true;\n removedKeys.delete(key);\n }\n typeState.needsAnimating[key] = true;\n const motionValue = visualElement.getValue(key);\n if (motionValue)\n motionValue.liveStyle = false;\n };\n for (const key in allKeys) {\n const next = resolvedValues[key];\n const prev = prevResolvedValues[key];\n // If we've already handled this we can just skip ahead\n if (encounteredKeys.hasOwnProperty(key))\n continue;\n /**\n * If the value has changed, we probably want to animate it.\n */\n let valueHasChanged = false;\n if (isKeyframesTarget(next) && isKeyframesTarget(prev)) {\n valueHasChanged = !shallowCompare(next, prev);\n }\n else {\n valueHasChanged = next !== prev;\n }\n if (valueHasChanged) {\n if (next !== undefined && next !== null) {\n // If next is defined and doesn't equal prev, it needs animating\n markToAnimate(key);\n }\n else {\n // If it's undefined, it's been removed.\n removedKeys.add(key);\n }\n }\n else if (next !== undefined && removedKeys.has(key)) {\n /**\n * If next hasn't changed and it isn't undefined, we want to check if it's\n * been removed by a higher priority\n */\n markToAnimate(key);\n }\n else {\n /**\n * If it hasn't changed, we add it to the list of protected values\n * to ensure it doesn't get animated.\n */\n typeState.protectedKeys[key] = true;\n }\n }\n /**\n * Update the typeState so next time animateChanges is called we can compare the\n * latest prop and resolvedValues to these.\n */\n typeState.prevProp = prop;\n typeState.prevResolvedValues = resolvedValues;\n /**\n *\n */\n if (typeState.isActive) {\n encounteredKeys = { ...encounteredKeys, ...resolvedValues };\n }\n if (isInitialRender && visualElement.blockInitialAnimation) {\n shouldAnimateType = false;\n }\n /**\n * If this is an inherited prop we want to hard-block animations\n */\n if (shouldAnimateType && (!isInherited || handledRemovedValues)) {\n animations.push(...definitionList.map((animation) => ({\n animation: animation,\n options: { type },\n })));\n }\n }\n /**\n * If there are some removed value that haven't been dealt with,\n * we need to create a new animation that falls back either to the value\n * defined in the style prop, or the last read value.\n */\n if (removedKeys.size) {\n const fallbackAnimation = {};\n removedKeys.forEach((key) => {\n const fallbackTarget = visualElement.getBaseTarget(key);\n const motionValue = visualElement.getValue(key);\n if (motionValue)\n motionValue.liveStyle = true;\n // @ts-expect-error - @mattgperry to figure if we should do something here\n fallbackAnimation[key] = fallbackTarget !== null && fallbackTarget !== void 0 ? fallbackTarget : null;\n });\n animations.push({ animation: fallbackAnimation });\n }\n let shouldAnimate = Boolean(animations.length);\n if (isInitialRender &&\n (props.initial === false || props.initial === props.animate) &&\n !visualElement.manuallyAnimateOnMount) {\n shouldAnimate = false;\n }\n isInitialRender = false;\n return shouldAnimate ? animate(animations) : Promise.resolve();\n }\n /**\n * Change whether a certain animation type is active.\n */\n function setActive(type, isActive) {\n var _a;\n // If the active state hasn't changed, we can safely do nothing here\n if (state[type].isActive === isActive)\n return Promise.resolve();\n // Propagate active change to children\n (_a = visualElement.variantChildren) === null || _a === void 0 ? void 0 : _a.forEach((child) => { var _a; return (_a = child.animationState) === null || _a === void 0 ? void 0 : _a.setActive(type, isActive); });\n state[type].isActive = isActive;\n const animations = animateChanges(type);\n for (const key in state) {\n state[key].protectedKeys = {};\n }\n return animations;\n }\n return {\n animateChanges,\n setActive,\n setAnimateFunction,\n getState: () => state,\n reset: () => {\n state = createState();\n isInitialRender = true;\n },\n };\n}\nfunction checkVariantsDidChange(prev, next) {\n if (typeof next === \"string\") {\n return next !== prev;\n }\n else if (Array.isArray(next)) {\n return !shallowCompare(next, prev);\n }\n return false;\n}\nfunction createTypeState(isActive = false) {\n return {\n isActive,\n protectedKeys: {},\n needsAnimating: {},\n prevResolvedValues: {},\n };\n}\nfunction createState() {\n return {\n animate: createTypeState(true),\n whileInView: createTypeState(),\n whileHover: createTypeState(),\n whileTap: createTypeState(),\n whileDrag: createTypeState(),\n whileFocus: createTypeState(),\n exit: createTypeState(),\n };\n}\n\nexport { checkVariantsDidChange, createAnimationState };\n","const compareByDepth = (a, b) => a.depth - b.depth;\n\nexport { compareByDepth };\n","import { addUniqueItem, removeItem } from '../../utils/array.mjs';\nimport { compareByDepth } from './compare-by-depth.mjs';\n\nclass FlatTree {\n constructor() {\n this.children = [];\n this.isDirty = false;\n }\n add(child) {\n addUniqueItem(this.children, child);\n this.isDirty = true;\n }\n remove(child) {\n removeItem(this.children, child);\n this.isDirty = true;\n }\n forEach(callback) {\n this.isDirty && this.children.sort(compareByDepth);\n this.isDirty = false;\n this.children.forEach(callback);\n }\n}\n\nexport { FlatTree };\n","import { isAnimationControls } from '../../animation/utils/is-animation-controls.mjs';\nimport { isVariantLabel } from './is-variant-label.mjs';\nimport { variantProps } from './variant-props.mjs';\n\nfunction isControllingVariants(props) {\n return (isAnimationControls(props.animate) ||\n variantProps.some((name) => isVariantLabel(props[name])));\n}\nfunction isVariantNode(props) {\n return Boolean(isControllingVariants(props) || props.variants);\n}\n\nexport { isControllingVariants, isVariantNode };\n","/**\n * Decides if the supplied variable is variant label\n */\nfunction isVariantLabel(v) {\n return typeof v === \"string\" || Array.isArray(v);\n}\n\nexport { isVariantLabel };\n","import { warnOnce } from '../../utils/warn-once.mjs';\nimport { motionValue } from '../../value/index.mjs';\nimport { isMotionValue } from '../../value/utils/is-motion-value.mjs';\n\nfunction updateMotionValuesFromProps(element, next, prev) {\n for (const key in next) {\n const nextValue = next[key];\n const prevValue = prev[key];\n if (isMotionValue(nextValue)) {\n /**\n * If this is a motion value found in props or style, we want to add it\n * to our visual element's motion value map.\n */\n element.addValue(key, nextValue);\n /**\n * Check the version of the incoming motion value with this version\n * and warn against mismatches.\n */\n if (process.env.NODE_ENV === \"development\") {\n warnOnce(nextValue.version === \"11.4.0\", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.4.0 may not work as expected.`);\n }\n }\n else if (isMotionValue(prevValue)) {\n /**\n * If we're swapping from a motion value to a static value,\n * create a new motion value from that\n */\n element.addValue(key, motionValue(nextValue, { owner: element }));\n }\n else if (prevValue !== nextValue) {\n /**\n * If this is a flat value that has changed, update the motion value\n * or create one if it doesn't exist. We only want to do this if we're\n * not handling the value with our animation state.\n */\n if (element.hasValue(key)) {\n const existingValue = element.getValue(key);\n if (existingValue.liveStyle === true) {\n existingValue.jump(nextValue);\n }\n else if (!existingValue.hasAnimated) {\n existingValue.set(nextValue);\n }\n }\n else {\n const latestValue = element.getStaticValue(key);\n element.addValue(key, motionValue(latestValue !== undefined ? latestValue : nextValue, { owner: element }));\n }\n }\n }\n // Handle removed values\n for (const key in prev) {\n if (next[key] === undefined)\n element.removeValue(key);\n }\n return next;\n}\n\nexport { updateMotionValuesFromProps };\n","import { resolveVariantFromProps } from './resolve-variants.mjs';\n\nfunction resolveVariant(visualElement, definition, custom) {\n const props = visualElement.getProps();\n return resolveVariantFromProps(props, definition, custom !== undefined ? custom : props.custom, visualElement);\n}\n\nexport { resolveVariant };\n","function getValueState(visualElement) {\n const state = [{}, {}];\n visualElement === null || visualElement === void 0 ? void 0 : visualElement.values.forEach((value, key) => {\n state[0][key] = value.get();\n state[1][key] = value.getVelocity();\n });\n return state;\n}\nfunction resolveVariantFromProps(props, definition, custom, visualElement) {\n /**\n * If the variant definition is a function, resolve.\n */\n if (typeof definition === \"function\") {\n const [current, velocity] = getValueState(visualElement);\n definition = definition(custom !== undefined ? custom : props.custom, current, velocity);\n }\n /**\n * If the variant definition is a variant label, or\n * the function returned a variant label, resolve.\n */\n if (typeof definition === \"string\") {\n definition = props.variants && props.variants[definition];\n }\n /**\n * At this point we've resolved both functions and variant labels,\n * but the resolved variant label might itself have been a function.\n * If so, resolve. This can only have returned a valid target object.\n */\n if (typeof definition === \"function\") {\n const [current, velocity] = getValueState(visualElement);\n definition = definition(custom !== undefined ? custom : props.custom, current, velocity);\n }\n return definition;\n}\n\nexport { resolveVariantFromProps };\n","import { resolveFinalValueInKeyframes } from '../../utils/resolve-value.mjs';\nimport { motionValue } from '../../value/index.mjs';\nimport { resolveVariant } from './resolve-dynamic-variants.mjs';\n\n/**\n * Set VisualElement's MotionValue, creating a new MotionValue for it if\n * it doesn't exist.\n */\nfunction setMotionValue(visualElement, key, value) {\n if (visualElement.hasValue(key)) {\n visualElement.getValue(key).set(value);\n }\n else {\n visualElement.addValue(key, motionValue(value));\n }\n}\nfunction setTarget(visualElement, definition) {\n const resolved = resolveVariant(visualElement, definition);\n let { transitionEnd = {}, transition = {}, ...target } = resolved || {};\n target = { ...target, ...transitionEnd };\n for (const key in target) {\n const value = resolveFinalValueInKeyframes(target[key]);\n setMotionValue(visualElement, key, value);\n }\n}\n\nexport { setTarget };\n","const variantPriorityOrder = [\n \"animate\",\n \"whileInView\",\n \"whileFocus\",\n \"whileHover\",\n \"whileTap\",\n \"whileDrag\",\n \"exit\",\n];\nconst variantProps = [\"initial\", ...variantPriorityOrder];\n\nexport { variantPriorityOrder, variantProps };\n","const MotionGlobalConfig = {\n skipAnimations: false,\n useManualTiming: false,\n};\n\nexport { MotionGlobalConfig };\n","function addUniqueItem(arr, item) {\n if (arr.indexOf(item) === -1)\n arr.push(item);\n}\nfunction removeItem(arr, item) {\n const index = arr.indexOf(item);\n if (index > -1)\n arr.splice(index, 1);\n}\n// Adapted from array-move\nfunction moveItem([...arr], fromIndex, toIndex) {\n const startIndex = fromIndex < 0 ? arr.length + fromIndex : fromIndex;\n if (startIndex >= 0 && startIndex < arr.length) {\n const endIndex = toIndex < 0 ? arr.length + toIndex : toIndex;\n const [item] = arr.splice(fromIndex, 1);\n arr.splice(endIndex, 0, item);\n }\n return arr;\n}\n\nexport { addUniqueItem, moveItem, removeItem };\n","const clamp = (min, max, v) => {\n if (v > max)\n return max;\n if (v < min)\n return min;\n return v;\n};\n\nexport { clamp };\n","import { time } from '../frameloop/sync-time.mjs';\nimport { frame, cancelFrame } from '../frameloop/frame.mjs';\n\n/**\n * Timeout defined in ms\n */\nfunction delay(callback, timeout) {\n const start = time.now();\n const checkElapsed = ({ timestamp }) => {\n const elapsed = timestamp - start;\n if (elapsed >= timeout) {\n cancelFrame(checkElapsed);\n callback(elapsed - timeout);\n }\n };\n frame.read(checkElapsed, true);\n return () => cancelFrame(checkElapsed);\n}\n\nexport { delay };\n","const distance = (a, b) => Math.abs(a - b);\nfunction distance2D(a, b) {\n // Multi-dimensional\n const xDelta = distance(a.x, b.x);\n const yDelta = distance(a.y, b.y);\n return Math.sqrt(xDelta ** 2 + yDelta ** 2);\n}\n\nexport { distance, distance2D };\n","import { noop } from './noop.mjs';\n\nlet warning = noop;\nlet invariant = noop;\nif (process.env.NODE_ENV !== \"production\") {\n warning = (check, message) => {\n if (!check && typeof console !== \"undefined\") {\n console.warn(message);\n }\n };\n invariant = (check, message) => {\n if (!check) {\n throw new Error(message);\n }\n };\n}\n\nexport { invariant, warning };\n","// Fixes https://github.com/framer/motion/issues/2270\nconst getContextWindow = ({ current }) => {\n return current ? current.ownerDocument.defaultView : null;\n};\n\nexport { getContextWindow };\n","// Adapted from https://gist.github.com/mjackson/5311256\nfunction hueToRgb(p, q, t) {\n if (t < 0)\n t += 1;\n if (t > 1)\n t -= 1;\n if (t < 1 / 6)\n return p + (q - p) * 6 * t;\n if (t < 1 / 2)\n return q;\n if (t < 2 / 3)\n return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n}\nfunction hslaToRgba({ hue, saturation, lightness, alpha }) {\n hue /= 360;\n saturation /= 100;\n lightness /= 100;\n let red = 0;\n let green = 0;\n let blue = 0;\n if (!saturation) {\n red = green = blue = lightness;\n }\n else {\n const q = lightness < 0.5\n ? lightness * (1 + saturation)\n : lightness + saturation - lightness * saturation;\n const p = 2 * lightness - q;\n red = hueToRgb(p, q, hue + 1 / 3);\n green = hueToRgb(p, q, hue);\n blue = hueToRgb(p, q, hue - 1 / 3);\n }\n return {\n red: Math.round(red * 255),\n green: Math.round(green * 255),\n blue: Math.round(blue * 255),\n alpha,\n };\n}\n\nexport { hslaToRgba };\n","import { invariant } from './errors.mjs';\nimport { clamp } from './clamp.mjs';\nimport { pipe } from './pipe.mjs';\nimport { progress } from './progress.mjs';\nimport { noop } from './noop.mjs';\nimport { mix } from './mix/index.mjs';\n\nfunction createMixers(output, ease, customMixer) {\n const mixers = [];\n const mixerFactory = customMixer || mix;\n const numMixers = output.length - 1;\n for (let i = 0; i < numMixers; i++) {\n let mixer = mixerFactory(output[i], output[i + 1]);\n if (ease) {\n const easingFunction = Array.isArray(ease) ? ease[i] || noop : ease;\n mixer = pipe(easingFunction, mixer);\n }\n mixers.push(mixer);\n }\n return mixers;\n}\n/**\n * Create a function that maps from a numerical input array to a generic output array.\n *\n * Accepts:\n * - Numbers\n * - Colors (hex, hsl, hsla, rgb, rgba)\n * - Complex (combinations of one or more numbers or strings)\n *\n * ```jsx\n * const mixColor = interpolate([0, 1], ['#fff', '#000'])\n *\n * mixColor(0.5) // 'rgba(128, 128, 128, 1)'\n * ```\n *\n * TODO Revist this approach once we've moved to data models for values,\n * probably not needed to pregenerate mixer functions.\n *\n * @public\n */\nfunction interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {}) {\n const inputLength = input.length;\n invariant(inputLength === output.length, \"Both input and output ranges must be the same length\");\n /**\n * If we're only provided a single input, we can just make a function\n * that returns the output.\n */\n if (inputLength === 1)\n return () => output[0];\n if (inputLength === 2 && input[0] === input[1])\n return () => output[1];\n // If input runs highest -> lowest, reverse both arrays\n if (input[0] > input[inputLength - 1]) {\n input = [...input].reverse();\n output = [...output].reverse();\n }\n const mixers = createMixers(output, ease, mixer);\n const numMixers = mixers.length;\n const interpolator = (v) => {\n let i = 0;\n if (numMixers > 1) {\n for (; i < input.length - 2; i++) {\n if (v < input[i + 1])\n break;\n }\n }\n const progressInRange = progress(input[i], input[i + 1], v);\n return mixers[i](progressInRange);\n };\n return isClamp\n ? (v) => interpolator(clamp(input[0], input[inputLength - 1], v))\n : interpolator;\n}\n\nexport { interpolate };\n","const isBrowser = typeof window !== \"undefined\";\n\nexport { isBrowser };\n","/**\n * Check if value is a numerical string, ie a string that is purely a number eg \"100\" or \"-100.1\"\n */\nconst isNumericalString = (v) => /^-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)$/u.test(v);\n\nexport { isNumericalString };\n","function isRefObject(ref) {\n return (ref &&\n typeof ref === \"object\" &&\n Object.prototype.hasOwnProperty.call(ref, \"current\"));\n}\n\nexport { isRefObject };\n","/**\n * Check if the value is a zero value string like \"0px\" or \"0%\"\n */\nconst isZeroValueString = (v) => /^0[^.\\s]+$/u.test(v);\n\nexport { isZeroValueString };\n","function memo(callback) {\n let result;\n return () => {\n if (result === undefined)\n result = callback();\n return result;\n };\n}\n\nexport { memo };\n","import { mixNumber } from './number.mjs';\nimport { warning } from '../errors.mjs';\nimport { hslaToRgba } from '../hsla-to-rgba.mjs';\nimport { hex } from '../../value/types/color/hex.mjs';\nimport { rgba } from '../../value/types/color/rgba.mjs';\nimport { hsla } from '../../value/types/color/hsla.mjs';\nimport { mixImmediate } from './immediate.mjs';\n\n// Linear color space blending\n// Explained https://www.youtube.com/watch?v=LKnqECcg6Gw\n// Demonstrated http://codepen.io/osublake/pen/xGVVaN\nconst mixLinearColor = (from, to, v) => {\n const fromExpo = from * from;\n const expo = v * (to * to - fromExpo) + fromExpo;\n return expo < 0 ? 0 : Math.sqrt(expo);\n};\nconst colorTypes = [hex, rgba, hsla];\nconst getColorType = (v) => colorTypes.find((type) => type.test(v));\nfunction asRGBA(color) {\n const type = getColorType(color);\n warning(Boolean(type), `'${color}' is not an animatable color. Use the equivalent color code instead.`);\n if (!Boolean(type))\n return false;\n let model = type.parse(color);\n if (type === hsla) {\n // TODO Remove this cast - needed since Framer Motion's stricter typing\n model = hslaToRgba(model);\n }\n return model;\n}\nconst mixColor = (from, to) => {\n const fromRGBA = asRGBA(from);\n const toRGBA = asRGBA(to);\n if (!fromRGBA || !toRGBA) {\n return mixImmediate(from, to);\n }\n const blended = { ...fromRGBA };\n return (v) => {\n blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);\n blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);\n blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);\n blended.alpha = mixNumber(fromRGBA.alpha, toRGBA.alpha, v);\n return rgba.transform(blended);\n };\n};\n\nexport { mixColor, mixLinearColor };\n","import { mixNumber as mixNumber$1 } from './number.mjs';\nimport { mixColor } from './color.mjs';\nimport { pipe } from '../pipe.mjs';\nimport { warning } from '../errors.mjs';\nimport { color } from '../../value/types/color/index.mjs';\nimport { complex, analyseComplexValue } from '../../value/types/complex/index.mjs';\nimport { isCSSVariableToken } from '../../render/dom/utils/is-css-variable.mjs';\nimport { invisibleValues, mixVisibility } from './visibility.mjs';\nimport { mixImmediate } from './immediate.mjs';\n\nfunction mixNumber(a, b) {\n return (p) => mixNumber$1(a, b, p);\n}\nfunction getMixer(a) {\n if (typeof a === \"number\") {\n return mixNumber;\n }\n else if (typeof a === \"string\") {\n return isCSSVariableToken(a)\n ? mixImmediate\n : color.test(a)\n ? mixColor\n : mixComplex;\n }\n else if (Array.isArray(a)) {\n return mixArray;\n }\n else if (typeof a === \"object\") {\n return color.test(a) ? mixColor : mixObject;\n }\n return mixImmediate;\n}\nfunction mixArray(a, b) {\n const output = [...a];\n const numValues = output.length;\n const blendValue = a.map((v, i) => getMixer(v)(v, b[i]));\n return (p) => {\n for (let i = 0; i < numValues; i++) {\n output[i] = blendValue[i](p);\n }\n return output;\n };\n}\nfunction mixObject(a, b) {\n const output = { ...a, ...b };\n const blendValue = {};\n for (const key in output) {\n if (a[key] !== undefined && b[key] !== undefined) {\n blendValue[key] = getMixer(a[key])(a[key], b[key]);\n }\n }\n return (v) => {\n for (const key in blendValue) {\n output[key] = blendValue[key](v);\n }\n return output;\n };\n}\nfunction matchOrder(origin, target) {\n var _a;\n const orderedOrigin = [];\n const pointers = { color: 0, var: 0, number: 0 };\n for (let i = 0; i < target.values.length; i++) {\n const type = target.types[i];\n const originIndex = origin.indexes[type][pointers[type]];\n const originValue = (_a = origin.values[originIndex]) !== null && _a !== void 0 ? _a : 0;\n orderedOrigin[i] = originValue;\n pointers[type]++;\n }\n return orderedOrigin;\n}\nconst mixComplex = (origin, target) => {\n const template = complex.createTransformer(target);\n const originStats = analyseComplexValue(origin);\n const targetStats = analyseComplexValue(target);\n const canInterpolate = originStats.indexes.var.length === targetStats.indexes.var.length &&\n originStats.indexes.color.length === targetStats.indexes.color.length &&\n originStats.indexes.number.length >= targetStats.indexes.number.length;\n if (canInterpolate) {\n if ((invisibleValues.has(origin) &&\n !targetStats.values.length) ||\n (invisibleValues.has(target) &&\n !originStats.values.length)) {\n return mixVisibility(origin, target);\n }\n return pipe(mixArray(matchOrder(originStats, targetStats), targetStats.values), template);\n }\n else {\n warning(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`);\n return mixImmediate(origin, target);\n }\n};\n\nexport { getMixer, mixArray, mixComplex, mixObject };\n","function mixImmediate(a, b) {\n return (p) => (p > 0 ? b : a);\n}\n\nexport { mixImmediate };\n","import { getMixer } from './complex.mjs';\nimport { mixNumber } from './number.mjs';\n\nfunction mix(from, to, p) {\n if (typeof from === \"number\" &&\n typeof to === \"number\" &&\n typeof p === \"number\") {\n return mixNumber(from, to, p);\n }\n const mixer = getMixer(from);\n return mixer(from, to);\n}\n\nexport { mix };\n","/*\n Value in range from progress\n\n Given a lower limit and an upper limit, we return the value within\n that range as expressed by progress (usually a number from 0 to 1)\n\n So progress = 0.5 would change\n\n from -------- to\n\n to\n\n from ---- to\n\n E.g. from = 10, to = 20, progress = 0.5 => 15\n\n @param [number]: Lower limit of range\n @param [number]: Upper limit of range\n @param [number]: The progress between lower and upper limits expressed 0-1\n @return [number]: Value as calculated from progress within range (not limited within range)\n*/\nconst mixNumber = (from, to, progress) => {\n return from + (to - from) * progress;\n};\n\nexport { mixNumber };\n","const invisibleValues = new Set([\"none\", \"hidden\"]);\n/**\n * Returns a function that, when provided a progress value between 0 and 1,\n * will return the \"none\" or \"hidden\" string only when the progress is that of\n * the origin or target.\n */\nfunction mixVisibility(origin, target) {\n if (invisibleValues.has(origin)) {\n return (p) => (p <= 0 ? origin : target);\n }\n else {\n return (p) => (p >= 1 ? target : origin);\n }\n}\n\nexport { invisibleValues, mixVisibility };\n","const noop = (any) => any;\n\nexport { noop };\n","import { fillOffset } from './fill.mjs';\n\nfunction defaultOffset(arr) {\n const offset = [0];\n fillOffset(offset, arr.length - 1);\n return offset;\n}\n\nexport { defaultOffset };\n","import { mixNumber } from '../mix/number.mjs';\nimport { progress } from '../progress.mjs';\n\nfunction fillOffset(offset, remaining) {\n const min = offset[offset.length - 1];\n for (let i = 1; i <= remaining; i++) {\n const offsetProgress = progress(0, remaining, i);\n offset.push(mixNumber(min, 1, offsetProgress));\n }\n}\n\nexport { fillOffset };\n","function convertOffsetToTimes(offset, duration) {\n return offset.map((o) => o * duration);\n}\n\nexport { convertOffsetToTimes };\n","/**\n * Pipe\n * Compose other transformers to run linearily\n * pipe(min(20), max(40))\n * @param {...functions} transformers\n * @return {function}\n */\nconst combineFunctions = (a, b) => (v) => b(a(v));\nconst pipe = (...transformers) => transformers.reduce(combineFunctions);\n\nexport { pipe };\n","/*\n Progress within given range\n\n Given a lower limit and an upper limit, we return the progress\n (expressed as a number 0-1) represented by the given value, and\n limit that progress to within 0-1.\n\n @param [number]: Lower limit\n @param [number]: Upper limit\n @param [number]: Value to find progress within given range\n @return [number]: Progress of value within range as expressed 0-1\n*/\nconst progress = (from, to, value) => {\n const toFromDifference = to - from;\n return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;\n};\n\nexport { progress };\n","import { isBrowser } from '../is-browser.mjs';\nimport { hasReducedMotionListener, prefersReducedMotion } from './state.mjs';\n\nfunction initPrefersReducedMotion() {\n hasReducedMotionListener.current = true;\n if (!isBrowser)\n return;\n if (window.matchMedia) {\n const motionMediaQuery = window.matchMedia(\"(prefers-reduced-motion)\");\n const setReducedMotionPreferences = () => (prefersReducedMotion.current = motionMediaQuery.matches);\n motionMediaQuery.addListener(setReducedMotionPreferences);\n setReducedMotionPreferences();\n }\n else {\n prefersReducedMotion.current = false;\n }\n}\n\nexport { initPrefersReducedMotion };\n","// Does this device prefer reduced motion? Returns `null` server-side.\nconst prefersReducedMotion = { current: null };\nconst hasReducedMotionListener = { current: false };\n\nexport { hasReducedMotionListener, prefersReducedMotion };\n","import { isKeyframesTarget } from '../animation/utils/is-keyframes-target.mjs';\n\nconst isCustomValue = (v) => {\n return Boolean(v && typeof v === \"object\" && v.mix && v.toValue);\n};\nconst resolveFinalValueInKeyframes = (v) => {\n // TODO maybe throw if v.length - 1 is placeholder token?\n return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;\n};\n\nexport { isCustomValue, resolveFinalValueInKeyframes };\n","function shallowCompare(next, prev) {\n if (!Array.isArray(prev))\n return false;\n const prevLength = prev.length;\n if (prevLength !== next.length)\n return false;\n for (let i = 0; i < prevLength; i++) {\n if (prev[i] !== next[i])\n return false;\n }\n return true;\n}\n\nexport { shallowCompare };\n","import { addUniqueItem, removeItem } from './array.mjs';\n\nclass SubscriptionManager {\n constructor() {\n this.subscriptions = [];\n }\n add(handler) {\n addUniqueItem(this.subscriptions, handler);\n return () => removeItem(this.subscriptions, handler);\n }\n notify(a, b, c) {\n const numSubscriptions = this.subscriptions.length;\n if (!numSubscriptions)\n return;\n if (numSubscriptions === 1) {\n /**\n * If there's only a single handler we can just call it without invoking a loop.\n */\n this.subscriptions[0](a, b, c);\n }\n else {\n for (let i = 0; i < numSubscriptions; i++) {\n /**\n * Check whether the handler exists before firing as it's possible\n * the subscriptions were modified during this loop running.\n */\n const handler = this.subscriptions[i];\n handler && handler(a, b, c);\n }\n }\n }\n getSize() {\n return this.subscriptions.length;\n }\n clear() {\n this.subscriptions.length = 0;\n }\n}\n\nexport { SubscriptionManager };\n","/**\n * Converts seconds to milliseconds\n *\n * @param seconds - Time in seconds.\n * @return milliseconds - Converted time in milliseconds.\n */\nconst secondsToMilliseconds = (seconds) => seconds * 1000;\nconst millisecondsToSeconds = (milliseconds) => milliseconds / 1000;\n\nexport { millisecondsToSeconds, secondsToMilliseconds };\n","import { useRef } from 'react';\n\n/**\n * Creates a constant value over the lifecycle of a component.\n *\n * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer\n * a guarantee that it won't re-run for performance reasons later on. By using `useConstant`\n * you can ensure that initialisers don't execute twice or more.\n */\nfunction useConstant(init) {\n const ref = useRef(null);\n if (ref.current === null) {\n ref.current = init();\n }\n return ref.current;\n}\n\nexport { useConstant };\n","const instantAnimationState = {\n current: false,\n};\n\nexport { instantAnimationState };\n","import { useLayoutEffect, useEffect } from 'react';\nimport { isBrowser } from './is-browser.mjs';\n\nconst useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;\n\nexport { useIsomorphicLayoutEffect };\n","/*\n Convert velocity into velocity per second\n\n @param [number]: Unit per frame\n @param [number]: Frame duration in ms\n*/\nfunction velocityPerSecond(velocity, frameDuration) {\n return frameDuration ? velocity * (1000 / frameDuration) : 0;\n}\n\nexport { velocityPerSecond };\n","const warned = new Set();\nfunction warnOnce(condition, message, element) {\n if (condition || warned.has(message))\n return;\n console.warn(message);\n if (element)\n console.warn(element);\n warned.add(message);\n}\n\nexport { warnOnce };\n","import { SubscriptionManager } from '../utils/subscription-manager.mjs';\nimport { velocityPerSecond } from '../utils/velocity-per-second.mjs';\nimport { warnOnce } from '../utils/warn-once.mjs';\nimport { time } from '../frameloop/sync-time.mjs';\nimport { frame } from '../frameloop/frame.mjs';\n\n/**\n * Maximum time between the value of two frames, beyond which we\n * assume the velocity has since been 0.\n */\nconst MAX_VELOCITY_DELTA = 30;\nconst isFloat = (value) => {\n return !isNaN(parseFloat(value));\n};\nconst collectMotionValues = {\n current: undefined,\n};\n/**\n * `MotionValue` is used to track the state and velocity of motion values.\n *\n * @public\n */\nclass MotionValue {\n /**\n * @param init - The initiating value\n * @param config - Optional configuration options\n *\n * - `transformer`: A function to transform incoming values with.\n *\n * @internal\n */\n constructor(init, options = {}) {\n /**\n * This will be replaced by the build step with the latest version number.\n * When MotionValues are provided to motion components, warn if versions are mixed.\n */\n this.version = \"11.4.0\";\n /**\n * Tracks whether this value can output a velocity. Currently this is only true\n * if the value is numerical, but we might be able to widen the scope here and support\n * other value types.\n *\n * @internal\n */\n this.canTrackVelocity = null;\n /**\n * An object containing a SubscriptionManager for each active event.\n */\n this.events = {};\n this.updateAndNotify = (v, render = true) => {\n const currentTime = time.now();\n /**\n * If we're updating the value during another frame or eventloop\n * than the previous frame, then the we set the previous frame value\n * to current.\n */\n if (this.updatedAt !== currentTime) {\n this.setPrevFrameValue();\n }\n this.prev = this.current;\n this.setCurrent(v);\n // Update update subscribers\n if (this.current !== this.prev && this.events.change) {\n this.events.change.notify(this.current);\n }\n // Update render subscribers\n if (render && this.events.renderRequest) {\n this.events.renderRequest.notify(this.current);\n }\n };\n this.hasAnimated = false;\n this.setCurrent(init);\n this.owner = options.owner;\n }\n setCurrent(current) {\n this.current = current;\n this.updatedAt = time.now();\n if (this.canTrackVelocity === null && current !== undefined) {\n this.canTrackVelocity = isFloat(this.current);\n }\n }\n setPrevFrameValue(prevFrameValue = this.current) {\n this.prevFrameValue = prevFrameValue;\n this.prevUpdatedAt = this.updatedAt;\n }\n /**\n * Adds a function that will be notified when the `MotionValue` is updated.\n *\n * It returns a function that, when called, will cancel the subscription.\n *\n * When calling `onChange` inside a React component, it should be wrapped with the\n * `useEffect` hook. As it returns an unsubscribe function, this should be returned\n * from the `useEffect` function to ensure you don't add duplicate subscribers..\n *\n * ```jsx\n * export const MyComponent = () => {\n * const x = useMotionValue(0)\n * const y = useMotionValue(0)\n * const opacity = useMotionValue(1)\n *\n * useEffect(() => {\n * function updateOpacity() {\n * const maxXY = Math.max(x.get(), y.get())\n * const newOpacity = transform(maxXY, [0, 100], [1, 0])\n * opacity.set(newOpacity)\n * }\n *\n * const unsubscribeX = x.on(\"change\", updateOpacity)\n * const unsubscribeY = y.on(\"change\", updateOpacity)\n *\n * return () => {\n * unsubscribeX()\n * unsubscribeY()\n * }\n * }, [])\n *\n * return \n * }\n * ```\n *\n * @param subscriber - A function that receives the latest value.\n * @returns A function that, when called, will cancel this subscription.\n *\n * @deprecated\n */\n onChange(subscription) {\n if (process.env.NODE_ENV !== \"production\") {\n warnOnce(false, `value.onChange(callback) is deprecated. Switch to value.on(\"change\", callback).`);\n }\n return this.on(\"change\", subscription);\n }\n on(eventName, callback) {\n if (!this.events[eventName]) {\n this.events[eventName] = new SubscriptionManager();\n }\n const unsubscribe = this.events[eventName].add(callback);\n if (eventName === \"change\") {\n return () => {\n unsubscribe();\n /**\n * If we have no more change listeners by the start\n * of the next frame, stop active animations.\n */\n frame.read(() => {\n if (!this.events.change.getSize()) {\n this.stop();\n }\n });\n };\n }\n return unsubscribe;\n }\n clearListeners() {\n for (const eventManagers in this.events) {\n this.events[eventManagers].clear();\n }\n }\n /**\n * Attaches a passive effect to the `MotionValue`.\n *\n * @internal\n */\n attach(passiveEffect, stopPassiveEffect) {\n this.passiveEffect = passiveEffect;\n this.stopPassiveEffect = stopPassiveEffect;\n }\n /**\n * Sets the state of the `MotionValue`.\n *\n * @remarks\n *\n * ```jsx\n * const x = useMotionValue(0)\n * x.set(10)\n * ```\n *\n * @param latest - Latest value to set.\n * @param render - Whether to notify render subscribers. Defaults to `true`\n *\n * @public\n */\n set(v, render = true) {\n if (!render || !this.passiveEffect) {\n this.updateAndNotify(v, render);\n }\n else {\n this.passiveEffect(v, this.updateAndNotify);\n }\n }\n setWithVelocity(prev, current, delta) {\n this.set(current);\n this.prev = undefined;\n this.prevFrameValue = prev;\n this.prevUpdatedAt = this.updatedAt - delta;\n }\n /**\n * Set the state of the `MotionValue`, stopping any active animations,\n * effects, and resets velocity to `0`.\n */\n jump(v, endAnimation = true) {\n this.updateAndNotify(v);\n this.prev = v;\n this.prevUpdatedAt = this.prevFrameValue = undefined;\n endAnimation && this.stop();\n if (this.stopPassiveEffect)\n this.stopPassiveEffect();\n }\n /**\n * Returns the latest state of `MotionValue`\n *\n * @returns - The latest state of `MotionValue`\n *\n * @public\n */\n get() {\n if (collectMotionValues.current) {\n collectMotionValues.current.push(this);\n }\n return this.current;\n }\n /**\n * @public\n */\n getPrevious() {\n return this.prev;\n }\n /**\n * Returns the latest velocity of `MotionValue`\n *\n * @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.\n *\n * @public\n */\n getVelocity() {\n const currentTime = time.now();\n if (!this.canTrackVelocity ||\n this.prevFrameValue === undefined ||\n currentTime - this.updatedAt > MAX_VELOCITY_DELTA) {\n return 0;\n }\n const delta = Math.min(this.updatedAt - this.prevUpdatedAt, MAX_VELOCITY_DELTA);\n // Casts because of parseFloat's poor typing\n return velocityPerSecond(parseFloat(this.current) -\n parseFloat(this.prevFrameValue), delta);\n }\n /**\n * Registers a new animation to control this `MotionValue`. Only one\n * animation can drive a `MotionValue` at one time.\n *\n * ```jsx\n * value.start()\n * ```\n *\n * @param animation - A function that starts the provided animation\n *\n * @internal\n */\n start(startAnimation) {\n this.stop();\n return new Promise((resolve) => {\n this.hasAnimated = true;\n this.animation = startAnimation(resolve);\n if (this.events.animationStart) {\n this.events.animationStart.notify();\n }\n }).then(() => {\n if (this.events.animationComplete) {\n this.events.animationComplete.notify();\n }\n this.clearAnimation();\n });\n }\n /**\n * Stop the currently active animation.\n *\n * @public\n */\n stop() {\n if (this.animation) {\n this.animation.stop();\n if (this.events.animationCancel) {\n this.events.animationCancel.notify();\n }\n }\n this.clearAnimation();\n }\n /**\n * Returns `true` if this value is currently animating.\n *\n * @public\n */\n isAnimating() {\n return !!this.animation;\n }\n clearAnimation() {\n delete this.animation;\n }\n /**\n * Destroy and clean up subscribers to this `MotionValue`.\n *\n * The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically\n * handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually\n * created a `MotionValue` via the `motionValue` function.\n *\n * @public\n */\n destroy() {\n this.clearListeners();\n this.stop();\n if (this.stopPassiveEffect) {\n this.stopPassiveEffect();\n }\n }\n}\nfunction motionValue(init, options) {\n return new MotionValue(init, options);\n}\n\nexport { MotionValue, collectMotionValues, motionValue };\n","import { rgba } from './rgba.mjs';\nimport { isColorString } from './utils.mjs';\n\nfunction parseHex(v) {\n let r = \"\";\n let g = \"\";\n let b = \"\";\n let a = \"\";\n // If we have 6 characters, ie #FF0000\n if (v.length > 5) {\n r = v.substring(1, 3);\n g = v.substring(3, 5);\n b = v.substring(5, 7);\n a = v.substring(7, 9);\n // Or we have 3 characters, ie #F00\n }\n else {\n r = v.substring(1, 2);\n g = v.substring(2, 3);\n b = v.substring(3, 4);\n a = v.substring(4, 5);\n r += r;\n g += g;\n b += b;\n a += a;\n }\n return {\n red: parseInt(r, 16),\n green: parseInt(g, 16),\n blue: parseInt(b, 16),\n alpha: a ? parseInt(a, 16) / 255 : 1,\n };\n}\nconst hex = {\n test: isColorString(\"#\"),\n parse: parseHex,\n transform: rgba.transform,\n};\n\nexport { hex };\n","import { alpha } from '../numbers/index.mjs';\nimport { percent } from '../numbers/units.mjs';\nimport { sanitize } from '../utils.mjs';\nimport { isColorString, splitColor } from './utils.mjs';\n\nconst hsla = {\n test: isColorString(\"hsl\", \"hue\"),\n parse: splitColor(\"hue\", \"saturation\", \"lightness\"),\n transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {\n return (\"hsla(\" +\n Math.round(hue) +\n \", \" +\n percent.transform(sanitize(saturation)) +\n \", \" +\n percent.transform(sanitize(lightness)) +\n \", \" +\n sanitize(alpha.transform(alpha$1)) +\n \")\");\n },\n};\n\nexport { hsla };\n","import { isString } from '../utils.mjs';\nimport { hex } from './hex.mjs';\nimport { hsla } from './hsla.mjs';\nimport { rgba } from './rgba.mjs';\n\nconst color = {\n test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),\n parse: (v) => {\n if (rgba.test(v)) {\n return rgba.parse(v);\n }\n else if (hsla.test(v)) {\n return hsla.parse(v);\n }\n else {\n return hex.parse(v);\n }\n },\n transform: (v) => {\n return isString(v)\n ? v\n : v.hasOwnProperty(\"red\")\n ? rgba.transform(v)\n : hsla.transform(v);\n },\n};\n\nexport { color };\n","import { clamp } from '../../../utils/clamp.mjs';\nimport { alpha, number } from '../numbers/index.mjs';\nimport { sanitize } from '../utils.mjs';\nimport { isColorString, splitColor } from './utils.mjs';\n\nconst clampRgbUnit = (v) => clamp(0, 255, v);\nconst rgbUnit = {\n ...number,\n transform: (v) => Math.round(clampRgbUnit(v)),\n};\nconst rgba = {\n test: isColorString(\"rgb\", \"red\"),\n parse: splitColor(\"red\", \"green\", \"blue\"),\n transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => \"rgba(\" +\n rgbUnit.transform(red) +\n \", \" +\n rgbUnit.transform(green) +\n \", \" +\n rgbUnit.transform(blue) +\n \", \" +\n sanitize(alpha.transform(alpha$1)) +\n \")\",\n};\n\nexport { rgbUnit, rgba };\n","import { isString, singleColorRegex, isNullish, floatRegex } from '../utils.mjs';\n\n/**\n * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,\n * but false if a number or multiple colors\n */\nconst isColorString = (type, testProp) => (v) => {\n return Boolean((isString(v) && singleColorRegex.test(v) && v.startsWith(type)) ||\n (testProp &&\n !isNullish(v) &&\n Object.prototype.hasOwnProperty.call(v, testProp)));\n};\nconst splitColor = (aName, bName, cName) => (v) => {\n if (!isString(v))\n return v;\n const [a, b, c, alpha] = v.match(floatRegex);\n return {\n [aName]: parseFloat(a),\n [bName]: parseFloat(b),\n [cName]: parseFloat(c),\n alpha: alpha !== undefined ? parseFloat(alpha) : 1,\n };\n};\n\nexport { isColorString, splitColor };\n","import { complex } from './index.mjs';\nimport { floatRegex } from '../utils.mjs';\n\n/**\n * Properties that should default to 1 or 100%\n */\nconst maxDefaults = new Set([\"brightness\", \"contrast\", \"saturate\", \"opacity\"]);\nfunction applyDefaultFilter(v) {\n const [name, value] = v.slice(0, -1).split(\"(\");\n if (name === \"drop-shadow\")\n return v;\n const [number] = value.match(floatRegex) || [];\n if (!number)\n return v;\n const unit = value.replace(number, \"\");\n let defaultValue = maxDefaults.has(name) ? 1 : 0;\n if (number !== value)\n defaultValue *= 100;\n return name + \"(\" + defaultValue + unit + \")\";\n}\nconst functionRegex = /\\b([a-z-]*)\\(.*?\\)/gu;\nconst filter = {\n ...complex,\n getAnimatableNone: (v) => {\n const functions = v.match(functionRegex);\n return functions ? functions.map(applyDefaultFilter).join(\" \") : v;\n },\n};\n\nexport { filter };\n","import { color } from '../color/index.mjs';\nimport { isString, floatRegex, colorRegex, sanitize } from '../utils.mjs';\n\nfunction test(v) {\n var _a, _b;\n return (isNaN(v) &&\n isString(v) &&\n (((_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) || 0) +\n (((_b = v.match(colorRegex)) === null || _b === void 0 ? void 0 : _b.length) || 0) >\n 0);\n}\nconst NUMBER_TOKEN = \"number\";\nconst COLOR_TOKEN = \"color\";\nconst VAR_TOKEN = \"var\";\nconst VAR_FUNCTION_TOKEN = \"var(\";\nconst SPLIT_TOKEN = \"${}\";\n// this regex consists of the `singleCssVariableRegex|rgbHSLValueRegex|digitRegex`\nconst complexRegex = /var\\s*\\(\\s*--(?:[\\w-]+\\s*|[\\w-]+\\s*,(?:\\s*[^)(\\s]|\\s*\\((?:[^)(]|\\([^)(]*\\))*\\))+\\s*)\\)|#[\\da-f]{3,8}|(?:rgb|hsl)a?\\((?:-?[\\d.]+%?[,\\s]+){2}-?[\\d.]+%?\\s*(?:[,/]\\s*)?(?:\\b\\d+(?:\\.\\d+)?|\\.\\d+)?%?\\)|-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)/giu;\nfunction analyseComplexValue(value) {\n const originalValue = value.toString();\n const values = [];\n const indexes = {\n color: [],\n number: [],\n var: [],\n };\n const types = [];\n let i = 0;\n const tokenised = originalValue.replace(complexRegex, (parsedValue) => {\n if (color.test(parsedValue)) {\n indexes.color.push(i);\n types.push(COLOR_TOKEN);\n values.push(color.parse(parsedValue));\n }\n else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {\n indexes.var.push(i);\n types.push(VAR_TOKEN);\n values.push(parsedValue);\n }\n else {\n indexes.number.push(i);\n types.push(NUMBER_TOKEN);\n values.push(parseFloat(parsedValue));\n }\n ++i;\n return SPLIT_TOKEN;\n });\n const split = tokenised.split(SPLIT_TOKEN);\n return { values, split, indexes, types };\n}\nfunction parseComplexValue(v) {\n return analyseComplexValue(v).values;\n}\nfunction createTransformer(source) {\n const { split, types } = analyseComplexValue(source);\n const numSections = split.length;\n return (v) => {\n let output = \"\";\n for (let i = 0; i < numSections; i++) {\n output += split[i];\n if (v[i] !== undefined) {\n const type = types[i];\n if (type === NUMBER_TOKEN) {\n output += sanitize(v[i]);\n }\n else if (type === COLOR_TOKEN) {\n output += color.transform(v[i]);\n }\n else {\n output += v[i];\n }\n }\n }\n return output;\n };\n}\nconst convertNumbersToZero = (v) => typeof v === \"number\" ? 0 : v;\nfunction getAnimatableNone(v) {\n const parsed = parseComplexValue(v);\n const transformer = createTransformer(v);\n return transformer(parsed.map(convertNumbersToZero));\n}\nconst complex = {\n test,\n parse: parseComplexValue,\n createTransformer,\n getAnimatableNone,\n};\n\nexport { analyseComplexValue, complex };\n","import { clamp } from '../../../utils/clamp.mjs';\n\nconst number = {\n test: (v) => typeof v === \"number\",\n parse: parseFloat,\n transform: (v) => v,\n};\nconst alpha = {\n ...number,\n transform: (v) => clamp(0, 1, v),\n};\nconst scale = {\n ...number,\n default: 1,\n};\n\nexport { alpha, number, scale };\n","import { isString } from '../utils.mjs';\n\nconst createUnitType = (unit) => ({\n test: (v) => isString(v) && v.endsWith(unit) && v.split(\" \").length === 1,\n parse: parseFloat,\n transform: (v) => `${v}${unit}`,\n});\nconst degrees = createUnitType(\"deg\");\nconst percent = createUnitType(\"%\");\nconst px = createUnitType(\"px\");\nconst vh = createUnitType(\"vh\");\nconst vw = createUnitType(\"vw\");\nconst progressPercentage = {\n ...percent,\n parse: (v) => percent.parse(v) / 100,\n transform: (v) => percent.transform(v * 100),\n};\n\nexport { degrees, percent, progressPercentage, px, vh, vw };\n","/**\n * TODO: When we move from string as a source of truth to data models\n * everything in this folder should probably be referred to as models vs types\n */\n// If this number is a decimal, make it just five decimal places\n// to avoid exponents\nconst sanitize = (v) => Math.round(v * 100000) / 100000;\nconst floatRegex = /-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)/gu;\nconst colorRegex = /(?:#[\\da-f]{3,8}|(?:rgb|hsl)a?\\((?:-?[\\d.]+%?[,\\s]+){2}-?[\\d.]+%?\\s*(?:[,/]\\s*)?(?:\\b\\d+(?:\\.\\d+)?|\\.\\d+)?%?\\))/giu;\nconst singleColorRegex = /^(?:#[\\da-f]{3,8}|(?:rgb|hsl)a?\\((?:-?[\\d.]+%?[,\\s]+){2}-?[\\d.]+%?\\s*(?:[,/]\\s*)?(?:\\b\\d+(?:\\.\\d+)?|\\.\\d+)?%?\\))$/iu;\nfunction isString(v) {\n return typeof v === \"string\";\n}\nfunction isNullish(v) {\n return v == null;\n}\n\nexport { colorRegex, floatRegex, isNullish, isString, sanitize, singleColorRegex };\n","import { MotionValue } from '../index.mjs';\nimport { getWillChangeName } from './get-will-change-name.mjs';\nimport { removeItem } from '../../utils/array.mjs';\n\nclass WillChangeMotionValue extends MotionValue {\n constructor() {\n super(...arguments);\n this.output = [];\n this.counts = new Map();\n }\n add(name) {\n const styleName = getWillChangeName(name);\n if (!styleName)\n return;\n /**\n * Update counter. Each value has an indepdent counter\n * as multiple sources could be requesting the same value\n * gets added to will-change.\n */\n const prevCount = this.counts.get(styleName) || 0;\n this.counts.set(styleName, prevCount + 1);\n if (prevCount === 0) {\n this.output.push(styleName);\n this.update();\n }\n /**\n * Prevents the remove function from being called multiple times.\n */\n let hasRemoved = false;\n return () => {\n if (hasRemoved)\n return;\n hasRemoved = true;\n const newCount = this.counts.get(styleName) - 1;\n this.counts.set(styleName, newCount);\n if (newCount === 0) {\n removeItem(this.output, styleName);\n this.update();\n }\n };\n }\n update() {\n this.set(this.output.length ? this.output.join(\", \") : \"auto\");\n }\n}\n\nexport { WillChangeMotionValue };\n","import { WillChangeMotionValue } from './WillChangeMotionValue.mjs';\nimport { isWillChangeMotionValue } from './is.mjs';\n\nfunction addValueToWillChange(visualElement, key) {\n var _a;\n if (!visualElement.applyWillChange)\n return;\n let willChange = visualElement.getValue(\"willChange\");\n /**\n * If we haven't created a willChange MotionValue, and the we haven't been\n * manually provided one, create one.\n */\n if (!willChange && !((_a = visualElement.props.style) === null || _a === void 0 ? void 0 : _a.willChange)) {\n willChange = new WillChangeMotionValue(\"auto\");\n visualElement.addValue(\"willChange\", willChange);\n }\n /**\n * It could be that a user has set willChange to a regular MotionValue,\n * in which case we can't add the value to it.\n */\n if (isWillChangeMotionValue(willChange)) {\n return willChange.add(key);\n }\n}\n\nexport { addValueToWillChange };\n","import { acceleratedValues } from '../../animation/animators/utils/accelerated-values.mjs';\nimport { camelToDash } from '../../render/dom/utils/camel-to-dash.mjs';\nimport { transformProps } from '../../render/html/utils/transform.mjs';\n\nfunction getWillChangeName(name) {\n if (transformProps.has(name)) {\n return \"transform\";\n }\n else if (acceleratedValues.has(name)) {\n return camelToDash(name);\n }\n}\n\nexport { getWillChangeName };\n","import { isMotionValue } from '../utils/is-motion-value.mjs';\n\nfunction isWillChangeMotionValue(value) {\n return Boolean(isMotionValue(value) && value.add);\n}\n\nexport { isWillChangeMotionValue };\n","const isMotionValue = (value) => Boolean(value && value.getVelocity);\n\nexport { isMotionValue };\n","import { isCustomValue } from '../../utils/resolve-value.mjs';\nimport { isMotionValue } from './is-motion-value.mjs';\n\n/**\n * If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself\n *\n * TODO: Remove and move to library\n */\nfunction resolveMotionValue(value) {\n const unwrappedValue = isMotionValue(value) ? value.get() : value;\n return isCustomValue(unwrappedValue)\n ? unwrappedValue.toValue()\n : unwrappedValue;\n}\n\nexport { resolveMotionValue };\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction createCommand(type) {\n return {\n type\n } ;\n}\nconst SELECTION_CHANGE_COMMAND = createCommand('SELECTION_CHANGE_COMMAND');\nconst SELECTION_INSERT_CLIPBOARD_NODES_COMMAND = createCommand('SELECTION_INSERT_CLIPBOARD_NODES_COMMAND');\nconst CLICK_COMMAND = createCommand('CLICK_COMMAND');\nconst DELETE_CHARACTER_COMMAND = createCommand('DELETE_CHARACTER_COMMAND');\nconst INSERT_LINE_BREAK_COMMAND = createCommand('INSERT_LINE_BREAK_COMMAND');\nconst INSERT_PARAGRAPH_COMMAND = createCommand('INSERT_PARAGRAPH_COMMAND');\nconst CONTROLLED_TEXT_INSERTION_COMMAND = createCommand('CONTROLLED_TEXT_INSERTION_COMMAND');\nconst PASTE_COMMAND = createCommand('PASTE_COMMAND');\nconst REMOVE_TEXT_COMMAND = createCommand('REMOVE_TEXT_COMMAND');\nconst DELETE_WORD_COMMAND = createCommand('DELETE_WORD_COMMAND');\nconst DELETE_LINE_COMMAND = createCommand('DELETE_LINE_COMMAND');\nconst FORMAT_TEXT_COMMAND = createCommand('FORMAT_TEXT_COMMAND');\nconst UNDO_COMMAND = createCommand('UNDO_COMMAND');\nconst REDO_COMMAND = createCommand('REDO_COMMAND');\nconst KEY_DOWN_COMMAND = createCommand('KEYDOWN_COMMAND');\nconst KEY_ARROW_RIGHT_COMMAND = createCommand('KEY_ARROW_RIGHT_COMMAND');\nconst MOVE_TO_END = createCommand('MOVE_TO_END');\nconst KEY_ARROW_LEFT_COMMAND = createCommand('KEY_ARROW_LEFT_COMMAND');\nconst MOVE_TO_START = createCommand('MOVE_TO_START');\nconst KEY_ARROW_UP_COMMAND = createCommand('KEY_ARROW_UP_COMMAND');\nconst KEY_ARROW_DOWN_COMMAND = createCommand('KEY_ARROW_DOWN_COMMAND');\nconst KEY_ENTER_COMMAND = createCommand('KEY_ENTER_COMMAND');\nconst KEY_SPACE_COMMAND = createCommand('KEY_SPACE_COMMAND');\nconst KEY_BACKSPACE_COMMAND = createCommand('KEY_BACKSPACE_COMMAND');\nconst KEY_ESCAPE_COMMAND = createCommand('KEY_ESCAPE_COMMAND');\nconst KEY_DELETE_COMMAND = createCommand('KEY_DELETE_COMMAND');\nconst KEY_TAB_COMMAND = createCommand('KEY_TAB_COMMAND');\nconst INSERT_TAB_COMMAND = createCommand('INSERT_TAB_COMMAND');\nconst INDENT_CONTENT_COMMAND = createCommand('INDENT_CONTENT_COMMAND');\nconst OUTDENT_CONTENT_COMMAND = createCommand('OUTDENT_CONTENT_COMMAND');\nconst DROP_COMMAND = createCommand('DROP_COMMAND');\nconst FORMAT_ELEMENT_COMMAND = createCommand('FORMAT_ELEMENT_COMMAND');\nconst DRAGSTART_COMMAND = createCommand('DRAGSTART_COMMAND');\nconst DRAGOVER_COMMAND = createCommand('DRAGOVER_COMMAND');\nconst DRAGEND_COMMAND = createCommand('DRAGEND_COMMAND');\nconst COPY_COMMAND = createCommand('COPY_COMMAND');\nconst CUT_COMMAND = createCommand('CUT_COMMAND');\nconst SELECT_ALL_COMMAND = createCommand('SELECT_ALL_COMMAND');\nconst CLEAR_EDITOR_COMMAND = createCommand('CLEAR_EDITOR_COMMAND');\nconst CLEAR_HISTORY_COMMAND = createCommand('CLEAR_HISTORY_COMMAND');\nconst CAN_REDO_COMMAND = createCommand('CAN_REDO_COMMAND');\nconst CAN_UNDO_COMMAND = createCommand('CAN_UNDO_COMMAND');\nconst FOCUS_COMMAND = createCommand('FOCUS_COMMAND');\nconst BLUR_COMMAND = createCommand('BLUR_COMMAND');\nconst KEY_MODIFIER_COMMAND = createCommand('KEY_MODIFIER_COMMAND');\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst documentMode = CAN_USE_DOM && 'documentMode' in document ? document.documentMode : null;\nconst IS_APPLE = CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform);\nconst IS_FIREFOX = CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);\nconst CAN_USE_BEFORE_INPUT = CAN_USE_DOM && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;\nconst IS_SAFARI = CAN_USE_DOM && /Version\\/[\\d.]+.*Safari/.test(navigator.userAgent);\nconst IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\nconst IS_ANDROID = CAN_USE_DOM && /Android/.test(navigator.userAgent);\n\n// Keep these in case we need to use them in the future.\n// export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);\nconst IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent);\n// export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;\n\nconst IS_ANDROID_CHROME = CAN_USE_DOM && IS_ANDROID && IS_CHROME;\nconst IS_APPLE_WEBKIT = CAN_USE_DOM && /AppleWebKit\\/[\\d.]+/.test(navigator.userAgent) && !IS_CHROME;\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// DOM\nconst DOM_ELEMENT_TYPE = 1;\nconst DOM_TEXT_TYPE = 3;\n\n// Reconciling\nconst NO_DIRTY_NODES = 0;\nconst HAS_DIRTY_NODES = 1;\nconst FULL_RECONCILE = 2;\n\n// Text node modes\nconst IS_NORMAL = 0;\nconst IS_TOKEN = 1;\nconst IS_SEGMENTED = 2;\n// IS_INERT = 3\n\n// Text node formatting\nconst IS_BOLD = 1;\nconst IS_ITALIC = 1 << 1;\nconst IS_STRIKETHROUGH = 1 << 2;\nconst IS_UNDERLINE = 1 << 3;\nconst IS_CODE = 1 << 4;\nconst IS_SUBSCRIPT = 1 << 5;\nconst IS_SUPERSCRIPT = 1 << 6;\nconst IS_HIGHLIGHT = 1 << 7;\nconst IS_ALL_FORMATTING = IS_BOLD | IS_ITALIC | IS_STRIKETHROUGH | IS_UNDERLINE | IS_CODE | IS_SUBSCRIPT | IS_SUPERSCRIPT | IS_HIGHLIGHT;\n\n// Text node details\nconst IS_DIRECTIONLESS = 1;\nconst IS_UNMERGEABLE = 1 << 1;\n\n// Element node formatting\nconst IS_ALIGN_LEFT = 1;\nconst IS_ALIGN_CENTER = 2;\nconst IS_ALIGN_RIGHT = 3;\nconst IS_ALIGN_JUSTIFY = 4;\nconst IS_ALIGN_START = 5;\nconst IS_ALIGN_END = 6;\n\n// Reconciliation\nconst NON_BREAKING_SPACE = '\\u00A0';\nconst ZERO_WIDTH_SPACE = '\\u200b';\n\n// For iOS/Safari we use a non breaking space, otherwise the cursor appears\n// overlapping the composed text.\nconst COMPOSITION_SUFFIX = IS_SAFARI || IS_IOS || IS_APPLE_WEBKIT ? NON_BREAKING_SPACE : ZERO_WIDTH_SPACE;\nconst DOUBLE_LINE_BREAK = '\\n\\n';\n\n// For FF, we need to use a non-breaking space, or it gets composition\n// in a stuck state.\nconst COMPOSITION_START_CHAR = IS_FIREFOX ? NON_BREAKING_SPACE : COMPOSITION_SUFFIX;\nconst RTL = '\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC';\nconst LTR = 'A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6' + '\\u00F8-\\u02B8\\u0300-\\u0590\\u0800-\\u1FFF\\u200E\\u2C00-\\uFB1C' + '\\uFE00-\\uFE6F\\uFEFD-\\uFFFF';\n\n// eslint-disable-next-line no-misleading-character-class\nconst RTL_REGEX = new RegExp('^[^' + LTR + ']*[' + RTL + ']');\n// eslint-disable-next-line no-misleading-character-class\nconst LTR_REGEX = new RegExp('^[^' + RTL + ']*[' + LTR + ']');\nconst TEXT_TYPE_TO_FORMAT = {\n bold: IS_BOLD,\n code: IS_CODE,\n highlight: IS_HIGHLIGHT,\n italic: IS_ITALIC,\n strikethrough: IS_STRIKETHROUGH,\n subscript: IS_SUBSCRIPT,\n superscript: IS_SUPERSCRIPT,\n underline: IS_UNDERLINE\n};\nconst DETAIL_TYPE_TO_DETAIL = {\n directionless: IS_DIRECTIONLESS,\n unmergeable: IS_UNMERGEABLE\n};\nconst ELEMENT_TYPE_TO_FORMAT = {\n center: IS_ALIGN_CENTER,\n end: IS_ALIGN_END,\n justify: IS_ALIGN_JUSTIFY,\n left: IS_ALIGN_LEFT,\n right: IS_ALIGN_RIGHT,\n start: IS_ALIGN_START\n};\nconst ELEMENT_FORMAT_TO_TYPE = {\n [IS_ALIGN_CENTER]: 'center',\n [IS_ALIGN_END]: 'end',\n [IS_ALIGN_JUSTIFY]: 'justify',\n [IS_ALIGN_LEFT]: 'left',\n [IS_ALIGN_RIGHT]: 'right',\n [IS_ALIGN_START]: 'start'\n};\nconst TEXT_MODE_TO_TYPE = {\n normal: IS_NORMAL,\n segmented: IS_SEGMENTED,\n token: IS_TOKEN\n};\nconst TEXT_TYPE_TO_MODE = {\n [IS_NORMAL]: 'normal',\n [IS_SEGMENTED]: 'segmented',\n [IS_TOKEN]: 'token'\n};\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction normalizeClassNames(...classNames) {\n const rval = [];\n for (const className of classNames) {\n if (className && typeof className === 'string') {\n for (const [s] of className.matchAll(/\\S+/g)) {\n rval.push(s);\n }\n }\n }\n return rval;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n// The time between a text entry event and the mutation observer firing.\nconst TEXT_MUTATION_VARIANCE = 100;\nlet isProcessingMutations = false;\nlet lastTextEntryTimeStamp = 0;\nfunction getIsProcessingMutations() {\n return isProcessingMutations;\n}\nfunction updateTimeStamp(event) {\n lastTextEntryTimeStamp = event.timeStamp;\n}\nfunction initTextEntryListener(editor) {\n if (lastTextEntryTimeStamp === 0) {\n getWindow(editor).addEventListener('textInput', updateTimeStamp, true);\n }\n}\nfunction isManagedLineBreak(dom, target, editor) {\n return (\n // @ts-expect-error: internal field\n target.__lexicalLineBreak === dom ||\n // @ts-ignore We intentionally add this to the Node.\n dom[`__lexicalKey_${editor._key}`] !== undefined\n );\n}\nfunction getLastSelection(editor) {\n return editor.getEditorState().read(() => {\n const selection = $getSelection();\n return selection !== null ? selection.clone() : null;\n });\n}\nfunction $handleTextMutation(target, node, editor) {\n const domSelection = getDOMSelection(editor._window);\n let anchorOffset = null;\n let focusOffset = null;\n if (domSelection !== null && domSelection.anchorNode === target) {\n anchorOffset = domSelection.anchorOffset;\n focusOffset = domSelection.focusOffset;\n }\n const text = target.nodeValue;\n if (text !== null) {\n $updateTextNodeFromDOMContent(node, text, anchorOffset, focusOffset, false);\n }\n}\nfunction shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) {\n if ($isRangeSelection(selection)) {\n const anchorNode = selection.anchor.getNode();\n if (anchorNode.is(targetNode) && selection.format !== anchorNode.getFormat()) {\n return false;\n }\n }\n return targetDOM.nodeType === DOM_TEXT_TYPE && targetNode.isAttached();\n}\nfunction $flushMutations$1(editor, mutations, observer) {\n isProcessingMutations = true;\n const shouldFlushTextMutations = performance.now() - lastTextEntryTimeStamp > TEXT_MUTATION_VARIANCE;\n try {\n updateEditor(editor, () => {\n const selection = $getSelection() || getLastSelection(editor);\n const badDOMTargets = new Map();\n const rootElement = editor.getRootElement();\n // We use the current editor state, as that reflects what is\n // actually \"on screen\".\n const currentEditorState = editor._editorState;\n const blockCursorElement = editor._blockCursorElement;\n let shouldRevertSelection = false;\n let possibleTextForFirefoxPaste = '';\n for (let i = 0; i < mutations.length; i++) {\n const mutation = mutations[i];\n const type = mutation.type;\n const targetDOM = mutation.target;\n let targetNode = $getNearestNodeFromDOMNode(targetDOM, currentEditorState);\n if (targetNode === null && targetDOM !== rootElement || $isDecoratorNode(targetNode)) {\n continue;\n }\n if (type === 'characterData') {\n // Text mutations are deferred and passed to mutation listeners to be\n // processed outside of the Lexical engine.\n if (shouldFlushTextMutations && $isTextNode(targetNode) && shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode)) {\n $handleTextMutation(\n // nodeType === DOM_TEXT_TYPE is a Text DOM node\n targetDOM, targetNode, editor);\n }\n } else if (type === 'childList') {\n shouldRevertSelection = true;\n // We attempt to \"undo\" any changes that have occurred outside\n // of Lexical. We want Lexical's editor state to be source of truth.\n // To the user, these will look like no-ops.\n const addedDOMs = mutation.addedNodes;\n for (let s = 0; s < addedDOMs.length; s++) {\n const addedDOM = addedDOMs[s];\n const node = $getNodeFromDOMNode(addedDOM);\n const parentDOM = addedDOM.parentNode;\n if (parentDOM != null && addedDOM !== blockCursorElement && node === null && (addedDOM.nodeName !== 'BR' || !isManagedLineBreak(addedDOM, parentDOM, editor))) {\n if (IS_FIREFOX) {\n const possibleText = addedDOM.innerText || addedDOM.nodeValue;\n if (possibleText) {\n possibleTextForFirefoxPaste += possibleText;\n }\n }\n parentDOM.removeChild(addedDOM);\n }\n }\n const removedDOMs = mutation.removedNodes;\n const removedDOMsLength = removedDOMs.length;\n if (removedDOMsLength > 0) {\n let unremovedBRs = 0;\n for (let s = 0; s < removedDOMsLength; s++) {\n const removedDOM = removedDOMs[s];\n if (removedDOM.nodeName === 'BR' && isManagedLineBreak(removedDOM, targetDOM, editor) || blockCursorElement === removedDOM) {\n targetDOM.appendChild(removedDOM);\n unremovedBRs++;\n }\n }\n if (removedDOMsLength !== unremovedBRs) {\n if (targetDOM === rootElement) {\n targetNode = internalGetRoot(currentEditorState);\n }\n badDOMTargets.set(targetDOM, targetNode);\n }\n }\n }\n }\n\n // Now we process each of the unique target nodes, attempting\n // to restore their contents back to the source of truth, which\n // is Lexical's \"current\" editor state. This is basically like\n // an internal revert on the DOM.\n if (badDOMTargets.size > 0) {\n for (const [targetDOM, targetNode] of badDOMTargets) {\n if ($isElementNode(targetNode)) {\n const childKeys = targetNode.getChildrenKeys();\n let currentDOM = targetDOM.firstChild;\n for (let s = 0; s < childKeys.length; s++) {\n const key = childKeys[s];\n const correctDOM = editor.getElementByKey(key);\n if (correctDOM === null) {\n continue;\n }\n if (currentDOM == null) {\n targetDOM.appendChild(correctDOM);\n currentDOM = correctDOM;\n } else if (currentDOM !== correctDOM) {\n targetDOM.replaceChild(correctDOM, currentDOM);\n }\n currentDOM = currentDOM.nextSibling;\n }\n } else if ($isTextNode(targetNode)) {\n targetNode.markDirty();\n }\n }\n }\n\n // Capture all the mutations made during this function. This\n // also prevents us having to process them on the next cycle\n // of onMutation, as these mutations were made by us.\n const records = observer.takeRecords();\n\n // Check for any random auto-added
elements, and remove them.\n // These get added by the browser when we undo the above mutations\n // and this can lead to a broken UI.\n if (records.length > 0) {\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const addedNodes = record.addedNodes;\n const target = record.target;\n for (let s = 0; s < addedNodes.length; s++) {\n const addedDOM = addedNodes[s];\n const parentDOM = addedDOM.parentNode;\n if (parentDOM != null && addedDOM.nodeName === 'BR' && !isManagedLineBreak(addedDOM, target, editor)) {\n parentDOM.removeChild(addedDOM);\n }\n }\n }\n\n // Clear any of those removal mutations\n observer.takeRecords();\n }\n if (selection !== null) {\n if (shouldRevertSelection) {\n selection.dirty = true;\n $setSelection(selection);\n }\n if (IS_FIREFOX && isFirefoxClipboardEvents(editor)) {\n selection.insertRawText(possibleTextForFirefoxPaste);\n }\n }\n });\n } finally {\n isProcessingMutations = false;\n }\n}\nfunction $flushRootMutations(editor) {\n const observer = editor._observer;\n if (observer !== null) {\n const mutations = observer.takeRecords();\n $flushMutations$1(editor, mutations, observer);\n }\n}\nfunction initMutationObserver(editor) {\n initTextEntryListener(editor);\n editor._observer = new MutationObserver((mutations, observer) => {\n $flushMutations$1(editor, mutations, observer);\n });\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction $canSimpleTextNodesBeMerged(node1, node2) {\n const node1Mode = node1.__mode;\n const node1Format = node1.__format;\n const node1Style = node1.__style;\n const node2Mode = node2.__mode;\n const node2Format = node2.__format;\n const node2Style = node2.__style;\n return (node1Mode === null || node1Mode === node2Mode) && (node1Format === null || node1Format === node2Format) && (node1Style === null || node1Style === node2Style);\n}\nfunction $mergeTextNodes(node1, node2) {\n const writableNode1 = node1.mergeWithSibling(node2);\n const normalizedNodes = getActiveEditor()._normalizedNodes;\n normalizedNodes.add(node1.__key);\n normalizedNodes.add(node2.__key);\n return writableNode1;\n}\nfunction $normalizeTextNode(textNode) {\n let node = textNode;\n if (node.__text === '' && node.isSimpleText() && !node.isUnmergeable()) {\n node.remove();\n return;\n }\n\n // Backward\n let previousNode;\n while ((previousNode = node.getPreviousSibling()) !== null && $isTextNode(previousNode) && previousNode.isSimpleText() && !previousNode.isUnmergeable()) {\n if (previousNode.__text === '') {\n previousNode.remove();\n } else if ($canSimpleTextNodesBeMerged(previousNode, node)) {\n node = $mergeTextNodes(previousNode, node);\n break;\n } else {\n break;\n }\n }\n\n // Forward\n let nextNode;\n while ((nextNode = node.getNextSibling()) !== null && $isTextNode(nextNode) && nextNode.isSimpleText() && !nextNode.isUnmergeable()) {\n if (nextNode.__text === '') {\n nextNode.remove();\n } else if ($canSimpleTextNodesBeMerged(node, nextNode)) {\n node = $mergeTextNodes(node, nextNode);\n break;\n } else {\n break;\n }\n }\n}\nfunction $normalizeSelection(selection) {\n $normalizePoint(selection.anchor);\n $normalizePoint(selection.focus);\n return selection;\n}\nfunction $normalizePoint(point) {\n while (point.type === 'element') {\n const node = point.getNode();\n const offset = point.offset;\n let nextNode;\n let nextOffsetAtEnd;\n if (offset === node.getChildrenSize()) {\n nextNode = node.getChildAtIndex(offset - 1);\n nextOffsetAtEnd = true;\n } else {\n nextNode = node.getChildAtIndex(offset);\n nextOffsetAtEnd = false;\n }\n if ($isTextNode(nextNode)) {\n point.set(nextNode.__key, nextOffsetAtEnd ? nextNode.getTextContentSize() : 0, 'text');\n break;\n } else if (!$isElementNode(nextNode)) {\n break;\n }\n point.set(nextNode.__key, nextOffsetAtEnd ? nextNode.getChildrenSize() : 0, 'element');\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nlet keyCounter = 1;\nfunction resetRandomKey() {\n keyCounter = 1;\n}\nfunction generateRandomKey() {\n return '' + keyCounter++;\n}\nfunction getRegisteredNodeOrThrow(editor, nodeType) {\n const registeredNode = editor._nodes.get(nodeType);\n if (registeredNode === undefined) {\n {\n throw Error(`registeredNode: Type ${nodeType} not found`);\n }\n }\n return registeredNode;\n}\nconst scheduleMicroTask = typeof queueMicrotask === 'function' ? queueMicrotask : fn => {\n // No window prefix intended (#1400)\n Promise.resolve().then(fn);\n};\nfunction $isSelectionCapturedInDecorator(node) {\n return $isDecoratorNode($getNearestNodeFromDOMNode(node));\n}\nfunction isSelectionCapturedInDecoratorInput(anchorDOM) {\n const activeElement = document.activeElement;\n if (activeElement === null) {\n return false;\n }\n const nodeName = activeElement.nodeName;\n return $isDecoratorNode($getNearestNodeFromDOMNode(anchorDOM)) && (nodeName === 'INPUT' || nodeName === 'TEXTAREA' || activeElement.contentEditable === 'true' && getEditorPropertyFromDOMNode(activeElement) == null);\n}\nfunction isSelectionWithinEditor(editor, anchorDOM, focusDOM) {\n const rootElement = editor.getRootElement();\n try {\n return rootElement !== null && rootElement.contains(anchorDOM) && rootElement.contains(focusDOM) &&\n // Ignore if selection is within nested editor\n anchorDOM !== null && !isSelectionCapturedInDecoratorInput(anchorDOM) && getNearestEditorFromDOMNode(anchorDOM) === editor;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * @returns true if the given argument is a LexicalEditor instance from this build of Lexical\n */\nfunction isLexicalEditor(editor) {\n // Check instanceof to prevent issues with multiple embedded Lexical installations\n return editor instanceof LexicalEditor;\n}\nfunction getNearestEditorFromDOMNode(node) {\n let currentNode = node;\n while (currentNode != null) {\n const editor = getEditorPropertyFromDOMNode(currentNode);\n if (isLexicalEditor(editor)) {\n return editor;\n }\n currentNode = getParentElement(currentNode);\n }\n return null;\n}\n\n/** @internal */\nfunction getEditorPropertyFromDOMNode(node) {\n // @ts-expect-error: internal field\n return node ? node.__lexicalEditor : null;\n}\nfunction getTextDirection(text) {\n if (RTL_REGEX.test(text)) {\n return 'rtl';\n }\n if (LTR_REGEX.test(text)) {\n return 'ltr';\n }\n return null;\n}\nfunction $isTokenOrSegmented(node) {\n return node.isToken() || node.isSegmented();\n}\nfunction isDOMNodeLexicalTextNode(node) {\n return node.nodeType === DOM_TEXT_TYPE;\n}\nfunction getDOMTextNode(element) {\n let node = element;\n while (node != null) {\n if (isDOMNodeLexicalTextNode(node)) {\n return node;\n }\n node = node.firstChild;\n }\n return null;\n}\nfunction toggleTextFormatType(format, type, alignWithFormat) {\n const activeFormat = TEXT_TYPE_TO_FORMAT[type];\n if (alignWithFormat !== null && (format & activeFormat) === (alignWithFormat & activeFormat)) {\n return format;\n }\n let newFormat = format ^ activeFormat;\n if (type === 'subscript') {\n newFormat &= ~TEXT_TYPE_TO_FORMAT.superscript;\n } else if (type === 'superscript') {\n newFormat &= ~TEXT_TYPE_TO_FORMAT.subscript;\n }\n return newFormat;\n}\nfunction $isLeafNode(node) {\n return $isTextNode(node) || $isLineBreakNode(node) || $isDecoratorNode(node);\n}\nfunction $setNodeKey(node, existingKey) {\n if (existingKey != null) {\n {\n errorOnNodeKeyConstructorMismatch(node, existingKey);\n }\n node.__key = existingKey;\n return;\n }\n errorOnReadOnly();\n errorOnInfiniteTransforms();\n const editor = getActiveEditor();\n const editorState = getActiveEditorState();\n const key = generateRandomKey();\n editorState._nodeMap.set(key, node);\n // TODO Split this function into leaf/element\n if ($isElementNode(node)) {\n editor._dirtyElements.set(key, true);\n } else {\n editor._dirtyLeaves.add(key);\n }\n editor._cloneNotNeeded.add(key);\n editor._dirtyType = HAS_DIRTY_NODES;\n node.__key = key;\n}\nfunction errorOnNodeKeyConstructorMismatch(node, existingKey) {\n const editorState = internalGetActiveEditorState();\n if (!editorState) {\n // tests expect to be able to do this kind of clone without an active editor state\n return;\n }\n const existingNode = editorState._nodeMap.get(existingKey);\n if (existingNode && existingNode.constructor !== node.constructor) {\n // Lifted condition to if statement because the inverted logic is a bit confusing\n if (node.constructor.name !== existingNode.constructor.name) {\n {\n throw Error(`Lexical node with constructor ${node.constructor.name} attempted to re-use key from node in active editor state with constructor ${existingNode.constructor.name}. Keys must not be re-used when the type is changed.`);\n }\n } else {\n {\n throw Error(`Lexical node with constructor ${node.constructor.name} attempted to re-use key from node in active editor state with different constructor with the same name (possibly due to invalid Hot Module Replacement). Keys must not be re-used when the type is changed.`);\n }\n }\n }\n}\nfunction internalMarkParentElementsAsDirty(parentKey, nodeMap, dirtyElements) {\n let nextParentKey = parentKey;\n while (nextParentKey !== null) {\n if (dirtyElements.has(nextParentKey)) {\n return;\n }\n const node = nodeMap.get(nextParentKey);\n if (node === undefined) {\n break;\n }\n dirtyElements.set(nextParentKey, false);\n nextParentKey = node.__parent;\n }\n}\n\n// TODO #6031 this function or their callers have to adjust selection (i.e. insertBefore)\nfunction removeFromParent(node) {\n const oldParent = node.getParent();\n if (oldParent !== null) {\n const writableNode = node.getWritable();\n const writableParent = oldParent.getWritable();\n const prevSibling = node.getPreviousSibling();\n const nextSibling = node.getNextSibling();\n // TODO: this function duplicates a bunch of operations, can be simplified.\n if (prevSibling === null) {\n if (nextSibling !== null) {\n const writableNextSibling = nextSibling.getWritable();\n writableParent.__first = nextSibling.__key;\n writableNextSibling.__prev = null;\n } else {\n writableParent.__first = null;\n }\n } else {\n const writablePrevSibling = prevSibling.getWritable();\n if (nextSibling !== null) {\n const writableNextSibling = nextSibling.getWritable();\n writableNextSibling.__prev = writablePrevSibling.__key;\n writablePrevSibling.__next = writableNextSibling.__key;\n } else {\n writablePrevSibling.__next = null;\n }\n writableNode.__prev = null;\n }\n if (nextSibling === null) {\n if (prevSibling !== null) {\n const writablePrevSibling = prevSibling.getWritable();\n writableParent.__last = prevSibling.__key;\n writablePrevSibling.__next = null;\n } else {\n writableParent.__last = null;\n }\n } else {\n const writableNextSibling = nextSibling.getWritable();\n if (prevSibling !== null) {\n const writablePrevSibling = prevSibling.getWritable();\n writablePrevSibling.__next = writableNextSibling.__key;\n writableNextSibling.__prev = writablePrevSibling.__key;\n } else {\n writableNextSibling.__prev = null;\n }\n writableNode.__next = null;\n }\n writableParent.__size--;\n writableNode.__parent = null;\n }\n}\n\n// Never use this function directly! It will break\n// the cloning heuristic. Instead use node.getWritable().\nfunction internalMarkNodeAsDirty(node) {\n errorOnInfiniteTransforms();\n const latest = node.getLatest();\n const parent = latest.__parent;\n const editorState = getActiveEditorState();\n const editor = getActiveEditor();\n const nodeMap = editorState._nodeMap;\n const dirtyElements = editor._dirtyElements;\n if (parent !== null) {\n internalMarkParentElementsAsDirty(parent, nodeMap, dirtyElements);\n }\n const key = latest.__key;\n editor._dirtyType = HAS_DIRTY_NODES;\n if ($isElementNode(node)) {\n dirtyElements.set(key, true);\n } else {\n // TODO split internally MarkNodeAsDirty into two dedicated Element/leave functions\n editor._dirtyLeaves.add(key);\n }\n}\nfunction internalMarkSiblingsAsDirty(node) {\n const previousNode = node.getPreviousSibling();\n const nextNode = node.getNextSibling();\n if (previousNode !== null) {\n internalMarkNodeAsDirty(previousNode);\n }\n if (nextNode !== null) {\n internalMarkNodeAsDirty(nextNode);\n }\n}\nfunction $setCompositionKey(compositionKey) {\n errorOnReadOnly();\n const editor = getActiveEditor();\n const previousCompositionKey = editor._compositionKey;\n if (compositionKey !== previousCompositionKey) {\n editor._compositionKey = compositionKey;\n if (previousCompositionKey !== null) {\n const node = $getNodeByKey(previousCompositionKey);\n if (node !== null) {\n node.getWritable();\n }\n }\n if (compositionKey !== null) {\n const node = $getNodeByKey(compositionKey);\n if (node !== null) {\n node.getWritable();\n }\n }\n }\n}\nfunction $getCompositionKey() {\n if (isCurrentlyReadOnlyMode()) {\n return null;\n }\n const editor = getActiveEditor();\n return editor._compositionKey;\n}\nfunction $getNodeByKey(key, _editorState) {\n const editorState = _editorState || getActiveEditorState();\n const node = editorState._nodeMap.get(key);\n if (node === undefined) {\n return null;\n }\n return node;\n}\nfunction $getNodeFromDOMNode(dom, editorState) {\n const editor = getActiveEditor();\n // @ts-ignore We intentionally add this to the Node.\n const key = dom[`__lexicalKey_${editor._key}`];\n if (key !== undefined) {\n return $getNodeByKey(key, editorState);\n }\n return null;\n}\nfunction $getNearestNodeFromDOMNode(startingDOM, editorState) {\n let dom = startingDOM;\n while (dom != null) {\n const node = $getNodeFromDOMNode(dom, editorState);\n if (node !== null) {\n return node;\n }\n dom = getParentElement(dom);\n }\n return null;\n}\nfunction cloneDecorators(editor) {\n const currentDecorators = editor._decorators;\n const pendingDecorators = Object.assign({}, currentDecorators);\n editor._pendingDecorators = pendingDecorators;\n return pendingDecorators;\n}\nfunction getEditorStateTextContent(editorState) {\n return editorState.read(() => $getRoot().getTextContent());\n}\nfunction markAllNodesAsDirty(editor, type) {\n // Mark all existing text nodes as dirty\n updateEditor(editor, () => {\n const editorState = getActiveEditorState();\n if (editorState.isEmpty()) {\n return;\n }\n if (type === 'root') {\n $getRoot().markDirty();\n return;\n }\n const nodeMap = editorState._nodeMap;\n for (const [, node] of nodeMap) {\n node.markDirty();\n }\n }, editor._pendingEditorState === null ? {\n tag: 'history-merge'\n } : undefined);\n}\nfunction $getRoot() {\n return internalGetRoot(getActiveEditorState());\n}\nfunction internalGetRoot(editorState) {\n return editorState._nodeMap.get('root');\n}\nfunction $setSelection(selection) {\n errorOnReadOnly();\n const editorState = getActiveEditorState();\n if (selection !== null) {\n {\n if (Object.isFrozen(selection)) {\n {\n throw Error(`$setSelection called on frozen selection object. Ensure selection is cloned before passing in.`);\n }\n }\n }\n selection.dirty = true;\n selection.setCachedNodes(null);\n }\n editorState._selection = selection;\n}\nfunction $flushMutations() {\n errorOnReadOnly();\n const editor = getActiveEditor();\n $flushRootMutations(editor);\n}\nfunction $getNodeFromDOM(dom) {\n const editor = getActiveEditor();\n const nodeKey = getNodeKeyFromDOM(dom, editor);\n if (nodeKey === null) {\n const rootElement = editor.getRootElement();\n if (dom === rootElement) {\n return $getNodeByKey('root');\n }\n return null;\n }\n return $getNodeByKey(nodeKey);\n}\nfunction getTextNodeOffset(node, moveSelectionToEnd) {\n return moveSelectionToEnd ? node.getTextContentSize() : 0;\n}\nfunction getNodeKeyFromDOM(\n// Note that node here refers to a DOM Node, not an Lexical Node\ndom, editor) {\n let node = dom;\n while (node != null) {\n // @ts-ignore We intentionally add this to the Node.\n const key = node[`__lexicalKey_${editor._key}`];\n if (key !== undefined) {\n return key;\n }\n node = getParentElement(node);\n }\n return null;\n}\nfunction doesContainGrapheme(str) {\n return /[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g.test(str);\n}\nfunction getEditorsToPropagate(editor) {\n const editorsToPropagate = [];\n let currentEditor = editor;\n while (currentEditor !== null) {\n editorsToPropagate.push(currentEditor);\n currentEditor = currentEditor._parentEditor;\n }\n return editorsToPropagate;\n}\nfunction createUID() {\n return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);\n}\nfunction getAnchorTextFromDOM(anchorNode) {\n if (anchorNode.nodeType === DOM_TEXT_TYPE) {\n return anchorNode.nodeValue;\n }\n return null;\n}\nfunction $updateSelectedTextFromDOM(isCompositionEnd, editor, data) {\n // Update the text content with the latest composition text\n const domSelection = getDOMSelection(editor._window);\n if (domSelection === null) {\n return;\n }\n const anchorNode = domSelection.anchorNode;\n let {\n anchorOffset,\n focusOffset\n } = domSelection;\n if (anchorNode !== null) {\n let textContent = getAnchorTextFromDOM(anchorNode);\n const node = $getNearestNodeFromDOMNode(anchorNode);\n if (textContent !== null && $isTextNode(node)) {\n // Data is intentionally truthy, as we check for boolean, null and empty string.\n if (textContent === COMPOSITION_SUFFIX && data) {\n const offset = data.length;\n textContent = data;\n anchorOffset = offset;\n focusOffset = offset;\n }\n if (textContent !== null) {\n $updateTextNodeFromDOMContent(node, textContent, anchorOffset, focusOffset, isCompositionEnd);\n }\n }\n }\n}\nfunction $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focusOffset, compositionEnd) {\n let node = textNode;\n if (node.isAttached() && (compositionEnd || !node.isDirty())) {\n const isComposing = node.isComposing();\n let normalizedTextContent = textContent;\n if ((isComposing || compositionEnd) && textContent[textContent.length - 1] === COMPOSITION_SUFFIX) {\n normalizedTextContent = textContent.slice(0, -1);\n }\n const prevTextContent = node.getTextContent();\n if (compositionEnd || normalizedTextContent !== prevTextContent) {\n if (normalizedTextContent === '') {\n $setCompositionKey(null);\n if (!IS_SAFARI && !IS_IOS && !IS_APPLE_WEBKIT) {\n // For composition (mainly Android), we have to remove the node on a later update\n const editor = getActiveEditor();\n setTimeout(() => {\n editor.update(() => {\n if (node.isAttached()) {\n node.remove();\n }\n });\n }, 20);\n } else {\n node.remove();\n }\n return;\n }\n const parent = node.getParent();\n const prevSelection = $getPreviousSelection();\n const prevTextContentSize = node.getTextContentSize();\n const compositionKey = $getCompositionKey();\n const nodeKey = node.getKey();\n if (node.isToken() || compositionKey !== null && nodeKey === compositionKey && !isComposing ||\n // Check if character was added at the start or boundaries when not insertable, and we need\n // to clear this input from occurring as that action wasn't permitted.\n $isRangeSelection(prevSelection) && (parent !== null && !parent.canInsertTextBefore() && prevSelection.anchor.offset === 0 || prevSelection.anchor.key === textNode.__key && prevSelection.anchor.offset === 0 && !node.canInsertTextBefore() && !isComposing || prevSelection.focus.key === textNode.__key && prevSelection.focus.offset === prevTextContentSize && !node.canInsertTextAfter() && !isComposing)) {\n node.markDirty();\n return;\n }\n const selection = $getSelection();\n if (!$isRangeSelection(selection) || anchorOffset === null || focusOffset === null) {\n node.setTextContent(normalizedTextContent);\n return;\n }\n selection.setTextNodeRange(node, anchorOffset, node, focusOffset);\n if (node.isSegmented()) {\n const originalTextContent = node.getTextContent();\n const replacement = $createTextNode(originalTextContent);\n node.replace(replacement);\n node = replacement;\n }\n node.setTextContent(normalizedTextContent);\n }\n }\n}\nfunction $previousSiblingDoesNotAcceptText(node) {\n const previousSibling = node.getPreviousSibling();\n return ($isTextNode(previousSibling) || $isElementNode(previousSibling) && previousSibling.isInline()) && !previousSibling.canInsertTextAfter();\n}\n\n// This function is connected to $shouldPreventDefaultAndInsertText and determines whether the\n// TextNode boundaries are writable or we should use the previous/next sibling instead. For example,\n// in the case of a LinkNode, boundaries are not writable.\nfunction $shouldInsertTextAfterOrBeforeTextNode(selection, node) {\n if (node.isSegmented()) {\n return true;\n }\n if (!selection.isCollapsed()) {\n return false;\n }\n const offset = selection.anchor.offset;\n const parent = node.getParentOrThrow();\n const isToken = node.isToken();\n if (offset === 0) {\n return !node.canInsertTextBefore() || !parent.canInsertTextBefore() && !node.isComposing() || isToken || $previousSiblingDoesNotAcceptText(node);\n } else if (offset === node.getTextContentSize()) {\n return !node.canInsertTextAfter() || !parent.canInsertTextAfter() && !node.isComposing() || isToken;\n } else {\n return false;\n }\n}\nfunction isTab(key, altKey, ctrlKey, metaKey) {\n return key === 'Tab' && !altKey && !ctrlKey && !metaKey;\n}\nfunction isBold(key, altKey, metaKey, ctrlKey) {\n return key.toLowerCase() === 'b' && !altKey && controlOrMeta(metaKey, ctrlKey);\n}\nfunction isItalic(key, altKey, metaKey, ctrlKey) {\n return key.toLowerCase() === 'i' && !altKey && controlOrMeta(metaKey, ctrlKey);\n}\nfunction isUnderline(key, altKey, metaKey, ctrlKey) {\n return key.toLowerCase() === 'u' && !altKey && controlOrMeta(metaKey, ctrlKey);\n}\nfunction isParagraph(key, shiftKey) {\n return isReturn(key) && !shiftKey;\n}\nfunction isLineBreak(key, shiftKey) {\n return isReturn(key) && shiftKey;\n}\n\n// Inserts a new line after the selection\n\nfunction isOpenLineBreak(key, ctrlKey) {\n // 79 = KeyO\n return IS_APPLE && ctrlKey && key.toLowerCase() === 'o';\n}\nfunction isDeleteWordBackward(key, altKey, ctrlKey) {\n return isBackspace(key) && (IS_APPLE ? altKey : ctrlKey);\n}\nfunction isDeleteWordForward(key, altKey, ctrlKey) {\n return isDelete(key) && (IS_APPLE ? altKey : ctrlKey);\n}\nfunction isDeleteLineBackward(key, metaKey) {\n return IS_APPLE && metaKey && isBackspace(key);\n}\nfunction isDeleteLineForward(key, metaKey) {\n return IS_APPLE && metaKey && isDelete(key);\n}\nfunction isDeleteBackward(key, altKey, metaKey, ctrlKey) {\n if (IS_APPLE) {\n if (altKey || metaKey) {\n return false;\n }\n return isBackspace(key) || key.toLowerCase() === 'h' && ctrlKey;\n }\n if (ctrlKey || altKey || metaKey) {\n return false;\n }\n return isBackspace(key);\n}\nfunction isDeleteForward(key, ctrlKey, shiftKey, altKey, metaKey) {\n if (IS_APPLE) {\n if (shiftKey || altKey || metaKey) {\n return false;\n }\n return isDelete(key) || key.toLowerCase() === 'd' && ctrlKey;\n }\n if (ctrlKey || altKey || metaKey) {\n return false;\n }\n return isDelete(key);\n}\nfunction isUndo(key, shiftKey, metaKey, ctrlKey) {\n return key.toLowerCase() === 'z' && !shiftKey && controlOrMeta(metaKey, ctrlKey);\n}\nfunction isRedo(key, shiftKey, metaKey, ctrlKey) {\n if (IS_APPLE) {\n return key.toLowerCase() === 'z' && metaKey && shiftKey;\n }\n return key.toLowerCase() === 'y' && ctrlKey || key.toLowerCase() === 'z' && ctrlKey && shiftKey;\n}\nfunction isCopy(key, shiftKey, metaKey, ctrlKey) {\n if (shiftKey) {\n return false;\n }\n if (key.toLowerCase() === 'c') {\n return IS_APPLE ? metaKey : ctrlKey;\n }\n return false;\n}\nfunction isCut(key, shiftKey, metaKey, ctrlKey) {\n if (shiftKey) {\n return false;\n }\n if (key.toLowerCase() === 'x') {\n return IS_APPLE ? metaKey : ctrlKey;\n }\n return false;\n}\nfunction isArrowLeft(key) {\n return key === 'ArrowLeft';\n}\nfunction isArrowRight(key) {\n return key === 'ArrowRight';\n}\nfunction isArrowUp(key) {\n return key === 'ArrowUp';\n}\nfunction isArrowDown(key) {\n return key === 'ArrowDown';\n}\nfunction isMoveBackward(key, ctrlKey, altKey, metaKey) {\n return isArrowLeft(key) && !ctrlKey && !metaKey && !altKey;\n}\nfunction isMoveToStart(key, ctrlKey, shiftKey, altKey, metaKey) {\n return isArrowLeft(key) && !altKey && !shiftKey && (ctrlKey || metaKey);\n}\nfunction isMoveForward(key, ctrlKey, altKey, metaKey) {\n return isArrowRight(key) && !ctrlKey && !metaKey && !altKey;\n}\nfunction isMoveToEnd(key, ctrlKey, shiftKey, altKey, metaKey) {\n return isArrowRight(key) && !altKey && !shiftKey && (ctrlKey || metaKey);\n}\nfunction isMoveUp(key, ctrlKey, metaKey) {\n return isArrowUp(key) && !ctrlKey && !metaKey;\n}\nfunction isMoveDown(key, ctrlKey, metaKey) {\n return isArrowDown(key) && !ctrlKey && !metaKey;\n}\nfunction isModifier(ctrlKey, shiftKey, altKey, metaKey) {\n return ctrlKey || shiftKey || altKey || metaKey;\n}\nfunction isSpace(key) {\n return key === ' ';\n}\nfunction controlOrMeta(metaKey, ctrlKey) {\n if (IS_APPLE) {\n return metaKey;\n }\n return ctrlKey;\n}\nfunction isReturn(key) {\n return key === 'Enter';\n}\nfunction isBackspace(key) {\n return key === 'Backspace';\n}\nfunction isEscape(key) {\n return key === 'Escape';\n}\nfunction isDelete(key) {\n return key === 'Delete';\n}\nfunction isSelectAll(key, metaKey, ctrlKey) {\n return key.toLowerCase() === 'a' && controlOrMeta(metaKey, ctrlKey);\n}\nfunction $selectAll() {\n const root = $getRoot();\n const selection = root.select(0, root.getChildrenSize());\n $setSelection($normalizeSelection(selection));\n}\nfunction getCachedClassNameArray(classNamesTheme, classNameThemeType) {\n if (classNamesTheme.__lexicalClassNameCache === undefined) {\n classNamesTheme.__lexicalClassNameCache = {};\n }\n const classNamesCache = classNamesTheme.__lexicalClassNameCache;\n const cachedClassNames = classNamesCache[classNameThemeType];\n if (cachedClassNames !== undefined) {\n return cachedClassNames;\n }\n const classNames = classNamesTheme[classNameThemeType];\n // As we're using classList, we need\n // to handle className tokens that have spaces.\n // The easiest way to do this to convert the\n // className tokens to an array that can be\n // applied to classList.add()/remove().\n if (typeof classNames === 'string') {\n const classNamesArr = normalizeClassNames(classNames);\n classNamesCache[classNameThemeType] = classNamesArr;\n return classNamesArr;\n }\n return classNames;\n}\nfunction setMutatedNode(mutatedNodes, registeredNodes, mutationListeners, node, mutation) {\n if (mutationListeners.size === 0) {\n return;\n }\n const nodeType = node.__type;\n const nodeKey = node.__key;\n const registeredNode = registeredNodes.get(nodeType);\n if (registeredNode === undefined) {\n {\n throw Error(`Type ${nodeType} not in registeredNodes`);\n }\n }\n const klass = registeredNode.klass;\n let mutatedNodesByType = mutatedNodes.get(klass);\n if (mutatedNodesByType === undefined) {\n mutatedNodesByType = new Map();\n mutatedNodes.set(klass, mutatedNodesByType);\n }\n const prevMutation = mutatedNodesByType.get(nodeKey);\n // If the node has already been \"destroyed\", yet we are\n // re-making it, then this means a move likely happened.\n // We should change the mutation to be that of \"updated\"\n // instead.\n const isMove = prevMutation === 'destroyed' && mutation === 'created';\n if (prevMutation === undefined || isMove) {\n mutatedNodesByType.set(nodeKey, isMove ? 'updated' : mutation);\n }\n}\nfunction $nodesOfType(klass) {\n const klassType = klass.getType();\n const editorState = getActiveEditorState();\n if (editorState._readOnly) {\n const nodes = getCachedTypeToNodeMap(editorState).get(klassType);\n return nodes ? Array.from(nodes.values()) : [];\n }\n const nodes = editorState._nodeMap;\n const nodesOfType = [];\n for (const [, node] of nodes) {\n if (node instanceof klass && node.__type === klassType && node.isAttached()) {\n nodesOfType.push(node);\n }\n }\n return nodesOfType;\n}\nfunction resolveElement(element, isBackward, focusOffset) {\n const parent = element.getParent();\n let offset = focusOffset;\n let block = element;\n if (parent !== null) {\n if (isBackward && focusOffset === 0) {\n offset = block.getIndexWithinParent();\n block = parent;\n } else if (!isBackward && focusOffset === block.getChildrenSize()) {\n offset = block.getIndexWithinParent() + 1;\n block = parent;\n }\n }\n return block.getChildAtIndex(isBackward ? offset - 1 : offset);\n}\nfunction $getAdjacentNode(focus, isBackward) {\n const focusOffset = focus.offset;\n if (focus.type === 'element') {\n const block = focus.getNode();\n return resolveElement(block, isBackward, focusOffset);\n } else {\n const focusNode = focus.getNode();\n if (isBackward && focusOffset === 0 || !isBackward && focusOffset === focusNode.getTextContentSize()) {\n const possibleNode = isBackward ? focusNode.getPreviousSibling() : focusNode.getNextSibling();\n if (possibleNode === null) {\n return resolveElement(focusNode.getParentOrThrow(), isBackward, focusNode.getIndexWithinParent() + (isBackward ? 0 : 1));\n }\n return possibleNode;\n }\n }\n return null;\n}\nfunction isFirefoxClipboardEvents(editor) {\n const event = getWindow(editor).event;\n const inputType = event && event.inputType;\n return inputType === 'insertFromPaste' || inputType === 'insertFromPasteAsQuotation';\n}\nfunction dispatchCommand(editor, command, payload) {\n return triggerCommandListeners(editor, command, payload);\n}\nfunction $textContentRequiresDoubleLinebreakAtEnd(node) {\n return !$isRootNode(node) && !node.isLastChild() && !node.isInline();\n}\nfunction getElementByKeyOrThrow(editor, key) {\n const element = editor._keyToDOMMap.get(key);\n if (element === undefined) {\n {\n throw Error(`Reconciliation: could not find DOM element for node key ${key}`);\n }\n }\n return element;\n}\nfunction getParentElement(node) {\n const parentElement = node.assignedSlot || node.parentElement;\n return parentElement !== null && parentElement.nodeType === 11 ? parentElement.host : parentElement;\n}\nfunction scrollIntoViewIfNeeded(editor, selectionRect, rootElement) {\n const doc = rootElement.ownerDocument;\n const defaultView = doc.defaultView;\n if (defaultView === null) {\n return;\n }\n let {\n top: currentTop,\n bottom: currentBottom\n } = selectionRect;\n let targetTop = 0;\n let targetBottom = 0;\n let element = rootElement;\n while (element !== null) {\n const isBodyElement = element === doc.body;\n if (isBodyElement) {\n targetTop = 0;\n targetBottom = getWindow(editor).innerHeight;\n } else {\n const targetRect = element.getBoundingClientRect();\n targetTop = targetRect.top;\n targetBottom = targetRect.bottom;\n }\n let diff = 0;\n if (currentTop < targetTop) {\n diff = -(targetTop - currentTop);\n } else if (currentBottom > targetBottom) {\n diff = currentBottom - targetBottom;\n }\n if (diff !== 0) {\n if (isBodyElement) {\n // Only handles scrolling of Y axis\n defaultView.scrollBy(0, diff);\n } else {\n const scrollTop = element.scrollTop;\n element.scrollTop += diff;\n const yOffset = element.scrollTop - scrollTop;\n currentTop -= yOffset;\n currentBottom -= yOffset;\n }\n }\n if (isBodyElement) {\n break;\n }\n element = getParentElement(element);\n }\n}\nfunction $hasUpdateTag(tag) {\n const editor = getActiveEditor();\n return editor._updateTags.has(tag);\n}\nfunction $addUpdateTag(tag) {\n errorOnReadOnly();\n const editor = getActiveEditor();\n editor._updateTags.add(tag);\n}\nfunction $maybeMoveChildrenSelectionToParent(parentNode) {\n const selection = $getSelection();\n if (!$isRangeSelection(selection) || !$isElementNode(parentNode)) {\n return selection;\n }\n const {\n anchor,\n focus\n } = selection;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n if ($hasAncestor(anchorNode, parentNode)) {\n anchor.set(parentNode.__key, 0, 'element');\n }\n if ($hasAncestor(focusNode, parentNode)) {\n focus.set(parentNode.__key, 0, 'element');\n }\n return selection;\n}\nfunction $hasAncestor(child, targetNode) {\n let parent = child.getParent();\n while (parent !== null) {\n if (parent.is(targetNode)) {\n return true;\n }\n parent = parent.getParent();\n }\n return false;\n}\nfunction getDefaultView(domElem) {\n const ownerDoc = domElem.ownerDocument;\n return ownerDoc && ownerDoc.defaultView || null;\n}\nfunction getWindow(editor) {\n const windowObj = editor._window;\n if (windowObj === null) {\n {\n throw Error(`window object not found`);\n }\n }\n return windowObj;\n}\nfunction $isInlineElementOrDecoratorNode(node) {\n return $isElementNode(node) && node.isInline() || $isDecoratorNode(node) && node.isInline();\n}\nfunction $getNearestRootOrShadowRoot(node) {\n let parent = node.getParentOrThrow();\n while (parent !== null) {\n if ($isRootOrShadowRoot(parent)) {\n return parent;\n }\n parent = parent.getParentOrThrow();\n }\n return parent;\n}\nfunction $isRootOrShadowRoot(node) {\n return $isRootNode(node) || $isElementNode(node) && node.isShadowRoot();\n}\n\n/**\n * Returns a shallow clone of node with a new key\n *\n * @param node - The node to be copied.\n * @returns The copy of the node.\n */\nfunction $copyNode(node) {\n const copy = node.constructor.clone(node);\n $setNodeKey(copy, null);\n return copy;\n}\nfunction $applyNodeReplacement(node) {\n const editor = getActiveEditor();\n const nodeType = node.constructor.getType();\n const registeredNode = editor._nodes.get(nodeType);\n if (registeredNode === undefined) {\n {\n throw Error(`$initializeNode failed. Ensure node has been registered to the editor. You can do this by passing the node class via the \"nodes\" array in the editor config.`);\n }\n }\n const replaceFunc = registeredNode.replace;\n if (replaceFunc !== null) {\n const replacementNode = replaceFunc(node);\n if (!(replacementNode instanceof node.constructor)) {\n {\n throw Error(`$initializeNode failed. Ensure replacement node is a subclass of the original node.`);\n }\n }\n return replacementNode;\n }\n return node;\n}\nfunction errorOnInsertTextNodeOnRoot(node, insertNode) {\n const parentNode = node.getParent();\n if ($isRootNode(parentNode) && !$isElementNode(insertNode) && !$isDecoratorNode(insertNode)) {\n {\n throw Error(`Only element or decorator nodes can be inserted in to the root node`);\n }\n }\n}\nfunction $getNodeByKeyOrThrow(key) {\n const node = $getNodeByKey(key);\n if (node === null) {\n {\n throw Error(`Expected node with key ${key} to exist but it's not in the nodeMap.`);\n }\n }\n return node;\n}\nfunction createBlockCursorElement(editorConfig) {\n const theme = editorConfig.theme;\n const element = document.createElement('div');\n element.contentEditable = 'false';\n element.setAttribute('data-lexical-cursor', 'true');\n let blockCursorTheme = theme.blockCursor;\n if (blockCursorTheme !== undefined) {\n if (typeof blockCursorTheme === 'string') {\n const classNamesArr = normalizeClassNames(blockCursorTheme);\n // @ts-expect-error: intentional\n blockCursorTheme = theme.blockCursor = classNamesArr;\n }\n if (blockCursorTheme !== undefined) {\n element.classList.add(...blockCursorTheme);\n }\n }\n return element;\n}\nfunction needsBlockCursor(node) {\n return ($isDecoratorNode(node) || $isElementNode(node) && !node.canBeEmpty()) && !node.isInline();\n}\nfunction removeDOMBlockCursorElement(blockCursorElement, editor, rootElement) {\n rootElement.style.removeProperty('caret-color');\n editor._blockCursorElement = null;\n const parentElement = blockCursorElement.parentElement;\n if (parentElement !== null) {\n parentElement.removeChild(blockCursorElement);\n }\n}\nfunction updateDOMBlockCursorElement(editor, rootElement, nextSelection) {\n let blockCursorElement = editor._blockCursorElement;\n if ($isRangeSelection(nextSelection) && nextSelection.isCollapsed() && nextSelection.anchor.type === 'element' && rootElement.contains(document.activeElement)) {\n const anchor = nextSelection.anchor;\n const elementNode = anchor.getNode();\n const offset = anchor.offset;\n const elementNodeSize = elementNode.getChildrenSize();\n let isBlockCursor = false;\n let insertBeforeElement = null;\n if (offset === elementNodeSize) {\n const child = elementNode.getChildAtIndex(offset - 1);\n if (needsBlockCursor(child)) {\n isBlockCursor = true;\n }\n } else {\n const child = elementNode.getChildAtIndex(offset);\n if (needsBlockCursor(child)) {\n const sibling = child.getPreviousSibling();\n if (sibling === null || needsBlockCursor(sibling)) {\n isBlockCursor = true;\n insertBeforeElement = editor.getElementByKey(child.__key);\n }\n }\n }\n if (isBlockCursor) {\n const elementDOM = editor.getElementByKey(elementNode.__key);\n if (blockCursorElement === null) {\n editor._blockCursorElement = blockCursorElement = createBlockCursorElement(editor._config);\n }\n rootElement.style.caretColor = 'transparent';\n if (insertBeforeElement === null) {\n elementDOM.appendChild(blockCursorElement);\n } else {\n elementDOM.insertBefore(blockCursorElement, insertBeforeElement);\n }\n return;\n }\n }\n // Remove cursor\n if (blockCursorElement !== null) {\n removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);\n }\n}\nfunction getDOMSelection(targetWindow) {\n return !CAN_USE_DOM ? null : (targetWindow || window).getSelection();\n}\nfunction $splitNode(node, offset) {\n let startNode = node.getChildAtIndex(offset);\n if (startNode == null) {\n startNode = node;\n }\n if (!!$isRootOrShadowRoot(node)) {\n throw Error(`Can not call $splitNode() on root element`);\n }\n const recurse = currentNode => {\n const parent = currentNode.getParentOrThrow();\n const isParentRoot = $isRootOrShadowRoot(parent);\n // The node we start split from (leaf) is moved, but its recursive\n // parents are copied to create separate tree\n const nodeToMove = currentNode === startNode && !isParentRoot ? currentNode : $copyNode(currentNode);\n if (isParentRoot) {\n if (!($isElementNode(currentNode) && $isElementNode(nodeToMove))) {\n throw Error(`Children of a root must be ElementNode`);\n }\n currentNode.insertAfter(nodeToMove);\n return [currentNode, nodeToMove, nodeToMove];\n } else {\n const [leftTree, rightTree, newParent] = recurse(parent);\n const nextSiblings = currentNode.getNextSiblings();\n newParent.append(nodeToMove, ...nextSiblings);\n return [leftTree, rightTree, nodeToMove];\n }\n };\n const [leftTree, rightTree] = recurse(startNode);\n return [leftTree, rightTree];\n}\n\n/**\n * @param x - The element being tested\n * @returns Returns true if x is an HTML anchor tag, false otherwise\n */\nfunction isHTMLAnchorElement(x) {\n return isHTMLElement(x) && x.tagName === 'A';\n}\n\n/**\n * @param x - The element being testing\n * @returns Returns true if x is an HTML element, false otherwise.\n */\nfunction isHTMLElement(x) {\n // @ts-ignore-next-line - strict check on nodeType here should filter out non-Element EventTarget implementors\n return x.nodeType === 1;\n}\n\n/**\n *\n * @param node - the Dom Node to check\n * @returns if the Dom Node is an inline node\n */\nfunction isInlineDomNode(node) {\n const inlineNodes = new RegExp(/^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var|#text)$/, 'i');\n return node.nodeName.match(inlineNodes) !== null;\n}\n\n/**\n *\n * @param node - the Dom Node to check\n * @returns if the Dom Node is a block node\n */\nfunction isBlockDomNode(node) {\n const blockNodes = new RegExp(/^(address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hr|li|main|nav|noscript|ol|p|pre|section|table|td|tfoot|ul|video)$/, 'i');\n return node.nodeName.match(blockNodes) !== null;\n}\n\n/**\n * This function is for internal use of the library.\n * Please do not use it as it may change in the future.\n */\nfunction INTERNAL_$isBlock(node) {\n if ($isRootNode(node) || $isDecoratorNode(node) && !node.isInline()) {\n return true;\n }\n if (!$isElementNode(node) || $isRootOrShadowRoot(node)) {\n return false;\n }\n const firstChild = node.getFirstChild();\n const isLeafElement = firstChild === null || $isLineBreakNode(firstChild) || $isTextNode(firstChild) || firstChild.isInline();\n return !node.isInline() && node.canBeEmpty() !== false && isLeafElement;\n}\nfunction $getAncestor(node, predicate) {\n let parent = node;\n while (parent !== null && parent.getParent() !== null && !predicate(parent)) {\n parent = parent.getParentOrThrow();\n }\n return predicate(parent) ? parent : null;\n}\n\n/**\n * Utility function for accessing current active editor instance.\n * @returns Current active editor\n */\nfunction $getEditor() {\n return getActiveEditor();\n}\n\n/** @internal */\n\n/**\n * @internal\n * Compute a cached Map of node type to nodes for a frozen EditorState\n */\nconst cachedNodeMaps = new WeakMap();\nconst EMPTY_TYPE_TO_NODE_MAP = new Map();\nfunction getCachedTypeToNodeMap(editorState) {\n // If this is a new Editor it may have a writable this._editorState\n // with only a 'root' entry.\n if (!editorState._readOnly && editorState.isEmpty()) {\n return EMPTY_TYPE_TO_NODE_MAP;\n }\n if (!editorState._readOnly) {\n throw Error(`getCachedTypeToNodeMap called with a writable EditorState`);\n }\n let typeToNodeMap = cachedNodeMaps.get(editorState);\n if (!typeToNodeMap) {\n typeToNodeMap = new Map();\n cachedNodeMaps.set(editorState, typeToNodeMap);\n for (const [nodeKey, node] of editorState._nodeMap) {\n const nodeType = node.__type;\n let nodeMap = typeToNodeMap.get(nodeType);\n if (!nodeMap) {\n nodeMap = new Map();\n typeToNodeMap.set(nodeType, nodeMap);\n }\n nodeMap.set(nodeKey, node);\n }\n }\n return typeToNodeMap;\n}\n\n/**\n * Returns a clone of a node using `node.constructor.clone()` followed by\n * `clone.afterCloneFrom(node)`. The resulting clone must have the same key,\n * parent/next/prev pointers, and other properties that are not set by\n * `node.constructor.clone` (format, style, etc.). This is primarily used by\n * {@link LexicalNode.getWritable} to create a writable version of an\n * existing node. The clone is the same logical node as the original node,\n * do not try and use this function to duplicate or copy an existing node.\n *\n * Does not mutate the EditorState.\n * @param node - The node to be cloned.\n * @returns The clone of the node.\n */\nfunction $cloneWithProperties(latestNode) {\n const constructor = latestNode.constructor;\n const mutableNode = constructor.clone(latestNode);\n mutableNode.afterCloneFrom(latestNode);\n {\n if (!(mutableNode.__key === latestNode.__key)) {\n throw Error(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') did not return a node with the same key, make sure to specify node.__key as the last argument to the constructor`);\n }\n if (!(mutableNode.__parent === latestNode.__parent && mutableNode.__next === latestNode.__next && mutableNode.__prev === latestNode.__prev)) {\n throw Error(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') overrided afterCloneFrom but did not call super.afterCloneFrom(prevNode)`);\n }\n }\n return mutableNode;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction $garbageCollectDetachedDecorators(editor, pendingEditorState) {\n const currentDecorators = editor._decorators;\n const pendingDecorators = editor._pendingDecorators;\n let decorators = pendingDecorators || currentDecorators;\n const nodeMap = pendingEditorState._nodeMap;\n let key;\n for (key in decorators) {\n if (!nodeMap.has(key)) {\n if (decorators === currentDecorators) {\n decorators = cloneDecorators(editor);\n }\n delete decorators[key];\n }\n }\n}\nfunction $garbageCollectDetachedDeepChildNodes(node, parentKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes) {\n let child = node.getFirstChild();\n while (child !== null) {\n const childKey = child.__key;\n // TODO Revise condition below, redundant? LexicalNode already cleans up children when moving Nodes\n if (child.__parent === parentKey) {\n if ($isElementNode(child)) {\n $garbageCollectDetachedDeepChildNodes(child, childKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes);\n }\n\n // If we have created a node and it was dereferenced, then also\n // remove it from out dirty nodes Set.\n if (!prevNodeMap.has(childKey)) {\n dirtyNodes.delete(childKey);\n }\n nodeMapDelete.push(childKey);\n }\n child = child.getNextSibling();\n }\n}\nfunction $garbageCollectDetachedNodes(prevEditorState, editorState, dirtyLeaves, dirtyElements) {\n const prevNodeMap = prevEditorState._nodeMap;\n const nodeMap = editorState._nodeMap;\n // Store dirtyElements in a queue for later deletion; deleting dirty subtrees too early will\n // hinder accessing .__next on child nodes\n const nodeMapDelete = [];\n for (const [nodeKey] of dirtyElements) {\n const node = nodeMap.get(nodeKey);\n if (node !== undefined) {\n // Garbage collect node and its children if they exist\n if (!node.isAttached()) {\n if ($isElementNode(node)) {\n $garbageCollectDetachedDeepChildNodes(node, nodeKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyElements);\n }\n // If we have created a node and it was dereferenced, then also\n // remove it from out dirty nodes Set.\n if (!prevNodeMap.has(nodeKey)) {\n dirtyElements.delete(nodeKey);\n }\n nodeMapDelete.push(nodeKey);\n }\n }\n }\n for (const nodeKey of nodeMapDelete) {\n nodeMap.delete(nodeKey);\n }\n for (const nodeKey of dirtyLeaves) {\n const node = nodeMap.get(nodeKey);\n if (node !== undefined && !node.isAttached()) {\n if (!prevNodeMap.has(nodeKey)) {\n dirtyLeaves.delete(nodeKey);\n }\n nodeMap.delete(nodeKey);\n }\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nlet subTreeTextContent = '';\nlet subTreeDirectionedTextContent = '';\nlet subTreeTextFormat = null;\nlet subTreeTextStyle = '';\nlet editorTextContent = '';\nlet activeEditorConfig;\nlet activeEditor$1;\nlet activeEditorNodes;\nlet treatAllNodesAsDirty = false;\nlet activeEditorStateReadOnly = false;\nlet activeMutationListeners;\nlet activeTextDirection = null;\nlet activeDirtyElements;\nlet activeDirtyLeaves;\nlet activePrevNodeMap;\nlet activeNextNodeMap;\nlet activePrevKeyToDOMMap;\nlet mutatedNodes;\nfunction destroyNode(key, parentDOM) {\n const node = activePrevNodeMap.get(key);\n if (parentDOM !== null) {\n const dom = getPrevElementByKeyOrThrow(key);\n if (dom.parentNode === parentDOM) {\n parentDOM.removeChild(dom);\n }\n }\n\n // This logic is really important, otherwise we will leak DOM nodes\n // when their corresponding LexicalNodes are removed from the editor state.\n if (!activeNextNodeMap.has(key)) {\n activeEditor$1._keyToDOMMap.delete(key);\n }\n if ($isElementNode(node)) {\n const children = createChildrenArray(node, activePrevNodeMap);\n destroyChildren(children, 0, children.length - 1, null);\n }\n if (node !== undefined) {\n setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, node, 'destroyed');\n }\n}\nfunction destroyChildren(children, _startIndex, endIndex, dom) {\n let startIndex = _startIndex;\n for (; startIndex <= endIndex; ++startIndex) {\n const child = children[startIndex];\n if (child !== undefined) {\n destroyNode(child, dom);\n }\n }\n}\nfunction setTextAlign(domStyle, value) {\n domStyle.setProperty('text-align', value);\n}\nconst DEFAULT_INDENT_VALUE = '40px';\nfunction setElementIndent(dom, indent) {\n const indentClassName = activeEditorConfig.theme.indent;\n if (typeof indentClassName === 'string') {\n const elementHasClassName = dom.classList.contains(indentClassName);\n if (indent > 0 && !elementHasClassName) {\n dom.classList.add(indentClassName);\n } else if (indent < 1 && elementHasClassName) {\n dom.classList.remove(indentClassName);\n }\n }\n const indentationBaseValue = getComputedStyle(dom).getPropertyValue('--lexical-indent-base-value') || DEFAULT_INDENT_VALUE;\n dom.style.setProperty('padding-inline-start', indent === 0 ? '' : `calc(${indent} * ${indentationBaseValue})`);\n}\nfunction setElementFormat(dom, format) {\n const domStyle = dom.style;\n if (format === 0) {\n setTextAlign(domStyle, '');\n } else if (format === IS_ALIGN_LEFT) {\n setTextAlign(domStyle, 'left');\n } else if (format === IS_ALIGN_CENTER) {\n setTextAlign(domStyle, 'center');\n } else if (format === IS_ALIGN_RIGHT) {\n setTextAlign(domStyle, 'right');\n } else if (format === IS_ALIGN_JUSTIFY) {\n setTextAlign(domStyle, 'justify');\n } else if (format === IS_ALIGN_START) {\n setTextAlign(domStyle, 'start');\n } else if (format === IS_ALIGN_END) {\n setTextAlign(domStyle, 'end');\n }\n}\nfunction $createNode(key, parentDOM, insertDOM) {\n const node = activeNextNodeMap.get(key);\n if (node === undefined) {\n {\n throw Error(`createNode: node does not exist in nodeMap`);\n }\n }\n const dom = node.createDOM(activeEditorConfig, activeEditor$1);\n storeDOMWithKey(key, dom, activeEditor$1);\n\n // This helps preserve the text, and stops spell check tools from\n // merging or break the spans (which happens if they are missing\n // this attribute).\n if ($isTextNode(node)) {\n dom.setAttribute('data-lexical-text', 'true');\n } else if ($isDecoratorNode(node)) {\n dom.setAttribute('data-lexical-decorator', 'true');\n }\n if ($isElementNode(node)) {\n const indent = node.__indent;\n const childrenSize = node.__size;\n if (indent !== 0) {\n setElementIndent(dom, indent);\n }\n if (childrenSize !== 0) {\n const endIndex = childrenSize - 1;\n const children = createChildrenArray(node, activeNextNodeMap);\n $createChildrenWithDirection(children, endIndex, node, dom);\n }\n const format = node.__format;\n if (format !== 0) {\n setElementFormat(dom, format);\n }\n if (!node.isInline()) {\n reconcileElementTerminatingLineBreak(null, node, dom);\n }\n if ($textContentRequiresDoubleLinebreakAtEnd(node)) {\n subTreeTextContent += DOUBLE_LINE_BREAK;\n editorTextContent += DOUBLE_LINE_BREAK;\n }\n } else {\n const text = node.getTextContent();\n if ($isDecoratorNode(node)) {\n const decorator = node.decorate(activeEditor$1, activeEditorConfig);\n if (decorator !== null) {\n reconcileDecorator(key, decorator);\n }\n // Decorators are always non editable\n dom.contentEditable = 'false';\n } else if ($isTextNode(node)) {\n if (!node.isDirectionless()) {\n subTreeDirectionedTextContent += text;\n }\n }\n subTreeTextContent += text;\n editorTextContent += text;\n }\n if (parentDOM !== null) {\n if (insertDOM != null) {\n parentDOM.insertBefore(dom, insertDOM);\n } else {\n // @ts-expect-error: internal field\n const possibleLineBreak = parentDOM.__lexicalLineBreak;\n if (possibleLineBreak != null) {\n parentDOM.insertBefore(dom, possibleLineBreak);\n } else {\n parentDOM.appendChild(dom);\n }\n }\n }\n {\n // Freeze the node in DEV to prevent accidental mutations\n Object.freeze(node);\n }\n setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, node, 'created');\n return dom;\n}\nfunction $createChildrenWithDirection(children, endIndex, element, dom) {\n const previousSubTreeDirectionedTextContent = subTreeDirectionedTextContent;\n subTreeDirectionedTextContent = '';\n $createChildren(children, element, 0, endIndex, dom, null);\n reconcileBlockDirection(element, dom);\n subTreeDirectionedTextContent = previousSubTreeDirectionedTextContent;\n}\nfunction $createChildren(children, element, _startIndex, endIndex, dom, insertDOM) {\n const previousSubTreeTextContent = subTreeTextContent;\n subTreeTextContent = '';\n let startIndex = _startIndex;\n for (; startIndex <= endIndex; ++startIndex) {\n $createNode(children[startIndex], dom, insertDOM);\n const node = activeNextNodeMap.get(children[startIndex]);\n if (node !== null && $isTextNode(node)) {\n if (subTreeTextFormat === null) {\n subTreeTextFormat = node.getFormat();\n }\n if (subTreeTextStyle === '') {\n subTreeTextStyle = node.getStyle();\n }\n }\n }\n if ($textContentRequiresDoubleLinebreakAtEnd(element)) {\n subTreeTextContent += DOUBLE_LINE_BREAK;\n }\n // @ts-expect-error: internal field\n dom.__lexicalTextContent = subTreeTextContent;\n subTreeTextContent = previousSubTreeTextContent + subTreeTextContent;\n}\nfunction isLastChildLineBreakOrDecorator(childKey, nodeMap) {\n const node = nodeMap.get(childKey);\n return $isLineBreakNode(node) || $isDecoratorNode(node) && node.isInline();\n}\n\n// If we end an element with a LineBreakNode, then we need to add an additional
\nfunction reconcileElementTerminatingLineBreak(prevElement, nextElement, dom) {\n const prevLineBreak = prevElement !== null && (prevElement.__size === 0 || isLastChildLineBreakOrDecorator(prevElement.__last, activePrevNodeMap));\n const nextLineBreak = nextElement.__size === 0 || isLastChildLineBreakOrDecorator(nextElement.__last, activeNextNodeMap);\n if (prevLineBreak) {\n if (!nextLineBreak) {\n // @ts-expect-error: internal field\n const element = dom.__lexicalLineBreak;\n if (element != null) {\n try {\n dom.removeChild(element);\n } catch (error) {\n if (typeof error === 'object' && error != null) {\n const msg = `${error.toString()} Parent: ${dom.tagName}, child: ${element.tagName}.`;\n throw new Error(msg);\n } else {\n throw error;\n }\n }\n }\n\n // @ts-expect-error: internal field\n dom.__lexicalLineBreak = null;\n }\n } else if (nextLineBreak) {\n const element = document.createElement('br');\n // @ts-expect-error: internal field\n dom.__lexicalLineBreak = element;\n dom.appendChild(element);\n }\n}\nfunction reconcileParagraphFormat(element) {\n if ($isParagraphNode(element) && subTreeTextFormat != null && subTreeTextFormat !== element.__textFormat && !activeEditorStateReadOnly) {\n element.setTextFormat(subTreeTextFormat);\n element.setTextStyle(subTreeTextStyle);\n }\n}\nfunction reconcileParagraphStyle(element) {\n if ($isParagraphNode(element) && subTreeTextStyle !== '' && subTreeTextStyle !== element.__textStyle && !activeEditorStateReadOnly) {\n element.setTextStyle(subTreeTextStyle);\n }\n}\nfunction reconcileBlockDirection(element, dom) {\n const previousSubTreeDirectionTextContent =\n // @ts-expect-error: internal field\n dom.__lexicalDirTextContent;\n // @ts-expect-error: internal field\n const previousDirection = dom.__lexicalDir;\n if (previousSubTreeDirectionTextContent !== subTreeDirectionedTextContent || previousDirection !== activeTextDirection) {\n const hasEmptyDirectionedTextContent = subTreeDirectionedTextContent === '';\n const direction = hasEmptyDirectionedTextContent ? activeTextDirection : getTextDirection(subTreeDirectionedTextContent);\n if (direction !== previousDirection) {\n const classList = dom.classList;\n const theme = activeEditorConfig.theme;\n let previousDirectionTheme = previousDirection !== null ? theme[previousDirection] : undefined;\n let nextDirectionTheme = direction !== null ? theme[direction] : undefined;\n\n // Remove the old theme classes if they exist\n if (previousDirectionTheme !== undefined) {\n if (typeof previousDirectionTheme === 'string') {\n const classNamesArr = normalizeClassNames(previousDirectionTheme);\n previousDirectionTheme = theme[previousDirection] = classNamesArr;\n }\n\n // @ts-ignore: intentional\n classList.remove(...previousDirectionTheme);\n }\n if (direction === null || hasEmptyDirectionedTextContent && direction === 'ltr') {\n // Remove direction\n dom.removeAttribute('dir');\n } else {\n // Apply the new theme classes if they exist\n if (nextDirectionTheme !== undefined) {\n if (typeof nextDirectionTheme === 'string') {\n const classNamesArr = normalizeClassNames(nextDirectionTheme);\n // @ts-expect-error: intentional\n nextDirectionTheme = theme[direction] = classNamesArr;\n }\n if (nextDirectionTheme !== undefined) {\n classList.add(...nextDirectionTheme);\n }\n }\n\n // Update direction\n dom.dir = direction;\n }\n if (!activeEditorStateReadOnly) {\n const writableNode = element.getWritable();\n writableNode.__dir = direction;\n }\n }\n activeTextDirection = direction;\n // @ts-expect-error: internal field\n dom.__lexicalDirTextContent = subTreeDirectionedTextContent;\n // @ts-expect-error: internal field\n dom.__lexicalDir = direction;\n }\n}\nfunction $reconcileChildrenWithDirection(prevElement, nextElement, dom) {\n const previousSubTreeDirectionTextContent = subTreeDirectionedTextContent;\n subTreeDirectionedTextContent = '';\n subTreeTextFormat = null;\n subTreeTextStyle = '';\n $reconcileChildren(prevElement, nextElement, dom);\n reconcileBlockDirection(nextElement, dom);\n reconcileParagraphFormat(nextElement);\n reconcileParagraphStyle(nextElement);\n subTreeDirectionedTextContent = previousSubTreeDirectionTextContent;\n}\nfunction createChildrenArray(element, nodeMap) {\n const children = [];\n let nodeKey = element.__first;\n while (nodeKey !== null) {\n const node = nodeMap.get(nodeKey);\n if (node === undefined) {\n {\n throw Error(`createChildrenArray: node does not exist in nodeMap`);\n }\n }\n children.push(nodeKey);\n nodeKey = node.__next;\n }\n return children;\n}\nfunction $reconcileChildren(prevElement, nextElement, dom) {\n const previousSubTreeTextContent = subTreeTextContent;\n const prevChildrenSize = prevElement.__size;\n const nextChildrenSize = nextElement.__size;\n subTreeTextContent = '';\n if (prevChildrenSize === 1 && nextChildrenSize === 1) {\n const prevFirstChildKey = prevElement.__first;\n const nextFrstChildKey = nextElement.__first;\n if (prevFirstChildKey === nextFrstChildKey) {\n $reconcileNode(prevFirstChildKey, dom);\n } else {\n const lastDOM = getPrevElementByKeyOrThrow(prevFirstChildKey);\n const replacementDOM = $createNode(nextFrstChildKey, null, null);\n try {\n dom.replaceChild(replacementDOM, lastDOM);\n } catch (error) {\n if (typeof error === 'object' && error != null) {\n const msg = `${error.toString()} Parent: ${dom.tagName}, new child: {tag: ${replacementDOM.tagName} key: ${nextFrstChildKey}}, old child: {tag: ${lastDOM.tagName}, key: ${prevFirstChildKey}}.`;\n throw new Error(msg);\n } else {\n throw error;\n }\n }\n destroyNode(prevFirstChildKey, null);\n }\n const nextChildNode = activeNextNodeMap.get(nextFrstChildKey);\n if ($isTextNode(nextChildNode)) {\n if (subTreeTextFormat === null) {\n subTreeTextFormat = nextChildNode.getFormat();\n }\n if (subTreeTextStyle === '') {\n subTreeTextStyle = nextChildNode.getStyle();\n }\n }\n } else {\n const prevChildren = createChildrenArray(prevElement, activePrevNodeMap);\n const nextChildren = createChildrenArray(nextElement, activeNextNodeMap);\n if (prevChildrenSize === 0) {\n if (nextChildrenSize !== 0) {\n $createChildren(nextChildren, nextElement, 0, nextChildrenSize - 1, dom, null);\n }\n } else if (nextChildrenSize === 0) {\n if (prevChildrenSize !== 0) {\n // @ts-expect-error: internal field\n const lexicalLineBreak = dom.__lexicalLineBreak;\n const canUseFastPath = lexicalLineBreak == null;\n destroyChildren(prevChildren, 0, prevChildrenSize - 1, canUseFastPath ? null : dom);\n if (canUseFastPath) {\n // Fast path for removing DOM nodes\n dom.textContent = '';\n }\n }\n } else {\n $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChildrenSize, nextChildrenSize, dom);\n }\n }\n if ($textContentRequiresDoubleLinebreakAtEnd(nextElement)) {\n subTreeTextContent += DOUBLE_LINE_BREAK;\n }\n\n // @ts-expect-error: internal field\n dom.__lexicalTextContent = subTreeTextContent;\n subTreeTextContent = previousSubTreeTextContent + subTreeTextContent;\n}\nfunction $reconcileNode(key, parentDOM) {\n const prevNode = activePrevNodeMap.get(key);\n let nextNode = activeNextNodeMap.get(key);\n if (prevNode === undefined || nextNode === undefined) {\n {\n throw Error(`reconcileNode: prevNode or nextNode does not exist in nodeMap`);\n }\n }\n const isDirty = treatAllNodesAsDirty || activeDirtyLeaves.has(key) || activeDirtyElements.has(key);\n const dom = getElementByKeyOrThrow(activeEditor$1, key);\n\n // If the node key points to the same instance in both states\n // and isn't dirty, we just update the text content cache\n // and return the existing DOM Node.\n if (prevNode === nextNode && !isDirty) {\n if ($isElementNode(prevNode)) {\n // @ts-expect-error: internal field\n const previousSubTreeTextContent = dom.__lexicalTextContent;\n if (previousSubTreeTextContent !== undefined) {\n subTreeTextContent += previousSubTreeTextContent;\n editorTextContent += previousSubTreeTextContent;\n }\n\n // @ts-expect-error: internal field\n const previousSubTreeDirectionTextContent = dom.__lexicalDirTextContent;\n if (previousSubTreeDirectionTextContent !== undefined) {\n subTreeDirectionedTextContent += previousSubTreeDirectionTextContent;\n }\n } else {\n const text = prevNode.getTextContent();\n if ($isTextNode(prevNode) && !prevNode.isDirectionless()) {\n subTreeDirectionedTextContent += text;\n }\n editorTextContent += text;\n subTreeTextContent += text;\n }\n return dom;\n }\n // If the node key doesn't point to the same instance in both maps,\n // it means it were cloned. If they're also dirty, we mark them as mutated.\n if (prevNode !== nextNode && isDirty) {\n setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, nextNode, 'updated');\n }\n\n // Update node. If it returns true, we need to unmount and re-create the node\n if (nextNode.updateDOM(prevNode, dom, activeEditorConfig)) {\n const replacementDOM = $createNode(key, null, null);\n if (parentDOM === null) {\n {\n throw Error(`reconcileNode: parentDOM is null`);\n }\n }\n parentDOM.replaceChild(replacementDOM, dom);\n destroyNode(key, null);\n return replacementDOM;\n }\n if ($isElementNode(prevNode) && $isElementNode(nextNode)) {\n // Reconcile element children\n const nextIndent = nextNode.__indent;\n if (nextIndent !== prevNode.__indent) {\n setElementIndent(dom, nextIndent);\n }\n const nextFormat = nextNode.__format;\n if (nextFormat !== prevNode.__format) {\n setElementFormat(dom, nextFormat);\n }\n if (isDirty) {\n $reconcileChildrenWithDirection(prevNode, nextNode, dom);\n if (!$isRootNode(nextNode) && !nextNode.isInline()) {\n reconcileElementTerminatingLineBreak(prevNode, nextNode, dom);\n }\n }\n if ($textContentRequiresDoubleLinebreakAtEnd(nextNode)) {\n subTreeTextContent += DOUBLE_LINE_BREAK;\n editorTextContent += DOUBLE_LINE_BREAK;\n }\n } else {\n const text = nextNode.getTextContent();\n if ($isDecoratorNode(nextNode)) {\n const decorator = nextNode.decorate(activeEditor$1, activeEditorConfig);\n if (decorator !== null) {\n reconcileDecorator(key, decorator);\n }\n } else if ($isTextNode(nextNode) && !nextNode.isDirectionless()) {\n // Handle text content, for LTR, LTR cases.\n subTreeDirectionedTextContent += text;\n }\n subTreeTextContent += text;\n editorTextContent += text;\n }\n if (!activeEditorStateReadOnly && $isRootNode(nextNode) && nextNode.__cachedText !== editorTextContent) {\n // Cache the latest text content.\n const nextRootNode = nextNode.getWritable();\n nextRootNode.__cachedText = editorTextContent;\n nextNode = nextRootNode;\n }\n {\n // Freeze the node in DEV to prevent accidental mutations\n Object.freeze(nextNode);\n }\n return dom;\n}\nfunction reconcileDecorator(key, decorator) {\n let pendingDecorators = activeEditor$1._pendingDecorators;\n const currentDecorators = activeEditor$1._decorators;\n if (pendingDecorators === null) {\n if (currentDecorators[key] === decorator) {\n return;\n }\n pendingDecorators = cloneDecorators(activeEditor$1);\n }\n pendingDecorators[key] = decorator;\n}\nfunction getFirstChild(element) {\n return element.firstChild;\n}\nfunction getNextSibling(element) {\n let nextSibling = element.nextSibling;\n if (nextSibling !== null && nextSibling === activeEditor$1._blockCursorElement) {\n nextSibling = nextSibling.nextSibling;\n }\n return nextSibling;\n}\nfunction $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom) {\n const prevEndIndex = prevChildrenLength - 1;\n const nextEndIndex = nextChildrenLength - 1;\n let prevChildrenSet;\n let nextChildrenSet;\n let siblingDOM = getFirstChild(dom);\n let prevIndex = 0;\n let nextIndex = 0;\n while (prevIndex <= prevEndIndex && nextIndex <= nextEndIndex) {\n const prevKey = prevChildren[prevIndex];\n const nextKey = nextChildren[nextIndex];\n if (prevKey === nextKey) {\n siblingDOM = getNextSibling($reconcileNode(nextKey, dom));\n prevIndex++;\n nextIndex++;\n } else {\n if (prevChildrenSet === undefined) {\n prevChildrenSet = new Set(prevChildren);\n }\n if (nextChildrenSet === undefined) {\n nextChildrenSet = new Set(nextChildren);\n }\n const nextHasPrevKey = nextChildrenSet.has(prevKey);\n const prevHasNextKey = prevChildrenSet.has(nextKey);\n if (!nextHasPrevKey) {\n // Remove prev\n siblingDOM = getNextSibling(getPrevElementByKeyOrThrow(prevKey));\n destroyNode(prevKey, dom);\n prevIndex++;\n } else if (!prevHasNextKey) {\n // Create next\n $createNode(nextKey, dom, siblingDOM);\n nextIndex++;\n } else {\n // Move next\n const childDOM = getElementByKeyOrThrow(activeEditor$1, nextKey);\n if (childDOM === siblingDOM) {\n siblingDOM = getNextSibling($reconcileNode(nextKey, dom));\n } else {\n if (siblingDOM != null) {\n dom.insertBefore(childDOM, siblingDOM);\n } else {\n dom.appendChild(childDOM);\n }\n $reconcileNode(nextKey, dom);\n }\n prevIndex++;\n nextIndex++;\n }\n }\n const node = activeNextNodeMap.get(nextKey);\n if (node !== null && $isTextNode(node)) {\n if (subTreeTextFormat === null) {\n subTreeTextFormat = node.getFormat();\n }\n if (subTreeTextStyle === '') {\n subTreeTextStyle = node.getStyle();\n }\n }\n }\n const appendNewChildren = prevIndex > prevEndIndex;\n const removeOldChildren = nextIndex > nextEndIndex;\n if (appendNewChildren && !removeOldChildren) {\n const previousNode = nextChildren[nextEndIndex + 1];\n const insertDOM = previousNode === undefined ? null : activeEditor$1.getElementByKey(previousNode);\n $createChildren(nextChildren, nextElement, nextIndex, nextEndIndex, dom, insertDOM);\n } else if (removeOldChildren && !appendNewChildren) {\n destroyChildren(prevChildren, prevIndex, prevEndIndex, dom);\n }\n}\nfunction $reconcileRoot(prevEditorState, nextEditorState, editor, dirtyType, dirtyElements, dirtyLeaves) {\n // We cache text content to make retrieval more efficient.\n // The cache must be rebuilt during reconciliation to account for any changes.\n subTreeTextContent = '';\n editorTextContent = '';\n subTreeDirectionedTextContent = '';\n // Rather than pass around a load of arguments through the stack recursively\n // we instead set them as bindings within the scope of the module.\n treatAllNodesAsDirty = dirtyType === FULL_RECONCILE;\n activeTextDirection = null;\n activeEditor$1 = editor;\n activeEditorConfig = editor._config;\n activeEditorNodes = editor._nodes;\n activeMutationListeners = activeEditor$1._listeners.mutation;\n activeDirtyElements = dirtyElements;\n activeDirtyLeaves = dirtyLeaves;\n activePrevNodeMap = prevEditorState._nodeMap;\n activeNextNodeMap = nextEditorState._nodeMap;\n activeEditorStateReadOnly = nextEditorState._readOnly;\n activePrevKeyToDOMMap = new Map(editor._keyToDOMMap);\n // We keep track of mutated nodes so we can trigger mutation\n // listeners later in the update cycle.\n const currentMutatedNodes = new Map();\n mutatedNodes = currentMutatedNodes;\n $reconcileNode('root', null);\n // We don't want a bunch of void checks throughout the scope\n // so instead we make it seem that these values are always set.\n // We also want to make sure we clear them down, otherwise we\n // can leak memory.\n // @ts-ignore\n activeEditor$1 = undefined;\n // @ts-ignore\n activeEditorNodes = undefined;\n // @ts-ignore\n activeDirtyElements = undefined;\n // @ts-ignore\n activeDirtyLeaves = undefined;\n // @ts-ignore\n activePrevNodeMap = undefined;\n // @ts-ignore\n activeNextNodeMap = undefined;\n // @ts-ignore\n activeEditorConfig = undefined;\n // @ts-ignore\n activePrevKeyToDOMMap = undefined;\n // @ts-ignore\n mutatedNodes = undefined;\n return currentMutatedNodes;\n}\nfunction storeDOMWithKey(key, dom, editor) {\n const keyToDOMMap = editor._keyToDOMMap;\n // @ts-ignore We intentionally add this to the Node.\n dom['__lexicalKey_' + editor._key] = key;\n keyToDOMMap.set(key, dom);\n}\nfunction getPrevElementByKeyOrThrow(key) {\n const element = activePrevKeyToDOMMap.get(key);\n if (element === undefined) {\n {\n throw Error(`Reconciliation: could not find DOM element for node key ${key}`);\n }\n }\n return element;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nconst PASS_THROUGH_COMMAND = Object.freeze({});\nconst ANDROID_COMPOSITION_LATENCY = 30;\nconst rootElementEvents = [['keydown', onKeyDown], ['pointerdown', onPointerDown], ['compositionstart', onCompositionStart], ['compositionend', onCompositionEnd], ['input', onInput], ['click', onClick], ['cut', PASS_THROUGH_COMMAND], ['copy', PASS_THROUGH_COMMAND], ['dragstart', PASS_THROUGH_COMMAND], ['dragover', PASS_THROUGH_COMMAND], ['dragend', PASS_THROUGH_COMMAND], ['paste', PASS_THROUGH_COMMAND], ['focus', PASS_THROUGH_COMMAND], ['blur', PASS_THROUGH_COMMAND], ['drop', PASS_THROUGH_COMMAND]];\nif (CAN_USE_BEFORE_INPUT) {\n rootElementEvents.push(['beforeinput', (event, editor) => onBeforeInput(event, editor)]);\n}\nlet lastKeyDownTimeStamp = 0;\nlet lastKeyCode = null;\nlet lastBeforeInputInsertTextTimeStamp = 0;\nlet unprocessedBeforeInputData = null;\nconst rootElementsRegistered = new WeakMap();\nlet isSelectionChangeFromDOMUpdate = false;\nlet isSelectionChangeFromMouseDown = false;\nlet isInsertLineBreak = false;\nlet isFirefoxEndingComposition = false;\nlet collapsedSelectionFormat = [0, '', 0, 'root', 0];\n\n// This function is used to determine if Lexical should attempt to override\n// the default browser behavior for insertion of text and use its own internal\n// heuristics. This is an extremely important function, and makes much of Lexical\n// work as intended between different browsers and across word, line and character\n// boundary/formats. It also is important for text replacement, node schemas and\n// composition mechanics.\n\nfunction $shouldPreventDefaultAndInsertText(selection, domTargetRange, text, timeStamp, isBeforeInput) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const editor = getActiveEditor();\n const domSelection = getDOMSelection(editor._window);\n const domAnchorNode = domSelection !== null ? domSelection.anchorNode : null;\n const anchorKey = anchor.key;\n const backingAnchorElement = editor.getElementByKey(anchorKey);\n const textLength = text.length;\n return anchorKey !== focus.key ||\n // If we're working with a non-text node.\n !$isTextNode(anchorNode) ||\n // If we are replacing a range with a single character or grapheme, and not composing.\n (!isBeforeInput && (!CAN_USE_BEFORE_INPUT ||\n // We check to see if there has been\n // a recent beforeinput event for \"textInput\". If there has been one in the last\n // 50ms then we proceed as normal. However, if there is not, then this is likely\n // a dangling `input` event caused by execCommand('insertText').\n lastBeforeInputInsertTextTimeStamp < timeStamp + 50) || anchorNode.isDirty() && textLength < 2 || doesContainGrapheme(text)) && anchor.offset !== focus.offset && !anchorNode.isComposing() ||\n // Any non standard text node.\n $isTokenOrSegmented(anchorNode) ||\n // If the text length is more than a single character and we're either\n // dealing with this in \"beforeinput\" or where the node has already recently\n // been changed (thus is dirty).\n anchorNode.isDirty() && textLength > 1 ||\n // If the DOM selection element is not the same as the backing node during beforeinput.\n (isBeforeInput || !CAN_USE_BEFORE_INPUT) && backingAnchorElement !== null && !anchorNode.isComposing() && domAnchorNode !== getDOMTextNode(backingAnchorElement) ||\n // If TargetRange is not the same as the DOM selection; browser trying to edit random parts\n // of the editor.\n domSelection !== null && domTargetRange !== null && (!domTargetRange.collapsed || domTargetRange.startContainer !== domSelection.anchorNode || domTargetRange.startOffset !== domSelection.anchorOffset) ||\n // Check if we're changing from bold to italics, or some other format.\n anchorNode.getFormat() !== selection.format || anchorNode.getStyle() !== selection.style ||\n // One last set of heuristics to check against.\n $shouldInsertTextAfterOrBeforeTextNode(selection, anchorNode);\n}\nfunction shouldSkipSelectionChange(domNode, offset) {\n return domNode !== null && domNode.nodeValue !== null && domNode.nodeType === DOM_TEXT_TYPE && offset !== 0 && offset !== domNode.nodeValue.length;\n}\nfunction onSelectionChange(domSelection, editor, isActive) {\n const {\n anchorNode: anchorDOM,\n anchorOffset,\n focusNode: focusDOM,\n focusOffset\n } = domSelection;\n if (isSelectionChangeFromDOMUpdate) {\n isSelectionChangeFromDOMUpdate = false;\n\n // If native DOM selection is on a DOM element, then\n // we should continue as usual, as Lexical's selection\n // may have normalized to a better child. If the DOM\n // element is a text node, we can safely apply this\n // optimization and skip the selection change entirely.\n // We also need to check if the offset is at the boundary,\n // because in this case, we might need to normalize to a\n // sibling instead.\n if (shouldSkipSelectionChange(anchorDOM, anchorOffset) && shouldSkipSelectionChange(focusDOM, focusOffset)) {\n return;\n }\n }\n updateEditor(editor, () => {\n // Non-active editor don't need any extra logic for selection, it only needs update\n // to reconcile selection (set it to null) to ensure that only one editor has non-null selection.\n if (!isActive) {\n $setSelection(null);\n return;\n }\n if (!isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {\n return;\n }\n const selection = $getSelection();\n\n // Update the selection format\n if ($isRangeSelection(selection)) {\n const anchor = selection.anchor;\n const anchorNode = anchor.getNode();\n if (selection.isCollapsed()) {\n // Badly interpreted range selection when collapsed - #1482\n if (domSelection.type === 'Range' && domSelection.anchorNode === domSelection.focusNode) {\n selection.dirty = true;\n }\n\n // If we have marked a collapsed selection format, and we're\n // within the given time range – then attempt to use that format\n // instead of getting the format from the anchor node.\n const windowEvent = getWindow(editor).event;\n const currentTimeStamp = windowEvent ? windowEvent.timeStamp : performance.now();\n const [lastFormat, lastStyle, lastOffset, lastKey, timeStamp] = collapsedSelectionFormat;\n const root = $getRoot();\n const isRootTextContentEmpty = editor.isComposing() === false && root.getTextContent() === '';\n if (currentTimeStamp < timeStamp + 200 && anchor.offset === lastOffset && anchor.key === lastKey) {\n selection.format = lastFormat;\n selection.style = lastStyle;\n } else {\n if (anchor.type === 'text') {\n if (!$isTextNode(anchorNode)) {\n throw Error(`Point.getNode() must return TextNode when type is text`);\n }\n selection.format = anchorNode.getFormat();\n selection.style = anchorNode.getStyle();\n } else if (anchor.type === 'element' && !isRootTextContentEmpty) {\n const lastNode = anchor.getNode();\n selection.style = '';\n if (lastNode instanceof ParagraphNode && lastNode.getChildrenSize() === 0) {\n selection.format = lastNode.getTextFormat();\n selection.style = lastNode.getTextStyle();\n } else {\n selection.format = 0;\n }\n }\n }\n } else {\n const anchorKey = anchor.key;\n const focus = selection.focus;\n const focusKey = focus.key;\n const nodes = selection.getNodes();\n const nodesLength = nodes.length;\n const isBackward = selection.isBackward();\n const startOffset = isBackward ? focusOffset : anchorOffset;\n const endOffset = isBackward ? anchorOffset : focusOffset;\n const startKey = isBackward ? focusKey : anchorKey;\n const endKey = isBackward ? anchorKey : focusKey;\n let combinedFormat = IS_ALL_FORMATTING;\n let hasTextNodes = false;\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n const textContentSize = node.getTextContentSize();\n if ($isTextNode(node) && textContentSize !== 0 &&\n // Exclude empty text nodes at boundaries resulting from user's selection\n !(i === 0 && node.__key === startKey && startOffset === textContentSize || i === nodesLength - 1 && node.__key === endKey && endOffset === 0)) {\n // TODO: what about style?\n hasTextNodes = true;\n combinedFormat &= node.getFormat();\n if (combinedFormat === 0) {\n break;\n }\n }\n }\n selection.format = hasTextNodes ? combinedFormat : 0;\n }\n }\n dispatchCommand(editor, SELECTION_CHANGE_COMMAND, undefined);\n });\n}\n\n// This is a work-around is mainly Chrome specific bug where if you select\n// the contents of an empty block, you cannot easily unselect anything.\n// This results in a tiny selection box that looks buggy/broken. This can\n// also help other browsers when selection might \"appear\" lost, when it\n// really isn't.\nfunction onClick(event, editor) {\n updateEditor(editor, () => {\n const selection = $getSelection();\n const domSelection = getDOMSelection(editor._window);\n const lastSelection = $getPreviousSelection();\n if (domSelection) {\n if ($isRangeSelection(selection)) {\n const anchor = selection.anchor;\n const anchorNode = anchor.getNode();\n if (anchor.type === 'element' && anchor.offset === 0 && selection.isCollapsed() && !$isRootNode(anchorNode) && $getRoot().getChildrenSize() === 1 && anchorNode.getTopLevelElementOrThrow().isEmpty() && lastSelection !== null && selection.is(lastSelection)) {\n domSelection.removeAllRanges();\n selection.dirty = true;\n } else if (event.detail === 3 && !selection.isCollapsed()) {\n // Tripple click causing selection to overflow into the nearest element. In that\n // case visually it looks like a single element content is selected, focus node\n // is actually at the beginning of the next element (if present) and any manipulations\n // with selection (formatting) are affecting second element as well\n const focus = selection.focus;\n const focusNode = focus.getNode();\n if (anchorNode !== focusNode) {\n if ($isElementNode(anchorNode)) {\n anchorNode.select(0);\n } else {\n anchorNode.getParentOrThrow().select(0);\n }\n }\n }\n } else if (event.pointerType === 'touch') {\n // This is used to update the selection on touch devices when the user clicks on text after a\n // node selection. See isSelectionChangeFromMouseDown for the inverse\n const domAnchorNode = domSelection.anchorNode;\n if (domAnchorNode !== null) {\n const nodeType = domAnchorNode.nodeType;\n // If the user is attempting to click selection back onto text, then\n // we should attempt create a range selection.\n // When we click on an empty paragraph node or the end of a paragraph that ends\n // with an image/poll, the nodeType will be ELEMENT_NODE\n if (nodeType === DOM_ELEMENT_TYPE || nodeType === DOM_TEXT_TYPE) {\n const newSelection = $internalCreateRangeSelection(lastSelection, domSelection, editor, event);\n $setSelection(newSelection);\n }\n }\n }\n }\n dispatchCommand(editor, CLICK_COMMAND, event);\n });\n}\nfunction onPointerDown(event, editor) {\n // TODO implement text drag & drop\n const target = event.target;\n const pointerType = event.pointerType;\n if (target instanceof Node && pointerType !== 'touch') {\n updateEditor(editor, () => {\n // Drag & drop should not recompute selection until mouse up; otherwise the initially\n // selected content is lost.\n if (!$isSelectionCapturedInDecorator(target)) {\n isSelectionChangeFromMouseDown = true;\n }\n });\n }\n}\nfunction getTargetRange(event) {\n if (!event.getTargetRanges) {\n return null;\n }\n const targetRanges = event.getTargetRanges();\n if (targetRanges.length === 0) {\n return null;\n }\n return targetRanges[0];\n}\nfunction $canRemoveText(anchorNode, focusNode) {\n return anchorNode !== focusNode || $isElementNode(anchorNode) || $isElementNode(focusNode) || !anchorNode.isToken() || !focusNode.isToken();\n}\nfunction isPossiblyAndroidKeyPress(timeStamp) {\n return lastKeyCode === 'MediaLast' && timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY;\n}\nfunction onBeforeInput(event, editor) {\n const inputType = event.inputType;\n const targetRange = getTargetRange(event);\n\n // We let the browser do its own thing for composition.\n if (inputType === 'deleteCompositionText' ||\n // If we're pasting in FF, we shouldn't get this event\n // as the `paste` event should have triggered, unless the\n // user has dom.event.clipboardevents.enabled disabled in\n // about:config. In that case, we need to process the\n // pasted content in the DOM mutation phase.\n IS_FIREFOX && isFirefoxClipboardEvents(editor)) {\n return;\n } else if (inputType === 'insertCompositionText') {\n return;\n }\n updateEditor(editor, () => {\n const selection = $getSelection();\n if (inputType === 'deleteContentBackward') {\n if (selection === null) {\n // Use previous selection\n const prevSelection = $getPreviousSelection();\n if (!$isRangeSelection(prevSelection)) {\n return;\n }\n $setSelection(prevSelection.clone());\n }\n if ($isRangeSelection(selection)) {\n const isSelectionAnchorSameAsFocus = selection.anchor.key === selection.focus.key;\n if (isPossiblyAndroidKeyPress(event.timeStamp) && editor.isComposing() && isSelectionAnchorSameAsFocus) {\n $setCompositionKey(null);\n lastKeyDownTimeStamp = 0;\n // Fixes an Android bug where selection flickers when backspacing\n setTimeout(() => {\n updateEditor(editor, () => {\n $setCompositionKey(null);\n });\n }, ANDROID_COMPOSITION_LATENCY);\n if ($isRangeSelection(selection)) {\n const anchorNode = selection.anchor.getNode();\n anchorNode.markDirty();\n selection.format = anchorNode.getFormat();\n if (!$isTextNode(anchorNode)) {\n throw Error(`Anchor node must be a TextNode`);\n }\n selection.style = anchorNode.getStyle();\n }\n } else {\n $setCompositionKey(null);\n event.preventDefault();\n // Chromium Android at the moment seems to ignore the preventDefault\n // on 'deleteContentBackward' and still deletes the content. Which leads\n // to multiple deletions. So we let the browser handle the deletion in this case.\n const selectedNodeText = selection.anchor.getNode().getTextContent();\n const hasSelectedAllTextInNode = selection.anchor.offset === 0 && selection.focus.offset === selectedNodeText.length;\n const shouldLetBrowserHandleDelete = IS_ANDROID_CHROME && isSelectionAnchorSameAsFocus && !hasSelectedAllTextInNode;\n if (!shouldLetBrowserHandleDelete) {\n dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true);\n }\n }\n return;\n }\n }\n if (!$isRangeSelection(selection)) {\n return;\n }\n const data = event.data;\n\n // This represents the case when two beforeinput events are triggered at the same time (without a\n // full event loop ending at input). This happens with MacOS with the default keyboard settings,\n // a combination of autocorrection + autocapitalization.\n // Having Lexical run everything in controlled mode would fix the issue without additional code\n // but this would kill the massive performance win from the most common typing event.\n // Alternatively, when this happens we can prematurely update our EditorState based on the DOM\n // content, a job that would usually be the input event's responsibility.\n if (unprocessedBeforeInputData !== null) {\n $updateSelectedTextFromDOM(false, editor, unprocessedBeforeInputData);\n }\n if ((!selection.dirty || unprocessedBeforeInputData !== null) && selection.isCollapsed() && !$isRootNode(selection.anchor.getNode()) && targetRange !== null) {\n selection.applyDOMRange(targetRange);\n }\n unprocessedBeforeInputData = null;\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n if (inputType === 'insertText' || inputType === 'insertTranspose') {\n if (data === '\\n') {\n event.preventDefault();\n dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, false);\n } else if (data === DOUBLE_LINE_BREAK) {\n event.preventDefault();\n dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND, undefined);\n } else if (data == null && event.dataTransfer) {\n // Gets around a Safari text replacement bug.\n const text = event.dataTransfer.getData('text/plain');\n event.preventDefault();\n selection.insertRawText(text);\n } else if (data != null && $shouldPreventDefaultAndInsertText(selection, targetRange, data, event.timeStamp, true)) {\n event.preventDefault();\n dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);\n } else {\n unprocessedBeforeInputData = data;\n }\n lastBeforeInputInsertTextTimeStamp = event.timeStamp;\n return;\n }\n\n // Prevent the browser from carrying out\n // the input event, so we can control the\n // output.\n event.preventDefault();\n switch (inputType) {\n case 'insertFromYank':\n case 'insertFromDrop':\n case 'insertReplacementText':\n {\n dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, event);\n break;\n }\n case 'insertFromComposition':\n {\n // This is the end of composition\n $setCompositionKey(null);\n dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, event);\n break;\n }\n case 'insertLineBreak':\n {\n // Used for Android\n $setCompositionKey(null);\n dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, false);\n break;\n }\n case 'insertParagraph':\n {\n // Used for Android\n $setCompositionKey(null);\n\n // Safari does not provide the type \"insertLineBreak\".\n // So instead, we need to infer it from the keyboard event.\n // We do not apply this logic to iOS to allow newline auto-capitalization\n // work without creating linebreaks when pressing Enter\n if (isInsertLineBreak && !IS_IOS) {\n isInsertLineBreak = false;\n dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, false);\n } else {\n dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND, undefined);\n }\n break;\n }\n case 'insertFromPaste':\n case 'insertFromPasteAsQuotation':\n {\n dispatchCommand(editor, PASTE_COMMAND, event);\n break;\n }\n case 'deleteByComposition':\n {\n if ($canRemoveText(anchorNode, focusNode)) {\n dispatchCommand(editor, REMOVE_TEXT_COMMAND, event);\n }\n break;\n }\n case 'deleteByDrag':\n case 'deleteByCut':\n {\n dispatchCommand(editor, REMOVE_TEXT_COMMAND, event);\n break;\n }\n case 'deleteContent':\n {\n dispatchCommand(editor, DELETE_CHARACTER_COMMAND, false);\n break;\n }\n case 'deleteWordBackward':\n {\n dispatchCommand(editor, DELETE_WORD_COMMAND, true);\n break;\n }\n case 'deleteWordForward':\n {\n dispatchCommand(editor, DELETE_WORD_COMMAND, false);\n break;\n }\n case 'deleteHardLineBackward':\n case 'deleteSoftLineBackward':\n {\n dispatchCommand(editor, DELETE_LINE_COMMAND, true);\n break;\n }\n case 'deleteContentForward':\n case 'deleteHardLineForward':\n case 'deleteSoftLineForward':\n {\n dispatchCommand(editor, DELETE_LINE_COMMAND, false);\n break;\n }\n case 'formatStrikeThrough':\n {\n dispatchCommand(editor, FORMAT_TEXT_COMMAND, 'strikethrough');\n break;\n }\n case 'formatBold':\n {\n dispatchCommand(editor, FORMAT_TEXT_COMMAND, 'bold');\n break;\n }\n case 'formatItalic':\n {\n dispatchCommand(editor, FORMAT_TEXT_COMMAND, 'italic');\n break;\n }\n case 'formatUnderline':\n {\n dispatchCommand(editor, FORMAT_TEXT_COMMAND, 'underline');\n break;\n }\n case 'historyUndo':\n {\n dispatchCommand(editor, UNDO_COMMAND, undefined);\n break;\n }\n case 'historyRedo':\n {\n dispatchCommand(editor, REDO_COMMAND, undefined);\n break;\n }\n // NO-OP\n }\n });\n}\nfunction onInput(event, editor) {\n // We don't want the onInput to bubble, in the case of nested editors.\n event.stopPropagation();\n updateEditor(editor, () => {\n const selection = $getSelection();\n const data = event.data;\n const targetRange = getTargetRange(event);\n if (data != null && $isRangeSelection(selection) && $shouldPreventDefaultAndInsertText(selection, targetRange, data, event.timeStamp, false)) {\n // Given we're over-riding the default behavior, we will need\n // to ensure to disable composition before dispatching the\n // insertText command for when changing the sequence for FF.\n if (isFirefoxEndingComposition) {\n $onCompositionEndImpl(editor, data);\n isFirefoxEndingComposition = false;\n }\n const anchor = selection.anchor;\n const anchorNode = anchor.getNode();\n const domSelection = getDOMSelection(editor._window);\n if (domSelection === null) {\n return;\n }\n const isBackward = selection.isBackward();\n const startOffset = isBackward ? selection.anchor.offset : selection.focus.offset;\n const endOffset = isBackward ? selection.focus.offset : selection.anchor.offset;\n // If the content is the same as inserted, then don't dispatch an insertion.\n // Given onInput doesn't take the current selection (it uses the previous)\n // we can compare that against what the DOM currently says.\n if (!CAN_USE_BEFORE_INPUT || selection.isCollapsed() || !$isTextNode(anchorNode) || domSelection.anchorNode === null || anchorNode.getTextContent().slice(0, startOffset) + data + anchorNode.getTextContent().slice(startOffset + endOffset) !== getAnchorTextFromDOM(domSelection.anchorNode)) {\n dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);\n }\n const textLength = data.length;\n\n // Another hack for FF, as it's possible that the IME is still\n // open, even though compositionend has already fired (sigh).\n if (IS_FIREFOX && textLength > 1 && event.inputType === 'insertCompositionText' && !editor.isComposing()) {\n selection.anchor.offset -= textLength;\n }\n\n // This ensures consistency on Android.\n if (!IS_SAFARI && !IS_IOS && !IS_APPLE_WEBKIT && editor.isComposing()) {\n lastKeyDownTimeStamp = 0;\n $setCompositionKey(null);\n }\n } else {\n const characterData = data !== null ? data : undefined;\n $updateSelectedTextFromDOM(false, editor, characterData);\n\n // onInput always fires after onCompositionEnd for FF.\n if (isFirefoxEndingComposition) {\n $onCompositionEndImpl(editor, data || undefined);\n isFirefoxEndingComposition = false;\n }\n }\n\n // Also flush any other mutations that might have occurred\n // since the change.\n $flushMutations();\n });\n unprocessedBeforeInputData = null;\n}\nfunction onCompositionStart(event, editor) {\n updateEditor(editor, () => {\n const selection = $getSelection();\n if ($isRangeSelection(selection) && !editor.isComposing()) {\n const anchor = selection.anchor;\n const node = selection.anchor.getNode();\n $setCompositionKey(anchor.key);\n if (\n // If it has been 30ms since the last keydown, then we should\n // apply the empty space heuristic. We can't do this for Safari,\n // as the keydown fires after composition start.\n event.timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY ||\n // FF has issues around composing multibyte characters, so we also\n // need to invoke the empty space heuristic below.\n anchor.type === 'element' || !selection.isCollapsed() || node.getFormat() !== selection.format || $isTextNode(node) && node.getStyle() !== selection.style) {\n // We insert a zero width character, ready for the composition\n // to get inserted into the new node we create. If\n // we don't do this, Safari will fail on us because\n // there is no text node matching the selection.\n dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, COMPOSITION_START_CHAR);\n }\n }\n });\n}\nfunction $onCompositionEndImpl(editor, data) {\n const compositionKey = editor._compositionKey;\n $setCompositionKey(null);\n\n // Handle termination of composition.\n if (compositionKey !== null && data != null) {\n // Composition can sometimes move to an adjacent DOM node when backspacing.\n // So check for the empty case.\n if (data === '') {\n const node = $getNodeByKey(compositionKey);\n const textNode = getDOMTextNode(editor.getElementByKey(compositionKey));\n if (textNode !== null && textNode.nodeValue !== null && $isTextNode(node)) {\n $updateTextNodeFromDOMContent(node, textNode.nodeValue, null, null, true);\n }\n return;\n }\n\n // Composition can sometimes be that of a new line. In which case, we need to\n // handle that accordingly.\n if (data[data.length - 1] === '\\n') {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n // If the last character is a line break, we also need to insert\n // a line break.\n const focus = selection.focus;\n selection.anchor.set(focus.key, focus.offset, focus.type);\n dispatchCommand(editor, KEY_ENTER_COMMAND, null);\n return;\n }\n }\n }\n $updateSelectedTextFromDOM(true, editor, data);\n}\nfunction onCompositionEnd(event, editor) {\n // Firefox fires onCompositionEnd before onInput, but Chrome/Webkit,\n // fire onInput before onCompositionEnd. To ensure the sequence works\n // like Chrome/Webkit we use the isFirefoxEndingComposition flag to\n // defer handling of onCompositionEnd in Firefox till we have processed\n // the logic in onInput.\n if (IS_FIREFOX) {\n isFirefoxEndingComposition = true;\n } else {\n updateEditor(editor, () => {\n $onCompositionEndImpl(editor, event.data);\n });\n }\n}\nfunction onKeyDown(event, editor) {\n lastKeyDownTimeStamp = event.timeStamp;\n lastKeyCode = event.key;\n if (editor.isComposing()) {\n return;\n }\n const {\n key,\n shiftKey,\n ctrlKey,\n metaKey,\n altKey\n } = event;\n if (dispatchCommand(editor, KEY_DOWN_COMMAND, event)) {\n return;\n }\n if (key == null) {\n return;\n }\n if (isMoveForward(key, ctrlKey, altKey, metaKey)) {\n dispatchCommand(editor, KEY_ARROW_RIGHT_COMMAND, event);\n } else if (isMoveToEnd(key, ctrlKey, shiftKey, altKey, metaKey)) {\n dispatchCommand(editor, MOVE_TO_END, event);\n } else if (isMoveBackward(key, ctrlKey, altKey, metaKey)) {\n dispatchCommand(editor, KEY_ARROW_LEFT_COMMAND, event);\n } else if (isMoveToStart(key, ctrlKey, shiftKey, altKey, metaKey)) {\n dispatchCommand(editor, MOVE_TO_START, event);\n } else if (isMoveUp(key, ctrlKey, metaKey)) {\n dispatchCommand(editor, KEY_ARROW_UP_COMMAND, event);\n } else if (isMoveDown(key, ctrlKey, metaKey)) {\n dispatchCommand(editor, KEY_ARROW_DOWN_COMMAND, event);\n } else if (isLineBreak(key, shiftKey)) {\n isInsertLineBreak = true;\n dispatchCommand(editor, KEY_ENTER_COMMAND, event);\n } else if (isSpace(key)) {\n dispatchCommand(editor, KEY_SPACE_COMMAND, event);\n } else if (isOpenLineBreak(key, ctrlKey)) {\n event.preventDefault();\n isInsertLineBreak = true;\n dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, true);\n } else if (isParagraph(key, shiftKey)) {\n isInsertLineBreak = false;\n dispatchCommand(editor, KEY_ENTER_COMMAND, event);\n } else if (isDeleteBackward(key, altKey, metaKey, ctrlKey)) {\n if (isBackspace(key)) {\n dispatchCommand(editor, KEY_BACKSPACE_COMMAND, event);\n } else {\n event.preventDefault();\n dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true);\n }\n } else if (isEscape(key)) {\n dispatchCommand(editor, KEY_ESCAPE_COMMAND, event);\n } else if (isDeleteForward(key, ctrlKey, shiftKey, altKey, metaKey)) {\n if (isDelete(key)) {\n dispatchCommand(editor, KEY_DELETE_COMMAND, event);\n } else {\n event.preventDefault();\n dispatchCommand(editor, DELETE_CHARACTER_COMMAND, false);\n }\n } else if (isDeleteWordBackward(key, altKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, DELETE_WORD_COMMAND, true);\n } else if (isDeleteWordForward(key, altKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, DELETE_WORD_COMMAND, false);\n } else if (isDeleteLineBackward(key, metaKey)) {\n event.preventDefault();\n dispatchCommand(editor, DELETE_LINE_COMMAND, true);\n } else if (isDeleteLineForward(key, metaKey)) {\n event.preventDefault();\n dispatchCommand(editor, DELETE_LINE_COMMAND, false);\n } else if (isBold(key, altKey, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, FORMAT_TEXT_COMMAND, 'bold');\n } else if (isUnderline(key, altKey, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, FORMAT_TEXT_COMMAND, 'underline');\n } else if (isItalic(key, altKey, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, FORMAT_TEXT_COMMAND, 'italic');\n } else if (isTab(key, altKey, ctrlKey, metaKey)) {\n dispatchCommand(editor, KEY_TAB_COMMAND, event);\n } else if (isUndo(key, shiftKey, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, UNDO_COMMAND, undefined);\n } else if (isRedo(key, shiftKey, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, REDO_COMMAND, undefined);\n } else {\n const prevSelection = editor._editorState._selection;\n if ($isNodeSelection(prevSelection)) {\n if (isCopy(key, shiftKey, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, COPY_COMMAND, event);\n } else if (isCut(key, shiftKey, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, CUT_COMMAND, event);\n } else if (isSelectAll(key, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, SELECT_ALL_COMMAND, event);\n }\n // FF does it well (no need to override behavior)\n } else if (!IS_FIREFOX && isSelectAll(key, metaKey, ctrlKey)) {\n event.preventDefault();\n dispatchCommand(editor, SELECT_ALL_COMMAND, event);\n }\n }\n if (isModifier(ctrlKey, shiftKey, altKey, metaKey)) {\n dispatchCommand(editor, KEY_MODIFIER_COMMAND, event);\n }\n}\nfunction getRootElementRemoveHandles(rootElement) {\n // @ts-expect-error: internal field\n let eventHandles = rootElement.__lexicalEventHandles;\n if (eventHandles === undefined) {\n eventHandles = [];\n // @ts-expect-error: internal field\n rootElement.__lexicalEventHandles = eventHandles;\n }\n return eventHandles;\n}\n\n// Mapping root editors to their active nested editors, contains nested editors\n// mapping only, so if root editor is selected map will have no reference to free up memory\nconst activeNestedEditorsMap = new Map();\nfunction onDocumentSelectionChange(event) {\n const target = event.target;\n const targetWindow = target == null ? null : target.nodeType === 9 ? target.defaultView : target.ownerDocument.defaultView;\n const domSelection = getDOMSelection(targetWindow);\n if (domSelection === null) {\n return;\n }\n const nextActiveEditor = getNearestEditorFromDOMNode(domSelection.anchorNode);\n if (nextActiveEditor === null) {\n return;\n }\n if (isSelectionChangeFromMouseDown) {\n isSelectionChangeFromMouseDown = false;\n updateEditor(nextActiveEditor, () => {\n const lastSelection = $getPreviousSelection();\n const domAnchorNode = domSelection.anchorNode;\n if (domAnchorNode === null) {\n return;\n }\n const nodeType = domAnchorNode.nodeType;\n // If the user is attempting to click selection back onto text, then\n // we should attempt create a range selection.\n // When we click on an empty paragraph node or the end of a paragraph that ends\n // with an image/poll, the nodeType will be ELEMENT_NODE\n if (nodeType !== DOM_ELEMENT_TYPE && nodeType !== DOM_TEXT_TYPE) {\n return;\n }\n const newSelection = $internalCreateRangeSelection(lastSelection, domSelection, nextActiveEditor, event);\n $setSelection(newSelection);\n });\n }\n\n // When editor receives selection change event, we're checking if\n // it has any sibling editors (within same parent editor) that were active\n // before, and trigger selection change on it to nullify selection.\n const editors = getEditorsToPropagate(nextActiveEditor);\n const rootEditor = editors[editors.length - 1];\n const rootEditorKey = rootEditor._key;\n const activeNestedEditor = activeNestedEditorsMap.get(rootEditorKey);\n const prevActiveEditor = activeNestedEditor || rootEditor;\n if (prevActiveEditor !== nextActiveEditor) {\n onSelectionChange(domSelection, prevActiveEditor, false);\n }\n onSelectionChange(domSelection, nextActiveEditor, true);\n\n // If newly selected editor is nested, then add it to the map, clean map otherwise\n if (nextActiveEditor !== rootEditor) {\n activeNestedEditorsMap.set(rootEditorKey, nextActiveEditor);\n } else if (activeNestedEditor) {\n activeNestedEditorsMap.delete(rootEditorKey);\n }\n}\nfunction stopLexicalPropagation(event) {\n // We attach a special property to ensure the same event doesn't re-fire\n // for parent editors.\n // @ts-ignore\n event._lexicalHandled = true;\n}\nfunction hasStoppedLexicalPropagation(event) {\n // @ts-ignore\n const stopped = event._lexicalHandled === true;\n return stopped;\n}\nfunction addRootElementEvents(rootElement, editor) {\n // We only want to have a single global selectionchange event handler, shared\n // between all editor instances.\n const doc = rootElement.ownerDocument;\n const documentRootElementsCount = rootElementsRegistered.get(doc);\n if (documentRootElementsCount === undefined || documentRootElementsCount < 1) {\n doc.addEventListener('selectionchange', onDocumentSelectionChange);\n }\n rootElementsRegistered.set(doc, (documentRootElementsCount || 0) + 1);\n\n // @ts-expect-error: internal field\n rootElement.__lexicalEditor = editor;\n const removeHandles = getRootElementRemoveHandles(rootElement);\n for (let i = 0; i < rootElementEvents.length; i++) {\n const [eventName, onEvent] = rootElementEvents[i];\n const eventHandler = typeof onEvent === 'function' ? event => {\n if (hasStoppedLexicalPropagation(event)) {\n return;\n }\n stopLexicalPropagation(event);\n if (editor.isEditable() || eventName === 'click') {\n onEvent(event, editor);\n }\n } : event => {\n if (hasStoppedLexicalPropagation(event)) {\n return;\n }\n stopLexicalPropagation(event);\n const isEditable = editor.isEditable();\n switch (eventName) {\n case 'cut':\n return isEditable && dispatchCommand(editor, CUT_COMMAND, event);\n case 'copy':\n return dispatchCommand(editor, COPY_COMMAND, event);\n case 'paste':\n return isEditable && dispatchCommand(editor, PASTE_COMMAND, event);\n case 'dragstart':\n return isEditable && dispatchCommand(editor, DRAGSTART_COMMAND, event);\n case 'dragover':\n return isEditable && dispatchCommand(editor, DRAGOVER_COMMAND, event);\n case 'dragend':\n return isEditable && dispatchCommand(editor, DRAGEND_COMMAND, event);\n case 'focus':\n return isEditable && dispatchCommand(editor, FOCUS_COMMAND, event);\n case 'blur':\n {\n return isEditable && dispatchCommand(editor, BLUR_COMMAND, event);\n }\n case 'drop':\n return isEditable && dispatchCommand(editor, DROP_COMMAND, event);\n }\n };\n rootElement.addEventListener(eventName, eventHandler);\n removeHandles.push(() => {\n rootElement.removeEventListener(eventName, eventHandler);\n });\n }\n}\nfunction removeRootElementEvents(rootElement) {\n const doc = rootElement.ownerDocument;\n const documentRootElementsCount = rootElementsRegistered.get(doc);\n if (!(documentRootElementsCount !== undefined)) {\n throw Error(`Root element not registered`);\n } // We only want to have a single global selectionchange event handler, shared\n // between all editor instances.\n const newCount = documentRootElementsCount - 1;\n if (!(newCount >= 0)) {\n throw Error(`Root element count less than 0`);\n }\n rootElementsRegistered.set(doc, newCount);\n if (newCount === 0) {\n doc.removeEventListener('selectionchange', onDocumentSelectionChange);\n }\n const editor = getEditorPropertyFromDOMNode(rootElement);\n if (isLexicalEditor(editor)) {\n cleanActiveNestedEditorsMap(editor);\n // @ts-expect-error: internal field\n rootElement.__lexicalEditor = null;\n } else if (editor) {\n {\n throw Error(`Attempted to remove event handlers from a node that does not belong to this build of Lexical`);\n }\n }\n const removeHandles = getRootElementRemoveHandles(rootElement);\n for (let i = 0; i < removeHandles.length; i++) {\n removeHandles[i]();\n }\n\n // @ts-expect-error: internal field\n rootElement.__lexicalEventHandles = [];\n}\nfunction cleanActiveNestedEditorsMap(editor) {\n if (editor._parentEditor !== null) {\n // For nested editor cleanup map if this editor was marked as active\n const editors = getEditorsToPropagate(editor);\n const rootEditor = editors[editors.length - 1];\n const rootEditorKey = rootEditor._key;\n if (activeNestedEditorsMap.get(rootEditorKey) === editor) {\n activeNestedEditorsMap.delete(rootEditorKey);\n }\n } else {\n // For top-level editors cleanup map\n activeNestedEditorsMap.delete(editor._key);\n }\n}\nfunction markSelectionChangeFromDOMUpdate() {\n isSelectionChangeFromDOMUpdate = true;\n}\nfunction markCollapsedSelectionFormat(format, style, offset, key, timeStamp) {\n collapsedSelectionFormat = [format, style, offset, key, timeStamp];\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction $removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {\n errorOnReadOnly();\n const key = nodeToRemove.__key;\n const parent = nodeToRemove.getParent();\n if (parent === null) {\n return;\n }\n const selection = $maybeMoveChildrenSelectionToParent(nodeToRemove);\n let selectionMoved = false;\n if ($isRangeSelection(selection) && restoreSelection) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n if (anchor.key === key) {\n moveSelectionPointToSibling(anchor, nodeToRemove, parent, nodeToRemove.getPreviousSibling(), nodeToRemove.getNextSibling());\n selectionMoved = true;\n }\n if (focus.key === key) {\n moveSelectionPointToSibling(focus, nodeToRemove, parent, nodeToRemove.getPreviousSibling(), nodeToRemove.getNextSibling());\n selectionMoved = true;\n }\n } else if ($isNodeSelection(selection) && restoreSelection && nodeToRemove.isSelected()) {\n nodeToRemove.selectPrevious();\n }\n if ($isRangeSelection(selection) && restoreSelection && !selectionMoved) {\n // Doing this is O(n) so lets avoid it unless we need to do it\n const index = nodeToRemove.getIndexWithinParent();\n removeFromParent(nodeToRemove);\n $updateElementSelectionOnCreateDeleteNode(selection, parent, index, -1);\n } else {\n removeFromParent(nodeToRemove);\n }\n if (!preserveEmptyParent && !$isRootOrShadowRoot(parent) && !parent.canBeEmpty() && parent.isEmpty()) {\n $removeNode(parent, restoreSelection);\n }\n if (restoreSelection && $isRootNode(parent) && parent.isEmpty()) {\n parent.selectEnd();\n }\n}\nclass LexicalNode {\n // Allow us to look up the type including static props\n\n /** @internal */\n\n /** @internal */\n //@ts-ignore We set the key in the constructor.\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n // Flow doesn't support abstract classes unfortunately, so we can't _force_\n // subclasses of Node to implement statics. All subclasses of Node should have\n // a static getType and clone method though. We define getType and clone here so we can call it\n // on any Node, and we throw this error by default since the subclass should provide\n // their own implementation.\n /**\n * Returns the string type of this node. Every node must\n * implement this and it MUST BE UNIQUE amongst nodes registered\n * on the editor.\n *\n */\n static getType() {\n {\n throw Error(`LexicalNode: Node ${this.name} does not implement .getType().`);\n }\n }\n\n /**\n * Clones this node, creating a new node with a different key\n * and adding it to the EditorState (but not attaching it anywhere!). All nodes must\n * implement this method.\n *\n */\n static clone(_data) {\n {\n throw Error(`LexicalNode: Node ${this.name} does not implement .clone().`);\n }\n }\n\n /**\n * Perform any state updates on the clone of prevNode that are not already\n * handled by the constructor call in the static clone method. If you have\n * state to update in your clone that is not handled directly by the\n * constructor, it is advisable to override this method but it is required\n * to include a call to `super.afterCloneFrom(prevNode)` in your\n * implementation. This is only intended to be called by\n * {@link $cloneWithProperties} function or via a super call.\n *\n * @example\n * ```ts\n * class ClassesTextNode extends TextNode {\n * // Not shown: static getType, static importJSON, exportJSON, createDOM, updateDOM\n * __classes = new Set();\n * static clone(node: ClassesTextNode): ClassesTextNode {\n * // The inherited TextNode constructor is used here, so\n * // classes is not set by this method.\n * return new ClassesTextNode(node.__text, node.__key);\n * }\n * afterCloneFrom(node: this): void {\n * // This calls TextNode.afterCloneFrom and LexicalNode.afterCloneFrom\n * // for necessary state updates\n * super.afterCloneFrom(node);\n * this.__addClasses(node.__classes);\n * }\n * // This method is a private implementation detail, it is not\n * // suitable for the public API because it does not call getWritable\n * __addClasses(classNames: Iterable): this {\n * for (const className of classNames) {\n * this.__classes.add(className);\n * }\n * return this;\n * }\n * addClass(...classNames: string[]): this {\n * return this.getWritable().__addClasses(classNames);\n * }\n * removeClass(...classNames: string[]): this {\n * const node = this.getWritable();\n * for (const className of classNames) {\n * this.__classes.delete(className);\n * }\n * return this;\n * }\n * getClasses(): Set {\n * return this.getLatest().__classes;\n * }\n * }\n * ```\n *\n */\n afterCloneFrom(prevNode) {\n this.__parent = prevNode.__parent;\n this.__next = prevNode.__next;\n this.__prev = prevNode.__prev;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n\n constructor(key) {\n this.__type = this.constructor.getType();\n this.__parent = null;\n this.__prev = null;\n this.__next = null;\n $setNodeKey(this, key);\n {\n if (this.__type !== 'root') {\n errorOnReadOnly();\n errorOnTypeKlassMismatch(this.__type, this.constructor);\n }\n }\n }\n // Getters and Traversers\n\n /**\n * Returns the string type of this node.\n */\n getType() {\n return this.__type;\n }\n isInline() {\n {\n throw Error(`LexicalNode: Node ${this.constructor.name} does not implement .isInline().`);\n }\n }\n\n /**\n * Returns true if there is a path between this node and the RootNode, false otherwise.\n * This is a way of determining if the node is \"attached\" EditorState. Unattached nodes\n * won't be reconciled and will ultimatelt be cleaned up by the Lexical GC.\n */\n isAttached() {\n let nodeKey = this.__key;\n while (nodeKey !== null) {\n if (nodeKey === 'root') {\n return true;\n }\n const node = $getNodeByKey(nodeKey);\n if (node === null) {\n break;\n }\n nodeKey = node.__parent;\n }\n return false;\n }\n\n /**\n * Returns true if this node is contained within the provided Selection., false otherwise.\n * Relies on the algorithms implemented in {@link BaseSelection.getNodes} to determine\n * what's included.\n *\n * @param selection - The selection that we want to determine if the node is in.\n */\n isSelected(selection) {\n const targetSelection = selection || $getSelection();\n if (targetSelection == null) {\n return false;\n }\n const isSelected = targetSelection.getNodes().some(n => n.__key === this.__key);\n if ($isTextNode(this)) {\n return isSelected;\n }\n // For inline images inside of element nodes.\n // Without this change the image will be selected if the cursor is before or after it.\n const isElementRangeSelection = $isRangeSelection(targetSelection) && targetSelection.anchor.type === 'element' && targetSelection.focus.type === 'element';\n if (isElementRangeSelection) {\n if (targetSelection.isCollapsed()) {\n return false;\n }\n const parentNode = this.getParent();\n if ($isDecoratorNode(this) && this.isInline() && parentNode) {\n const firstPoint = targetSelection.isBackward() ? targetSelection.focus : targetSelection.anchor;\n const firstElement = firstPoint.getNode();\n if (firstPoint.offset === firstElement.getChildrenSize() && firstElement.is(parentNode) && firstElement.getLastChildOrThrow().is(this)) {\n return false;\n }\n }\n }\n return isSelected;\n }\n\n /**\n * Returns this nodes key.\n */\n getKey() {\n // Key is stable between copies\n return this.__key;\n }\n\n /**\n * Returns the zero-based index of this node within the parent.\n */\n getIndexWithinParent() {\n const parent = this.getParent();\n if (parent === null) {\n return -1;\n }\n let node = parent.getFirstChild();\n let index = 0;\n while (node !== null) {\n if (this.is(node)) {\n return index;\n }\n index++;\n node = node.getNextSibling();\n }\n return -1;\n }\n\n /**\n * Returns the parent of this node, or null if none is found.\n */\n getParent() {\n const parent = this.getLatest().__parent;\n if (parent === null) {\n return null;\n }\n return $getNodeByKey(parent);\n }\n\n /**\n * Returns the parent of this node, or throws if none is found.\n */\n getParentOrThrow() {\n const parent = this.getParent();\n if (parent === null) {\n {\n throw Error(`Expected node ${this.__key} to have a parent.`);\n }\n }\n return parent;\n }\n\n /**\n * Returns the highest (in the EditorState tree)\n * non-root ancestor of this node, or null if none is found. See {@link lexical!$isRootOrShadowRoot}\n * for more information on which Elements comprise \"roots\".\n */\n getTopLevelElement() {\n let node = this;\n while (node !== null) {\n const parent = node.getParent();\n if ($isRootOrShadowRoot(parent)) {\n if (!($isElementNode(node) || node === this && $isDecoratorNode(node))) {\n throw Error(`Children of root nodes must be elements or decorators`);\n }\n return node;\n }\n node = parent;\n }\n return null;\n }\n\n /**\n * Returns the highest (in the EditorState tree)\n * non-root ancestor of this node, or throws if none is found. See {@link lexical!$isRootOrShadowRoot}\n * for more information on which Elements comprise \"roots\".\n */\n getTopLevelElementOrThrow() {\n const parent = this.getTopLevelElement();\n if (parent === null) {\n {\n throw Error(`Expected node ${this.__key} to have a top parent element.`);\n }\n }\n return parent;\n }\n\n /**\n * Returns a list of the every ancestor of this node,\n * all the way up to the RootNode.\n *\n */\n getParents() {\n const parents = [];\n let node = this.getParent();\n while (node !== null) {\n parents.push(node);\n node = node.getParent();\n }\n return parents;\n }\n\n /**\n * Returns a list of the keys of every ancestor of this node,\n * all the way up to the RootNode.\n *\n */\n getParentKeys() {\n const parents = [];\n let node = this.getParent();\n while (node !== null) {\n parents.push(node.__key);\n node = node.getParent();\n }\n return parents;\n }\n\n /**\n * Returns the \"previous\" siblings - that is, the node that comes\n * before this one in the same parent.\n *\n */\n getPreviousSibling() {\n const self = this.getLatest();\n const prevKey = self.__prev;\n return prevKey === null ? null : $getNodeByKey(prevKey);\n }\n\n /**\n * Returns the \"previous\" siblings - that is, the nodes that come between\n * this one and the first child of it's parent, inclusive.\n *\n */\n getPreviousSiblings() {\n const siblings = [];\n const parent = this.getParent();\n if (parent === null) {\n return siblings;\n }\n let node = parent.getFirstChild();\n while (node !== null) {\n if (node.is(this)) {\n break;\n }\n siblings.push(node);\n node = node.getNextSibling();\n }\n return siblings;\n }\n\n /**\n * Returns the \"next\" siblings - that is, the node that comes\n * after this one in the same parent\n *\n */\n getNextSibling() {\n const self = this.getLatest();\n const nextKey = self.__next;\n return nextKey === null ? null : $getNodeByKey(nextKey);\n }\n\n /**\n * Returns all \"next\" siblings - that is, the nodes that come between this\n * one and the last child of it's parent, inclusive.\n *\n */\n getNextSiblings() {\n const siblings = [];\n let node = this.getNextSibling();\n while (node !== null) {\n siblings.push(node);\n node = node.getNextSibling();\n }\n return siblings;\n }\n\n /**\n * Returns the closest common ancestor of this node and the provided one or null\n * if one cannot be found.\n *\n * @param node - the other node to find the common ancestor of.\n */\n getCommonAncestor(node) {\n const a = this.getParents();\n const b = node.getParents();\n if ($isElementNode(this)) {\n a.unshift(this);\n }\n if ($isElementNode(node)) {\n b.unshift(node);\n }\n const aLength = a.length;\n const bLength = b.length;\n if (aLength === 0 || bLength === 0 || a[aLength - 1] !== b[bLength - 1]) {\n return null;\n }\n const bSet = new Set(b);\n for (let i = 0; i < aLength; i++) {\n const ancestor = a[i];\n if (bSet.has(ancestor)) {\n return ancestor;\n }\n }\n return null;\n }\n\n /**\n * Returns true if the provided node is the exact same one as this node, from Lexical's perspective.\n * Always use this instead of referential equality.\n *\n * @param object - the node to perform the equality comparison on.\n */\n is(object) {\n if (object == null) {\n return false;\n }\n return this.__key === object.__key;\n }\n\n /**\n * Returns true if this node logical precedes the target node in the editor state.\n *\n * @param targetNode - the node we're testing to see if it's after this one.\n */\n isBefore(targetNode) {\n if (this === targetNode) {\n return false;\n }\n if (targetNode.isParentOf(this)) {\n return true;\n }\n if (this.isParentOf(targetNode)) {\n return false;\n }\n const commonAncestor = this.getCommonAncestor(targetNode);\n let indexA = 0;\n let indexB = 0;\n let node = this;\n while (true) {\n const parent = node.getParentOrThrow();\n if (parent === commonAncestor) {\n indexA = node.getIndexWithinParent();\n break;\n }\n node = parent;\n }\n node = targetNode;\n while (true) {\n const parent = node.getParentOrThrow();\n if (parent === commonAncestor) {\n indexB = node.getIndexWithinParent();\n break;\n }\n node = parent;\n }\n return indexA < indexB;\n }\n\n /**\n * Returns true if this node is the parent of the target node, false otherwise.\n *\n * @param targetNode - the would-be child node.\n */\n isParentOf(targetNode) {\n const key = this.__key;\n if (key === targetNode.__key) {\n return false;\n }\n let node = targetNode;\n while (node !== null) {\n if (node.__key === key) {\n return true;\n }\n node = node.getParent();\n }\n return false;\n }\n\n // TO-DO: this function can be simplified a lot\n /**\n * Returns a list of nodes that are between this node and\n * the target node in the EditorState.\n *\n * @param targetNode - the node that marks the other end of the range of nodes to be returned.\n */\n getNodesBetween(targetNode) {\n const isBefore = this.isBefore(targetNode);\n const nodes = [];\n const visited = new Set();\n let node = this;\n while (true) {\n if (node === null) {\n break;\n }\n const key = node.__key;\n if (!visited.has(key)) {\n visited.add(key);\n nodes.push(node);\n }\n if (node === targetNode) {\n break;\n }\n const child = $isElementNode(node) ? isBefore ? node.getFirstChild() : node.getLastChild() : null;\n if (child !== null) {\n node = child;\n continue;\n }\n const nextSibling = isBefore ? node.getNextSibling() : node.getPreviousSibling();\n if (nextSibling !== null) {\n node = nextSibling;\n continue;\n }\n const parent = node.getParentOrThrow();\n if (!visited.has(parent.__key)) {\n nodes.push(parent);\n }\n if (parent === targetNode) {\n break;\n }\n let parentSibling = null;\n let ancestor = parent;\n do {\n if (ancestor === null) {\n {\n throw Error(`getNodesBetween: ancestor is null`);\n }\n }\n parentSibling = isBefore ? ancestor.getNextSibling() : ancestor.getPreviousSibling();\n ancestor = ancestor.getParent();\n if (ancestor !== null) {\n if (parentSibling === null && !visited.has(ancestor.__key)) {\n nodes.push(ancestor);\n }\n } else {\n break;\n }\n } while (parentSibling === null);\n node = parentSibling;\n }\n if (!isBefore) {\n nodes.reverse();\n }\n return nodes;\n }\n\n /**\n * Returns true if this node has been marked dirty during this update cycle.\n *\n */\n isDirty() {\n const editor = getActiveEditor();\n const dirtyLeaves = editor._dirtyLeaves;\n return dirtyLeaves !== null && dirtyLeaves.has(this.__key);\n }\n\n /**\n * Returns the latest version of the node from the active EditorState.\n * This is used to avoid getting values from stale node references.\n *\n */\n getLatest() {\n const latest = $getNodeByKey(this.__key);\n if (latest === null) {\n {\n throw Error(`Lexical node does not exist in active editor state. Avoid using the same node references between nested closures from editorState.read/editor.update.`);\n }\n }\n return latest;\n }\n\n /**\n * Returns a mutable version of the node using {@link $cloneWithProperties}\n * if necessary. Will throw an error if called outside of a Lexical Editor\n * {@link LexicalEditor.update} callback.\n *\n */\n getWritable() {\n errorOnReadOnly();\n const editorState = getActiveEditorState();\n const editor = getActiveEditor();\n const nodeMap = editorState._nodeMap;\n const key = this.__key;\n // Ensure we get the latest node from pending state\n const latestNode = this.getLatest();\n const cloneNotNeeded = editor._cloneNotNeeded;\n const selection = $getSelection();\n if (selection !== null) {\n selection.setCachedNodes(null);\n }\n if (cloneNotNeeded.has(key)) {\n // Transforms clear the dirty node set on each iteration to keep track on newly dirty nodes\n internalMarkNodeAsDirty(latestNode);\n return latestNode;\n }\n const mutableNode = $cloneWithProperties(latestNode);\n cloneNotNeeded.add(key);\n internalMarkNodeAsDirty(mutableNode);\n // Update reference in node map\n nodeMap.set(key, mutableNode);\n return mutableNode;\n }\n\n /**\n * Returns the text content of the node. Override this for\n * custom nodes that should have a representation in plain text\n * format (for copy + paste, for example)\n *\n */\n getTextContent() {\n return '';\n }\n\n /**\n * Returns the length of the string produced by calling getTextContent on this node.\n *\n */\n getTextContentSize() {\n return this.getTextContent().length;\n }\n\n // View\n\n /**\n * Called during the reconciliation process to determine which nodes\n * to insert into the DOM for this Lexical Node.\n *\n * This method must return exactly one HTMLElement. Nested elements are not supported.\n *\n * Do not attempt to update the Lexical EditorState during this phase of the update lifecyle.\n *\n * @param _config - allows access to things like the EditorTheme (to apply classes) during reconciliation.\n * @param _editor - allows access to the editor for context during reconciliation.\n *\n * */\n createDOM(_config, _editor) {\n {\n throw Error(`createDOM: base method not extended`);\n }\n }\n\n /**\n * Called when a node changes and should update the DOM\n * in whatever way is necessary to make it align with any changes that might\n * have happened during the update.\n *\n * Returning \"true\" here will cause lexical to unmount and recreate the DOM node\n * (by calling createDOM). You would need to do this if the element tag changes,\n * for instance.\n *\n * */\n updateDOM(_prevNode, _dom, _config) {\n {\n throw Error(`updateDOM: base method not extended`);\n }\n }\n\n /**\n * Controls how the this node is serialized to HTML. This is important for\n * copy and paste between Lexical and non-Lexical editors, or Lexical editors with different namespaces,\n * in which case the primary transfer format is HTML. It's also important if you're serializing\n * to HTML for any other reason via {@link @lexical/html!$generateHtmlFromNodes}. You could\n * also use this method to build your own HTML renderer.\n *\n * */\n exportDOM(editor) {\n const element = this.createDOM(editor._config, editor);\n return {\n element\n };\n }\n\n /**\n * Controls how the this node is serialized to JSON. This is important for\n * copy and paste between Lexical editors sharing the same namespace. It's also important\n * if you're serializing to JSON for persistent storage somewhere.\n * See [Serialization & Deserialization](https://lexical.dev/docs/concepts/serialization#lexical---html).\n *\n * */\n exportJSON() {\n {\n throw Error(`exportJSON: base method not extended`);\n }\n }\n\n /**\n * Controls how the this node is deserialized from JSON. This is usually boilerplate,\n * but provides an abstraction between the node implementation and serialized interface that can\n * be important if you ever make breaking changes to a node schema (by adding or removing properties).\n * See [Serialization & Deserialization](https://lexical.dev/docs/concepts/serialization#lexical---html).\n *\n * */\n static importJSON(_serializedNode) {\n {\n throw Error(`LexicalNode: Node ${this.name} does not implement .importJSON().`);\n }\n }\n /**\n * @experimental\n *\n * Registers the returned function as a transform on the node during\n * Editor initialization. Most such use cases should be addressed via\n * the {@link LexicalEditor.registerNodeTransform} API.\n *\n * Experimental - use at your own risk.\n */\n static transform() {\n return null;\n }\n\n // Setters and mutators\n\n /**\n * Removes this LexicalNode from the EditorState. If the node isn't re-inserted\n * somewhere, the Lexical garbage collector will eventually clean it up.\n *\n * @param preserveEmptyParent - If falsy, the node's parent will be removed if\n * it's empty after the removal operation. This is the default behavior, subject to\n * other node heuristics such as {@link ElementNode#canBeEmpty}\n * */\n remove(preserveEmptyParent) {\n $removeNode(this, true, preserveEmptyParent);\n }\n\n /**\n * Replaces this LexicalNode with the provided node, optionally transferring the children\n * of the replaced node to the replacing node.\n *\n * @param replaceWith - The node to replace this one with.\n * @param includeChildren - Whether or not to transfer the children of this node to the replacing node.\n * */\n replace(replaceWith, includeChildren) {\n errorOnReadOnly();\n let selection = $getSelection();\n if (selection !== null) {\n selection = selection.clone();\n }\n errorOnInsertTextNodeOnRoot(this, replaceWith);\n const self = this.getLatest();\n const toReplaceKey = this.__key;\n const key = replaceWith.__key;\n const writableReplaceWith = replaceWith.getWritable();\n const writableParent = this.getParentOrThrow().getWritable();\n const size = writableParent.__size;\n removeFromParent(writableReplaceWith);\n const prevSibling = self.getPreviousSibling();\n const nextSibling = self.getNextSibling();\n const prevKey = self.__prev;\n const nextKey = self.__next;\n const parentKey = self.__parent;\n $removeNode(self, false, true);\n if (prevSibling === null) {\n writableParent.__first = key;\n } else {\n const writablePrevSibling = prevSibling.getWritable();\n writablePrevSibling.__next = key;\n }\n writableReplaceWith.__prev = prevKey;\n if (nextSibling === null) {\n writableParent.__last = key;\n } else {\n const writableNextSibling = nextSibling.getWritable();\n writableNextSibling.__prev = key;\n }\n writableReplaceWith.__next = nextKey;\n writableReplaceWith.__parent = parentKey;\n writableParent.__size = size;\n if (includeChildren) {\n if (!($isElementNode(this) && $isElementNode(writableReplaceWith))) {\n throw Error(`includeChildren should only be true for ElementNodes`);\n }\n this.getChildren().forEach(child => {\n writableReplaceWith.append(child);\n });\n }\n if ($isRangeSelection(selection)) {\n $setSelection(selection);\n const anchor = selection.anchor;\n const focus = selection.focus;\n if (anchor.key === toReplaceKey) {\n $moveSelectionPointToEnd(anchor, writableReplaceWith);\n }\n if (focus.key === toReplaceKey) {\n $moveSelectionPointToEnd(focus, writableReplaceWith);\n }\n }\n if ($getCompositionKey() === toReplaceKey) {\n $setCompositionKey(key);\n }\n return writableReplaceWith;\n }\n\n /**\n * Inserts a node after this LexicalNode (as the next sibling).\n *\n * @param nodeToInsert - The node to insert after this one.\n * @param restoreSelection - Whether or not to attempt to resolve the\n * selection to the appropriate place after the operation is complete.\n * */\n insertAfter(nodeToInsert, restoreSelection = true) {\n errorOnReadOnly();\n errorOnInsertTextNodeOnRoot(this, nodeToInsert);\n const writableSelf = this.getWritable();\n const writableNodeToInsert = nodeToInsert.getWritable();\n const oldParent = writableNodeToInsert.getParent();\n const selection = $getSelection();\n let elementAnchorSelectionOnNode = false;\n let elementFocusSelectionOnNode = false;\n if (oldParent !== null) {\n // TODO: this is O(n), can we improve?\n const oldIndex = nodeToInsert.getIndexWithinParent();\n removeFromParent(writableNodeToInsert);\n if ($isRangeSelection(selection)) {\n const oldParentKey = oldParent.__key;\n const anchor = selection.anchor;\n const focus = selection.focus;\n elementAnchorSelectionOnNode = anchor.type === 'element' && anchor.key === oldParentKey && anchor.offset === oldIndex + 1;\n elementFocusSelectionOnNode = focus.type === 'element' && focus.key === oldParentKey && focus.offset === oldIndex + 1;\n }\n }\n const nextSibling = this.getNextSibling();\n const writableParent = this.getParentOrThrow().getWritable();\n const insertKey = writableNodeToInsert.__key;\n const nextKey = writableSelf.__next;\n if (nextSibling === null) {\n writableParent.__last = insertKey;\n } else {\n const writableNextSibling = nextSibling.getWritable();\n writableNextSibling.__prev = insertKey;\n }\n writableParent.__size++;\n writableSelf.__next = insertKey;\n writableNodeToInsert.__next = nextKey;\n writableNodeToInsert.__prev = writableSelf.__key;\n writableNodeToInsert.__parent = writableSelf.__parent;\n if (restoreSelection && $isRangeSelection(selection)) {\n const index = this.getIndexWithinParent();\n $updateElementSelectionOnCreateDeleteNode(selection, writableParent, index + 1);\n const writableParentKey = writableParent.__key;\n if (elementAnchorSelectionOnNode) {\n selection.anchor.set(writableParentKey, index + 2, 'element');\n }\n if (elementFocusSelectionOnNode) {\n selection.focus.set(writableParentKey, index + 2, 'element');\n }\n }\n return nodeToInsert;\n }\n\n /**\n * Inserts a node before this LexicalNode (as the previous sibling).\n *\n * @param nodeToInsert - The node to insert before this one.\n * @param restoreSelection - Whether or not to attempt to resolve the\n * selection to the appropriate place after the operation is complete.\n * */\n insertBefore(nodeToInsert, restoreSelection = true) {\n errorOnReadOnly();\n errorOnInsertTextNodeOnRoot(this, nodeToInsert);\n const writableSelf = this.getWritable();\n const writableNodeToInsert = nodeToInsert.getWritable();\n const insertKey = writableNodeToInsert.__key;\n removeFromParent(writableNodeToInsert);\n const prevSibling = this.getPreviousSibling();\n const writableParent = this.getParentOrThrow().getWritable();\n const prevKey = writableSelf.__prev;\n // TODO: this is O(n), can we improve?\n const index = this.getIndexWithinParent();\n if (prevSibling === null) {\n writableParent.__first = insertKey;\n } else {\n const writablePrevSibling = prevSibling.getWritable();\n writablePrevSibling.__next = insertKey;\n }\n writableParent.__size++;\n writableSelf.__prev = insertKey;\n writableNodeToInsert.__prev = prevKey;\n writableNodeToInsert.__next = writableSelf.__key;\n writableNodeToInsert.__parent = writableSelf.__parent;\n const selection = $getSelection();\n if (restoreSelection && $isRangeSelection(selection)) {\n const parent = this.getParentOrThrow();\n $updateElementSelectionOnCreateDeleteNode(selection, parent, index);\n }\n return nodeToInsert;\n }\n\n /**\n * Whether or not this node has a required parent. Used during copy + paste operations\n * to normalize nodes that would otherwise be orphaned. For example, ListItemNodes without\n * a ListNode parent or TextNodes with a ParagraphNode parent.\n *\n * */\n isParentRequired() {\n return false;\n }\n\n /**\n * The creation logic for any required parent. Should be implemented if {@link isParentRequired} returns true.\n *\n * */\n createParentElementNode() {\n return $createParagraphNode();\n }\n selectStart() {\n return this.selectPrevious();\n }\n selectEnd() {\n return this.selectNext(0, 0);\n }\n\n /**\n * Moves selection to the previous sibling of this node, at the specified offsets.\n *\n * @param anchorOffset - The anchor offset for selection.\n * @param focusOffset - The focus offset for selection\n * */\n selectPrevious(anchorOffset, focusOffset) {\n errorOnReadOnly();\n const prevSibling = this.getPreviousSibling();\n const parent = this.getParentOrThrow();\n if (prevSibling === null) {\n return parent.select(0, 0);\n }\n if ($isElementNode(prevSibling)) {\n return prevSibling.select();\n } else if (!$isTextNode(prevSibling)) {\n const index = prevSibling.getIndexWithinParent() + 1;\n return parent.select(index, index);\n }\n return prevSibling.select(anchorOffset, focusOffset);\n }\n\n /**\n * Moves selection to the next sibling of this node, at the specified offsets.\n *\n * @param anchorOffset - The anchor offset for selection.\n * @param focusOffset - The focus offset for selection\n * */\n selectNext(anchorOffset, focusOffset) {\n errorOnReadOnly();\n const nextSibling = this.getNextSibling();\n const parent = this.getParentOrThrow();\n if (nextSibling === null) {\n return parent.select();\n }\n if ($isElementNode(nextSibling)) {\n return nextSibling.select(0, 0);\n } else if (!$isTextNode(nextSibling)) {\n const index = nextSibling.getIndexWithinParent();\n return parent.select(index, index);\n }\n return nextSibling.select(anchorOffset, focusOffset);\n }\n\n /**\n * Marks a node dirty, triggering transforms and\n * forcing it to be reconciled during the update cycle.\n *\n * */\n markDirty() {\n this.getWritable();\n }\n}\nfunction errorOnTypeKlassMismatch(type, klass) {\n const registeredNode = getActiveEditor()._nodes.get(type);\n // Common error - split in its own invariant\n if (registeredNode === undefined) {\n {\n throw Error(`Create node: Attempted to create node ${klass.name} that was not configured to be used on the editor.`);\n }\n }\n const editorKlass = registeredNode.klass;\n if (editorKlass !== klass) {\n {\n throw Error(`Create node: Type ${type} in node ${klass.name} does not match registered node ${editorKlass.name} with the same type`);\n }\n }\n}\n\n/**\n * Insert a series of nodes after this LexicalNode (as next siblings)\n *\n * @param firstToInsert - The first node to insert after this one.\n * @param lastToInsert - The last node to insert after this one. Must be a\n * later sibling of FirstNode. If not provided, it will be its last sibling.\n */\nfunction insertRangeAfter(node, firstToInsert, lastToInsert) {\n const lastToInsert2 = firstToInsert.getParentOrThrow().getLastChild();\n let current = firstToInsert;\n const nodesToInsert = [firstToInsert];\n while (current !== lastToInsert2) {\n if (!current.getNextSibling()) {\n {\n throw Error(`insertRangeAfter: lastToInsert must be a later sibling of firstToInsert`);\n }\n }\n current = current.getNextSibling();\n nodesToInsert.push(current);\n }\n let currentNode = node;\n for (const nodeToInsert of nodesToInsert) {\n currentNode = currentNode.insertAfter(nodeToInsert);\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/** @noInheritDoc */\nclass LineBreakNode extends LexicalNode {\n static getType() {\n return 'linebreak';\n }\n static clone(node) {\n return new LineBreakNode(node.__key);\n }\n constructor(key) {\n super(key);\n }\n getTextContent() {\n return '\\n';\n }\n createDOM() {\n return document.createElement('br');\n }\n updateDOM() {\n return false;\n }\n static importDOM() {\n return {\n br: node => {\n if (isOnlyChildInBlockNode(node) || isLastChildInBlockNode(node)) {\n return null;\n }\n return {\n conversion: $convertLineBreakElement,\n priority: 0\n };\n }\n };\n }\n static importJSON(serializedLineBreakNode) {\n return $createLineBreakNode();\n }\n exportJSON() {\n return {\n type: 'linebreak',\n version: 1\n };\n }\n}\nfunction $convertLineBreakElement(node) {\n return {\n node: $createLineBreakNode()\n };\n}\nfunction $createLineBreakNode() {\n return $applyNodeReplacement(new LineBreakNode());\n}\nfunction $isLineBreakNode(node) {\n return node instanceof LineBreakNode;\n}\nfunction isOnlyChildInBlockNode(node) {\n const parentElement = node.parentElement;\n if (parentElement !== null && isBlockDomNode(parentElement)) {\n const firstChild = parentElement.firstChild;\n if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {\n const lastChild = parentElement.lastChild;\n if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) {\n return true;\n }\n }\n }\n return false;\n}\nfunction isLastChildInBlockNode(node) {\n const parentElement = node.parentElement;\n if (parentElement !== null && isBlockDomNode(parentElement)) {\n // check if node is first child, because only childs dont count\n const firstChild = parentElement.firstChild;\n if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {\n return false;\n }\n\n // check if its last child\n const lastChild = parentElement.lastChild;\n if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) {\n return true;\n }\n }\n return false;\n}\nfunction isWhitespaceDomTextNode(node) {\n return node.nodeType === DOM_TEXT_TYPE && /^( |\\t|\\r?\\n)+$/.test(node.textContent || '');\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction getElementOuterTag(node, format) {\n if (format & IS_CODE) {\n return 'code';\n }\n if (format & IS_HIGHLIGHT) {\n return 'mark';\n }\n if (format & IS_SUBSCRIPT) {\n return 'sub';\n }\n if (format & IS_SUPERSCRIPT) {\n return 'sup';\n }\n return null;\n}\nfunction getElementInnerTag(node, format) {\n if (format & IS_BOLD) {\n return 'strong';\n }\n if (format & IS_ITALIC) {\n return 'em';\n }\n return 'span';\n}\nfunction setTextThemeClassNames(tag, prevFormat, nextFormat, dom, textClassNames) {\n const domClassList = dom.classList;\n // Firstly we handle the base theme.\n let classNames = getCachedClassNameArray(textClassNames, 'base');\n if (classNames !== undefined) {\n domClassList.add(...classNames);\n }\n // Secondly we handle the special case: underline + strikethrough.\n // We have to do this as we need a way to compose the fact that\n // the same CSS property will need to be used: text-decoration.\n // In an ideal world we shouldn't have to do this, but there's no\n // easy workaround for many atomic CSS systems today.\n classNames = getCachedClassNameArray(textClassNames, 'underlineStrikethrough');\n let hasUnderlineStrikethrough = false;\n const prevUnderlineStrikethrough = prevFormat & IS_UNDERLINE && prevFormat & IS_STRIKETHROUGH;\n const nextUnderlineStrikethrough = nextFormat & IS_UNDERLINE && nextFormat & IS_STRIKETHROUGH;\n if (classNames !== undefined) {\n if (nextUnderlineStrikethrough) {\n hasUnderlineStrikethrough = true;\n if (!prevUnderlineStrikethrough) {\n domClassList.add(...classNames);\n }\n } else if (prevUnderlineStrikethrough) {\n domClassList.remove(...classNames);\n }\n }\n for (const key in TEXT_TYPE_TO_FORMAT) {\n const format = key;\n const flag = TEXT_TYPE_TO_FORMAT[format];\n classNames = getCachedClassNameArray(textClassNames, key);\n if (classNames !== undefined) {\n if (nextFormat & flag) {\n if (hasUnderlineStrikethrough && (key === 'underline' || key === 'strikethrough')) {\n if (prevFormat & flag) {\n domClassList.remove(...classNames);\n }\n continue;\n }\n if ((prevFormat & flag) === 0 || prevUnderlineStrikethrough && key === 'underline' || key === 'strikethrough') {\n domClassList.add(...classNames);\n }\n } else if (prevFormat & flag) {\n domClassList.remove(...classNames);\n }\n }\n }\n}\nfunction diffComposedText(a, b) {\n const aLength = a.length;\n const bLength = b.length;\n let left = 0;\n let right = 0;\n while (left < aLength && left < bLength && a[left] === b[left]) {\n left++;\n }\n while (right + left < aLength && right + left < bLength && a[aLength - right - 1] === b[bLength - right - 1]) {\n right++;\n }\n return [left, aLength - left - right, b.slice(left, bLength - right)];\n}\nfunction setTextContent(nextText, dom, node) {\n const firstChild = dom.firstChild;\n const isComposing = node.isComposing();\n // Always add a suffix if we're composing a node\n const suffix = isComposing ? COMPOSITION_SUFFIX : '';\n const text = nextText + suffix;\n if (firstChild == null) {\n dom.textContent = text;\n } else {\n const nodeValue = firstChild.nodeValue;\n if (nodeValue !== text) {\n if (isComposing || IS_FIREFOX) {\n // We also use the diff composed text for general text in FF to avoid\n // the spellcheck red line from flickering.\n const [index, remove, insert] = diffComposedText(nodeValue, text);\n if (remove !== 0) {\n // @ts-expect-error\n firstChild.deleteData(index, remove);\n }\n // @ts-expect-error\n firstChild.insertData(index, insert);\n } else {\n firstChild.nodeValue = text;\n }\n }\n }\n}\nfunction createTextInnerDOM(innerDOM, node, innerTag, format, text, config) {\n setTextContent(text, innerDOM, node);\n const theme = config.theme;\n // Apply theme class names\n const textClassNames = theme.text;\n if (textClassNames !== undefined) {\n setTextThemeClassNames(innerTag, 0, format, innerDOM, textClassNames);\n }\n}\nfunction wrapElementWith(element, tag) {\n const el = document.createElement(tag);\n el.appendChild(element);\n return el;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\n\n/** @noInheritDoc */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nclass TextNode extends LexicalNode {\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n static getType() {\n return 'text';\n }\n static clone(node) {\n return new TextNode(node.__text, node.__key);\n }\n afterCloneFrom(prevNode) {\n super.afterCloneFrom(prevNode);\n this.__format = prevNode.__format;\n this.__style = prevNode.__style;\n this.__mode = prevNode.__mode;\n this.__detail = prevNode.__detail;\n }\n constructor(text, key) {\n super(key);\n this.__text = text;\n this.__format = 0;\n this.__style = '';\n this.__mode = 0;\n this.__detail = 0;\n }\n\n /**\n * Returns a 32-bit integer that represents the TextFormatTypes currently applied to the\n * TextNode. You probably don't want to use this method directly - consider using TextNode.hasFormat instead.\n *\n * @returns a number representing the format of the text node.\n */\n getFormat() {\n const self = this.getLatest();\n return self.__format;\n }\n\n /**\n * Returns a 32-bit integer that represents the TextDetailTypes currently applied to the\n * TextNode. You probably don't want to use this method directly - consider using TextNode.isDirectionless\n * or TextNode.isUnmergeable instead.\n *\n * @returns a number representing the detail of the text node.\n */\n getDetail() {\n const self = this.getLatest();\n return self.__detail;\n }\n\n /**\n * Returns the mode (TextModeType) of the TextNode, which may be \"normal\", \"token\", or \"segmented\"\n *\n * @returns TextModeType.\n */\n getMode() {\n const self = this.getLatest();\n return TEXT_TYPE_TO_MODE[self.__mode];\n }\n\n /**\n * Returns the styles currently applied to the node. This is analogous to CSSText in the DOM.\n *\n * @returns CSSText-like string of styles applied to the underlying DOM node.\n */\n getStyle() {\n const self = this.getLatest();\n return self.__style;\n }\n\n /**\n * Returns whether or not the node is in \"token\" mode. TextNodes in token mode can be navigated through character-by-character\n * with a RangeSelection, but are deleted as a single entity (not invdividually by character).\n *\n * @returns true if the node is in token mode, false otherwise.\n */\n isToken() {\n const self = this.getLatest();\n return self.__mode === IS_TOKEN;\n }\n\n /**\n *\n * @returns true if Lexical detects that an IME or other 3rd-party script is attempting to\n * mutate the TextNode, false otherwise.\n */\n isComposing() {\n return this.__key === $getCompositionKey();\n }\n\n /**\n * Returns whether or not the node is in \"segemented\" mode. TextNodes in segemented mode can be navigated through character-by-character\n * with a RangeSelection, but are deleted in space-delimited \"segments\".\n *\n * @returns true if the node is in segmented mode, false otherwise.\n */\n isSegmented() {\n const self = this.getLatest();\n return self.__mode === IS_SEGMENTED;\n }\n /**\n * Returns whether or not the node is \"directionless\". Directionless nodes don't respect changes between RTL and LTR modes.\n *\n * @returns true if the node is directionless, false otherwise.\n */\n isDirectionless() {\n const self = this.getLatest();\n return (self.__detail & IS_DIRECTIONLESS) !== 0;\n }\n /**\n * Returns whether or not the node is unmergeable. In some scenarios, Lexical tries to merge\n * adjacent TextNodes into a single TextNode. If a TextNode is unmergeable, this won't happen.\n *\n * @returns true if the node is unmergeable, false otherwise.\n */\n isUnmergeable() {\n const self = this.getLatest();\n return (self.__detail & IS_UNMERGEABLE) !== 0;\n }\n\n /**\n * Returns whether or not the node has the provided format applied. Use this with the human-readable TextFormatType\n * string values to get the format of a TextNode.\n *\n * @param type - the TextFormatType to check for.\n *\n * @returns true if the node has the provided format, false otherwise.\n */\n hasFormat(type) {\n const formatFlag = TEXT_TYPE_TO_FORMAT[type];\n return (this.getFormat() & formatFlag) !== 0;\n }\n\n /**\n * Returns whether or not the node is simple text. Simple text is defined as a TextNode that has the string type \"text\"\n * (i.e., not a subclass) and has no mode applied to it (i.e., not segmented or token).\n *\n * @returns true if the node is simple text, false otherwise.\n */\n isSimpleText() {\n return this.__type === 'text' && this.__mode === 0;\n }\n\n /**\n * Returns the text content of the node as a string.\n *\n * @returns a string representing the text content of the node.\n */\n getTextContent() {\n const self = this.getLatest();\n return self.__text;\n }\n\n /**\n * Returns the format flags applied to the node as a 32-bit integer.\n *\n * @returns a number representing the TextFormatTypes applied to the node.\n */\n getFormatFlags(type, alignWithFormat) {\n const self = this.getLatest();\n const format = self.__format;\n return toggleTextFormatType(format, type, alignWithFormat);\n }\n\n /**\n *\n * @returns true if the text node supports font styling, false otherwise.\n */\n canHaveFormat() {\n return true;\n }\n\n // View\n\n createDOM(config, editor) {\n const format = this.__format;\n const outerTag = getElementOuterTag(this, format);\n const innerTag = getElementInnerTag(this, format);\n const tag = outerTag === null ? innerTag : outerTag;\n const dom = document.createElement(tag);\n let innerDOM = dom;\n if (this.hasFormat('code')) {\n dom.setAttribute('spellcheck', 'false');\n }\n if (outerTag !== null) {\n innerDOM = document.createElement(innerTag);\n dom.appendChild(innerDOM);\n }\n const text = this.__text;\n createTextInnerDOM(innerDOM, this, innerTag, format, text, config);\n const style = this.__style;\n if (style !== '') {\n dom.style.cssText = style;\n }\n return dom;\n }\n updateDOM(prevNode, dom, config) {\n const nextText = this.__text;\n const prevFormat = prevNode.__format;\n const nextFormat = this.__format;\n const prevOuterTag = getElementOuterTag(this, prevFormat);\n const nextOuterTag = getElementOuterTag(this, nextFormat);\n const prevInnerTag = getElementInnerTag(this, prevFormat);\n const nextInnerTag = getElementInnerTag(this, nextFormat);\n const prevTag = prevOuterTag === null ? prevInnerTag : prevOuterTag;\n const nextTag = nextOuterTag === null ? nextInnerTag : nextOuterTag;\n if (prevTag !== nextTag) {\n return true;\n }\n if (prevOuterTag === nextOuterTag && prevInnerTag !== nextInnerTag) {\n // should always be an element\n const prevInnerDOM = dom.firstChild;\n if (prevInnerDOM == null) {\n {\n throw Error(`updateDOM: prevInnerDOM is null or undefined`);\n }\n }\n const nextInnerDOM = document.createElement(nextInnerTag);\n createTextInnerDOM(nextInnerDOM, this, nextInnerTag, nextFormat, nextText, config);\n dom.replaceChild(nextInnerDOM, prevInnerDOM);\n return false;\n }\n let innerDOM = dom;\n if (nextOuterTag !== null) {\n if (prevOuterTag !== null) {\n innerDOM = dom.firstChild;\n if (innerDOM == null) {\n {\n throw Error(`updateDOM: innerDOM is null or undefined`);\n }\n }\n }\n }\n setTextContent(nextText, innerDOM, this);\n const theme = config.theme;\n // Apply theme class names\n const textClassNames = theme.text;\n if (textClassNames !== undefined && prevFormat !== nextFormat) {\n setTextThemeClassNames(nextInnerTag, prevFormat, nextFormat, innerDOM, textClassNames);\n }\n const prevStyle = prevNode.__style;\n const nextStyle = this.__style;\n if (prevStyle !== nextStyle) {\n dom.style.cssText = nextStyle;\n }\n return false;\n }\n static importDOM() {\n return {\n '#text': () => ({\n conversion: $convertTextDOMNode,\n priority: 0\n }),\n b: () => ({\n conversion: convertBringAttentionToElement,\n priority: 0\n }),\n code: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n }),\n em: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n }),\n i: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n }),\n s: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n }),\n span: () => ({\n conversion: convertSpanElement,\n priority: 0\n }),\n strong: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n }),\n sub: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n }),\n sup: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n }),\n u: () => ({\n conversion: convertTextFormatElement,\n priority: 0\n })\n };\n }\n static importJSON(serializedNode) {\n const node = $createTextNode(serializedNode.text);\n node.setFormat(serializedNode.format);\n node.setDetail(serializedNode.detail);\n node.setMode(serializedNode.mode);\n node.setStyle(serializedNode.style);\n return node;\n }\n\n // This improves Lexical's basic text output in copy+paste plus\n // for headless mode where people might use Lexical to generate\n // HTML content and not have the ability to use CSS classes.\n exportDOM(editor) {\n let {\n element\n } = super.exportDOM(editor);\n if (!(element !== null && isHTMLElement(element))) {\n throw Error(`Expected TextNode createDOM to always return a HTMLElement`);\n }\n element.style.whiteSpace = 'pre-wrap';\n // This is the only way to properly add support for most clients,\n // even if it's semantically incorrect to have to resort to using\n // , , , elements.\n if (this.hasFormat('bold')) {\n element = wrapElementWith(element, 'b');\n }\n if (this.hasFormat('italic')) {\n element = wrapElementWith(element, 'i');\n }\n if (this.hasFormat('strikethrough')) {\n element = wrapElementWith(element, 's');\n }\n if (this.hasFormat('underline')) {\n element = wrapElementWith(element, 'u');\n }\n return {\n element\n };\n }\n exportJSON() {\n return {\n detail: this.getDetail(),\n format: this.getFormat(),\n mode: this.getMode(),\n style: this.getStyle(),\n text: this.getTextContent(),\n type: 'text',\n version: 1\n };\n }\n\n // Mutators\n selectionTransform(prevSelection, nextSelection) {\n return;\n }\n\n /**\n * Sets the node format to the provided TextFormatType or 32-bit integer. Note that the TextFormatType\n * version of the argument can only specify one format and doing so will remove all other formats that\n * may be applied to the node. For toggling behavior, consider using {@link TextNode.toggleFormat}\n *\n * @param format - TextFormatType or 32-bit integer representing the node format.\n *\n * @returns this TextNode.\n * // TODO 0.12 This should just be a `string`.\n */\n setFormat(format) {\n const self = this.getWritable();\n self.__format = typeof format === 'string' ? TEXT_TYPE_TO_FORMAT[format] : format;\n return self;\n }\n\n /**\n * Sets the node detail to the provided TextDetailType or 32-bit integer. Note that the TextDetailType\n * version of the argument can only specify one detail value and doing so will remove all other detail values that\n * may be applied to the node. For toggling behavior, consider using {@link TextNode.toggleDirectionless}\n * or {@link TextNode.toggleUnmergeable}\n *\n * @param detail - TextDetailType or 32-bit integer representing the node detail.\n *\n * @returns this TextNode.\n * // TODO 0.12 This should just be a `string`.\n */\n setDetail(detail) {\n const self = this.getWritable();\n self.__detail = typeof detail === 'string' ? DETAIL_TYPE_TO_DETAIL[detail] : detail;\n return self;\n }\n\n /**\n * Sets the node style to the provided CSSText-like string. Set this property as you\n * would an HTMLElement style attribute to apply inline styles to the underlying DOM Element.\n *\n * @param style - CSSText to be applied to the underlying HTMLElement.\n *\n * @returns this TextNode.\n */\n setStyle(style) {\n const self = this.getWritable();\n self.__style = style;\n return self;\n }\n\n /**\n * Applies the provided format to this TextNode if it's not present. Removes it if it's present.\n * The subscript and superscript formats are mutually exclusive.\n * Prefer using this method to turn specific formats on and off.\n *\n * @param type - TextFormatType to toggle.\n *\n * @returns this TextNode.\n */\n toggleFormat(type) {\n const format = this.getFormat();\n const newFormat = toggleTextFormatType(format, type, null);\n return this.setFormat(newFormat);\n }\n\n /**\n * Toggles the directionless detail value of the node. Prefer using this method over setDetail.\n *\n * @returns this TextNode.\n */\n toggleDirectionless() {\n const self = this.getWritable();\n self.__detail ^= IS_DIRECTIONLESS;\n return self;\n }\n\n /**\n * Toggles the unmergeable detail value of the node. Prefer using this method over setDetail.\n *\n * @returns this TextNode.\n */\n toggleUnmergeable() {\n const self = this.getWritable();\n self.__detail ^= IS_UNMERGEABLE;\n return self;\n }\n\n /**\n * Sets the mode of the node.\n *\n * @returns this TextNode.\n */\n setMode(type) {\n const mode = TEXT_MODE_TO_TYPE[type];\n if (this.__mode === mode) {\n return this;\n }\n const self = this.getWritable();\n self.__mode = mode;\n return self;\n }\n\n /**\n * Sets the text content of the node.\n *\n * @param text - the string to set as the text value of the node.\n *\n * @returns this TextNode.\n */\n setTextContent(text) {\n if (this.__text === text) {\n return this;\n }\n const self = this.getWritable();\n self.__text = text;\n return self;\n }\n\n /**\n * Sets the current Lexical selection to be a RangeSelection with anchor and focus on this TextNode at the provided offsets.\n *\n * @param _anchorOffset - the offset at which the Selection anchor will be placed.\n * @param _focusOffset - the offset at which the Selection focus will be placed.\n *\n * @returns the new RangeSelection.\n */\n select(_anchorOffset, _focusOffset) {\n errorOnReadOnly();\n let anchorOffset = _anchorOffset;\n let focusOffset = _focusOffset;\n const selection = $getSelection();\n const text = this.getTextContent();\n const key = this.__key;\n if (typeof text === 'string') {\n const lastOffset = text.length;\n if (anchorOffset === undefined) {\n anchorOffset = lastOffset;\n }\n if (focusOffset === undefined) {\n focusOffset = lastOffset;\n }\n } else {\n anchorOffset = 0;\n focusOffset = 0;\n }\n if (!$isRangeSelection(selection)) {\n return $internalMakeRangeSelection(key, anchorOffset, key, focusOffset, 'text', 'text');\n } else {\n const compositionKey = $getCompositionKey();\n if (compositionKey === selection.anchor.key || compositionKey === selection.focus.key) {\n $setCompositionKey(key);\n }\n selection.setTextNodeRange(this, anchorOffset, this, focusOffset);\n }\n return selection;\n }\n selectStart() {\n return this.select(0, 0);\n }\n selectEnd() {\n const size = this.getTextContentSize();\n return this.select(size, size);\n }\n\n /**\n * Inserts the provided text into this TextNode at the provided offset, deleting the number of characters\n * specified. Can optionally calculate a new selection after the operation is complete.\n *\n * @param offset - the offset at which the splice operation should begin.\n * @param delCount - the number of characters to delete, starting from the offset.\n * @param newText - the text to insert into the TextNode at the offset.\n * @param moveSelection - optional, whether or not to move selection to the end of the inserted substring.\n *\n * @returns this TextNode.\n */\n spliceText(offset, delCount, newText, moveSelection) {\n const writableSelf = this.getWritable();\n const text = writableSelf.__text;\n const handledTextLength = newText.length;\n let index = offset;\n if (index < 0) {\n index = handledTextLength + index;\n if (index < 0) {\n index = 0;\n }\n }\n const selection = $getSelection();\n if (moveSelection && $isRangeSelection(selection)) {\n const newOffset = offset + handledTextLength;\n selection.setTextNodeRange(writableSelf, newOffset, writableSelf, newOffset);\n }\n const updatedText = text.slice(0, index) + newText + text.slice(index + delCount);\n writableSelf.__text = updatedText;\n return writableSelf;\n }\n\n /**\n * This method is meant to be overriden by TextNode subclasses to control the behavior of those nodes\n * when a user event would cause text to be inserted before them in the editor. If true, Lexical will attempt\n * to insert text into this node. If false, it will insert the text in a new sibling node.\n *\n * @returns true if text can be inserted before the node, false otherwise.\n */\n canInsertTextBefore() {\n return true;\n }\n\n /**\n * This method is meant to be overriden by TextNode subclasses to control the behavior of those nodes\n * when a user event would cause text to be inserted after them in the editor. If true, Lexical will attempt\n * to insert text into this node. If false, it will insert the text in a new sibling node.\n *\n * @returns true if text can be inserted after the node, false otherwise.\n */\n canInsertTextAfter() {\n return true;\n }\n\n /**\n * Splits this TextNode at the provided character offsets, forming new TextNodes from the substrings\n * formed by the split, and inserting those new TextNodes into the editor, replacing the one that was split.\n *\n * @param splitOffsets - rest param of the text content character offsets at which this node should be split.\n *\n * @returns an Array containing the newly-created TextNodes.\n */\n splitText(...splitOffsets) {\n errorOnReadOnly();\n const self = this.getLatest();\n const textContent = self.getTextContent();\n const key = self.__key;\n const compositionKey = $getCompositionKey();\n const offsetsSet = new Set(splitOffsets);\n const parts = [];\n const textLength = textContent.length;\n let string = '';\n for (let i = 0; i < textLength; i++) {\n if (string !== '' && offsetsSet.has(i)) {\n parts.push(string);\n string = '';\n }\n string += textContent[i];\n }\n if (string !== '') {\n parts.push(string);\n }\n const partsLength = parts.length;\n if (partsLength === 0) {\n return [];\n } else if (parts[0] === textContent) {\n return [self];\n }\n const firstPart = parts[0];\n const parent = self.getParent();\n let writableNode;\n const format = self.getFormat();\n const style = self.getStyle();\n const detail = self.__detail;\n let hasReplacedSelf = false;\n if (self.isSegmented()) {\n // Create a new TextNode\n writableNode = $createTextNode(firstPart);\n writableNode.__format = format;\n writableNode.__style = style;\n writableNode.__detail = detail;\n hasReplacedSelf = true;\n } else {\n // For the first part, update the existing node\n writableNode = self.getWritable();\n writableNode.__text = firstPart;\n }\n\n // Handle selection\n const selection = $getSelection();\n\n // Then handle all other parts\n const splitNodes = [writableNode];\n let textSize = firstPart.length;\n for (let i = 1; i < partsLength; i++) {\n const part = parts[i];\n const partSize = part.length;\n const sibling = $createTextNode(part).getWritable();\n sibling.__format = format;\n sibling.__style = style;\n sibling.__detail = detail;\n const siblingKey = sibling.__key;\n const nextTextSize = textSize + partSize;\n if ($isRangeSelection(selection)) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n if (anchor.key === key && anchor.type === 'text' && anchor.offset > textSize && anchor.offset <= nextTextSize) {\n anchor.key = siblingKey;\n anchor.offset -= textSize;\n selection.dirty = true;\n }\n if (focus.key === key && focus.type === 'text' && focus.offset > textSize && focus.offset <= nextTextSize) {\n focus.key = siblingKey;\n focus.offset -= textSize;\n selection.dirty = true;\n }\n }\n if (compositionKey === key) {\n $setCompositionKey(siblingKey);\n }\n textSize = nextTextSize;\n splitNodes.push(sibling);\n }\n\n // Insert the nodes into the parent's children\n if (parent !== null) {\n internalMarkSiblingsAsDirty(this);\n const writableParent = parent.getWritable();\n const insertionIndex = this.getIndexWithinParent();\n if (hasReplacedSelf) {\n writableParent.splice(insertionIndex, 0, splitNodes);\n this.remove();\n } else {\n writableParent.splice(insertionIndex, 1, splitNodes);\n }\n if ($isRangeSelection(selection)) {\n $updateElementSelectionOnCreateDeleteNode(selection, parent, insertionIndex, partsLength - 1);\n }\n }\n return splitNodes;\n }\n\n /**\n * Merges the target TextNode into this TextNode, removing the target node.\n *\n * @param target - the TextNode to merge into this one.\n *\n * @returns this TextNode.\n */\n mergeWithSibling(target) {\n const isBefore = target === this.getPreviousSibling();\n if (!isBefore && target !== this.getNextSibling()) {\n {\n throw Error(`mergeWithSibling: sibling must be a previous or next sibling`);\n }\n }\n const key = this.__key;\n const targetKey = target.__key;\n const text = this.__text;\n const textLength = text.length;\n const compositionKey = $getCompositionKey();\n if (compositionKey === targetKey) {\n $setCompositionKey(key);\n }\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n if (anchor !== null && anchor.key === targetKey) {\n adjustPointOffsetForMergedSibling(anchor, isBefore, key, target, textLength);\n selection.dirty = true;\n }\n if (focus !== null && focus.key === targetKey) {\n adjustPointOffsetForMergedSibling(focus, isBefore, key, target, textLength);\n selection.dirty = true;\n }\n }\n const targetText = target.__text;\n const newText = isBefore ? targetText + text : text + targetText;\n this.setTextContent(newText);\n const writableSelf = this.getWritable();\n target.remove();\n return writableSelf;\n }\n\n /**\n * This method is meant to be overriden by TextNode subclasses to control the behavior of those nodes\n * when used with the registerLexicalTextEntity function. If you're using registerLexicalTextEntity, the\n * node class that you create and replace matched text with should return true from this method.\n *\n * @returns true if the node is to be treated as a \"text entity\", false otherwise.\n */\n isTextEntity() {\n return false;\n }\n}\nfunction convertSpanElement(domNode) {\n // domNode is a since we matched it by nodeName\n const span = domNode;\n const style = span.style;\n return {\n forChild: applyTextFormatFromStyle(style),\n node: null\n };\n}\nfunction convertBringAttentionToElement(domNode) {\n // domNode is a since we matched it by nodeName\n const b = domNode;\n // Google Docs wraps all copied HTML in a with font-weight normal\n const hasNormalFontWeight = b.style.fontWeight === 'normal';\n return {\n forChild: applyTextFormatFromStyle(b.style, hasNormalFontWeight ? undefined : 'bold'),\n node: null\n };\n}\nconst preParentCache = new WeakMap();\nfunction isNodePre(node) {\n return node.nodeName === 'PRE' || node.nodeType === DOM_ELEMENT_TYPE && node.style !== undefined && node.style.whiteSpace !== undefined && node.style.whiteSpace.startsWith('pre');\n}\nfunction findParentPreDOMNode(node) {\n let cached;\n let parent = node.parentNode;\n const visited = [node];\n while (parent !== null && (cached = preParentCache.get(parent)) === undefined && !isNodePre(parent)) {\n visited.push(parent);\n parent = parent.parentNode;\n }\n const resultNode = cached === undefined ? parent : cached;\n for (let i = 0; i < visited.length; i++) {\n preParentCache.set(visited[i], resultNode);\n }\n return resultNode;\n}\nfunction $convertTextDOMNode(domNode) {\n const domNode_ = domNode;\n const parentDom = domNode.parentElement;\n if (!(parentDom !== null)) {\n throw Error(`Expected parentElement of Text not to be null`);\n }\n let textContent = domNode_.textContent || '';\n // No collapse and preserve segment break for pre, pre-wrap and pre-line\n if (findParentPreDOMNode(domNode_) !== null) {\n const parts = textContent.split(/(\\r?\\n|\\t)/);\n const nodes = [];\n const length = parts.length;\n for (let i = 0; i < length; i++) {\n const part = parts[i];\n if (part === '\\n' || part === '\\r\\n') {\n nodes.push($createLineBreakNode());\n } else if (part === '\\t') {\n nodes.push($createTabNode());\n } else if (part !== '') {\n nodes.push($createTextNode(part));\n }\n }\n return {\n node: nodes\n };\n }\n textContent = textContent.replace(/\\r/g, '').replace(/[ \\t\\n]+/g, ' ');\n if (textContent === '') {\n return {\n node: null\n };\n }\n if (textContent[0] === ' ') {\n // Traverse backward while in the same line. If content contains new line or tab -> pontential\n // delete, other elements can borrow from this one. Deletion depends on whether it's also the\n // last space (see next condition: textContent[textContent.length - 1] === ' '))\n let previousText = domNode_;\n let isStartOfLine = true;\n while (previousText !== null && (previousText = findTextInLine(previousText, false)) !== null) {\n const previousTextContent = previousText.textContent || '';\n if (previousTextContent.length > 0) {\n if (/[ \\t\\n]$/.test(previousTextContent)) {\n textContent = textContent.slice(1);\n }\n isStartOfLine = false;\n break;\n }\n }\n if (isStartOfLine) {\n textContent = textContent.slice(1);\n }\n }\n if (textContent[textContent.length - 1] === ' ') {\n // Traverse forward while in the same line, preserve if next inline will require a space\n let nextText = domNode_;\n let isEndOfLine = true;\n while (nextText !== null && (nextText = findTextInLine(nextText, true)) !== null) {\n const nextTextContent = (nextText.textContent || '').replace(/^( |\\t|\\r?\\n)+/, '');\n if (nextTextContent.length > 0) {\n isEndOfLine = false;\n break;\n }\n }\n if (isEndOfLine) {\n textContent = textContent.slice(0, textContent.length - 1);\n }\n }\n if (textContent === '') {\n return {\n node: null\n };\n }\n return {\n node: $createTextNode(textContent)\n };\n}\nfunction findTextInLine(text, forward) {\n let node = text;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let sibling;\n while ((sibling = forward ? node.nextSibling : node.previousSibling) === null) {\n const parentElement = node.parentElement;\n if (parentElement === null) {\n return null;\n }\n node = parentElement;\n }\n node = sibling;\n if (node.nodeType === DOM_ELEMENT_TYPE) {\n const display = node.style.display;\n if (display === '' && !isInlineDomNode(node) || display !== '' && !display.startsWith('inline')) {\n return null;\n }\n }\n let descendant = node;\n while ((descendant = forward ? node.firstChild : node.lastChild) !== null) {\n node = descendant;\n }\n if (node.nodeType === DOM_TEXT_TYPE) {\n return node;\n } else if (node.nodeName === 'BR') {\n return null;\n }\n }\n}\nconst nodeNameToTextFormat = {\n code: 'code',\n em: 'italic',\n i: 'italic',\n s: 'strikethrough',\n strong: 'bold',\n sub: 'subscript',\n sup: 'superscript',\n u: 'underline'\n};\nfunction convertTextFormatElement(domNode) {\n const format = nodeNameToTextFormat[domNode.nodeName.toLowerCase()];\n if (format === undefined) {\n return {\n node: null\n };\n }\n return {\n forChild: applyTextFormatFromStyle(domNode.style, format),\n node: null\n };\n}\nfunction $createTextNode(text = '') {\n return $applyNodeReplacement(new TextNode(text));\n}\nfunction $isTextNode(node) {\n return node instanceof TextNode;\n}\nfunction applyTextFormatFromStyle(style, shouldApply) {\n const fontWeight = style.fontWeight;\n const textDecoration = style.textDecoration.split(' ');\n // Google Docs uses span tags + font-weight for bold text\n const hasBoldFontWeight = fontWeight === '700' || fontWeight === 'bold';\n // Google Docs uses span tags + text-decoration: line-through for strikethrough text\n const hasLinethroughTextDecoration = textDecoration.includes('line-through');\n // Google Docs uses span tags + font-style for italic text\n const hasItalicFontStyle = style.fontStyle === 'italic';\n // Google Docs uses span tags + text-decoration: underline for underline text\n const hasUnderlineTextDecoration = textDecoration.includes('underline');\n // Google Docs uses span tags + vertical-align to specify subscript and superscript\n const verticalAlign = style.verticalAlign;\n return lexicalNode => {\n if (!$isTextNode(lexicalNode)) {\n return lexicalNode;\n }\n if (hasBoldFontWeight && !lexicalNode.hasFormat('bold')) {\n lexicalNode.toggleFormat('bold');\n }\n if (hasLinethroughTextDecoration && !lexicalNode.hasFormat('strikethrough')) {\n lexicalNode.toggleFormat('strikethrough');\n }\n if (hasItalicFontStyle && !lexicalNode.hasFormat('italic')) {\n lexicalNode.toggleFormat('italic');\n }\n if (hasUnderlineTextDecoration && !lexicalNode.hasFormat('underline')) {\n lexicalNode.toggleFormat('underline');\n }\n if (verticalAlign === 'sub' && !lexicalNode.hasFormat('subscript')) {\n lexicalNode.toggleFormat('subscript');\n }\n if (verticalAlign === 'super' && !lexicalNode.hasFormat('superscript')) {\n lexicalNode.toggleFormat('superscript');\n }\n if (shouldApply && !lexicalNode.hasFormat(shouldApply)) {\n lexicalNode.toggleFormat(shouldApply);\n }\n return lexicalNode;\n };\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/** @noInheritDoc */\nclass TabNode extends TextNode {\n static getType() {\n return 'tab';\n }\n static clone(node) {\n return new TabNode(node.__key);\n }\n afterCloneFrom(prevNode) {\n super.afterCloneFrom(prevNode);\n // TabNode __text can be either '\\t' or ''. insertText will remove the empty Node\n this.__text = prevNode.__text;\n }\n constructor(key) {\n super('\\t', key);\n this.__detail = IS_UNMERGEABLE;\n }\n static importDOM() {\n return null;\n }\n static importJSON(serializedTabNode) {\n const node = $createTabNode();\n node.setFormat(serializedTabNode.format);\n node.setStyle(serializedTabNode.style);\n return node;\n }\n exportJSON() {\n return {\n ...super.exportJSON(),\n type: 'tab',\n version: 1\n };\n }\n setTextContent(_text) {\n {\n throw Error(`TabNode does not support setTextContent`);\n }\n }\n setDetail(_detail) {\n {\n throw Error(`TabNode does not support setDetail`);\n }\n }\n setMode(_type) {\n {\n throw Error(`TabNode does not support setMode`);\n }\n }\n canInsertTextBefore() {\n return false;\n }\n canInsertTextAfter() {\n return false;\n }\n}\nfunction $createTabNode() {\n return $applyNodeReplacement(new TabNode());\n}\nfunction $isTabNode(node) {\n return node instanceof TabNode;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nclass Point {\n constructor(key, offset, type) {\n this._selection = null;\n this.key = key;\n this.offset = offset;\n this.type = type;\n }\n is(point) {\n return this.key === point.key && this.offset === point.offset && this.type === point.type;\n }\n isBefore(b) {\n let aNode = this.getNode();\n let bNode = b.getNode();\n const aOffset = this.offset;\n const bOffset = b.offset;\n if ($isElementNode(aNode)) {\n const aNodeDescendant = aNode.getDescendantByIndex(aOffset);\n aNode = aNodeDescendant != null ? aNodeDescendant : aNode;\n }\n if ($isElementNode(bNode)) {\n const bNodeDescendant = bNode.getDescendantByIndex(bOffset);\n bNode = bNodeDescendant != null ? bNodeDescendant : bNode;\n }\n if (aNode === bNode) {\n return aOffset < bOffset;\n }\n return aNode.isBefore(bNode);\n }\n getNode() {\n const key = this.key;\n const node = $getNodeByKey(key);\n if (node === null) {\n {\n throw Error(`Point.getNode: node not found`);\n }\n }\n return node;\n }\n set(key, offset, type) {\n const selection = this._selection;\n const oldKey = this.key;\n this.key = key;\n this.offset = offset;\n this.type = type;\n if (!isCurrentlyReadOnlyMode()) {\n if ($getCompositionKey() === oldKey) {\n $setCompositionKey(key);\n }\n if (selection !== null) {\n selection.setCachedNodes(null);\n selection.dirty = true;\n }\n }\n }\n}\nfunction $createPoint(key, offset, type) {\n // @ts-expect-error: intentionally cast as we use a class for perf reasons\n return new Point(key, offset, type);\n}\nfunction selectPointOnNode(point, node) {\n let key = node.__key;\n let offset = point.offset;\n let type = 'element';\n if ($isTextNode(node)) {\n type = 'text';\n const textContentLength = node.getTextContentSize();\n if (offset > textContentLength) {\n offset = textContentLength;\n }\n } else if (!$isElementNode(node)) {\n const nextSibling = node.getNextSibling();\n if ($isTextNode(nextSibling)) {\n key = nextSibling.__key;\n offset = 0;\n type = 'text';\n } else {\n const parentNode = node.getParent();\n if (parentNode) {\n key = parentNode.__key;\n offset = node.getIndexWithinParent() + 1;\n }\n }\n }\n point.set(key, offset, type);\n}\nfunction $moveSelectionPointToEnd(point, node) {\n if ($isElementNode(node)) {\n const lastNode = node.getLastDescendant();\n if ($isElementNode(lastNode) || $isTextNode(lastNode)) {\n selectPointOnNode(point, lastNode);\n } else {\n selectPointOnNode(point, node);\n }\n } else {\n selectPointOnNode(point, node);\n }\n}\nfunction $transferStartingElementPointToTextPoint(start, end, format, style) {\n const element = start.getNode();\n const placementNode = element.getChildAtIndex(start.offset);\n const textNode = $createTextNode();\n const target = $isRootNode(element) ? $createParagraphNode().append(textNode) : textNode;\n textNode.setFormat(format);\n textNode.setStyle(style);\n if (placementNode === null) {\n element.append(target);\n } else {\n placementNode.insertBefore(target);\n }\n // Transfer the element point to a text point.\n if (start.is(end)) {\n end.set(textNode.__key, 0, 'text');\n }\n start.set(textNode.__key, 0, 'text');\n}\nfunction $setPointValues(point, key, offset, type) {\n point.key = key;\n point.offset = offset;\n point.type = type;\n}\nclass NodeSelection {\n constructor(objects) {\n this._cachedNodes = null;\n this._nodes = objects;\n this.dirty = false;\n }\n getCachedNodes() {\n return this._cachedNodes;\n }\n setCachedNodes(nodes) {\n this._cachedNodes = nodes;\n }\n is(selection) {\n if (!$isNodeSelection(selection)) {\n return false;\n }\n const a = this._nodes;\n const b = selection._nodes;\n return a.size === b.size && Array.from(a).every(key => b.has(key));\n }\n isCollapsed() {\n return false;\n }\n isBackward() {\n return false;\n }\n getStartEndPoints() {\n return null;\n }\n add(key) {\n this.dirty = true;\n this._nodes.add(key);\n this._cachedNodes = null;\n }\n delete(key) {\n this.dirty = true;\n this._nodes.delete(key);\n this._cachedNodes = null;\n }\n clear() {\n this.dirty = true;\n this._nodes.clear();\n this._cachedNodes = null;\n }\n has(key) {\n return this._nodes.has(key);\n }\n clone() {\n return new NodeSelection(new Set(this._nodes));\n }\n extract() {\n return this.getNodes();\n }\n insertRawText(text) {\n // Do nothing?\n }\n insertText() {\n // Do nothing?\n }\n insertNodes(nodes) {\n const selectedNodes = this.getNodes();\n const selectedNodesLength = selectedNodes.length;\n const lastSelectedNode = selectedNodes[selectedNodesLength - 1];\n let selectionAtEnd;\n // Insert nodes\n if ($isTextNode(lastSelectedNode)) {\n selectionAtEnd = lastSelectedNode.select();\n } else {\n const index = lastSelectedNode.getIndexWithinParent() + 1;\n selectionAtEnd = lastSelectedNode.getParentOrThrow().select(index, index);\n }\n selectionAtEnd.insertNodes(nodes);\n // Remove selected nodes\n for (let i = 0; i < selectedNodesLength; i++) {\n selectedNodes[i].remove();\n }\n }\n getNodes() {\n const cachedNodes = this._cachedNodes;\n if (cachedNodes !== null) {\n return cachedNodes;\n }\n const objects = this._nodes;\n const nodes = [];\n for (const object of objects) {\n const node = $getNodeByKey(object);\n if (node !== null) {\n nodes.push(node);\n }\n }\n if (!isCurrentlyReadOnlyMode()) {\n this._cachedNodes = nodes;\n }\n return nodes;\n }\n getTextContent() {\n const nodes = this.getNodes();\n let textContent = '';\n for (let i = 0; i < nodes.length; i++) {\n textContent += nodes[i].getTextContent();\n }\n return textContent;\n }\n}\nfunction $isRangeSelection(x) {\n return x instanceof RangeSelection;\n}\nclass RangeSelection {\n constructor(anchor, focus, format, style) {\n this.anchor = anchor;\n this.focus = focus;\n anchor._selection = this;\n focus._selection = this;\n this._cachedNodes = null;\n this.format = format;\n this.style = style;\n this.dirty = false;\n }\n getCachedNodes() {\n return this._cachedNodes;\n }\n setCachedNodes(nodes) {\n this._cachedNodes = nodes;\n }\n\n /**\n * Used to check if the provided selections is equal to this one by value,\n * inluding anchor, focus, format, and style properties.\n * @param selection - the Selection to compare this one to.\n * @returns true if the Selections are equal, false otherwise.\n */\n is(selection) {\n if (!$isRangeSelection(selection)) {\n return false;\n }\n return this.anchor.is(selection.anchor) && this.focus.is(selection.focus) && this.format === selection.format && this.style === selection.style;\n }\n\n /**\n * Returns whether the Selection is \"collapsed\", meaning the anchor and focus are\n * the same node and have the same offset.\n *\n * @returns true if the Selection is collapsed, false otherwise.\n */\n isCollapsed() {\n return this.anchor.is(this.focus);\n }\n\n /**\n * Gets all the nodes in the Selection. Uses caching to make it generally suitable\n * for use in hot paths.\n *\n * @returns an Array containing all the nodes in the Selection\n */\n getNodes() {\n const cachedNodes = this._cachedNodes;\n if (cachedNodes !== null) {\n return cachedNodes;\n }\n const anchor = this.anchor;\n const focus = this.focus;\n const isBefore = anchor.isBefore(focus);\n const firstPoint = isBefore ? anchor : focus;\n const lastPoint = isBefore ? focus : anchor;\n let firstNode = firstPoint.getNode();\n let lastNode = lastPoint.getNode();\n const startOffset = firstPoint.offset;\n const endOffset = lastPoint.offset;\n if ($isElementNode(firstNode)) {\n const firstNodeDescendant = firstNode.getDescendantByIndex(startOffset);\n firstNode = firstNodeDescendant != null ? firstNodeDescendant : firstNode;\n }\n if ($isElementNode(lastNode)) {\n let lastNodeDescendant = lastNode.getDescendantByIndex(endOffset);\n // We don't want to over-select, as node selection infers the child before\n // the last descendant, not including that descendant.\n if (lastNodeDescendant !== null && lastNodeDescendant !== firstNode && lastNode.getChildAtIndex(endOffset) === lastNodeDescendant) {\n lastNodeDescendant = lastNodeDescendant.getPreviousSibling();\n }\n lastNode = lastNodeDescendant != null ? lastNodeDescendant : lastNode;\n }\n let nodes;\n if (firstNode.is(lastNode)) {\n if ($isElementNode(firstNode) && firstNode.getChildrenSize() > 0) {\n nodes = [];\n } else {\n nodes = [firstNode];\n }\n } else {\n nodes = firstNode.getNodesBetween(lastNode);\n }\n if (!isCurrentlyReadOnlyMode()) {\n this._cachedNodes = nodes;\n }\n return nodes;\n }\n\n /**\n * Sets this Selection to be of type \"text\" at the provided anchor and focus values.\n *\n * @param anchorNode - the anchor node to set on the Selection\n * @param anchorOffset - the offset to set on the Selection\n * @param focusNode - the focus node to set on the Selection\n * @param focusOffset - the focus offset to set on the Selection\n */\n setTextNodeRange(anchorNode, anchorOffset, focusNode, focusOffset) {\n $setPointValues(this.anchor, anchorNode.__key, anchorOffset, 'text');\n $setPointValues(this.focus, focusNode.__key, focusOffset, 'text');\n this._cachedNodes = null;\n this.dirty = true;\n }\n\n /**\n * Gets the (plain) text content of all the nodes in the selection.\n *\n * @returns a string representing the text content of all the nodes in the Selection\n */\n getTextContent() {\n const nodes = this.getNodes();\n if (nodes.length === 0) {\n return '';\n }\n const firstNode = nodes[0];\n const lastNode = nodes[nodes.length - 1];\n const anchor = this.anchor;\n const focus = this.focus;\n const isBefore = anchor.isBefore(focus);\n const [anchorOffset, focusOffset] = $getCharacterOffsets(this);\n let textContent = '';\n let prevWasElement = true;\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n if ($isElementNode(node) && !node.isInline()) {\n if (!prevWasElement) {\n textContent += '\\n';\n }\n if (node.isEmpty()) {\n prevWasElement = false;\n } else {\n prevWasElement = true;\n }\n } else {\n prevWasElement = false;\n if ($isTextNode(node)) {\n let text = node.getTextContent();\n if (node === firstNode) {\n if (node === lastNode) {\n if (anchor.type !== 'element' || focus.type !== 'element' || focus.offset === anchor.offset) {\n text = anchorOffset < focusOffset ? text.slice(anchorOffset, focusOffset) : text.slice(focusOffset, anchorOffset);\n }\n } else {\n text = isBefore ? text.slice(anchorOffset) : text.slice(focusOffset);\n }\n } else if (node === lastNode) {\n text = isBefore ? text.slice(0, focusOffset) : text.slice(0, anchorOffset);\n }\n textContent += text;\n } else if (($isDecoratorNode(node) || $isLineBreakNode(node)) && (node !== lastNode || !this.isCollapsed())) {\n textContent += node.getTextContent();\n }\n }\n }\n return textContent;\n }\n\n /**\n * Attempts to map a DOM selection range onto this Lexical Selection,\n * setting the anchor, focus, and type accordingly\n *\n * @param range a DOM Selection range conforming to the StaticRange interface.\n */\n applyDOMRange(range) {\n const editor = getActiveEditor();\n const currentEditorState = editor.getEditorState();\n const lastSelection = currentEditorState._selection;\n const resolvedSelectionPoints = $internalResolveSelectionPoints(range.startContainer, range.startOffset, range.endContainer, range.endOffset, editor, lastSelection);\n if (resolvedSelectionPoints === null) {\n return;\n }\n const [anchorPoint, focusPoint] = resolvedSelectionPoints;\n $setPointValues(this.anchor, anchorPoint.key, anchorPoint.offset, anchorPoint.type);\n $setPointValues(this.focus, focusPoint.key, focusPoint.offset, focusPoint.type);\n this._cachedNodes = null;\n }\n\n /**\n * Creates a new RangeSelection, copying over all the property values from this one.\n *\n * @returns a new RangeSelection with the same property values as this one.\n */\n clone() {\n const anchor = this.anchor;\n const focus = this.focus;\n const selection = new RangeSelection($createPoint(anchor.key, anchor.offset, anchor.type), $createPoint(focus.key, focus.offset, focus.type), this.format, this.style);\n return selection;\n }\n\n /**\n * Toggles the provided format on all the TextNodes in the Selection.\n *\n * @param format a string TextFormatType to toggle on the TextNodes in the selection\n */\n toggleFormat(format) {\n this.format = toggleTextFormatType(this.format, format, null);\n this.dirty = true;\n }\n\n /**\n * Sets the value of the style property on the Selection\n *\n * @param style - the style to set at the value of the style property.\n */\n setStyle(style) {\n this.style = style;\n this.dirty = true;\n }\n\n /**\n * Returns whether the provided TextFormatType is present on the Selection. This will be true if any node in the Selection\n * has the specified format.\n *\n * @param type the TextFormatType to check for.\n * @returns true if the provided format is currently toggled on on the Selection, false otherwise.\n */\n hasFormat(type) {\n const formatFlag = TEXT_TYPE_TO_FORMAT[type];\n return (this.format & formatFlag) !== 0;\n }\n\n /**\n * Attempts to insert the provided text into the EditorState at the current Selection.\n * converts tabs, newlines, and carriage returns into LexicalNodes.\n *\n * @param text the text to insert into the Selection\n */\n insertRawText(text) {\n const parts = text.split(/(\\r?\\n|\\t)/);\n const nodes = [];\n const length = parts.length;\n for (let i = 0; i < length; i++) {\n const part = parts[i];\n if (part === '\\n' || part === '\\r\\n') {\n nodes.push($createLineBreakNode());\n } else if (part === '\\t') {\n nodes.push($createTabNode());\n } else {\n nodes.push($createTextNode(part));\n }\n }\n this.insertNodes(nodes);\n }\n\n /**\n * Attempts to insert the provided text into the EditorState at the current Selection as a new\n * Lexical TextNode, according to a series of insertion heuristics based on the selection type and position.\n *\n * @param text the text to insert into the Selection\n */\n insertText(text) {\n const anchor = this.anchor;\n const focus = this.focus;\n const format = this.format;\n const style = this.style;\n let firstPoint = anchor;\n let endPoint = focus;\n if (!this.isCollapsed() && focus.isBefore(anchor)) {\n firstPoint = focus;\n endPoint = anchor;\n }\n if (firstPoint.type === 'element') {\n $transferStartingElementPointToTextPoint(firstPoint, endPoint, format, style);\n }\n const startOffset = firstPoint.offset;\n let endOffset = endPoint.offset;\n const selectedNodes = this.getNodes();\n const selectedNodesLength = selectedNodes.length;\n let firstNode = selectedNodes[0];\n if (!$isTextNode(firstNode)) {\n {\n throw Error(`insertText: first node is not a text node`);\n }\n }\n const firstNodeText = firstNode.getTextContent();\n const firstNodeTextLength = firstNodeText.length;\n const firstNodeParent = firstNode.getParentOrThrow();\n const lastIndex = selectedNodesLength - 1;\n let lastNode = selectedNodes[lastIndex];\n if (selectedNodesLength === 1 && endPoint.type === 'element') {\n endOffset = firstNodeTextLength;\n endPoint.set(firstPoint.key, endOffset, 'text');\n }\n if (this.isCollapsed() && startOffset === firstNodeTextLength && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter() && firstNode.getNextSibling() === null)) {\n let nextSibling = firstNode.getNextSibling();\n if (!$isTextNode(nextSibling) || !nextSibling.canInsertTextBefore() || $isTokenOrSegmented(nextSibling)) {\n nextSibling = $createTextNode();\n nextSibling.setFormat(format);\n nextSibling.setStyle(style);\n if (!firstNodeParent.canInsertTextAfter()) {\n firstNodeParent.insertAfter(nextSibling);\n } else {\n firstNode.insertAfter(nextSibling);\n }\n }\n nextSibling.select(0, 0);\n firstNode = nextSibling;\n if (text !== '') {\n this.insertText(text);\n return;\n }\n } else if (this.isCollapsed() && startOffset === 0 && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore() && firstNode.getPreviousSibling() === null)) {\n let prevSibling = firstNode.getPreviousSibling();\n if (!$isTextNode(prevSibling) || $isTokenOrSegmented(prevSibling)) {\n prevSibling = $createTextNode();\n prevSibling.setFormat(format);\n if (!firstNodeParent.canInsertTextBefore()) {\n firstNodeParent.insertBefore(prevSibling);\n } else {\n firstNode.insertBefore(prevSibling);\n }\n }\n prevSibling.select();\n firstNode = prevSibling;\n if (text !== '') {\n this.insertText(text);\n return;\n }\n } else if (firstNode.isSegmented() && startOffset !== firstNodeTextLength) {\n const textNode = $createTextNode(firstNode.getTextContent());\n textNode.setFormat(format);\n firstNode.replace(textNode);\n firstNode = textNode;\n } else if (!this.isCollapsed() && text !== '') {\n // When the firstNode or lastNode parents are elements that\n // do not allow text to be inserted before or after, we first\n // clear the content. Then we normalize selection, then insert\n // the new content.\n const lastNodeParent = lastNode.getParent();\n if (!firstNodeParent.canInsertTextBefore() || !firstNodeParent.canInsertTextAfter() || $isElementNode(lastNodeParent) && (!lastNodeParent.canInsertTextBefore() || !lastNodeParent.canInsertTextAfter())) {\n this.insertText('');\n $normalizeSelectionPointsForBoundaries(this.anchor, this.focus, null);\n this.insertText(text);\n return;\n }\n }\n if (selectedNodesLength === 1) {\n if (firstNode.isToken()) {\n const textNode = $createTextNode(text);\n textNode.select();\n firstNode.replace(textNode);\n return;\n }\n const firstNodeFormat = firstNode.getFormat();\n const firstNodeStyle = firstNode.getStyle();\n if (startOffset === endOffset && (firstNodeFormat !== format || firstNodeStyle !== style)) {\n if (firstNode.getTextContent() === '') {\n firstNode.setFormat(format);\n firstNode.setStyle(style);\n } else {\n const textNode = $createTextNode(text);\n textNode.setFormat(format);\n textNode.setStyle(style);\n textNode.select();\n if (startOffset === 0) {\n firstNode.insertBefore(textNode, false);\n } else {\n const [targetNode] = firstNode.splitText(startOffset);\n targetNode.insertAfter(textNode, false);\n }\n // When composing, we need to adjust the anchor offset so that\n // we correctly replace that right range.\n if (textNode.isComposing() && this.anchor.type === 'text') {\n this.anchor.offset -= text.length;\n }\n return;\n }\n } else if ($isTabNode(firstNode)) {\n // We don't need to check for delCount because there is only the entire selected node case\n // that can hit here for content size 1 and with canInsertTextBeforeAfter false\n const textNode = $createTextNode(text);\n textNode.setFormat(format);\n textNode.setStyle(style);\n textNode.select();\n firstNode.replace(textNode);\n return;\n }\n const delCount = endOffset - startOffset;\n firstNode = firstNode.spliceText(startOffset, delCount, text, true);\n if (firstNode.getTextContent() === '') {\n firstNode.remove();\n } else if (this.anchor.type === 'text') {\n if (firstNode.isComposing()) {\n // When composing, we need to adjust the anchor offset so that\n // we correctly replace that right range.\n this.anchor.offset -= text.length;\n } else {\n this.format = firstNodeFormat;\n this.style = firstNodeStyle;\n }\n }\n } else {\n const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]);\n\n // We have to get the parent elements before the next section,\n // as in that section we might mutate the lastNode.\n const firstElement = $isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();\n let lastElement = $isElementNode(lastNode) ? lastNode : lastNode.getParentOrThrow();\n let lastElementChild = lastNode;\n\n // If the last element is inline, we should instead look at getting\n // the nodes of its parent, rather than itself. This behavior will\n // then better match how text node insertions work. We will need to\n // also update the last element's child accordingly as we do this.\n if (!firstElement.is(lastElement) && lastElement.isInline()) {\n // Keep traversing till we have a non-inline element parent.\n do {\n lastElementChild = lastElement;\n lastElement = lastElement.getParentOrThrow();\n } while (lastElement.isInline());\n }\n\n // Handle mutations to the last node.\n if (endPoint.type === 'text' && (endOffset !== 0 || lastNode.getTextContent() === '') || endPoint.type === 'element' && lastNode.getIndexWithinParent() < endOffset) {\n if ($isTextNode(lastNode) && !lastNode.isToken() && endOffset !== lastNode.getTextContentSize()) {\n if (lastNode.isSegmented()) {\n const textNode = $createTextNode(lastNode.getTextContent());\n lastNode.replace(textNode);\n lastNode = textNode;\n }\n // root node selections only select whole nodes, so no text splice is necessary\n if (!$isRootNode(endPoint.getNode()) && endPoint.type === 'text') {\n lastNode = lastNode.spliceText(0, endOffset, '');\n }\n markedNodeKeysForKeep.add(lastNode.__key);\n } else {\n const lastNodeParent = lastNode.getParentOrThrow();\n if (!lastNodeParent.canBeEmpty() && lastNodeParent.getChildrenSize() === 1) {\n lastNodeParent.remove();\n } else {\n lastNode.remove();\n }\n }\n } else {\n markedNodeKeysForKeep.add(lastNode.__key);\n }\n\n // Either move the remaining nodes of the last parent to after\n // the first child, or remove them entirely. If the last parent\n // is the same as the first parent, this logic also works.\n const lastNodeChildren = lastElement.getChildren();\n const selectedNodesSet = new Set(selectedNodes);\n const firstAndLastElementsAreEqual = firstElement.is(lastElement);\n\n // We choose a target to insert all nodes after. In the case of having\n // and inline starting parent element with a starting node that has no\n // siblings, we should insert after the starting parent element, otherwise\n // we will incorrectly merge into the starting parent element.\n // TODO: should we keep on traversing parents if we're inside another\n // nested inline element?\n const insertionTarget = firstElement.isInline() && firstNode.getNextSibling() === null ? firstElement : firstNode;\n for (let i = lastNodeChildren.length - 1; i >= 0; i--) {\n const lastNodeChild = lastNodeChildren[i];\n if (lastNodeChild.is(firstNode) || $isElementNode(lastNodeChild) && lastNodeChild.isParentOf(firstNode)) {\n break;\n }\n if (lastNodeChild.isAttached()) {\n if (!selectedNodesSet.has(lastNodeChild) || lastNodeChild.is(lastElementChild)) {\n if (!firstAndLastElementsAreEqual) {\n insertionTarget.insertAfter(lastNodeChild, false);\n }\n } else {\n lastNodeChild.remove();\n }\n }\n }\n if (!firstAndLastElementsAreEqual) {\n // Check if we have already moved out all the nodes of the\n // last parent, and if so, traverse the parent tree and mark\n // them all as being able to deleted too.\n let parent = lastElement;\n let lastRemovedParent = null;\n while (parent !== null) {\n const children = parent.getChildren();\n const childrenLength = children.length;\n if (childrenLength === 0 || children[childrenLength - 1].is(lastRemovedParent)) {\n markedNodeKeysForKeep.delete(parent.__key);\n lastRemovedParent = parent;\n }\n parent = parent.getParent();\n }\n }\n\n // Ensure we do splicing after moving of nodes, as splicing\n // can have side-effects (in the case of hashtags).\n if (!firstNode.isToken()) {\n firstNode = firstNode.spliceText(startOffset, firstNodeTextLength - startOffset, text, true);\n if (firstNode.getTextContent() === '') {\n firstNode.remove();\n } else if (firstNode.isComposing() && this.anchor.type === 'text') {\n // When composing, we need to adjust the anchor offset so that\n // we correctly replace that right range.\n this.anchor.offset -= text.length;\n }\n } else if (startOffset === firstNodeTextLength) {\n firstNode.select();\n } else {\n const textNode = $createTextNode(text);\n textNode.select();\n firstNode.replace(textNode);\n }\n\n // Remove all selected nodes that haven't already been removed.\n for (let i = 1; i < selectedNodesLength; i++) {\n const selectedNode = selectedNodes[i];\n const key = selectedNode.__key;\n if (!markedNodeKeysForKeep.has(key)) {\n selectedNode.remove();\n }\n }\n }\n }\n\n /**\n * Removes the text in the Selection, adjusting the EditorState accordingly.\n */\n removeText() {\n this.insertText('');\n }\n\n /**\n * Applies the provided format to the TextNodes in the Selection, splitting or\n * merging nodes as necessary.\n *\n * @param formatType the format type to apply to the nodes in the Selection.\n */\n formatText(formatType) {\n if (this.isCollapsed()) {\n this.toggleFormat(formatType);\n // When changing format, we should stop composition\n $setCompositionKey(null);\n return;\n }\n const selectedNodes = this.getNodes();\n const selectedTextNodes = [];\n for (const selectedNode of selectedNodes) {\n if ($isTextNode(selectedNode)) {\n selectedTextNodes.push(selectedNode);\n }\n }\n const selectedTextNodesLength = selectedTextNodes.length;\n if (selectedTextNodesLength === 0) {\n this.toggleFormat(formatType);\n // When changing format, we should stop composition\n $setCompositionKey(null);\n return;\n }\n const anchor = this.anchor;\n const focus = this.focus;\n const isBackward = this.isBackward();\n const startPoint = isBackward ? focus : anchor;\n const endPoint = isBackward ? anchor : focus;\n let firstIndex = 0;\n let firstNode = selectedTextNodes[0];\n let startOffset = startPoint.type === 'element' ? 0 : startPoint.offset;\n\n // In case selection started at the end of text node use next text node\n if (startPoint.type === 'text' && startOffset === firstNode.getTextContentSize()) {\n firstIndex = 1;\n firstNode = selectedTextNodes[1];\n startOffset = 0;\n }\n if (firstNode == null) {\n return;\n }\n const firstNextFormat = firstNode.getFormatFlags(formatType, null);\n const lastIndex = selectedTextNodesLength - 1;\n let lastNode = selectedTextNodes[lastIndex];\n const endOffset = endPoint.type === 'text' ? endPoint.offset : lastNode.getTextContentSize();\n\n // Single node selected\n if (firstNode.is(lastNode)) {\n // No actual text is selected, so do nothing.\n if (startOffset === endOffset) {\n return;\n }\n // The entire node is selected or it is token, so just format it\n if ($isTokenOrSegmented(firstNode) || startOffset === 0 && endOffset === firstNode.getTextContentSize()) {\n firstNode.setFormat(firstNextFormat);\n } else {\n // Node is partially selected, so split it into two nodes\n // add style the selected one.\n const splitNodes = firstNode.splitText(startOffset, endOffset);\n const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];\n replacement.setFormat(firstNextFormat);\n\n // Update selection only if starts/ends on text node\n if (startPoint.type === 'text') {\n startPoint.set(replacement.__key, 0, 'text');\n }\n if (endPoint.type === 'text') {\n endPoint.set(replacement.__key, endOffset - startOffset, 'text');\n }\n }\n this.format = firstNextFormat;\n return;\n }\n // Multiple nodes selected\n // The entire first node isn't selected, so split it\n if (startOffset !== 0 && !$isTokenOrSegmented(firstNode)) {\n [, firstNode] = firstNode.splitText(startOffset);\n startOffset = 0;\n }\n firstNode.setFormat(firstNextFormat);\n const lastNextFormat = lastNode.getFormatFlags(formatType, firstNextFormat);\n // If the offset is 0, it means no actual characters are selected,\n // so we skip formatting the last node altogether.\n if (endOffset > 0) {\n if (endOffset !== lastNode.getTextContentSize() && !$isTokenOrSegmented(lastNode)) {\n [lastNode] = lastNode.splitText(endOffset);\n }\n lastNode.setFormat(lastNextFormat);\n }\n\n // Process all text nodes in between\n for (let i = firstIndex + 1; i < lastIndex; i++) {\n const textNode = selectedTextNodes[i];\n const nextFormat = textNode.getFormatFlags(formatType, lastNextFormat);\n textNode.setFormat(nextFormat);\n }\n\n // Update selection only if starts/ends on text node\n if (startPoint.type === 'text') {\n startPoint.set(firstNode.__key, startOffset, 'text');\n }\n if (endPoint.type === 'text') {\n endPoint.set(lastNode.__key, endOffset, 'text');\n }\n this.format = firstNextFormat | lastNextFormat;\n }\n\n /**\n * Attempts to \"intelligently\" insert an arbitrary list of Lexical nodes into the EditorState at the\n * current Selection according to a set of heuristics that determine how surrounding nodes\n * should be changed, replaced, or moved to accomodate the incoming ones.\n *\n * @param nodes - the nodes to insert\n */\n insertNodes(nodes) {\n if (nodes.length === 0) {\n return;\n }\n if (this.anchor.key === 'root') {\n this.insertParagraph();\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n throw Error(`Expected RangeSelection after insertParagraph`);\n }\n return selection.insertNodes(nodes);\n }\n const firstPoint = this.isBackward() ? this.focus : this.anchor;\n const firstBlock = $getAncestor(firstPoint.getNode(), INTERNAL_$isBlock);\n const last = nodes[nodes.length - 1];\n\n // CASE 1: insert inside a code block\n if ('__language' in firstBlock && $isElementNode(firstBlock)) {\n if ('__language' in nodes[0]) {\n this.insertText(nodes[0].getTextContent());\n } else {\n const index = $removeTextAndSplitBlock(this);\n firstBlock.splice(index, 0, nodes);\n last.selectEnd();\n }\n return;\n }\n\n // CASE 2: All elements of the array are inline\n const notInline = node => ($isElementNode(node) || $isDecoratorNode(node)) && !node.isInline();\n if (!nodes.some(notInline)) {\n if (!$isElementNode(firstBlock)) {\n throw Error(`Expected 'firstBlock' to be an ElementNode`);\n }\n const index = $removeTextAndSplitBlock(this);\n firstBlock.splice(index, 0, nodes);\n last.selectEnd();\n return;\n }\n\n // CASE 3: At least 1 element of the array is not inline\n const blocksParent = $wrapInlineNodes(nodes);\n const nodeToSelect = blocksParent.getLastDescendant();\n const blocks = blocksParent.getChildren();\n const isMergeable = node => $isElementNode(node) && INTERNAL_$isBlock(node) && !node.isEmpty() && $isElementNode(firstBlock) && (!firstBlock.isEmpty() || firstBlock.canMergeWhenEmpty());\n const shouldInsert = !$isElementNode(firstBlock) || !firstBlock.isEmpty();\n const insertedParagraph = shouldInsert ? this.insertParagraph() : null;\n const lastToInsert = blocks[blocks.length - 1];\n let firstToInsert = blocks[0];\n if (isMergeable(firstToInsert)) {\n if (!$isElementNode(firstBlock)) {\n throw Error(`Expected 'firstBlock' to be an ElementNode`);\n }\n firstBlock.append(...firstToInsert.getChildren());\n firstToInsert = blocks[1];\n }\n if (firstToInsert) {\n insertRangeAfter(firstBlock, firstToInsert);\n }\n const lastInsertedBlock = $getAncestor(nodeToSelect, INTERNAL_$isBlock);\n if (insertedParagraph && $isElementNode(lastInsertedBlock) && (insertedParagraph.canMergeWhenEmpty() || INTERNAL_$isBlock(lastToInsert))) {\n lastInsertedBlock.append(...insertedParagraph.getChildren());\n insertedParagraph.remove();\n }\n if ($isElementNode(firstBlock) && firstBlock.isEmpty()) {\n firstBlock.remove();\n }\n nodeToSelect.selectEnd();\n\n // To understand this take a look at the test \"can wrap post-linebreak nodes into new element\"\n const lastChild = $isElementNode(firstBlock) ? firstBlock.getLastChild() : null;\n if ($isLineBreakNode(lastChild) && lastInsertedBlock !== firstBlock) {\n lastChild.remove();\n }\n }\n\n /**\n * Inserts a new ParagraphNode into the EditorState at the current Selection\n *\n * @returns the newly inserted node.\n */\n insertParagraph() {\n if (this.anchor.key === 'root') {\n const paragraph = $createParagraphNode();\n $getRoot().splice(this.anchor.offset, 0, [paragraph]);\n paragraph.select();\n return paragraph;\n }\n const index = $removeTextAndSplitBlock(this);\n const block = $getAncestor(this.anchor.getNode(), INTERNAL_$isBlock);\n if (!$isElementNode(block)) {\n throw Error(`Expected ancestor to be an ElementNode`);\n }\n const firstToAppend = block.getChildAtIndex(index);\n const nodesToInsert = firstToAppend ? [firstToAppend, ...firstToAppend.getNextSiblings()] : [];\n const newBlock = block.insertNewAfter(this, false);\n if (newBlock) {\n newBlock.append(...nodesToInsert);\n newBlock.selectStart();\n return newBlock;\n }\n // if newBlock is null, it means that block is of type CodeNode.\n return null;\n }\n\n /**\n * Inserts a logical linebreak, which may be a new LineBreakNode or a new ParagraphNode, into the EditorState at the\n * current Selection.\n */\n insertLineBreak(selectStart) {\n const lineBreak = $createLineBreakNode();\n this.insertNodes([lineBreak]);\n // this is used in MacOS with the command 'ctrl-O' (openLineBreak)\n if (selectStart) {\n const parent = lineBreak.getParentOrThrow();\n const index = lineBreak.getIndexWithinParent();\n parent.select(index, index);\n }\n }\n\n /**\n * Extracts the nodes in the Selection, splitting nodes where necessary\n * to get offset-level precision.\n *\n * @returns The nodes in the Selection\n */\n extract() {\n const selectedNodes = this.getNodes();\n const selectedNodesLength = selectedNodes.length;\n const lastIndex = selectedNodesLength - 1;\n const anchor = this.anchor;\n const focus = this.focus;\n let firstNode = selectedNodes[0];\n let lastNode = selectedNodes[lastIndex];\n const [anchorOffset, focusOffset] = $getCharacterOffsets(this);\n if (selectedNodesLength === 0) {\n return [];\n } else if (selectedNodesLength === 1) {\n if ($isTextNode(firstNode) && !this.isCollapsed()) {\n const startOffset = anchorOffset > focusOffset ? focusOffset : anchorOffset;\n const endOffset = anchorOffset > focusOffset ? anchorOffset : focusOffset;\n const splitNodes = firstNode.splitText(startOffset, endOffset);\n const node = startOffset === 0 ? splitNodes[0] : splitNodes[1];\n return node != null ? [node] : [];\n }\n return [firstNode];\n }\n const isBefore = anchor.isBefore(focus);\n if ($isTextNode(firstNode)) {\n const startOffset = isBefore ? anchorOffset : focusOffset;\n if (startOffset === firstNode.getTextContentSize()) {\n selectedNodes.shift();\n } else if (startOffset !== 0) {\n [, firstNode] = firstNode.splitText(startOffset);\n selectedNodes[0] = firstNode;\n }\n }\n if ($isTextNode(lastNode)) {\n const lastNodeText = lastNode.getTextContent();\n const lastNodeTextLength = lastNodeText.length;\n const endOffset = isBefore ? focusOffset : anchorOffset;\n if (endOffset === 0) {\n selectedNodes.pop();\n } else if (endOffset !== lastNodeTextLength) {\n [lastNode] = lastNode.splitText(endOffset);\n selectedNodes[lastIndex] = lastNode;\n }\n }\n return selectedNodes;\n }\n\n /**\n * Modifies the Selection according to the parameters and a set of heuristics that account for\n * various node types. Can be used to safely move or extend selection by one logical \"unit\" without\n * dealing explicitly with all the possible node types.\n *\n * @param alter the type of modification to perform\n * @param isBackward whether or not selection is backwards\n * @param granularity the granularity at which to apply the modification\n */\n modify(alter, isBackward, granularity) {\n const focus = this.focus;\n const anchor = this.anchor;\n const collapse = alter === 'move';\n\n // Handle the selection movement around decorators.\n const possibleNode = $getAdjacentNode(focus, isBackward);\n if ($isDecoratorNode(possibleNode) && !possibleNode.isIsolated()) {\n // Make it possible to move selection from range selection to\n // node selection on the node.\n if (collapse && possibleNode.isKeyboardSelectable()) {\n const nodeSelection = $createNodeSelection();\n nodeSelection.add(possibleNode.__key);\n $setSelection(nodeSelection);\n return;\n }\n const sibling = isBackward ? possibleNode.getPreviousSibling() : possibleNode.getNextSibling();\n if (!$isTextNode(sibling)) {\n const parent = possibleNode.getParentOrThrow();\n let offset;\n let elementKey;\n if ($isElementNode(sibling)) {\n elementKey = sibling.__key;\n offset = isBackward ? sibling.getChildrenSize() : 0;\n } else {\n offset = possibleNode.getIndexWithinParent();\n elementKey = parent.__key;\n if (!isBackward) {\n offset++;\n }\n }\n focus.set(elementKey, offset, 'element');\n if (collapse) {\n anchor.set(elementKey, offset, 'element');\n }\n return;\n } else {\n const siblingKey = sibling.__key;\n const offset = isBackward ? sibling.getTextContent().length : 0;\n focus.set(siblingKey, offset, 'text');\n if (collapse) {\n anchor.set(siblingKey, offset, 'text');\n }\n return;\n }\n }\n const editor = getActiveEditor();\n const domSelection = getDOMSelection(editor._window);\n if (!domSelection) {\n return;\n }\n const blockCursorElement = editor._blockCursorElement;\n const rootElement = editor._rootElement;\n // Remove the block cursor element if it exists. This will ensure selection\n // works as intended. If we leave it in the DOM all sorts of strange bugs\n // occur. :/\n if (rootElement !== null && blockCursorElement !== null && $isElementNode(possibleNode) && !possibleNode.isInline() && !possibleNode.canBeEmpty()) {\n removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);\n }\n // We use the DOM selection.modify API here to \"tell\" us what the selection\n // will be. We then use it to update the Lexical selection accordingly. This\n // is much more reliable than waiting for a beforeinput and using the ranges\n // from getTargetRanges(), and is also better than trying to do it ourselves\n // using Intl.Segmenter or other workarounds that struggle with word segments\n // and line segments (especially with word wrapping and non-Roman languages).\n moveNativeSelection(domSelection, alter, isBackward ? 'backward' : 'forward', granularity);\n // Guard against no ranges\n if (domSelection.rangeCount > 0) {\n const range = domSelection.getRangeAt(0);\n // Apply the DOM selection to our Lexical selection.\n const anchorNode = this.anchor.getNode();\n const root = $isRootNode(anchorNode) ? anchorNode : $getNearestRootOrShadowRoot(anchorNode);\n this.applyDOMRange(range);\n this.dirty = true;\n if (!collapse) {\n // Validate selection; make sure that the new extended selection respects shadow roots\n const nodes = this.getNodes();\n const validNodes = [];\n let shrinkSelection = false;\n for (let i = 0; i < nodes.length; i++) {\n const nextNode = nodes[i];\n if ($hasAncestor(nextNode, root)) {\n validNodes.push(nextNode);\n } else {\n shrinkSelection = true;\n }\n }\n if (shrinkSelection && validNodes.length > 0) {\n // validNodes length check is a safeguard against an invalid selection; as getNodes()\n // will return an empty array in this case\n if (isBackward) {\n const firstValidNode = validNodes[0];\n if ($isElementNode(firstValidNode)) {\n firstValidNode.selectStart();\n } else {\n firstValidNode.getParentOrThrow().selectStart();\n }\n } else {\n const lastValidNode = validNodes[validNodes.length - 1];\n if ($isElementNode(lastValidNode)) {\n lastValidNode.selectEnd();\n } else {\n lastValidNode.getParentOrThrow().selectEnd();\n }\n }\n }\n\n // Because a range works on start and end, we might need to flip\n // the anchor and focus points to match what the DOM has, not what\n // the range has specifically.\n if (domSelection.anchorNode !== range.startContainer || domSelection.anchorOffset !== range.startOffset) {\n $swapPoints(this);\n }\n }\n }\n }\n /**\n * Helper for handling forward character and word deletion that prevents element nodes\n * like a table, columns layout being destroyed\n *\n * @param anchor the anchor\n * @param anchorNode the anchor node in the selection\n * @param isBackward whether or not selection is backwards\n */\n forwardDeletion(anchor, anchorNode, isBackward) {\n if (!isBackward && (\n // Delete forward handle case\n anchor.type === 'element' && $isElementNode(anchorNode) && anchor.offset === anchorNode.getChildrenSize() || anchor.type === 'text' && anchor.offset === anchorNode.getTextContentSize())) {\n const parent = anchorNode.getParent();\n const nextSibling = anchorNode.getNextSibling() || (parent === null ? null : parent.getNextSibling());\n if ($isElementNode(nextSibling) && nextSibling.isShadowRoot()) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Performs one logical character deletion operation on the EditorState based on the current Selection.\n * Handles different node types.\n *\n * @param isBackward whether or not the selection is backwards.\n */\n deleteCharacter(isBackward) {\n const wasCollapsed = this.isCollapsed();\n if (this.isCollapsed()) {\n const anchor = this.anchor;\n let anchorNode = anchor.getNode();\n if (this.forwardDeletion(anchor, anchorNode, isBackward)) {\n return;\n }\n\n // Handle the deletion around decorators.\n const focus = this.focus;\n const possibleNode = $getAdjacentNode(focus, isBackward);\n if ($isDecoratorNode(possibleNode) && !possibleNode.isIsolated()) {\n // Make it possible to move selection from range selection to\n // node selection on the node.\n if (possibleNode.isKeyboardSelectable() && $isElementNode(anchorNode) && anchorNode.getChildrenSize() === 0) {\n anchorNode.remove();\n const nodeSelection = $createNodeSelection();\n nodeSelection.add(possibleNode.__key);\n $setSelection(nodeSelection);\n } else {\n possibleNode.remove();\n const editor = getActiveEditor();\n editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined);\n }\n return;\n } else if (!isBackward && $isElementNode(possibleNode) && $isElementNode(anchorNode) && anchorNode.isEmpty()) {\n anchorNode.remove();\n possibleNode.selectStart();\n return;\n }\n this.modify('extend', isBackward, 'character');\n if (!this.isCollapsed()) {\n const focusNode = focus.type === 'text' ? focus.getNode() : null;\n anchorNode = anchor.type === 'text' ? anchor.getNode() : null;\n if (focusNode !== null && focusNode.isSegmented()) {\n const offset = focus.offset;\n const textContentSize = focusNode.getTextContentSize();\n if (focusNode.is(anchorNode) || isBackward && offset !== textContentSize || !isBackward && offset !== 0) {\n $removeSegment(focusNode, isBackward, offset);\n return;\n }\n } else if (anchorNode !== null && anchorNode.isSegmented()) {\n const offset = anchor.offset;\n const textContentSize = anchorNode.getTextContentSize();\n if (anchorNode.is(focusNode) || isBackward && offset !== 0 || !isBackward && offset !== textContentSize) {\n $removeSegment(anchorNode, isBackward, offset);\n return;\n }\n }\n $updateCaretSelectionForUnicodeCharacter(this, isBackward);\n } else if (isBackward && anchor.offset === 0) {\n // Special handling around rich text nodes\n const element = anchor.type === 'element' ? anchor.getNode() : anchor.getNode().getParentOrThrow();\n if (element.collapseAtStart(this)) {\n return;\n }\n }\n }\n this.removeText();\n if (isBackward && !wasCollapsed && this.isCollapsed() && this.anchor.type === 'element' && this.anchor.offset === 0) {\n const anchorNode = this.anchor.getNode();\n if (anchorNode.isEmpty() && $isRootNode(anchorNode.getParent()) && anchorNode.getIndexWithinParent() === 0) {\n anchorNode.collapseAtStart(this);\n }\n }\n }\n\n /**\n * Performs one logical line deletion operation on the EditorState based on the current Selection.\n * Handles different node types.\n *\n * @param isBackward whether or not the selection is backwards.\n */\n deleteLine(isBackward) {\n if (this.isCollapsed()) {\n // Since `domSelection.modify('extend', ..., 'lineboundary')` works well for text selections\n // but doesn't properly handle selections which end on elements, a space character is added\n // for such selections transforming their anchor's type to 'text'\n const anchorIsElement = this.anchor.type === 'element';\n if (anchorIsElement) {\n this.insertText(' ');\n }\n this.modify('extend', isBackward, 'lineboundary');\n\n // If selection is extended to cover text edge then extend it one character more\n // to delete its parent element. Otherwise text content will be deleted but empty\n // parent node will remain\n const endPoint = isBackward ? this.focus : this.anchor;\n if (endPoint.offset === 0) {\n this.modify('extend', isBackward, 'character');\n }\n\n // Adjusts selection to include an extra character added for element anchors to remove it\n if (anchorIsElement) {\n const startPoint = isBackward ? this.anchor : this.focus;\n startPoint.set(startPoint.key, startPoint.offset + 1, startPoint.type);\n }\n }\n this.removeText();\n }\n\n /**\n * Performs one logical word deletion operation on the EditorState based on the current Selection.\n * Handles different node types.\n *\n * @param isBackward whether or not the selection is backwards.\n */\n deleteWord(isBackward) {\n if (this.isCollapsed()) {\n const anchor = this.anchor;\n const anchorNode = anchor.getNode();\n if (this.forwardDeletion(anchor, anchorNode, isBackward)) {\n return;\n }\n this.modify('extend', isBackward, 'word');\n }\n this.removeText();\n }\n\n /**\n * Returns whether the Selection is \"backwards\", meaning the focus\n * logically precedes the anchor in the EditorState.\n * @returns true if the Selection is backwards, false otherwise.\n */\n isBackward() {\n return this.focus.isBefore(this.anchor);\n }\n getStartEndPoints() {\n return [this.anchor, this.focus];\n }\n}\nfunction $isNodeSelection(x) {\n return x instanceof NodeSelection;\n}\nfunction getCharacterOffset(point) {\n const offset = point.offset;\n if (point.type === 'text') {\n return offset;\n }\n const parent = point.getNode();\n return offset === parent.getChildrenSize() ? parent.getTextContent().length : 0;\n}\nfunction $getCharacterOffsets(selection) {\n const anchorAndFocus = selection.getStartEndPoints();\n if (anchorAndFocus === null) {\n return [0, 0];\n }\n const [anchor, focus] = anchorAndFocus;\n if (anchor.type === 'element' && focus.type === 'element' && anchor.key === focus.key && anchor.offset === focus.offset) {\n return [0, 0];\n }\n return [getCharacterOffset(anchor), getCharacterOffset(focus)];\n}\nfunction $swapPoints(selection) {\n const focus = selection.focus;\n const anchor = selection.anchor;\n const anchorKey = anchor.key;\n const anchorOffset = anchor.offset;\n const anchorType = anchor.type;\n $setPointValues(anchor, focus.key, focus.offset, focus.type);\n $setPointValues(focus, anchorKey, anchorOffset, anchorType);\n selection._cachedNodes = null;\n}\nfunction moveNativeSelection(domSelection, alter, direction, granularity) {\n // Selection.modify() method applies a change to the current selection or cursor position,\n // but is still non-standard in some browsers.\n domSelection.modify(alter, direction, granularity);\n}\nfunction $updateCaretSelectionForUnicodeCharacter(selection, isBackward) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n if (anchorNode === focusNode && anchor.type === 'text' && focus.type === 'text') {\n // Handling of multibyte characters\n const anchorOffset = anchor.offset;\n const focusOffset = focus.offset;\n const isBefore = anchorOffset < focusOffset;\n const startOffset = isBefore ? anchorOffset : focusOffset;\n const endOffset = isBefore ? focusOffset : anchorOffset;\n const characterOffset = endOffset - 1;\n if (startOffset !== characterOffset) {\n const text = anchorNode.getTextContent().slice(startOffset, endOffset);\n if (!doesContainGrapheme(text)) {\n if (isBackward) {\n focus.offset = characterOffset;\n } else {\n anchor.offset = characterOffset;\n }\n }\n }\n }\n}\nfunction $removeSegment(node, isBackward, offset) {\n const textNode = node;\n const textContent = textNode.getTextContent();\n const split = textContent.split(/(?=\\s)/g);\n const splitLength = split.length;\n let segmentOffset = 0;\n let restoreOffset = 0;\n for (let i = 0; i < splitLength; i++) {\n const text = split[i];\n const isLast = i === splitLength - 1;\n restoreOffset = segmentOffset;\n segmentOffset += text.length;\n if (isBackward && segmentOffset === offset || segmentOffset > offset || isLast) {\n split.splice(i, 1);\n if (isLast) {\n restoreOffset = undefined;\n }\n break;\n }\n }\n const nextTextContent = split.join('').trim();\n if (nextTextContent === '') {\n textNode.remove();\n } else {\n textNode.setTextContent(nextTextContent);\n textNode.select(restoreOffset, restoreOffset);\n }\n}\nfunction shouldResolveAncestor(resolvedElement, resolvedOffset, lastPoint) {\n const parent = resolvedElement.getParent();\n return lastPoint === null || parent === null || !parent.canBeEmpty() || parent !== lastPoint.getNode();\n}\nfunction $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {\n let resolvedOffset = offset;\n let resolvedNode;\n // If we have selection on an element, we will\n // need to figure out (using the offset) what text\n // node should be selected.\n\n if (dom.nodeType === DOM_ELEMENT_TYPE) {\n // Resolve element to a ElementNode, or TextNode, or null\n let moveSelectionToEnd = false;\n // Given we're moving selection to another node, selection is\n // definitely dirty.\n // We use the anchor to find which child node to select\n const childNodes = dom.childNodes;\n const childNodesLength = childNodes.length;\n const blockCursorElement = editor._blockCursorElement;\n // If the anchor is the same as length, then this means we\n // need to select the very last text node.\n if (resolvedOffset === childNodesLength) {\n moveSelectionToEnd = true;\n resolvedOffset = childNodesLength - 1;\n }\n let childDOM = childNodes[resolvedOffset];\n let hasBlockCursor = false;\n if (childDOM === blockCursorElement) {\n childDOM = childNodes[resolvedOffset + 1];\n hasBlockCursor = true;\n } else if (blockCursorElement !== null) {\n const blockCursorElementParent = blockCursorElement.parentNode;\n if (dom === blockCursorElementParent) {\n const blockCursorOffset = Array.prototype.indexOf.call(blockCursorElementParent.children, blockCursorElement);\n if (offset > blockCursorOffset) {\n resolvedOffset--;\n }\n }\n }\n resolvedNode = $getNodeFromDOM(childDOM);\n if ($isTextNode(resolvedNode)) {\n resolvedOffset = getTextNodeOffset(resolvedNode, moveSelectionToEnd);\n } else {\n let resolvedElement = $getNodeFromDOM(dom);\n // Ensure resolvedElement is actually a element.\n if (resolvedElement === null) {\n return null;\n }\n if ($isElementNode(resolvedElement)) {\n resolvedOffset = Math.min(resolvedElement.getChildrenSize(), resolvedOffset);\n let child = resolvedElement.getChildAtIndex(resolvedOffset);\n if ($isElementNode(child) && shouldResolveAncestor(child, resolvedOffset, lastPoint)) {\n const descendant = moveSelectionToEnd ? child.getLastDescendant() : child.getFirstDescendant();\n if (descendant === null) {\n resolvedElement = child;\n } else {\n child = descendant;\n resolvedElement = $isElementNode(child) ? child : child.getParentOrThrow();\n }\n resolvedOffset = 0;\n }\n if ($isTextNode(child)) {\n resolvedNode = child;\n resolvedElement = null;\n resolvedOffset = getTextNodeOffset(child, moveSelectionToEnd);\n } else if (child !== resolvedElement && moveSelectionToEnd && !hasBlockCursor) {\n resolvedOffset++;\n }\n } else {\n const index = resolvedElement.getIndexWithinParent();\n // When selecting decorators, there can be some selection issues when using resolvedOffset,\n // and instead we should be checking if we're using the offset\n if (offset === 0 && $isDecoratorNode(resolvedElement) && $getNodeFromDOM(dom) === resolvedElement) {\n resolvedOffset = index;\n } else {\n resolvedOffset = index + 1;\n }\n resolvedElement = resolvedElement.getParentOrThrow();\n }\n if ($isElementNode(resolvedElement)) {\n return $createPoint(resolvedElement.__key, resolvedOffset, 'element');\n }\n }\n } else {\n // TextNode or null\n resolvedNode = $getNodeFromDOM(dom);\n }\n if (!$isTextNode(resolvedNode)) {\n return null;\n }\n return $createPoint(resolvedNode.__key, resolvedOffset, 'text');\n}\nfunction resolveSelectionPointOnBoundary(point, isBackward, isCollapsed) {\n const offset = point.offset;\n const node = point.getNode();\n if (offset === 0) {\n const prevSibling = node.getPreviousSibling();\n const parent = node.getParent();\n if (!isBackward) {\n if ($isElementNode(prevSibling) && !isCollapsed && prevSibling.isInline()) {\n point.key = prevSibling.__key;\n point.offset = prevSibling.getChildrenSize();\n // @ts-expect-error: intentional\n point.type = 'element';\n } else if ($isTextNode(prevSibling)) {\n point.key = prevSibling.__key;\n point.offset = prevSibling.getTextContent().length;\n }\n } else if ((isCollapsed || !isBackward) && prevSibling === null && $isElementNode(parent) && parent.isInline()) {\n const parentSibling = parent.getPreviousSibling();\n if ($isTextNode(parentSibling)) {\n point.key = parentSibling.__key;\n point.offset = parentSibling.getTextContent().length;\n }\n }\n } else if (offset === node.getTextContent().length) {\n const nextSibling = node.getNextSibling();\n const parent = node.getParent();\n if (isBackward && $isElementNode(nextSibling) && nextSibling.isInline()) {\n point.key = nextSibling.__key;\n point.offset = 0;\n // @ts-expect-error: intentional\n point.type = 'element';\n } else if ((isCollapsed || isBackward) && nextSibling === null && $isElementNode(parent) && parent.isInline() && !parent.canInsertTextAfter()) {\n const parentSibling = parent.getNextSibling();\n if ($isTextNode(parentSibling)) {\n point.key = parentSibling.__key;\n point.offset = 0;\n }\n }\n }\n}\nfunction $normalizeSelectionPointsForBoundaries(anchor, focus, lastSelection) {\n if (anchor.type === 'text' && focus.type === 'text') {\n const isBackward = anchor.isBefore(focus);\n const isCollapsed = anchor.is(focus);\n\n // Attempt to normalize the offset to the previous sibling if we're at the\n // start of a text node and the sibling is a text node or inline element.\n resolveSelectionPointOnBoundary(anchor, isBackward, isCollapsed);\n resolveSelectionPointOnBoundary(focus, !isBackward, isCollapsed);\n if (isCollapsed) {\n focus.key = anchor.key;\n focus.offset = anchor.offset;\n focus.type = anchor.type;\n }\n const editor = getActiveEditor();\n if (editor.isComposing() && editor._compositionKey !== anchor.key && $isRangeSelection(lastSelection)) {\n const lastAnchor = lastSelection.anchor;\n const lastFocus = lastSelection.focus;\n $setPointValues(anchor, lastAnchor.key, lastAnchor.offset, lastAnchor.type);\n $setPointValues(focus, lastFocus.key, lastFocus.offset, lastFocus.type);\n }\n }\n}\nfunction $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection) {\n if (anchorDOM === null || focusDOM === null || !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {\n return null;\n }\n const resolvedAnchorPoint = $internalResolveSelectionPoint(anchorDOM, anchorOffset, $isRangeSelection(lastSelection) ? lastSelection.anchor : null, editor);\n if (resolvedAnchorPoint === null) {\n return null;\n }\n const resolvedFocusPoint = $internalResolveSelectionPoint(focusDOM, focusOffset, $isRangeSelection(lastSelection) ? lastSelection.focus : null, editor);\n if (resolvedFocusPoint === null) {\n return null;\n }\n if (resolvedAnchorPoint.type === 'element' && resolvedFocusPoint.type === 'element') {\n const anchorNode = $getNodeFromDOM(anchorDOM);\n const focusNode = $getNodeFromDOM(focusDOM);\n // Ensure if we're selecting the content of a decorator that we\n // return null for this point, as it's not in the controlled scope\n // of Lexical.\n if ($isDecoratorNode(anchorNode) && $isDecoratorNode(focusNode)) {\n return null;\n }\n }\n\n // Handle normalization of selection when it is at the boundaries.\n $normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint, lastSelection);\n return [resolvedAnchorPoint, resolvedFocusPoint];\n}\nfunction $isBlockElementNode(node) {\n return $isElementNode(node) && !node.isInline();\n}\n\n// This is used to make a selection when the existing\n// selection is null, i.e. forcing selection on the editor\n// when it current exists outside the editor.\n\nfunction $internalMakeRangeSelection(anchorKey, anchorOffset, focusKey, focusOffset, anchorType, focusType) {\n const editorState = getActiveEditorState();\n const selection = new RangeSelection($createPoint(anchorKey, anchorOffset, anchorType), $createPoint(focusKey, focusOffset, focusType), 0, '');\n selection.dirty = true;\n editorState._selection = selection;\n return selection;\n}\nfunction $createRangeSelection() {\n const anchor = $createPoint('root', 0, 'element');\n const focus = $createPoint('root', 0, 'element');\n return new RangeSelection(anchor, focus, 0, '');\n}\nfunction $createNodeSelection() {\n return new NodeSelection(new Set());\n}\nfunction $internalCreateSelection(editor) {\n const currentEditorState = editor.getEditorState();\n const lastSelection = currentEditorState._selection;\n const domSelection = getDOMSelection(editor._window);\n if ($isRangeSelection(lastSelection) || lastSelection == null) {\n return $internalCreateRangeSelection(lastSelection, domSelection, editor, null);\n }\n return lastSelection.clone();\n}\nfunction $createRangeSelectionFromDom(domSelection, editor) {\n return $internalCreateRangeSelection(null, domSelection, editor, null);\n}\nfunction $internalCreateRangeSelection(lastSelection, domSelection, editor, event) {\n const windowObj = editor._window;\n if (windowObj === null) {\n return null;\n }\n // When we create a selection, we try to use the previous\n // selection where possible, unless an actual user selection\n // change has occurred. When we do need to create a new selection\n // we validate we can have text nodes for both anchor and focus\n // nodes. If that holds true, we then return that selection\n // as a mutable object that we use for the editor state for this\n // update cycle. If a selection gets changed, and requires a\n // update to native DOM selection, it gets marked as \"dirty\".\n // If the selection changes, but matches with the existing\n // DOM selection, then we only need to sync it. Otherwise,\n // we generally bail out of doing an update to selection during\n // reconciliation unless there are dirty nodes that need\n // reconciling.\n\n const windowEvent = event || windowObj.event;\n const eventType = windowEvent ? windowEvent.type : undefined;\n const isSelectionChange = eventType === 'selectionchange';\n const useDOMSelection = !getIsProcessingMutations() && (isSelectionChange || eventType === 'beforeinput' || eventType === 'compositionstart' || eventType === 'compositionend' || eventType === 'click' && windowEvent && windowEvent.detail === 3 || eventType === 'drop' || eventType === undefined);\n let anchorDOM, focusDOM, anchorOffset, focusOffset;\n if (!$isRangeSelection(lastSelection) || useDOMSelection) {\n if (domSelection === null) {\n return null;\n }\n anchorDOM = domSelection.anchorNode;\n focusDOM = domSelection.focusNode;\n anchorOffset = domSelection.anchorOffset;\n focusOffset = domSelection.focusOffset;\n if (isSelectionChange && $isRangeSelection(lastSelection) && !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {\n return lastSelection.clone();\n }\n } else {\n return lastSelection.clone();\n }\n // Let's resolve the text nodes from the offsets and DOM nodes we have from\n // native selection.\n const resolvedSelectionPoints = $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection);\n if (resolvedSelectionPoints === null) {\n return null;\n }\n const [resolvedAnchorPoint, resolvedFocusPoint] = resolvedSelectionPoints;\n return new RangeSelection(resolvedAnchorPoint, resolvedFocusPoint, !$isRangeSelection(lastSelection) ? 0 : lastSelection.format, !$isRangeSelection(lastSelection) ? '' : lastSelection.style);\n}\nfunction $getSelection() {\n const editorState = getActiveEditorState();\n return editorState._selection;\n}\nfunction $getPreviousSelection() {\n const editor = getActiveEditor();\n return editor._editorState._selection;\n}\nfunction $updateElementSelectionOnCreateDeleteNode(selection, parentNode, nodeOffset, times = 1) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n if (!parentNode.is(anchorNode) && !parentNode.is(focusNode)) {\n return;\n }\n const parentKey = parentNode.__key;\n // Single node. We shift selection but never redimension it\n if (selection.isCollapsed()) {\n const selectionOffset = anchor.offset;\n if (nodeOffset <= selectionOffset && times > 0 || nodeOffset < selectionOffset && times < 0) {\n const newSelectionOffset = Math.max(0, selectionOffset + times);\n anchor.set(parentKey, newSelectionOffset, 'element');\n focus.set(parentKey, newSelectionOffset, 'element');\n // The new selection might point to text nodes, try to resolve them\n $updateSelectionResolveTextNodes(selection);\n }\n } else {\n // Multiple nodes selected. We shift or redimension selection\n const isBackward = selection.isBackward();\n const firstPoint = isBackward ? focus : anchor;\n const firstPointNode = firstPoint.getNode();\n const lastPoint = isBackward ? anchor : focus;\n const lastPointNode = lastPoint.getNode();\n if (parentNode.is(firstPointNode)) {\n const firstPointOffset = firstPoint.offset;\n if (nodeOffset <= firstPointOffset && times > 0 || nodeOffset < firstPointOffset && times < 0) {\n firstPoint.set(parentKey, Math.max(0, firstPointOffset + times), 'element');\n }\n }\n if (parentNode.is(lastPointNode)) {\n const lastPointOffset = lastPoint.offset;\n if (nodeOffset <= lastPointOffset && times > 0 || nodeOffset < lastPointOffset && times < 0) {\n lastPoint.set(parentKey, Math.max(0, lastPointOffset + times), 'element');\n }\n }\n }\n // The new selection might point to text nodes, try to resolve them\n $updateSelectionResolveTextNodes(selection);\n}\nfunction $updateSelectionResolveTextNodes(selection) {\n const anchor = selection.anchor;\n const anchorOffset = anchor.offset;\n const focus = selection.focus;\n const focusOffset = focus.offset;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n if (selection.isCollapsed()) {\n if (!$isElementNode(anchorNode)) {\n return;\n }\n const childSize = anchorNode.getChildrenSize();\n const anchorOffsetAtEnd = anchorOffset >= childSize;\n const child = anchorOffsetAtEnd ? anchorNode.getChildAtIndex(childSize - 1) : anchorNode.getChildAtIndex(anchorOffset);\n if ($isTextNode(child)) {\n let newOffset = 0;\n if (anchorOffsetAtEnd) {\n newOffset = child.getTextContentSize();\n }\n anchor.set(child.__key, newOffset, 'text');\n focus.set(child.__key, newOffset, 'text');\n }\n return;\n }\n if ($isElementNode(anchorNode)) {\n const childSize = anchorNode.getChildrenSize();\n const anchorOffsetAtEnd = anchorOffset >= childSize;\n const child = anchorOffsetAtEnd ? anchorNode.getChildAtIndex(childSize - 1) : anchorNode.getChildAtIndex(anchorOffset);\n if ($isTextNode(child)) {\n let newOffset = 0;\n if (anchorOffsetAtEnd) {\n newOffset = child.getTextContentSize();\n }\n anchor.set(child.__key, newOffset, 'text');\n }\n }\n if ($isElementNode(focusNode)) {\n const childSize = focusNode.getChildrenSize();\n const focusOffsetAtEnd = focusOffset >= childSize;\n const child = focusOffsetAtEnd ? focusNode.getChildAtIndex(childSize - 1) : focusNode.getChildAtIndex(focusOffset);\n if ($isTextNode(child)) {\n let newOffset = 0;\n if (focusOffsetAtEnd) {\n newOffset = child.getTextContentSize();\n }\n focus.set(child.__key, newOffset, 'text');\n }\n }\n}\nfunction applySelectionTransforms(nextEditorState, editor) {\n const prevEditorState = editor.getEditorState();\n const prevSelection = prevEditorState._selection;\n const nextSelection = nextEditorState._selection;\n if ($isRangeSelection(nextSelection)) {\n const anchor = nextSelection.anchor;\n const focus = nextSelection.focus;\n let anchorNode;\n if (anchor.type === 'text') {\n anchorNode = anchor.getNode();\n anchorNode.selectionTransform(prevSelection, nextSelection);\n }\n if (focus.type === 'text') {\n const focusNode = focus.getNode();\n if (anchorNode !== focusNode) {\n focusNode.selectionTransform(prevSelection, nextSelection);\n }\n }\n }\n}\nfunction moveSelectionPointToSibling(point, node, parent, prevSibling, nextSibling) {\n let siblingKey = null;\n let offset = 0;\n let type = null;\n if (prevSibling !== null) {\n siblingKey = prevSibling.__key;\n if ($isTextNode(prevSibling)) {\n offset = prevSibling.getTextContentSize();\n type = 'text';\n } else if ($isElementNode(prevSibling)) {\n offset = prevSibling.getChildrenSize();\n type = 'element';\n }\n } else {\n if (nextSibling !== null) {\n siblingKey = nextSibling.__key;\n if ($isTextNode(nextSibling)) {\n type = 'text';\n } else if ($isElementNode(nextSibling)) {\n type = 'element';\n }\n }\n }\n if (siblingKey !== null && type !== null) {\n point.set(siblingKey, offset, type);\n } else {\n offset = node.getIndexWithinParent();\n if (offset === -1) {\n // Move selection to end of parent\n offset = parent.getChildrenSize();\n }\n point.set(parent.__key, offset, 'element');\n }\n}\nfunction adjustPointOffsetForMergedSibling(point, isBefore, key, target, textLength) {\n if (point.type === 'text') {\n point.key = key;\n if (!isBefore) {\n point.offset += textLength;\n }\n } else if (point.offset > target.getIndexWithinParent()) {\n point.offset -= 1;\n }\n}\nfunction updateDOMSelection(prevSelection, nextSelection, editor, domSelection, tags, rootElement, nodeCount) {\n const anchorDOMNode = domSelection.anchorNode;\n const focusDOMNode = domSelection.focusNode;\n const anchorOffset = domSelection.anchorOffset;\n const focusOffset = domSelection.focusOffset;\n const activeElement = document.activeElement;\n\n // TODO: make this not hard-coded, and add another config option\n // that makes this configurable.\n if (tags.has('collaboration') && activeElement !== rootElement || activeElement !== null && isSelectionCapturedInDecoratorInput(activeElement)) {\n return;\n }\n if (!$isRangeSelection(nextSelection)) {\n // We don't remove selection if the prevSelection is null because\n // of editor.setRootElement(). If this occurs on init when the\n // editor is already focused, then this can cause the editor to\n // lose focus.\n if (prevSelection !== null && isSelectionWithinEditor(editor, anchorDOMNode, focusDOMNode)) {\n domSelection.removeAllRanges();\n }\n return;\n }\n const anchor = nextSelection.anchor;\n const focus = nextSelection.focus;\n const anchorKey = anchor.key;\n const focusKey = focus.key;\n const anchorDOM = getElementByKeyOrThrow(editor, anchorKey);\n const focusDOM = getElementByKeyOrThrow(editor, focusKey);\n const nextAnchorOffset = anchor.offset;\n const nextFocusOffset = focus.offset;\n const nextFormat = nextSelection.format;\n const nextStyle = nextSelection.style;\n const isCollapsed = nextSelection.isCollapsed();\n let nextAnchorNode = anchorDOM;\n let nextFocusNode = focusDOM;\n let anchorFormatOrStyleChanged = false;\n if (anchor.type === 'text') {\n nextAnchorNode = getDOMTextNode(anchorDOM);\n const anchorNode = anchor.getNode();\n anchorFormatOrStyleChanged = anchorNode.getFormat() !== nextFormat || anchorNode.getStyle() !== nextStyle;\n } else if ($isRangeSelection(prevSelection) && prevSelection.anchor.type === 'text') {\n anchorFormatOrStyleChanged = true;\n }\n if (focus.type === 'text') {\n nextFocusNode = getDOMTextNode(focusDOM);\n }\n\n // If we can't get an underlying text node for selection, then\n // we should avoid setting selection to something incorrect.\n if (nextAnchorNode === null || nextFocusNode === null) {\n return;\n }\n if (isCollapsed && (prevSelection === null || anchorFormatOrStyleChanged || $isRangeSelection(prevSelection) && (prevSelection.format !== nextFormat || prevSelection.style !== nextStyle))) {\n markCollapsedSelectionFormat(nextFormat, nextStyle, nextAnchorOffset, anchorKey, performance.now());\n }\n\n // Diff against the native DOM selection to ensure we don't do\n // an unnecessary selection update. We also skip this check if\n // we're moving selection to within an element, as this can\n // sometimes be problematic around scrolling.\n if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode &&\n // Badly interpreted range selection when collapsed - #1482\n !(domSelection.type === 'Range' && isCollapsed)) {\n // If the root element does not have focus, ensure it has focus\n if (activeElement === null || !rootElement.contains(activeElement)) {\n rootElement.focus({\n preventScroll: true\n });\n }\n if (anchor.type !== 'element') {\n return;\n }\n }\n\n // Apply the updated selection to the DOM. Note: this will trigger\n // a \"selectionchange\" event, although it will be asynchronous.\n try {\n domSelection.setBaseAndExtent(nextAnchorNode, nextAnchorOffset, nextFocusNode, nextFocusOffset);\n } catch (error) {\n // If we encounter an error, continue. This can sometimes\n // occur with FF and there's no good reason as to why it\n // should happen.\n {\n console.warn(error);\n }\n }\n if (!tags.has('skip-scroll-into-view') && nextSelection.isCollapsed() && rootElement !== null && rootElement === document.activeElement) {\n const selectionTarget = nextSelection instanceof RangeSelection && nextSelection.anchor.type === 'element' ? nextAnchorNode.childNodes[nextAnchorOffset] || null : domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null;\n if (selectionTarget !== null) {\n let selectionRect;\n if (selectionTarget instanceof Text) {\n const range = document.createRange();\n range.selectNode(selectionTarget);\n selectionRect = range.getBoundingClientRect();\n } else {\n selectionRect = selectionTarget.getBoundingClientRect();\n }\n scrollIntoViewIfNeeded(editor, selectionRect, rootElement);\n }\n }\n markSelectionChangeFromDOMUpdate();\n}\nfunction $insertNodes(nodes) {\n let selection = $getSelection() || $getPreviousSelection();\n if (selection === null) {\n selection = $getRoot().selectEnd();\n }\n selection.insertNodes(nodes);\n}\nfunction $getTextContent() {\n const selection = $getSelection();\n if (selection === null) {\n return '';\n }\n return selection.getTextContent();\n}\nfunction $removeTextAndSplitBlock(selection) {\n let selection_ = selection;\n if (!selection.isCollapsed()) {\n selection_.removeText();\n }\n // A new selection can originate as a result of node replacement, in which case is registered via\n // $setSelection\n const newSelection = $getSelection();\n if ($isRangeSelection(newSelection)) {\n selection_ = newSelection;\n }\n if (!$isRangeSelection(selection_)) {\n throw Error(`Unexpected dirty selection to be null`);\n }\n const anchor = selection_.anchor;\n let node = anchor.getNode();\n let offset = anchor.offset;\n while (!INTERNAL_$isBlock(node)) {\n [node, offset] = $splitNodeAtPoint(node, offset);\n }\n return offset;\n}\nfunction $splitNodeAtPoint(node, offset) {\n const parent = node.getParent();\n if (!parent) {\n const paragraph = $createParagraphNode();\n $getRoot().append(paragraph);\n paragraph.select();\n return [$getRoot(), 0];\n }\n if ($isTextNode(node)) {\n const split = node.splitText(offset);\n if (split.length === 0) {\n return [parent, node.getIndexWithinParent()];\n }\n const x = offset === 0 ? 0 : 1;\n const index = split[0].getIndexWithinParent() + x;\n return [parent, index];\n }\n if (!$isElementNode(node) || offset === 0) {\n return [parent, node.getIndexWithinParent()];\n }\n const firstToAppend = node.getChildAtIndex(offset);\n if (firstToAppend) {\n const insertPoint = new RangeSelection($createPoint(node.__key, offset, 'element'), $createPoint(node.__key, offset, 'element'), 0, '');\n const newElement = node.insertNewAfter(insertPoint);\n if (newElement) {\n newElement.append(firstToAppend, ...firstToAppend.getNextSiblings());\n }\n }\n return [parent, node.getIndexWithinParent() + 1];\n}\nfunction $wrapInlineNodes(nodes) {\n // We temporarily insert the topLevelNodes into an arbitrary ElementNode,\n // since insertAfter does not work on nodes that have no parent (TO-DO: fix that).\n const virtualRoot = $createParagraphNode();\n let currentBlock = null;\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n const isLineBreakNode = $isLineBreakNode(node);\n if (isLineBreakNode || $isDecoratorNode(node) && node.isInline() || $isElementNode(node) && node.isInline() || $isTextNode(node) || node.isParentRequired()) {\n if (currentBlock === null) {\n currentBlock = node.createParentElementNode();\n virtualRoot.append(currentBlock);\n // In the case of LineBreakNode, we just need to\n // add an empty ParagraphNode to the topLevelBlocks.\n if (isLineBreakNode) {\n continue;\n }\n }\n if (currentBlock !== null) {\n currentBlock.append(node);\n }\n } else {\n virtualRoot.append(node);\n currentBlock = null;\n }\n }\n return virtualRoot;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nlet activeEditorState = null;\nlet activeEditor = null;\nlet isReadOnlyMode = false;\nlet isAttemptingToRecoverFromReconcilerError = false;\nlet infiniteTransformCount = 0;\nconst observerOptions = {\n characterData: true,\n childList: true,\n subtree: true\n};\nfunction isCurrentlyReadOnlyMode() {\n return isReadOnlyMode || activeEditorState !== null && activeEditorState._readOnly;\n}\nfunction errorOnReadOnly() {\n if (isReadOnlyMode) {\n {\n throw Error(`Cannot use method in read-only mode.`);\n }\n }\n}\nfunction errorOnInfiniteTransforms() {\n if (infiniteTransformCount > 99) {\n {\n throw Error(`One or more transforms are endlessly triggering additional transforms. May have encountered infinite recursion caused by transforms that have their preconditions too lose and/or conflict with each other.`);\n }\n }\n}\nfunction getActiveEditorState() {\n if (activeEditorState === null) {\n {\n throw Error(`Unable to find an active editor state. State helpers or node methods can only be used synchronously during the callback of editor.update(), editor.read(), or editorState.read().${collectBuildInformation()}`);\n }\n }\n return activeEditorState;\n}\nfunction getActiveEditor() {\n if (activeEditor === null) {\n {\n throw Error(`Unable to find an active editor. This method can only be used synchronously during the callback of editor.update() or editor.read().${collectBuildInformation()}`);\n }\n }\n return activeEditor;\n}\nfunction collectBuildInformation() {\n let compatibleEditors = 0;\n const incompatibleEditors = new Set();\n const thisVersion = LexicalEditor.version;\n if (typeof window !== 'undefined') {\n for (const node of document.querySelectorAll('[contenteditable]')) {\n const editor = getEditorPropertyFromDOMNode(node);\n if (isLexicalEditor(editor)) {\n compatibleEditors++;\n } else if (editor) {\n let version = String(editor.constructor.version || '<0.17.1');\n if (version === thisVersion) {\n version += ' (separately built, likely a bundler configuration issue)';\n }\n incompatibleEditors.add(version);\n }\n }\n }\n let output = ` Detected on the page: ${compatibleEditors} compatible editor(s) with version ${thisVersion}`;\n if (incompatibleEditors.size) {\n output += ` and incompatible editors with versions ${Array.from(incompatibleEditors).join(', ')}`;\n }\n return output;\n}\nfunction internalGetActiveEditor() {\n return activeEditor;\n}\nfunction internalGetActiveEditorState() {\n return activeEditorState;\n}\nfunction $applyTransforms(editor, node, transformsCache) {\n const type = node.__type;\n const registeredNode = getRegisteredNodeOrThrow(editor, type);\n let transformsArr = transformsCache.get(type);\n if (transformsArr === undefined) {\n transformsArr = Array.from(registeredNode.transforms);\n transformsCache.set(type, transformsArr);\n }\n const transformsArrLength = transformsArr.length;\n for (let i = 0; i < transformsArrLength; i++) {\n transformsArr[i](node);\n if (!node.isAttached()) {\n break;\n }\n }\n}\nfunction $isNodeValidForTransform(node, compositionKey) {\n return node !== undefined &&\n // We don't want to transform nodes being composed\n node.__key !== compositionKey && node.isAttached();\n}\nfunction $normalizeAllDirtyTextNodes(editorState, editor) {\n const dirtyLeaves = editor._dirtyLeaves;\n const nodeMap = editorState._nodeMap;\n for (const nodeKey of dirtyLeaves) {\n const node = nodeMap.get(nodeKey);\n if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {\n $normalizeTextNode(node);\n }\n }\n}\n\n/**\n * Transform heuristic:\n * 1. We transform leaves first. If transforms generate additional dirty nodes we repeat step 1.\n * The reasoning behind this is that marking a leaf as dirty marks all its parent elements as dirty too.\n * 2. We transform elements. If element transforms generate additional dirty nodes we repeat step 1.\n * If element transforms only generate additional dirty elements we only repeat step 2.\n *\n * Note that to keep track of newly dirty nodes and subtrees we leverage the editor._dirtyNodes and\n * editor._subtrees which we reset in every loop.\n */\nfunction $applyAllTransforms(editorState, editor) {\n const dirtyLeaves = editor._dirtyLeaves;\n const dirtyElements = editor._dirtyElements;\n const nodeMap = editorState._nodeMap;\n const compositionKey = $getCompositionKey();\n const transformsCache = new Map();\n let untransformedDirtyLeaves = dirtyLeaves;\n let untransformedDirtyLeavesLength = untransformedDirtyLeaves.size;\n let untransformedDirtyElements = dirtyElements;\n let untransformedDirtyElementsLength = untransformedDirtyElements.size;\n while (untransformedDirtyLeavesLength > 0 || untransformedDirtyElementsLength > 0) {\n if (untransformedDirtyLeavesLength > 0) {\n // We leverage editor._dirtyLeaves to track the new dirty leaves after the transforms\n editor._dirtyLeaves = new Set();\n for (const nodeKey of untransformedDirtyLeaves) {\n const node = nodeMap.get(nodeKey);\n if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {\n $normalizeTextNode(node);\n }\n if (node !== undefined && $isNodeValidForTransform(node, compositionKey)) {\n $applyTransforms(editor, node, transformsCache);\n }\n dirtyLeaves.add(nodeKey);\n }\n untransformedDirtyLeaves = editor._dirtyLeaves;\n untransformedDirtyLeavesLength = untransformedDirtyLeaves.size;\n\n // We want to prioritize node transforms over element transforms\n if (untransformedDirtyLeavesLength > 0) {\n infiniteTransformCount++;\n continue;\n }\n }\n\n // All dirty leaves have been processed. Let's do elements!\n // We have previously processed dirty leaves, so let's restart the editor leaves Set to track\n // new ones caused by element transforms\n editor._dirtyLeaves = new Set();\n editor._dirtyElements = new Map();\n for (const currentUntransformedDirtyElement of untransformedDirtyElements) {\n const nodeKey = currentUntransformedDirtyElement[0];\n const intentionallyMarkedAsDirty = currentUntransformedDirtyElement[1];\n if (nodeKey !== 'root' && !intentionallyMarkedAsDirty) {\n continue;\n }\n const node = nodeMap.get(nodeKey);\n if (node !== undefined && $isNodeValidForTransform(node, compositionKey)) {\n $applyTransforms(editor, node, transformsCache);\n }\n dirtyElements.set(nodeKey, intentionallyMarkedAsDirty);\n }\n untransformedDirtyLeaves = editor._dirtyLeaves;\n untransformedDirtyLeavesLength = untransformedDirtyLeaves.size;\n untransformedDirtyElements = editor._dirtyElements;\n untransformedDirtyElementsLength = untransformedDirtyElements.size;\n infiniteTransformCount++;\n }\n editor._dirtyLeaves = dirtyLeaves;\n editor._dirtyElements = dirtyElements;\n}\nfunction $parseSerializedNode(serializedNode) {\n const internalSerializedNode = serializedNode;\n return $parseSerializedNodeImpl(internalSerializedNode, getActiveEditor()._nodes);\n}\nfunction $parseSerializedNodeImpl(serializedNode, registeredNodes) {\n const type = serializedNode.type;\n const registeredNode = registeredNodes.get(type);\n if (registeredNode === undefined) {\n {\n throw Error(`parseEditorState: type \"${type}\" + not found`);\n }\n }\n const nodeClass = registeredNode.klass;\n if (serializedNode.type !== nodeClass.getType()) {\n {\n throw Error(`LexicalNode: Node ${nodeClass.name} does not implement .importJSON().`);\n }\n }\n const node = nodeClass.importJSON(serializedNode);\n const children = serializedNode.children;\n if ($isElementNode(node) && Array.isArray(children)) {\n for (let i = 0; i < children.length; i++) {\n const serializedJSONChildNode = children[i];\n const childNode = $parseSerializedNodeImpl(serializedJSONChildNode, registeredNodes);\n node.append(childNode);\n }\n }\n return node;\n}\nfunction parseEditorState(serializedEditorState, editor, updateFn) {\n const editorState = createEmptyEditorState();\n const previousActiveEditorState = activeEditorState;\n const previousReadOnlyMode = isReadOnlyMode;\n const previousActiveEditor = activeEditor;\n const previousDirtyElements = editor._dirtyElements;\n const previousDirtyLeaves = editor._dirtyLeaves;\n const previousCloneNotNeeded = editor._cloneNotNeeded;\n const previousDirtyType = editor._dirtyType;\n editor._dirtyElements = new Map();\n editor._dirtyLeaves = new Set();\n editor._cloneNotNeeded = new Set();\n editor._dirtyType = 0;\n activeEditorState = editorState;\n isReadOnlyMode = false;\n activeEditor = editor;\n try {\n const registeredNodes = editor._nodes;\n const serializedNode = serializedEditorState.root;\n $parseSerializedNodeImpl(serializedNode, registeredNodes);\n if (updateFn) {\n updateFn();\n }\n\n // Make the editorState immutable\n editorState._readOnly = true;\n {\n handleDEVOnlyPendingUpdateGuarantees(editorState);\n }\n } catch (error) {\n if (error instanceof Error) {\n editor._onError(error);\n }\n } finally {\n editor._dirtyElements = previousDirtyElements;\n editor._dirtyLeaves = previousDirtyLeaves;\n editor._cloneNotNeeded = previousCloneNotNeeded;\n editor._dirtyType = previousDirtyType;\n activeEditorState = previousActiveEditorState;\n isReadOnlyMode = previousReadOnlyMode;\n activeEditor = previousActiveEditor;\n }\n return editorState;\n}\n\n// This technically isn't an update but given we need\n// exposure to the module's active bindings, we have this\n// function here\n\nfunction readEditorState(editor, editorState, callbackFn) {\n const previousActiveEditorState = activeEditorState;\n const previousReadOnlyMode = isReadOnlyMode;\n const previousActiveEditor = activeEditor;\n activeEditorState = editorState;\n isReadOnlyMode = true;\n activeEditor = editor;\n try {\n return callbackFn();\n } finally {\n activeEditorState = previousActiveEditorState;\n isReadOnlyMode = previousReadOnlyMode;\n activeEditor = previousActiveEditor;\n }\n}\nfunction handleDEVOnlyPendingUpdateGuarantees(pendingEditorState) {\n // Given we can't Object.freeze the nodeMap as it's a Map,\n // we instead replace its set, clear and delete methods.\n const nodeMap = pendingEditorState._nodeMap;\n nodeMap.set = () => {\n throw new Error('Cannot call set() on a frozen Lexical node map');\n };\n nodeMap.clear = () => {\n throw new Error('Cannot call clear() on a frozen Lexical node map');\n };\n nodeMap.delete = () => {\n throw new Error('Cannot call delete() on a frozen Lexical node map');\n };\n}\nfunction $commitPendingUpdates(editor, recoveryEditorState) {\n const pendingEditorState = editor._pendingEditorState;\n const rootElement = editor._rootElement;\n const shouldSkipDOM = editor._headless || rootElement === null;\n if (pendingEditorState === null) {\n return;\n }\n\n // ======\n // Reconciliation has started.\n // ======\n\n const currentEditorState = editor._editorState;\n const currentSelection = currentEditorState._selection;\n const pendingSelection = pendingEditorState._selection;\n const needsUpdate = editor._dirtyType !== NO_DIRTY_NODES;\n const previousActiveEditorState = activeEditorState;\n const previousReadOnlyMode = isReadOnlyMode;\n const previousActiveEditor = activeEditor;\n const previouslyUpdating = editor._updating;\n const observer = editor._observer;\n let mutatedNodes = null;\n editor._pendingEditorState = null;\n editor._editorState = pendingEditorState;\n if (!shouldSkipDOM && needsUpdate && observer !== null) {\n activeEditor = editor;\n activeEditorState = pendingEditorState;\n isReadOnlyMode = false;\n // We don't want updates to sync block the reconciliation.\n editor._updating = true;\n try {\n const dirtyType = editor._dirtyType;\n const dirtyElements = editor._dirtyElements;\n const dirtyLeaves = editor._dirtyLeaves;\n observer.disconnect();\n mutatedNodes = $reconcileRoot(currentEditorState, pendingEditorState, editor, dirtyType, dirtyElements, dirtyLeaves);\n } catch (error) {\n // Report errors\n if (error instanceof Error) {\n editor._onError(error);\n }\n\n // Reset editor and restore incoming editor state to the DOM\n if (!isAttemptingToRecoverFromReconcilerError) {\n resetEditor(editor, null, rootElement, pendingEditorState);\n initMutationObserver(editor);\n editor._dirtyType = FULL_RECONCILE;\n isAttemptingToRecoverFromReconcilerError = true;\n $commitPendingUpdates(editor, currentEditorState);\n isAttemptingToRecoverFromReconcilerError = false;\n } else {\n // To avoid a possible situation of infinite loops, lets throw\n throw error;\n }\n return;\n } finally {\n observer.observe(rootElement, observerOptions);\n editor._updating = previouslyUpdating;\n activeEditorState = previousActiveEditorState;\n isReadOnlyMode = previousReadOnlyMode;\n activeEditor = previousActiveEditor;\n }\n }\n if (!pendingEditorState._readOnly) {\n pendingEditorState._readOnly = true;\n {\n handleDEVOnlyPendingUpdateGuarantees(pendingEditorState);\n if ($isRangeSelection(pendingSelection)) {\n Object.freeze(pendingSelection.anchor);\n Object.freeze(pendingSelection.focus);\n }\n Object.freeze(pendingSelection);\n }\n }\n const dirtyLeaves = editor._dirtyLeaves;\n const dirtyElements = editor._dirtyElements;\n const normalizedNodes = editor._normalizedNodes;\n const tags = editor._updateTags;\n const deferred = editor._deferred;\n if (needsUpdate) {\n editor._dirtyType = NO_DIRTY_NODES;\n editor._cloneNotNeeded.clear();\n editor._dirtyLeaves = new Set();\n editor._dirtyElements = new Map();\n editor._normalizedNodes = new Set();\n editor._updateTags = new Set();\n }\n $garbageCollectDetachedDecorators(editor, pendingEditorState);\n\n // ======\n // Reconciliation has finished. Now update selection and trigger listeners.\n // ======\n\n const domSelection = shouldSkipDOM ? null : getDOMSelection(editor._window);\n\n // Attempt to update the DOM selection, including focusing of the root element,\n // and scroll into view if needed.\n if (editor._editable &&\n // domSelection will be null in headless\n domSelection !== null && (needsUpdate || pendingSelection === null || pendingSelection.dirty)) {\n activeEditor = editor;\n activeEditorState = pendingEditorState;\n try {\n if (observer !== null) {\n observer.disconnect();\n }\n if (needsUpdate || pendingSelection === null || pendingSelection.dirty) {\n const blockCursorElement = editor._blockCursorElement;\n if (blockCursorElement !== null) {\n removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);\n }\n updateDOMSelection(currentSelection, pendingSelection, editor, domSelection, tags, rootElement);\n }\n updateDOMBlockCursorElement(editor, rootElement, pendingSelection);\n if (observer !== null) {\n observer.observe(rootElement, observerOptions);\n }\n } finally {\n activeEditor = previousActiveEditor;\n activeEditorState = previousActiveEditorState;\n }\n }\n if (mutatedNodes !== null) {\n triggerMutationListeners(editor, mutatedNodes, tags, dirtyLeaves, currentEditorState);\n }\n if (!$isRangeSelection(pendingSelection) && pendingSelection !== null && (currentSelection === null || !currentSelection.is(pendingSelection))) {\n editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined);\n }\n /**\n * Capture pendingDecorators after garbage collecting detached decorators\n */\n const pendingDecorators = editor._pendingDecorators;\n if (pendingDecorators !== null) {\n editor._decorators = pendingDecorators;\n editor._pendingDecorators = null;\n triggerListeners('decorator', editor, true, pendingDecorators);\n }\n\n // If reconciler fails, we reset whole editor (so current editor state becomes empty)\n // and attempt to re-render pendingEditorState. If that goes through we trigger\n // listeners, but instead use recoverEditorState which is current editor state before reset\n // This specifically important for collab that relies on prevEditorState from update\n // listener to calculate delta of changed nodes/properties\n triggerTextContentListeners(editor, recoveryEditorState || currentEditorState, pendingEditorState);\n triggerListeners('update', editor, true, {\n dirtyElements,\n dirtyLeaves,\n editorState: pendingEditorState,\n normalizedNodes,\n prevEditorState: recoveryEditorState || currentEditorState,\n tags\n });\n triggerDeferredUpdateCallbacks(editor, deferred);\n $triggerEnqueuedUpdates(editor);\n}\nfunction triggerTextContentListeners(editor, currentEditorState, pendingEditorState) {\n const currentTextContent = getEditorStateTextContent(currentEditorState);\n const latestTextContent = getEditorStateTextContent(pendingEditorState);\n if (currentTextContent !== latestTextContent) {\n triggerListeners('textcontent', editor, true, latestTextContent);\n }\n}\nfunction triggerMutationListeners(editor, mutatedNodes, updateTags, dirtyLeaves, prevEditorState) {\n const listeners = Array.from(editor._listeners.mutation);\n const listenersLength = listeners.length;\n for (let i = 0; i < listenersLength; i++) {\n const [listener, klass] = listeners[i];\n const mutatedNodesByType = mutatedNodes.get(klass);\n if (mutatedNodesByType !== undefined) {\n listener(mutatedNodesByType, {\n dirtyLeaves,\n prevEditorState,\n updateTags\n });\n }\n }\n}\nfunction triggerListeners(type, editor, isCurrentlyEnqueuingUpdates, ...payload) {\n const previouslyUpdating = editor._updating;\n editor._updating = isCurrentlyEnqueuingUpdates;\n try {\n const listeners = Array.from(editor._listeners[type]);\n for (let i = 0; i < listeners.length; i++) {\n // @ts-ignore\n listeners[i].apply(null, payload);\n }\n } finally {\n editor._updating = previouslyUpdating;\n }\n}\nfunction triggerCommandListeners(editor, type, payload) {\n if (editor._updating === false || activeEditor !== editor) {\n let returnVal = false;\n editor.update(() => {\n returnVal = triggerCommandListeners(editor, type, payload);\n });\n return returnVal;\n }\n const editors = getEditorsToPropagate(editor);\n for (let i = 4; i >= 0; i--) {\n for (let e = 0; e < editors.length; e++) {\n const currentEditor = editors[e];\n const commandListeners = currentEditor._commands;\n const listenerInPriorityOrder = commandListeners.get(type);\n if (listenerInPriorityOrder !== undefined) {\n const listenersSet = listenerInPriorityOrder[i];\n if (listenersSet !== undefined) {\n const listeners = Array.from(listenersSet);\n const listenersLength = listeners.length;\n for (let j = 0; j < listenersLength; j++) {\n if (listeners[j](payload, editor) === true) {\n return true;\n }\n }\n }\n }\n }\n }\n return false;\n}\nfunction $triggerEnqueuedUpdates(editor) {\n const queuedUpdates = editor._updates;\n if (queuedUpdates.length !== 0) {\n const queuedUpdate = queuedUpdates.shift();\n if (queuedUpdate) {\n const [updateFn, options] = queuedUpdate;\n $beginUpdate(editor, updateFn, options);\n }\n }\n}\nfunction triggerDeferredUpdateCallbacks(editor, deferred) {\n editor._deferred = [];\n if (deferred.length !== 0) {\n const previouslyUpdating = editor._updating;\n editor._updating = true;\n try {\n for (let i = 0; i < deferred.length; i++) {\n deferred[i]();\n }\n } finally {\n editor._updating = previouslyUpdating;\n }\n }\n}\nfunction processNestedUpdates(editor, initialSkipTransforms) {\n const queuedUpdates = editor._updates;\n let skipTransforms = initialSkipTransforms || false;\n\n // Updates might grow as we process them, we so we'll need\n // to handle each update as we go until the updates array is\n // empty.\n while (queuedUpdates.length !== 0) {\n const queuedUpdate = queuedUpdates.shift();\n if (queuedUpdate) {\n const [nextUpdateFn, options] = queuedUpdate;\n let onUpdate;\n let tag;\n if (options !== undefined) {\n onUpdate = options.onUpdate;\n tag = options.tag;\n if (options.skipTransforms) {\n skipTransforms = true;\n }\n if (options.discrete) {\n const pendingEditorState = editor._pendingEditorState;\n if (!(pendingEditorState !== null)) {\n throw Error(`Unexpected empty pending editor state on discrete nested update`);\n }\n pendingEditorState._flushSync = true;\n }\n if (onUpdate) {\n editor._deferred.push(onUpdate);\n }\n if (tag) {\n editor._updateTags.add(tag);\n }\n }\n nextUpdateFn();\n }\n }\n return skipTransforms;\n}\nfunction $beginUpdate(editor, updateFn, options) {\n const updateTags = editor._updateTags;\n let onUpdate;\n let tag;\n let skipTransforms = false;\n let discrete = false;\n if (options !== undefined) {\n onUpdate = options.onUpdate;\n tag = options.tag;\n if (tag != null) {\n updateTags.add(tag);\n }\n skipTransforms = options.skipTransforms || false;\n discrete = options.discrete || false;\n }\n if (onUpdate) {\n editor._deferred.push(onUpdate);\n }\n const currentEditorState = editor._editorState;\n let pendingEditorState = editor._pendingEditorState;\n let editorStateWasCloned = false;\n if (pendingEditorState === null || pendingEditorState._readOnly) {\n pendingEditorState = editor._pendingEditorState = cloneEditorState(pendingEditorState || currentEditorState);\n editorStateWasCloned = true;\n }\n pendingEditorState._flushSync = discrete;\n const previousActiveEditorState = activeEditorState;\n const previousReadOnlyMode = isReadOnlyMode;\n const previousActiveEditor = activeEditor;\n const previouslyUpdating = editor._updating;\n activeEditorState = pendingEditorState;\n isReadOnlyMode = false;\n editor._updating = true;\n activeEditor = editor;\n try {\n if (editorStateWasCloned) {\n if (editor._headless) {\n if (currentEditorState._selection !== null) {\n pendingEditorState._selection = currentEditorState._selection.clone();\n }\n } else {\n pendingEditorState._selection = $internalCreateSelection(editor);\n }\n }\n const startingCompositionKey = editor._compositionKey;\n updateFn();\n skipTransforms = processNestedUpdates(editor, skipTransforms);\n applySelectionTransforms(pendingEditorState, editor);\n if (editor._dirtyType !== NO_DIRTY_NODES) {\n if (skipTransforms) {\n $normalizeAllDirtyTextNodes(pendingEditorState, editor);\n } else {\n $applyAllTransforms(pendingEditorState, editor);\n }\n processNestedUpdates(editor);\n $garbageCollectDetachedNodes(currentEditorState, pendingEditorState, editor._dirtyLeaves, editor._dirtyElements);\n }\n const endingCompositionKey = editor._compositionKey;\n if (startingCompositionKey !== endingCompositionKey) {\n pendingEditorState._flushSync = true;\n }\n const pendingSelection = pendingEditorState._selection;\n if ($isRangeSelection(pendingSelection)) {\n const pendingNodeMap = pendingEditorState._nodeMap;\n const anchorKey = pendingSelection.anchor.key;\n const focusKey = pendingSelection.focus.key;\n if (pendingNodeMap.get(anchorKey) === undefined || pendingNodeMap.get(focusKey) === undefined) {\n {\n throw Error(`updateEditor: selection has been lost because the previously selected nodes have been removed and selection wasn't moved to another node. Ensure selection changes after removing/replacing a selected node.`);\n }\n }\n } else if ($isNodeSelection(pendingSelection)) {\n // TODO: we should also validate node selection?\n if (pendingSelection._nodes.size === 0) {\n pendingEditorState._selection = null;\n }\n }\n } catch (error) {\n // Report errors\n if (error instanceof Error) {\n editor._onError(error);\n }\n\n // Restore existing editor state to the DOM\n editor._pendingEditorState = currentEditorState;\n editor._dirtyType = FULL_RECONCILE;\n editor._cloneNotNeeded.clear();\n editor._dirtyLeaves = new Set();\n editor._dirtyElements.clear();\n $commitPendingUpdates(editor);\n return;\n } finally {\n activeEditorState = previousActiveEditorState;\n isReadOnlyMode = previousReadOnlyMode;\n activeEditor = previousActiveEditor;\n editor._updating = previouslyUpdating;\n infiniteTransformCount = 0;\n }\n const shouldUpdate = editor._dirtyType !== NO_DIRTY_NODES || editorStateHasDirtySelection(pendingEditorState, editor);\n if (shouldUpdate) {\n if (pendingEditorState._flushSync) {\n pendingEditorState._flushSync = false;\n $commitPendingUpdates(editor);\n } else if (editorStateWasCloned) {\n scheduleMicroTask(() => {\n $commitPendingUpdates(editor);\n });\n }\n } else {\n pendingEditorState._flushSync = false;\n if (editorStateWasCloned) {\n updateTags.clear();\n editor._deferred = [];\n editor._pendingEditorState = null;\n }\n }\n}\nfunction updateEditor(editor, updateFn, options) {\n if (editor._updating) {\n editor._updates.push([updateFn, options]);\n } else {\n $beginUpdate(editor, updateFn, options);\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\n\n/** @noInheritDoc */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nclass ElementNode extends LexicalNode {\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n constructor(key) {\n super(key);\n this.__first = null;\n this.__last = null;\n this.__size = 0;\n this.__format = 0;\n this.__style = '';\n this.__indent = 0;\n this.__dir = null;\n }\n afterCloneFrom(prevNode) {\n super.afterCloneFrom(prevNode);\n this.__first = prevNode.__first;\n this.__last = prevNode.__last;\n this.__size = prevNode.__size;\n this.__indent = prevNode.__indent;\n this.__format = prevNode.__format;\n this.__style = prevNode.__style;\n this.__dir = prevNode.__dir;\n }\n getFormat() {\n const self = this.getLatest();\n return self.__format;\n }\n getFormatType() {\n const format = this.getFormat();\n return ELEMENT_FORMAT_TO_TYPE[format] || '';\n }\n getStyle() {\n const self = this.getLatest();\n return self.__style;\n }\n getIndent() {\n const self = this.getLatest();\n return self.__indent;\n }\n getChildren() {\n const children = [];\n let child = this.getFirstChild();\n while (child !== null) {\n children.push(child);\n child = child.getNextSibling();\n }\n return children;\n }\n getChildrenKeys() {\n const children = [];\n let child = this.getFirstChild();\n while (child !== null) {\n children.push(child.__key);\n child = child.getNextSibling();\n }\n return children;\n }\n getChildrenSize() {\n const self = this.getLatest();\n return self.__size;\n }\n isEmpty() {\n return this.getChildrenSize() === 0;\n }\n isDirty() {\n const editor = getActiveEditor();\n const dirtyElements = editor._dirtyElements;\n return dirtyElements !== null && dirtyElements.has(this.__key);\n }\n isLastChild() {\n const self = this.getLatest();\n const parentLastChild = this.getParentOrThrow().getLastChild();\n return parentLastChild !== null && parentLastChild.is(self);\n }\n getAllTextNodes() {\n const textNodes = [];\n let child = this.getFirstChild();\n while (child !== null) {\n if ($isTextNode(child)) {\n textNodes.push(child);\n }\n if ($isElementNode(child)) {\n const subChildrenNodes = child.getAllTextNodes();\n textNodes.push(...subChildrenNodes);\n }\n child = child.getNextSibling();\n }\n return textNodes;\n }\n getFirstDescendant() {\n let node = this.getFirstChild();\n while ($isElementNode(node)) {\n const child = node.getFirstChild();\n if (child === null) {\n break;\n }\n node = child;\n }\n return node;\n }\n getLastDescendant() {\n let node = this.getLastChild();\n while ($isElementNode(node)) {\n const child = node.getLastChild();\n if (child === null) {\n break;\n }\n node = child;\n }\n return node;\n }\n getDescendantByIndex(index) {\n const children = this.getChildren();\n const childrenLength = children.length;\n // For non-empty element nodes, we resolve its descendant\n // (either a leaf node or the bottom-most element)\n if (index >= childrenLength) {\n const resolvedNode = children[childrenLength - 1];\n return $isElementNode(resolvedNode) && resolvedNode.getLastDescendant() || resolvedNode || null;\n }\n const resolvedNode = children[index];\n return $isElementNode(resolvedNode) && resolvedNode.getFirstDescendant() || resolvedNode || null;\n }\n getFirstChild() {\n const self = this.getLatest();\n const firstKey = self.__first;\n return firstKey === null ? null : $getNodeByKey(firstKey);\n }\n getFirstChildOrThrow() {\n const firstChild = this.getFirstChild();\n if (firstChild === null) {\n {\n throw Error(`Expected node ${this.__key} to have a first child.`);\n }\n }\n return firstChild;\n }\n getLastChild() {\n const self = this.getLatest();\n const lastKey = self.__last;\n return lastKey === null ? null : $getNodeByKey(lastKey);\n }\n getLastChildOrThrow() {\n const lastChild = this.getLastChild();\n if (lastChild === null) {\n {\n throw Error(`Expected node ${this.__key} to have a last child.`);\n }\n }\n return lastChild;\n }\n getChildAtIndex(index) {\n const size = this.getChildrenSize();\n let node;\n let i;\n if (index < size / 2) {\n node = this.getFirstChild();\n i = 0;\n while (node !== null && i <= index) {\n if (i === index) {\n return node;\n }\n node = node.getNextSibling();\n i++;\n }\n return null;\n }\n node = this.getLastChild();\n i = size - 1;\n while (node !== null && i >= index) {\n if (i === index) {\n return node;\n }\n node = node.getPreviousSibling();\n i--;\n }\n return null;\n }\n getTextContent() {\n let textContent = '';\n const children = this.getChildren();\n const childrenLength = children.length;\n for (let i = 0; i < childrenLength; i++) {\n const child = children[i];\n textContent += child.getTextContent();\n if ($isElementNode(child) && i !== childrenLength - 1 && !child.isInline()) {\n textContent += DOUBLE_LINE_BREAK;\n }\n }\n return textContent;\n }\n getTextContentSize() {\n let textContentSize = 0;\n const children = this.getChildren();\n const childrenLength = children.length;\n for (let i = 0; i < childrenLength; i++) {\n const child = children[i];\n textContentSize += child.getTextContentSize();\n if ($isElementNode(child) && i !== childrenLength - 1 && !child.isInline()) {\n textContentSize += DOUBLE_LINE_BREAK.length;\n }\n }\n return textContentSize;\n }\n getDirection() {\n const self = this.getLatest();\n return self.__dir;\n }\n hasFormat(type) {\n if (type !== '') {\n const formatFlag = ELEMENT_TYPE_TO_FORMAT[type];\n return (this.getFormat() & formatFlag) !== 0;\n }\n return false;\n }\n\n // Mutators\n\n select(_anchorOffset, _focusOffset) {\n errorOnReadOnly();\n const selection = $getSelection();\n let anchorOffset = _anchorOffset;\n let focusOffset = _focusOffset;\n const childrenCount = this.getChildrenSize();\n if (!this.canBeEmpty()) {\n if (_anchorOffset === 0 && _focusOffset === 0) {\n const firstChild = this.getFirstChild();\n if ($isTextNode(firstChild) || $isElementNode(firstChild)) {\n return firstChild.select(0, 0);\n }\n } else if ((_anchorOffset === undefined || _anchorOffset === childrenCount) && (_focusOffset === undefined || _focusOffset === childrenCount)) {\n const lastChild = this.getLastChild();\n if ($isTextNode(lastChild) || $isElementNode(lastChild)) {\n return lastChild.select();\n }\n }\n }\n if (anchorOffset === undefined) {\n anchorOffset = childrenCount;\n }\n if (focusOffset === undefined) {\n focusOffset = childrenCount;\n }\n const key = this.__key;\n if (!$isRangeSelection(selection)) {\n return $internalMakeRangeSelection(key, anchorOffset, key, focusOffset, 'element', 'element');\n } else {\n selection.anchor.set(key, anchorOffset, 'element');\n selection.focus.set(key, focusOffset, 'element');\n selection.dirty = true;\n }\n return selection;\n }\n selectStart() {\n const firstNode = this.getFirstDescendant();\n return firstNode ? firstNode.selectStart() : this.select();\n }\n selectEnd() {\n const lastNode = this.getLastDescendant();\n return lastNode ? lastNode.selectEnd() : this.select();\n }\n clear() {\n const writableSelf = this.getWritable();\n const children = this.getChildren();\n children.forEach(child => child.remove());\n return writableSelf;\n }\n append(...nodesToAppend) {\n return this.splice(this.getChildrenSize(), 0, nodesToAppend);\n }\n setDirection(direction) {\n const self = this.getWritable();\n self.__dir = direction;\n return self;\n }\n setFormat(type) {\n const self = this.getWritable();\n self.__format = type !== '' ? ELEMENT_TYPE_TO_FORMAT[type] : 0;\n return this;\n }\n setStyle(style) {\n const self = this.getWritable();\n self.__style = style || '';\n return this;\n }\n setIndent(indentLevel) {\n const self = this.getWritable();\n self.__indent = indentLevel;\n return this;\n }\n splice(start, deleteCount, nodesToInsert) {\n const nodesToInsertLength = nodesToInsert.length;\n const oldSize = this.getChildrenSize();\n const writableSelf = this.getWritable();\n const writableSelfKey = writableSelf.__key;\n const nodesToInsertKeys = [];\n const nodesToRemoveKeys = [];\n const nodeAfterRange = this.getChildAtIndex(start + deleteCount);\n let nodeBeforeRange = null;\n let newSize = oldSize - deleteCount + nodesToInsertLength;\n if (start !== 0) {\n if (start === oldSize) {\n nodeBeforeRange = this.getLastChild();\n } else {\n const node = this.getChildAtIndex(start);\n if (node !== null) {\n nodeBeforeRange = node.getPreviousSibling();\n }\n }\n }\n if (deleteCount > 0) {\n let nodeToDelete = nodeBeforeRange === null ? this.getFirstChild() : nodeBeforeRange.getNextSibling();\n for (let i = 0; i < deleteCount; i++) {\n if (nodeToDelete === null) {\n {\n throw Error(`splice: sibling not found`);\n }\n }\n const nextSibling = nodeToDelete.getNextSibling();\n const nodeKeyToDelete = nodeToDelete.__key;\n const writableNodeToDelete = nodeToDelete.getWritable();\n removeFromParent(writableNodeToDelete);\n nodesToRemoveKeys.push(nodeKeyToDelete);\n nodeToDelete = nextSibling;\n }\n }\n let prevNode = nodeBeforeRange;\n for (let i = 0; i < nodesToInsertLength; i++) {\n const nodeToInsert = nodesToInsert[i];\n if (prevNode !== null && nodeToInsert.is(prevNode)) {\n nodeBeforeRange = prevNode = prevNode.getPreviousSibling();\n }\n const writableNodeToInsert = nodeToInsert.getWritable();\n if (writableNodeToInsert.__parent === writableSelfKey) {\n newSize--;\n }\n removeFromParent(writableNodeToInsert);\n const nodeKeyToInsert = nodeToInsert.__key;\n if (prevNode === null) {\n writableSelf.__first = nodeKeyToInsert;\n writableNodeToInsert.__prev = null;\n } else {\n const writablePrevNode = prevNode.getWritable();\n writablePrevNode.__next = nodeKeyToInsert;\n writableNodeToInsert.__prev = writablePrevNode.__key;\n }\n if (nodeToInsert.__key === writableSelfKey) {\n {\n throw Error(`append: attempting to append self`);\n }\n }\n // Set child parent to self\n writableNodeToInsert.__parent = writableSelfKey;\n nodesToInsertKeys.push(nodeKeyToInsert);\n prevNode = nodeToInsert;\n }\n if (start + deleteCount === oldSize) {\n if (prevNode !== null) {\n const writablePrevNode = prevNode.getWritable();\n writablePrevNode.__next = null;\n writableSelf.__last = prevNode.__key;\n }\n } else if (nodeAfterRange !== null) {\n const writableNodeAfterRange = nodeAfterRange.getWritable();\n if (prevNode !== null) {\n const writablePrevNode = prevNode.getWritable();\n writableNodeAfterRange.__prev = prevNode.__key;\n writablePrevNode.__next = nodeAfterRange.__key;\n } else {\n writableNodeAfterRange.__prev = null;\n }\n }\n writableSelf.__size = newSize;\n\n // In case of deletion we need to adjust selection, unlink removed nodes\n // and clean up node itself if it becomes empty. None of these needed\n // for insertion-only cases\n if (nodesToRemoveKeys.length) {\n // Adjusting selection, in case node that was anchor/focus will be deleted\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const nodesToRemoveKeySet = new Set(nodesToRemoveKeys);\n const nodesToInsertKeySet = new Set(nodesToInsertKeys);\n const {\n anchor,\n focus\n } = selection;\n if (isPointRemoved(anchor, nodesToRemoveKeySet, nodesToInsertKeySet)) {\n moveSelectionPointToSibling(anchor, anchor.getNode(), this, nodeBeforeRange, nodeAfterRange);\n }\n if (isPointRemoved(focus, nodesToRemoveKeySet, nodesToInsertKeySet)) {\n moveSelectionPointToSibling(focus, focus.getNode(), this, nodeBeforeRange, nodeAfterRange);\n }\n // Cleanup if node can't be empty\n if (newSize === 0 && !this.canBeEmpty() && !$isRootOrShadowRoot(this)) {\n this.remove();\n }\n }\n }\n return writableSelf;\n }\n // JSON serialization\n exportJSON() {\n return {\n children: [],\n direction: this.getDirection(),\n format: this.getFormatType(),\n indent: this.getIndent(),\n type: 'element',\n version: 1\n };\n }\n // These are intended to be extends for specific element heuristics.\n insertNewAfter(selection, restoreSelection) {\n return null;\n }\n canIndent() {\n return true;\n }\n /*\n * This method controls the behavior of a the node during backwards\n * deletion (i.e., backspace) when selection is at the beginning of\n * the node (offset 0)\n */\n collapseAtStart(selection) {\n return false;\n }\n excludeFromCopy(destination) {\n return false;\n }\n /** @deprecated @internal */\n canReplaceWith(replacement) {\n return true;\n }\n /** @deprecated @internal */\n canInsertAfter(node) {\n return true;\n }\n canBeEmpty() {\n return true;\n }\n canInsertTextBefore() {\n return true;\n }\n canInsertTextAfter() {\n return true;\n }\n isInline() {\n return false;\n }\n // A shadow root is a Node that behaves like RootNode. The shadow root (and RootNode) mark the\n // end of the hiercharchy, most implementations should treat it as there's nothing (upwards)\n // beyond this point. For example, node.getTopLevelElement(), when performed inside a TableCellNode\n // will return the immediate first child underneath TableCellNode instead of RootNode.\n isShadowRoot() {\n return false;\n }\n /** @deprecated @internal */\n canMergeWith(node) {\n return false;\n }\n extractWithChild(child, selection, destination) {\n return false;\n }\n\n /**\n * Determines whether this node, when empty, can merge with a first block\n * of nodes being inserted.\n *\n * This method is specifically called in {@link RangeSelection.insertNodes}\n * to determine merging behavior during nodes insertion.\n *\n * @example\n * // In a ListItemNode or QuoteNode implementation:\n * canMergeWhenEmpty(): true {\n * return true;\n * }\n */\n canMergeWhenEmpty() {\n return false;\n }\n}\nfunction $isElementNode(node) {\n return node instanceof ElementNode;\n}\nfunction isPointRemoved(point, nodesToRemoveKeySet, nodesToInsertKeySet) {\n let node = point.getNode();\n while (node) {\n const nodeKey = node.__key;\n if (nodesToRemoveKeySet.has(nodeKey) && !nodesToInsertKeySet.has(nodeKey)) {\n return true;\n }\n node = node.getParent();\n }\n return false;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\n/** @noInheritDoc */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nclass DecoratorNode extends LexicalNode {\n constructor(key) {\n super(key);\n }\n\n /**\n * The returned value is added to the LexicalEditor._decorators\n */\n decorate(editor, config) {\n {\n throw Error(`decorate: base method not extended`);\n }\n }\n isIsolated() {\n return false;\n }\n isInline() {\n return true;\n }\n isKeyboardSelectable() {\n return true;\n }\n}\nfunction $isDecoratorNode(node) {\n return node instanceof DecoratorNode;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/** @noInheritDoc */\nclass RootNode extends ElementNode {\n /** @internal */\n\n static getType() {\n return 'root';\n }\n static clone() {\n return new RootNode();\n }\n constructor() {\n super('root');\n this.__cachedText = null;\n }\n getTopLevelElementOrThrow() {\n {\n throw Error(`getTopLevelElementOrThrow: root nodes are not top level elements`);\n }\n }\n getTextContent() {\n const cachedText = this.__cachedText;\n if (isCurrentlyReadOnlyMode() || getActiveEditor()._dirtyType === NO_DIRTY_NODES) {\n if (cachedText !== null) {\n return cachedText;\n }\n }\n return super.getTextContent();\n }\n remove() {\n {\n throw Error(`remove: cannot be called on root nodes`);\n }\n }\n replace(node) {\n {\n throw Error(`replace: cannot be called on root nodes`);\n }\n }\n insertBefore(nodeToInsert) {\n {\n throw Error(`insertBefore: cannot be called on root nodes`);\n }\n }\n insertAfter(nodeToInsert) {\n {\n throw Error(`insertAfter: cannot be called on root nodes`);\n }\n }\n\n // View\n\n updateDOM(prevNode, dom) {\n return false;\n }\n\n // Mutate\n\n append(...nodesToAppend) {\n for (let i = 0; i < nodesToAppend.length; i++) {\n const node = nodesToAppend[i];\n if (!$isElementNode(node) && !$isDecoratorNode(node)) {\n {\n throw Error(`rootNode.append: Only element or decorator nodes can be appended to the root node`);\n }\n }\n }\n return super.append(...nodesToAppend);\n }\n static importJSON(serializedNode) {\n // We don't create a root, and instead use the existing root.\n const node = $getRoot();\n node.setFormat(serializedNode.format);\n node.setIndent(serializedNode.indent);\n node.setDirection(serializedNode.direction);\n return node;\n }\n exportJSON() {\n return {\n children: [],\n direction: this.getDirection(),\n format: this.getFormatType(),\n indent: this.getIndent(),\n type: 'root',\n version: 1\n };\n }\n collapseAtStart() {\n return true;\n }\n}\nfunction $createRootNode() {\n return new RootNode();\n}\nfunction $isRootNode(node) {\n return node instanceof RootNode;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nfunction editorStateHasDirtySelection(editorState, editor) {\n const currentSelection = editor.getEditorState()._selection;\n const pendingSelection = editorState._selection;\n\n // Check if we need to update because of changes in selection\n if (pendingSelection !== null) {\n if (pendingSelection.dirty || !pendingSelection.is(currentSelection)) {\n return true;\n }\n } else if (currentSelection !== null) {\n return true;\n }\n return false;\n}\nfunction cloneEditorState(current) {\n return new EditorState(new Map(current._nodeMap));\n}\nfunction createEmptyEditorState() {\n return new EditorState(new Map([['root', $createRootNode()]]));\n}\nfunction exportNodeToJSON(node) {\n const serializedNode = node.exportJSON();\n const nodeClass = node.constructor;\n if (serializedNode.type !== nodeClass.getType()) {\n {\n throw Error(`LexicalNode: Node ${nodeClass.name} does not match the serialized type. Check if .exportJSON() is implemented and it is returning the correct type.`);\n }\n }\n if ($isElementNode(node)) {\n const serializedChildren = serializedNode.children;\n if (!Array.isArray(serializedChildren)) {\n {\n throw Error(`LexicalNode: Node ${nodeClass.name} is an element but .exportJSON() does not have a children array.`);\n }\n }\n const children = node.getChildren();\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n const serializedChildNode = exportNodeToJSON(child);\n serializedChildren.push(serializedChildNode);\n }\n }\n\n // @ts-expect-error\n return serializedNode;\n}\nclass EditorState {\n constructor(nodeMap, selection) {\n this._nodeMap = nodeMap;\n this._selection = selection || null;\n this._flushSync = false;\n this._readOnly = false;\n }\n isEmpty() {\n return this._nodeMap.size === 1 && this._selection === null;\n }\n read(callbackFn, options) {\n return readEditorState(options && options.editor || null, this, callbackFn);\n }\n clone(selection) {\n const editorState = new EditorState(this._nodeMap, selection === undefined ? this._selection : selection);\n editorState._readOnly = true;\n return editorState;\n }\n toJSON() {\n return readEditorState(null, this, () => ({\n root: exportNodeToJSON($getRoot())\n }));\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// TODO: Cleanup ArtificialNode__DO_NOT_USE #5966\nclass ArtificialNode__DO_NOT_USE extends ElementNode {\n static getType() {\n return 'artificial';\n }\n createDOM(config) {\n // this isnt supposed to be used and is not used anywhere but defining it to appease the API\n const dom = document.createElement('div');\n return dom;\n }\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n/** @noInheritDoc */\nclass ParagraphNode extends ElementNode {\n /** @internal */\n\n constructor(key) {\n super(key);\n this.__textFormat = 0;\n this.__textStyle = '';\n }\n static getType() {\n return 'paragraph';\n }\n getTextFormat() {\n const self = this.getLatest();\n return self.__textFormat;\n }\n setTextFormat(type) {\n const self = this.getWritable();\n self.__textFormat = type;\n return self;\n }\n hasTextFormat(type) {\n const formatFlag = TEXT_TYPE_TO_FORMAT[type];\n return (this.getTextFormat() & formatFlag) !== 0;\n }\n getTextStyle() {\n const self = this.getLatest();\n return self.__textStyle;\n }\n setTextStyle(style) {\n const self = this.getWritable();\n self.__textStyle = style;\n return self;\n }\n static clone(node) {\n return new ParagraphNode(node.__key);\n }\n afterCloneFrom(prevNode) {\n super.afterCloneFrom(prevNode);\n this.__textFormat = prevNode.__textFormat;\n this.__textStyle = prevNode.__textStyle;\n }\n\n // View\n\n createDOM(config) {\n const dom = document.createElement('p');\n const classNames = getCachedClassNameArray(config.theme, 'paragraph');\n if (classNames !== undefined) {\n const domClassList = dom.classList;\n domClassList.add(...classNames);\n }\n return dom;\n }\n updateDOM(prevNode, dom, config) {\n return false;\n }\n static importDOM() {\n return {\n p: node => ({\n conversion: $convertParagraphElement,\n priority: 0\n })\n };\n }\n exportDOM(editor) {\n const {\n element\n } = super.exportDOM(editor);\n if (element && isHTMLElement(element)) {\n if (this.isEmpty()) {\n element.append(document.createElement('br'));\n }\n const formatType = this.getFormatType();\n element.style.textAlign = formatType;\n const direction = this.getDirection();\n if (direction) {\n element.dir = direction;\n }\n const indent = this.getIndent();\n if (indent > 0) {\n // padding-inline-start is not widely supported in email HTML, but\n // Lexical Reconciler uses padding-inline-start. Using text-indent instead.\n element.style.textIndent = `${indent * 20}px`;\n }\n }\n return {\n element\n };\n }\n static importJSON(serializedNode) {\n const node = $createParagraphNode();\n node.setFormat(serializedNode.format);\n node.setIndent(serializedNode.indent);\n node.setDirection(serializedNode.direction);\n node.setTextFormat(serializedNode.textFormat);\n return node;\n }\n exportJSON() {\n return {\n ...super.exportJSON(),\n textFormat: this.getTextFormat(),\n textStyle: this.getTextStyle(),\n type: 'paragraph',\n version: 1\n };\n }\n\n // Mutation\n\n insertNewAfter(rangeSelection, restoreSelection) {\n const newElement = $createParagraphNode();\n newElement.setTextFormat(rangeSelection.format);\n newElement.setTextStyle(rangeSelection.style);\n const direction = this.getDirection();\n newElement.setDirection(direction);\n newElement.setFormat(this.getFormatType());\n newElement.setStyle(this.getTextStyle());\n this.insertAfter(newElement, restoreSelection);\n return newElement;\n }\n collapseAtStart() {\n const children = this.getChildren();\n // If we have an empty (trimmed) first paragraph and try and remove it,\n // delete the paragraph as long as we have another sibling to go to\n if (children.length === 0 || $isTextNode(children[0]) && children[0].getTextContent().trim() === '') {\n const nextSibling = this.getNextSibling();\n if (nextSibling !== null) {\n this.selectNext();\n this.remove();\n return true;\n }\n const prevSibling = this.getPreviousSibling();\n if (prevSibling !== null) {\n this.selectPrevious();\n this.remove();\n return true;\n }\n }\n return false;\n }\n}\nfunction $convertParagraphElement(element) {\n const node = $createParagraphNode();\n if (element.style) {\n node.setFormat(element.style.textAlign);\n const indent = parseInt(element.style.textIndent, 10) / 20;\n if (indent > 0) {\n node.setIndent(indent);\n }\n }\n return {\n node\n };\n}\nfunction $createParagraphNode() {\n return $applyNodeReplacement(new ParagraphNode());\n}\nfunction $isParagraphNode(node) {\n return node instanceof ParagraphNode;\n}\n\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\n\n// https://github.com/microsoft/TypeScript/issues/3841\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\nconst DEFAULT_SKIP_INITIALIZATION = true;\nconst COMMAND_PRIORITY_EDITOR = 0;\nconst COMMAND_PRIORITY_LOW = 1;\nconst COMMAND_PRIORITY_NORMAL = 2;\nconst COMMAND_PRIORITY_HIGH = 3;\nconst COMMAND_PRIORITY_CRITICAL = 4;\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\n/**\n * Type helper for extracting the payload type from a command.\n *\n * @example\n * ```ts\n * const MY_COMMAND = createCommand();\n *\n * // ...\n *\n * editor.registerCommand(MY_COMMAND, payload => {\n * // Type of `payload` is inferred here. But lets say we want to extract a function to delegate to\n * handleMyCommand(editor, payload);\n * return true;\n * });\n *\n * function handleMyCommand(editor: LexicalEditor, payload: CommandPayloadType) {\n * // `payload` is of type `SomeType`, extracted from the command.\n * }\n * ```\n */\n\nfunction resetEditor(editor, prevRootElement, nextRootElement, pendingEditorState) {\n const keyNodeMap = editor._keyToDOMMap;\n keyNodeMap.clear();\n editor._editorState = createEmptyEditorState();\n editor._pendingEditorState = pendingEditorState;\n editor._compositionKey = null;\n editor._dirtyType = NO_DIRTY_NODES;\n editor._cloneNotNeeded.clear();\n editor._dirtyLeaves = new Set();\n editor._dirtyElements.clear();\n editor._normalizedNodes = new Set();\n editor._updateTags = new Set();\n editor._updates = [];\n editor._blockCursorElement = null;\n const observer = editor._observer;\n if (observer !== null) {\n observer.disconnect();\n editor._observer = null;\n }\n\n // Remove all the DOM nodes from the root element\n if (prevRootElement !== null) {\n prevRootElement.textContent = '';\n }\n if (nextRootElement !== null) {\n nextRootElement.textContent = '';\n keyNodeMap.set('root', nextRootElement);\n }\n}\nfunction initializeConversionCache(nodes, additionalConversions) {\n const conversionCache = new Map();\n const handledConversions = new Set();\n const addConversionsToCache = map => {\n Object.keys(map).forEach(key => {\n let currentCache = conversionCache.get(key);\n if (currentCache === undefined) {\n currentCache = [];\n conversionCache.set(key, currentCache);\n }\n currentCache.push(map[key]);\n });\n };\n nodes.forEach(node => {\n const importDOM = node.klass.importDOM;\n if (importDOM == null || handledConversions.has(importDOM)) {\n return;\n }\n handledConversions.add(importDOM);\n const map = importDOM.call(node.klass);\n if (map !== null) {\n addConversionsToCache(map);\n }\n });\n if (additionalConversions) {\n addConversionsToCache(additionalConversions);\n }\n return conversionCache;\n}\n\n/**\n * Creates a new LexicalEditor attached to a single contentEditable (provided in the config). This is\n * the lowest-level initialization API for a LexicalEditor. If you're using React or another framework,\n * consider using the appropriate abstractions, such as LexicalComposer\n * @param editorConfig - the editor configuration.\n * @returns a LexicalEditor instance\n */\nfunction createEditor(editorConfig) {\n const config = editorConfig || {};\n const activeEditor = internalGetActiveEditor();\n const theme = config.theme || {};\n const parentEditor = editorConfig === undefined ? activeEditor : config.parentEditor || null;\n const disableEvents = config.disableEvents || false;\n const editorState = createEmptyEditorState();\n const namespace = config.namespace || (parentEditor !== null ? parentEditor._config.namespace : createUID());\n const initialEditorState = config.editorState;\n const nodes = [RootNode, TextNode, LineBreakNode, TabNode, ParagraphNode, ArtificialNode__DO_NOT_USE, ...(config.nodes || [])];\n const {\n onError,\n html\n } = config;\n const isEditable = config.editable !== undefined ? config.editable : true;\n let registeredNodes;\n if (editorConfig === undefined && activeEditor !== null) {\n registeredNodes = activeEditor._nodes;\n } else {\n registeredNodes = new Map();\n for (let i = 0; i < nodes.length; i++) {\n let klass = nodes[i];\n let replace = null;\n let replaceWithKlass = null;\n if (typeof klass !== 'function') {\n const options = klass;\n klass = options.replace;\n replace = options.with;\n replaceWithKlass = options.withKlass || null;\n }\n // Ensure custom nodes implement required methods and replaceWithKlass is instance of base klass.\n {\n // ArtificialNode__DO_NOT_USE can get renamed, so we use the type\n const nodeType = Object.prototype.hasOwnProperty.call(klass, 'getType') && klass.getType();\n const name = klass.name;\n if (replaceWithKlass) {\n if (!(replaceWithKlass.prototype instanceof klass)) {\n throw Error(`${replaceWithKlass.name} doesn't extend the ${name}`);\n }\n }\n if (name !== 'RootNode' && nodeType !== 'root' && nodeType !== 'artificial') {\n const proto = klass.prototype;\n ['getType', 'clone'].forEach(method => {\n // eslint-disable-next-line no-prototype-builtins\n if (!klass.hasOwnProperty(method)) {\n console.warn(`${name} must implement static \"${method}\" method`);\n }\n });\n if (\n // eslint-disable-next-line no-prototype-builtins\n !klass.hasOwnProperty('importDOM') &&\n // eslint-disable-next-line no-prototype-builtins\n klass.hasOwnProperty('exportDOM')) {\n console.warn(`${name} should implement \"importDOM\" if using a custom \"exportDOM\" method to ensure HTML serialization (important for copy & paste) works as expected`);\n }\n if (proto instanceof DecoratorNode) {\n // eslint-disable-next-line no-prototype-builtins\n if (!proto.hasOwnProperty('decorate')) {\n console.warn(`${proto.constructor.name} must implement \"decorate\" method`);\n }\n }\n if (\n // eslint-disable-next-line no-prototype-builtins\n !klass.hasOwnProperty('importJSON')) {\n console.warn(`${name} should implement \"importJSON\" method to ensure JSON and default HTML serialization works as expected`);\n }\n if (\n // eslint-disable-next-line no-prototype-builtins\n !proto.hasOwnProperty('exportJSON')) {\n console.warn(`${name} should implement \"exportJSON\" method to ensure JSON and default HTML serialization works as expected`);\n }\n }\n }\n const type = klass.getType();\n const transform = klass.transform();\n const transforms = new Set();\n if (transform !== null) {\n transforms.add(transform);\n }\n registeredNodes.set(type, {\n exportDOM: html && html.export ? html.export.get(klass) : undefined,\n klass,\n replace,\n replaceWithKlass,\n transforms\n });\n }\n }\n const editor = new LexicalEditor(editorState, parentEditor, registeredNodes, {\n disableEvents,\n namespace,\n theme\n }, onError ? onError : console.error, initializeConversionCache(registeredNodes, html ? html.import : undefined), isEditable);\n if (initialEditorState !== undefined) {\n editor._pendingEditorState = initialEditorState;\n editor._dirtyType = FULL_RECONCILE;\n }\n return editor;\n}\nclass LexicalEditor {\n /** The version with build identifiers for this editor (since 0.17.1) */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n\n /** @internal */\n constructor(editorState, parentEditor, nodes, config, onError, htmlConversions, editable) {\n this._parentEditor = parentEditor;\n // The root element associated with this editor\n this._rootElement = null;\n // The current editor state\n this._editorState = editorState;\n // Handling of drafts and updates\n this._pendingEditorState = null;\n // Used to help co-ordinate selection and events\n this._compositionKey = null;\n this._deferred = [];\n // Used during reconciliation\n this._keyToDOMMap = new Map();\n this._updates = [];\n this._updating = false;\n // Listeners\n this._listeners = {\n decorator: new Set(),\n editable: new Set(),\n mutation: new Map(),\n root: new Set(),\n textcontent: new Set(),\n update: new Set()\n };\n // Commands\n this._commands = new Map();\n // Editor configuration for theme/context.\n this._config = config;\n // Mapping of types to their nodes\n this._nodes = nodes;\n // React node decorators for portals\n this._decorators = {};\n this._pendingDecorators = null;\n // Used to optimize reconciliation\n this._dirtyType = NO_DIRTY_NODES;\n this._cloneNotNeeded = new Set();\n this._dirtyLeaves = new Set();\n this._dirtyElements = new Map();\n this._normalizedNodes = new Set();\n this._updateTags = new Set();\n // Handling of DOM mutations\n this._observer = null;\n // Used for identifying owning editors\n this._key = createUID();\n this._onError = onError;\n this._htmlConversions = htmlConversions;\n this._editable = editable;\n this._headless = parentEditor !== null && parentEditor._headless;\n this._window = null;\n this._blockCursorElement = null;\n }\n\n /**\n *\n * @returns true if the editor is currently in \"composition\" mode due to receiving input\n * through an IME, or 3P extension, for example. Returns false otherwise.\n */\n isComposing() {\n return this._compositionKey != null;\n }\n /**\n * Registers a listener for Editor update event. Will trigger the provided callback\n * each time the editor goes through an update (via {@link LexicalEditor.update}) until the\n * teardown function is called.\n *\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerUpdateListener(listener) {\n const listenerSetOrMap = this._listeners.update;\n listenerSetOrMap.add(listener);\n return () => {\n listenerSetOrMap.delete(listener);\n };\n }\n /**\n * Registers a listener for for when the editor changes between editable and non-editable states.\n * Will trigger the provided callback each time the editor transitions between these states until the\n * teardown function is called.\n *\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerEditableListener(listener) {\n const listenerSetOrMap = this._listeners.editable;\n listenerSetOrMap.add(listener);\n return () => {\n listenerSetOrMap.delete(listener);\n };\n }\n /**\n * Registers a listener for when the editor's decorator object changes. The decorator object contains\n * all DecoratorNode keys -> their decorated value. This is primarily used with external UI frameworks.\n *\n * Will trigger the provided callback each time the editor transitions between these states until the\n * teardown function is called.\n *\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerDecoratorListener(listener) {\n const listenerSetOrMap = this._listeners.decorator;\n listenerSetOrMap.add(listener);\n return () => {\n listenerSetOrMap.delete(listener);\n };\n }\n /**\n * Registers a listener for when Lexical commits an update to the DOM and the text content of\n * the editor changes from the previous state of the editor. If the text content is the\n * same between updates, no notifications to the listeners will happen.\n *\n * Will trigger the provided callback each time the editor transitions between these states until the\n * teardown function is called.\n *\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerTextContentListener(listener) {\n const listenerSetOrMap = this._listeners.textcontent;\n listenerSetOrMap.add(listener);\n return () => {\n listenerSetOrMap.delete(listener);\n };\n }\n /**\n * Registers a listener for when the editor's root DOM element (the content editable\n * Lexical attaches to) changes. This is primarily used to attach event listeners to the root\n * element. The root listener function is executed directly upon registration and then on\n * any subsequent update.\n *\n * Will trigger the provided callback each time the editor transitions between these states until the\n * teardown function is called.\n *\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerRootListener(listener) {\n const listenerSetOrMap = this._listeners.root;\n listener(this._rootElement, null);\n listenerSetOrMap.add(listener);\n return () => {\n listener(null, this._rootElement);\n listenerSetOrMap.delete(listener);\n };\n }\n /**\n * Registers a listener that will trigger anytime the provided command\n * is dispatched, subject to priority. Listeners that run at a higher priority can \"intercept\"\n * commands and prevent them from propagating to other handlers by returning true.\n *\n * Listeners registered at the same priority level will run deterministically in the order of registration.\n *\n * @param command - the command that will trigger the callback.\n * @param listener - the function that will execute when the command is dispatched.\n * @param priority - the relative priority of the listener. 0 | 1 | 2 | 3 | 4\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerCommand(command, listener, priority) {\n if (priority === undefined) {\n {\n throw Error(`Listener for type \"command\" requires a \"priority\".`);\n }\n }\n const commandsMap = this._commands;\n if (!commandsMap.has(command)) {\n commandsMap.set(command, [new Set(), new Set(), new Set(), new Set(), new Set()]);\n }\n const listenersInPriorityOrder = commandsMap.get(command);\n if (listenersInPriorityOrder === undefined) {\n {\n throw Error(`registerCommand: Command ${String(command)} not found in command map`);\n }\n }\n const listeners = listenersInPriorityOrder[priority];\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n if (listenersInPriorityOrder.every(listenersSet => listenersSet.size === 0)) {\n commandsMap.delete(command);\n }\n };\n }\n\n /**\n * Registers a listener that will run when a Lexical node of the provided class is\n * mutated. The listener will receive a list of nodes along with the type of mutation\n * that was performed on each: created, destroyed, or updated.\n *\n * One common use case for this is to attach DOM event listeners to the underlying DOM nodes as Lexical nodes are created.\n * {@link LexicalEditor.getElementByKey} can be used for this.\n *\n * If any existing nodes are in the DOM, and skipInitialization is not true, the listener\n * will be called immediately with an updateTag of 'registerMutationListener' where all\n * nodes have the 'created' NodeMutation. This can be controlled with the skipInitialization option\n * (default is currently true for backwards compatibility in 0.16.x but will change to false in 0.17.0).\n *\n * @param klass - The class of the node that you want to listen to mutations on.\n * @param listener - The logic you want to run when the node is mutated.\n * @param options - see {@link MutationListenerOptions}\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerMutationListener(klass, listener, options) {\n const klassToMutate = this.resolveRegisteredNodeAfterReplacements(this.getRegisteredNode(klass)).klass;\n const mutations = this._listeners.mutation;\n mutations.set(listener, klassToMutate);\n const skipInitialization = options && options.skipInitialization;\n if (!(skipInitialization === undefined ? DEFAULT_SKIP_INITIALIZATION : skipInitialization)) {\n this.initializeMutationListener(listener, klassToMutate);\n }\n return () => {\n mutations.delete(listener);\n };\n }\n\n /** @internal */\n getRegisteredNode(klass) {\n const registeredNode = this._nodes.get(klass.getType());\n if (registeredNode === undefined) {\n {\n throw Error(`Node ${klass.name} has not been registered. Ensure node has been passed to createEditor.`);\n }\n }\n return registeredNode;\n }\n\n /** @internal */\n resolveRegisteredNodeAfterReplacements(registeredNode) {\n while (registeredNode.replaceWithKlass) {\n registeredNode = this.getRegisteredNode(registeredNode.replaceWithKlass);\n }\n return registeredNode;\n }\n\n /** @internal */\n initializeMutationListener(listener, klass) {\n const prevEditorState = this._editorState;\n const nodeMap = getCachedTypeToNodeMap(prevEditorState).get(klass.getType());\n if (!nodeMap) {\n return;\n }\n const nodeMutationMap = new Map();\n for (const k of nodeMap.keys()) {\n nodeMutationMap.set(k, 'created');\n }\n if (nodeMutationMap.size > 0) {\n listener(nodeMutationMap, {\n dirtyLeaves: new Set(),\n prevEditorState,\n updateTags: new Set(['registerMutationListener'])\n });\n }\n }\n\n /** @internal */\n registerNodeTransformToKlass(klass, listener) {\n const registeredNode = this.getRegisteredNode(klass);\n registeredNode.transforms.add(listener);\n return registeredNode;\n }\n\n /**\n * Registers a listener that will run when a Lexical node of the provided class is\n * marked dirty during an update. The listener will continue to run as long as the node\n * is marked dirty. There are no guarantees around the order of transform execution!\n *\n * Watch out for infinite loops. See [Node Transforms](https://lexical.dev/docs/concepts/transforms)\n * @param klass - The class of the node that you want to run transforms on.\n * @param listener - The logic you want to run when the node is updated.\n * @returns a teardown function that can be used to cleanup the listener.\n */\n registerNodeTransform(klass, listener) {\n const registeredNode = this.registerNodeTransformToKlass(klass, listener);\n const registeredNodes = [registeredNode];\n const replaceWithKlass = registeredNode.replaceWithKlass;\n if (replaceWithKlass != null) {\n const registeredReplaceWithNode = this.registerNodeTransformToKlass(replaceWithKlass, listener);\n registeredNodes.push(registeredReplaceWithNode);\n }\n markAllNodesAsDirty(this, klass.getType());\n return () => {\n registeredNodes.forEach(node => node.transforms.delete(listener));\n };\n }\n\n /**\n * Used to assert that a certain node is registered, usually by plugins to ensure nodes that they\n * depend on have been registered.\n * @returns True if the editor has registered the provided node type, false otherwise.\n */\n hasNode(node) {\n return this._nodes.has(node.getType());\n }\n\n /**\n * Used to assert that certain nodes are registered, usually by plugins to ensure nodes that they\n * depend on have been registered.\n * @returns True if the editor has registered all of the provided node types, false otherwise.\n */\n hasNodes(nodes) {\n return nodes.every(this.hasNode.bind(this));\n }\n\n /**\n * Dispatches a command of the specified type with the specified payload.\n * This triggers all command listeners (set by {@link LexicalEditor.registerCommand})\n * for this type, passing them the provided payload.\n * @param type - the type of command listeners to trigger.\n * @param payload - the data to pass as an argument to the command listeners.\n */\n dispatchCommand(type, payload) {\n return dispatchCommand(this, type, payload);\n }\n\n /**\n * Gets a map of all decorators in the editor.\n * @returns A mapping of call decorator keys to their decorated content\n */\n getDecorators() {\n return this._decorators;\n }\n\n /**\n *\n * @returns the current root element of the editor. If you want to register\n * an event listener, do it via {@link LexicalEditor.registerRootListener}, since\n * this reference may not be stable.\n */\n getRootElement() {\n return this._rootElement;\n }\n\n /**\n * Gets the key of the editor\n * @returns The editor key\n */\n getKey() {\n return this._key;\n }\n\n /**\n * Imperatively set the root contenteditable element that Lexical listens\n * for events on.\n */\n setRootElement(nextRootElement) {\n const prevRootElement = this._rootElement;\n if (nextRootElement !== prevRootElement) {\n const classNames = getCachedClassNameArray(this._config.theme, 'root');\n const pendingEditorState = this._pendingEditorState || this._editorState;\n this._rootElement = nextRootElement;\n resetEditor(this, prevRootElement, nextRootElement, pendingEditorState);\n if (prevRootElement !== null) {\n // TODO: remove this flag once we no longer use UEv2 internally\n if (!this._config.disableEvents) {\n removeRootElementEvents(prevRootElement);\n }\n if (classNames != null) {\n prevRootElement.classList.remove(...classNames);\n }\n }\n if (nextRootElement !== null) {\n const windowObj = getDefaultView(nextRootElement);\n const style = nextRootElement.style;\n style.userSelect = 'text';\n style.whiteSpace = 'pre-wrap';\n style.wordBreak = 'break-word';\n nextRootElement.setAttribute('data-lexical-editor', 'true');\n this._window = windowObj;\n this._dirtyType = FULL_RECONCILE;\n initMutationObserver(this);\n this._updateTags.add('history-merge');\n $commitPendingUpdates(this);\n\n // TODO: remove this flag once we no longer use UEv2 internally\n if (!this._config.disableEvents) {\n addRootElementEvents(nextRootElement, this);\n }\n if (classNames != null) {\n nextRootElement.classList.add(...classNames);\n }\n } else {\n // If content editable is unmounted we'll reset editor state back to original\n // (or pending) editor state since there will be no reconciliation\n this._editorState = pendingEditorState;\n this._pendingEditorState = null;\n this._window = null;\n }\n triggerListeners('root', this, false, nextRootElement, prevRootElement);\n }\n }\n\n /**\n * Gets the underlying HTMLElement associated with the LexicalNode for the given key.\n * @returns the HTMLElement rendered by the LexicalNode associated with the key.\n * @param key - the key of the LexicalNode.\n */\n getElementByKey(key) {\n return this._keyToDOMMap.get(key) || null;\n }\n\n /**\n * Gets the active editor state.\n * @returns The editor state\n */\n getEditorState() {\n return this._editorState;\n }\n\n /**\n * Imperatively set the EditorState. Triggers reconciliation like an update.\n * @param editorState - the state to set the editor\n * @param options - options for the update.\n */\n setEditorState(editorState, options) {\n if (editorState.isEmpty()) {\n {\n throw Error(`setEditorState: the editor state is empty. Ensure the editor state's root node never becomes empty.`);\n }\n }\n $flushRootMutations(this);\n const pendingEditorState = this._pendingEditorState;\n const tags = this._updateTags;\n const tag = options !== undefined ? options.tag : null;\n if (pendingEditorState !== null && !pendingEditorState.isEmpty()) {\n if (tag != null) {\n tags.add(tag);\n }\n $commitPendingUpdates(this);\n }\n this._pendingEditorState = editorState;\n this._dirtyType = FULL_RECONCILE;\n this._dirtyElements.set('root', false);\n this._compositionKey = null;\n if (tag != null) {\n tags.add(tag);\n }\n $commitPendingUpdates(this);\n }\n\n /**\n * Parses a SerializedEditorState (usually produced by {@link EditorState.toJSON}) and returns\n * and EditorState object that can be, for example, passed to {@link LexicalEditor.setEditorState}. Typically,\n * deserialization from JSON stored in a database uses this method.\n * @param maybeStringifiedEditorState\n * @param updateFn\n * @returns\n */\n parseEditorState(maybeStringifiedEditorState, updateFn) {\n const serializedEditorState = typeof maybeStringifiedEditorState === 'string' ? JSON.parse(maybeStringifiedEditorState) : maybeStringifiedEditorState;\n return parseEditorState(serializedEditorState, this, updateFn);\n }\n\n /**\n * Executes a read of the editor's state, with the\n * editor context available (useful for exporting and read-only DOM\n * operations). Much like update, but prevents any mutation of the\n * editor's state. Any pending updates will be flushed immediately before\n * the read.\n * @param callbackFn - A function that has access to read-only editor state.\n */\n read(callbackFn) {\n $commitPendingUpdates(this);\n return this.getEditorState().read(callbackFn, {\n editor: this\n });\n }\n\n /**\n * Executes an update to the editor state. The updateFn callback is the ONLY place\n * where Lexical editor state can be safely mutated.\n * @param updateFn - A function that has access to writable editor state.\n * @param options - A bag of options to control the behavior of the update.\n * @param options.onUpdate - A function to run once the update is complete.\n * Useful for synchronizing updates in some cases.\n * @param options.skipTransforms - Setting this to true will suppress all node\n * transforms for this update cycle.\n * @param options.tag - A tag to identify this update, in an update listener, for instance.\n * Some tags are reserved by the core and control update behavior in different ways.\n * @param options.discrete - If true, prevents this update from being batched, forcing it to\n * run synchronously.\n */\n update(updateFn, options) {\n updateEditor(this, updateFn, options);\n }\n\n /**\n * Focuses the editor\n * @param callbackFn - A function to run after the editor is focused.\n * @param options - A bag of options\n * @param options.defaultSelection - Where to move selection when the editor is\n * focused. Can be rootStart, rootEnd, or undefined. Defaults to rootEnd.\n */\n focus(callbackFn, options = {}) {\n const rootElement = this._rootElement;\n if (rootElement !== null) {\n // This ensures that iOS does not trigger caps lock upon focus\n rootElement.setAttribute('autocapitalize', 'off');\n updateEditor(this, () => {\n const selection = $getSelection();\n const root = $getRoot();\n if (selection !== null) {\n // Marking the selection dirty will force the selection back to it\n selection.dirty = true;\n } else if (root.getChildrenSize() !== 0) {\n if (options.defaultSelection === 'rootStart') {\n root.selectStart();\n } else {\n root.selectEnd();\n }\n }\n }, {\n onUpdate: () => {\n rootElement.removeAttribute('autocapitalize');\n if (callbackFn) {\n callbackFn();\n }\n },\n tag: 'focus'\n });\n // In the case where onUpdate doesn't fire (due to the focus update not\n // occuring).\n if (this._pendingEditorState === null) {\n rootElement.removeAttribute('autocapitalize');\n }\n }\n }\n\n /**\n * Removes focus from the editor.\n */\n blur() {\n const rootElement = this._rootElement;\n if (rootElement !== null) {\n rootElement.blur();\n }\n const domSelection = getDOMSelection(this._window);\n if (domSelection !== null) {\n domSelection.removeAllRanges();\n }\n }\n /**\n * Returns true if the editor is editable, false otherwise.\n * @returns True if the editor is editable, false otherwise.\n */\n isEditable() {\n return this._editable;\n }\n /**\n * Sets the editable property of the editor. When false, the\n * editor will not listen for user events on the underling contenteditable.\n * @param editable - the value to set the editable mode to.\n */\n setEditable(editable) {\n if (this._editable !== editable) {\n this._editable = editable;\n triggerListeners('editable', this, true, editable);\n }\n }\n /**\n * Returns a JSON-serializable javascript object NOT a JSON string.\n * You still must call JSON.stringify (or something else) to turn the\n * state into a string you can transfer over the wire and store in a database.\n *\n * See {@link LexicalNode.exportJSON}\n *\n * @returns A JSON-serializable javascript object\n */\n toJSON() {\n return {\n editorState: this._editorState.toJSON()\n };\n }\n}\nLexicalEditor.version = \"0.17.1+dev.esm\";\n\nexport { $addUpdateTag, $applyNodeReplacement, $cloneWithProperties, $copyNode, $createLineBreakNode, $createNodeSelection, $createParagraphNode, $createPoint, $createRangeSelection, $createRangeSelectionFromDom, $createTabNode, $createTextNode, $getAdjacentNode, $getCharacterOffsets, $getEditor, $getNearestNodeFromDOMNode, $getNearestRootOrShadowRoot, $getNodeByKey, $getNodeByKeyOrThrow, $getPreviousSelection, $getRoot, $getSelection, $getTextContent, $hasAncestor, $hasUpdateTag, $insertNodes, $isBlockElementNode, $isDecoratorNode, $isElementNode, $isInlineElementOrDecoratorNode, $isLeafNode, $isLineBreakNode, $isNodeSelection, $isParagraphNode, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isTabNode, $isTextNode, $isTokenOrSegmented, $nodesOfType, $normalizeSelection as $normalizeSelection__EXPERIMENTAL, $parseSerializedNode, $selectAll, $setCompositionKey, $setSelection, $splitNode, ArtificialNode__DO_NOT_USE, BLUR_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, CLEAR_EDITOR_COMMAND, CLEAR_HISTORY_COMMAND, CLICK_COMMAND, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_NORMAL, CONTROLLED_TEXT_INSERTION_COMMAND, COPY_COMMAND, CUT_COMMAND, DELETE_CHARACTER_COMMAND, DELETE_LINE_COMMAND, DELETE_WORD_COMMAND, DRAGEND_COMMAND, DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, DecoratorNode, ElementNode, FOCUS_COMMAND, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, INDENT_CONTENT_COMMAND, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND, INSERT_TAB_COMMAND, IS_ALL_FORMATTING, IS_BOLD, IS_CODE, IS_HIGHLIGHT, IS_ITALIC, IS_STRIKETHROUGH, IS_SUBSCRIPT, IS_SUPERSCRIPT, IS_UNDERLINE, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, KEY_MODIFIER_COMMAND, KEY_SPACE_COMMAND, KEY_TAB_COMMAND, LineBreakNode, MOVE_TO_END, MOVE_TO_START, OUTDENT_CONTENT_COMMAND, PASTE_COMMAND, ParagraphNode, REDO_COMMAND, REMOVE_TEXT_COMMAND, RootNode, SELECTION_CHANGE_COMMAND, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, SELECT_ALL_COMMAND, TEXT_TYPE_TO_FORMAT, TabNode, TextNode, UNDO_COMMAND, createCommand, createEditor, getEditorPropertyFromDOMNode, getNearestEditorFromDOMNode, isBlockDomNode, isCurrentlyReadOnlyMode, isHTMLAnchorElement, isHTMLElement, isInlineDomNode, isLexicalEditor, isSelectionCapturedInDecoratorInput, isSelectionWithinEditor, resetRandomKey };\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.js';\nimport { mergeClasses } from './shared/src/utils.js';\n\nconst Icon = forwardRef(\n ({\n color = \"currentColor\",\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = \"\",\n children,\n iconNode,\n ...rest\n }, ref) => {\n return createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n className: mergeClasses(\"lucide\", className),\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n );\n }\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses, toKebabCase } from './shared/src/utils.js';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className),\n ...props\n })\n );\n Component.displayName = `${iconName}`;\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Check = createLucideIcon(\"Check\", [[\"path\", { d: \"M20 6 9 17l-5-5\", key: \"1gmf2c\" }]]);\n\nexport { Check as default };\n//# sourceMappingURL=check.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronDown = createLucideIcon(\"ChevronDown\", [\n [\"path\", { d: \"m6 9 6 6 6-6\", key: \"qrunsl\" }]\n]);\n\nexport { ChevronDown as default };\n//# sourceMappingURL=chevron-down.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronRight = createLucideIcon(\"ChevronRight\", [\n [\"path\", { d: \"m9 18 6-6-6-6\", key: \"mthhwq\" }]\n]);\n\nexport { ChevronRight as default };\n//# sourceMappingURL=chevron-right.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronsUpDown = createLucideIcon(\"ChevronsUpDown\", [\n [\"path\", { d: \"m7 15 5 5 5-5\", key: \"1hf1tw\" }],\n [\"path\", { d: \"m7 9 5-5 5 5\", key: \"sgt6xg\" }]\n]);\n\nexport { ChevronsUpDown as default };\n//# sourceMappingURL=chevrons-up-down.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Ellipsis = createLucideIcon(\"Ellipsis\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"1\", key: \"41hilf\" }],\n [\"circle\", { cx: \"19\", cy: \"12\", r: \"1\", key: \"1wjl8i\" }],\n [\"circle\", { cx: \"5\", cy: \"12\", r: \"1\", key: \"1pcz8c\" }]\n]);\n\nexport { Ellipsis as default };\n//# sourceMappingURL=ellipsis.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Info = createLucideIcon(\"Info\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"M12 16v-4\", key: \"1dtifu\" }],\n [\"path\", { d: \"M12 8h.01\", key: \"e9boi3\" }]\n]);\n\nexport { Info as default };\n//# sourceMappingURL=info.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst LoaderCircle = createLucideIcon(\"LoaderCircle\", [\n [\"path\", { d: \"M21 12a9 9 0 1 1-6.219-8.56\", key: \"13zald\" }]\n]);\n\nexport { LoaderCircle as default };\n//# sourceMappingURL=loader-circle.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Minus = createLucideIcon(\"Minus\", [[\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }]]);\n\nexport { Minus as default };\n//# sourceMappingURL=minus.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst PanelLeftClose = createLucideIcon(\"PanelLeftClose\", [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M9 3v18\", key: \"fh3hqa\" }],\n [\"path\", { d: \"m16 15-3-3 3-3\", key: \"14y99z\" }]\n]);\n\nexport { PanelLeftClose as default };\n//# sourceMappingURL=panel-left-close.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst PanelLeftOpen = createLucideIcon(\"PanelLeftOpen\", [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M9 3v18\", key: \"fh3hqa\" }],\n [\"path\", { d: \"m14 9 3 3-3 3\", key: \"8010ee\" }]\n]);\n\nexport { PanelLeftOpen as default };\n//# sourceMappingURL=panel-left-open.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Plus = createLucideIcon(\"Plus\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n]);\n\nexport { Plus as default };\n//# sourceMappingURL=plus.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Search = createLucideIcon(\"Search\", [\n [\"circle\", { cx: \"11\", cy: \"11\", r: \"8\", key: \"4ej97u\" }],\n [\"path\", { d: \"m21 21-4.3-4.3\", key: \"1qie3q\" }]\n]);\n\nexport { Search as default };\n//# sourceMappingURL=search.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Trash2 = createLucideIcon(\"Trash2\", [\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\", key: \"4alrt4\" }],\n [\"path\", { d: \"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\", key: \"v07s0e\" }],\n [\"line\", { x1: \"10\", x2: \"10\", y1: \"11\", y2: \"17\", key: \"1uufr5\" }],\n [\"line\", { x1: \"14\", x2: \"14\", y1: \"11\", y2: \"17\", key: \"xtxkd\" }]\n]);\n\nexport { Trash2 as default };\n//# sourceMappingURL=trash-2.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst TriangleAlert = createLucideIcon(\"TriangleAlert\", [\n [\n \"path\",\n {\n d: \"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\",\n key: \"wmoenq\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n]);\n\nexport { TriangleAlert as default };\n//# sourceMappingURL=triangle-alert.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Upload = createLucideIcon(\"Upload\", [\n [\"path\", { d: \"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\", key: \"ih7n3h\" }],\n [\"polyline\", { points: \"17 8 12 3 7 8\", key: \"t8dd8p\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"3\", y2: \"15\", key: \"widbto\" }]\n]);\n\nexport { Upload as default };\n//# sourceMappingURL=upload.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst X = createLucideIcon(\"X\", [\n [\"path\", { d: \"M18 6 6 18\", key: \"1bl5f8\" }],\n [\"path\", { d: \"m6 6 12 12\", key: \"d8bk6v\" }]\n]);\n\nexport { X as default };\n//# sourceMappingURL=x.js.map\n","/**\n * @license lucide-react v0.417.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && array.indexOf(className) === index;\n}).join(\" \");\n\nexport { mergeClasses, toKebabCase };\n//# sourceMappingURL=utils.js.map\n","// extracted by mini-css-extract-plugin\nexport {};","/**\n * @license React\n * react-jsx-runtime.development.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nif (process.env.NODE_ENV !== \"production\") {\n (function() {\n'use strict';\n\nvar React = require('react');\n\n// ATTENTION\n// When adding new symbols to this file,\n// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'\n// The Symbol used to tag the ReactElement-like types.\nvar REACT_ELEMENT_TYPE = Symbol.for('react.element');\nvar REACT_PORTAL_TYPE = Symbol.for('react.portal');\nvar REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');\nvar REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');\nvar REACT_PROFILER_TYPE = Symbol.for('react.profiler');\nvar REACT_PROVIDER_TYPE = Symbol.for('react.provider');\nvar REACT_CONTEXT_TYPE = Symbol.for('react.context');\nvar REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');\nvar REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');\nvar REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');\nvar REACT_MEMO_TYPE = Symbol.for('react.memo');\nvar REACT_LAZY_TYPE = Symbol.for('react.lazy');\nvar REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');\nvar MAYBE_ITERATOR_SYMBOL = Symbol.iterator;\nvar FAUX_ITERATOR_SYMBOL = '@@iterator';\nfunction getIteratorFn(maybeIterable) {\n if (maybeIterable === null || typeof maybeIterable !== 'object') {\n return null;\n }\n\n var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];\n\n if (typeof maybeIterator === 'function') {\n return maybeIterator;\n }\n\n return null;\n}\n\nvar ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n\nfunction error(format) {\n {\n {\n for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n args[_key2 - 1] = arguments[_key2];\n }\n\n printWarning('error', format, args);\n }\n }\n}\n\nfunction printWarning(level, format, args) {\n // When changing this logic, you might want to also\n // update consoleWithStackDev.www.js as well.\n {\n var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;\n var stack = ReactDebugCurrentFrame.getStackAddendum();\n\n if (stack !== '') {\n format += '%s';\n args = args.concat([stack]);\n } // eslint-disable-next-line react-internal/safe-string-coercion\n\n\n var argsWithFormat = args.map(function (item) {\n return String(item);\n }); // Careful: RN currently depends on this prefix\n\n argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it\n // breaks IE9: https://github.com/facebook/react/issues/13610\n // eslint-disable-next-line react-internal/no-production-logging\n\n Function.prototype.apply.call(console[level], console, argsWithFormat);\n }\n}\n\n// -----------------------------------------------------------------------------\n\nvar enableScopeAPI = false; // Experimental Create Event Handle API.\nvar enableCacheElement = false;\nvar enableTransitionTracing = false; // No known bugs, but needs performance testing\n\nvar enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber\n// stuff. Intended to enable React core members to more easily debug scheduling\n// issues in DEV builds.\n\nvar enableDebugTracing = false; // Track which Fiber(s) schedule render work.\n\nvar REACT_MODULE_REFERENCE;\n\n{\n REACT_MODULE_REFERENCE = Symbol.for('react.module.reference');\n}\n\nfunction isValidElementType(type) {\n if (typeof type === 'string' || typeof type === 'function') {\n return true;\n } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).\n\n\n if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableCacheElement || enableTransitionTracing ) {\n return true;\n }\n\n if (typeof type === 'object' && type !== null) {\n if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object\n // types supported by any Flight configuration anywhere since\n // we don't know which Flight build this will end up being used\n // with.\n type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== undefined) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction getWrappedName(outerType, innerType, wrapperName) {\n var displayName = outerType.displayName;\n\n if (displayName) {\n return displayName;\n }\n\n var functionName = innerType.displayName || innerType.name || '';\n return functionName !== '' ? wrapperName + \"(\" + functionName + \")\" : wrapperName;\n} // Keep in sync with react-reconciler/getComponentNameFromFiber\n\n\nfunction getContextName(type) {\n return type.displayName || 'Context';\n} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.\n\n\nfunction getComponentNameFromType(type) {\n if (type == null) {\n // Host root, text node or just invalid type.\n return null;\n }\n\n {\n if (typeof type.tag === 'number') {\n error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.');\n }\n }\n\n if (typeof type === 'function') {\n return type.displayName || type.name || null;\n }\n\n if (typeof type === 'string') {\n return type;\n }\n\n switch (type) {\n case REACT_FRAGMENT_TYPE:\n return 'Fragment';\n\n case REACT_PORTAL_TYPE:\n return 'Portal';\n\n case REACT_PROFILER_TYPE:\n return 'Profiler';\n\n case REACT_STRICT_MODE_TYPE:\n return 'StrictMode';\n\n case REACT_SUSPENSE_TYPE:\n return 'Suspense';\n\n case REACT_SUSPENSE_LIST_TYPE:\n return 'SuspenseList';\n\n }\n\n if (typeof type === 'object') {\n switch (type.$$typeof) {\n case REACT_CONTEXT_TYPE:\n var context = type;\n return getContextName(context) + '.Consumer';\n\n case REACT_PROVIDER_TYPE:\n var provider = type;\n return getContextName(provider._context) + '.Provider';\n\n case REACT_FORWARD_REF_TYPE:\n return getWrappedName(type, type.render, 'ForwardRef');\n\n case REACT_MEMO_TYPE:\n var outerName = type.displayName || null;\n\n if (outerName !== null) {\n return outerName;\n }\n\n return getComponentNameFromType(type.type) || 'Memo';\n\n case REACT_LAZY_TYPE:\n {\n var lazyComponent = type;\n var payload = lazyComponent._payload;\n var init = lazyComponent._init;\n\n try {\n return getComponentNameFromType(init(payload));\n } catch (x) {\n return null;\n }\n }\n\n // eslint-disable-next-line no-fallthrough\n }\n }\n\n return null;\n}\n\nvar assign = Object.assign;\n\n// Helpers to patch console.logs to avoid logging during side-effect free\n// replaying on render function. This currently only patches the object\n// lazily which won't cover if the log function was extracted eagerly.\n// We could also eagerly patch the method.\nvar disabledDepth = 0;\nvar prevLog;\nvar prevInfo;\nvar prevWarn;\nvar prevError;\nvar prevGroup;\nvar prevGroupCollapsed;\nvar prevGroupEnd;\n\nfunction disabledLog() {}\n\ndisabledLog.__reactDisabledLog = true;\nfunction disableLogs() {\n {\n if (disabledDepth === 0) {\n /* eslint-disable react-internal/no-production-logging */\n prevLog = console.log;\n prevInfo = console.info;\n prevWarn = console.warn;\n prevError = console.error;\n prevGroup = console.group;\n prevGroupCollapsed = console.groupCollapsed;\n prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099\n\n var props = {\n configurable: true,\n enumerable: true,\n value: disabledLog,\n writable: true\n }; // $FlowFixMe Flow thinks console is immutable.\n\n Object.defineProperties(console, {\n info: props,\n log: props,\n warn: props,\n error: props,\n group: props,\n groupCollapsed: props,\n groupEnd: props\n });\n /* eslint-enable react-internal/no-production-logging */\n }\n\n disabledDepth++;\n }\n}\nfunction reenableLogs() {\n {\n disabledDepth--;\n\n if (disabledDepth === 0) {\n /* eslint-disable react-internal/no-production-logging */\n var props = {\n configurable: true,\n enumerable: true,\n writable: true\n }; // $FlowFixMe Flow thinks console is immutable.\n\n Object.defineProperties(console, {\n log: assign({}, props, {\n value: prevLog\n }),\n info: assign({}, props, {\n value: prevInfo\n }),\n warn: assign({}, props, {\n value: prevWarn\n }),\n error: assign({}, props, {\n value: prevError\n }),\n group: assign({}, props, {\n value: prevGroup\n }),\n groupCollapsed: assign({}, props, {\n value: prevGroupCollapsed\n }),\n groupEnd: assign({}, props, {\n value: prevGroupEnd\n })\n });\n /* eslint-enable react-internal/no-production-logging */\n }\n\n if (disabledDepth < 0) {\n error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.');\n }\n }\n}\n\nvar ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;\nvar prefix;\nfunction describeBuiltInComponentFrame(name, source, ownerFn) {\n {\n if (prefix === undefined) {\n // Extract the VM specific prefix used by each line.\n try {\n throw Error();\n } catch (x) {\n var match = x.stack.trim().match(/\\n( *(at )?)/);\n prefix = match && match[1] || '';\n }\n } // We use the prefix to ensure our stacks line up with native stack frames.\n\n\n return '\\n' + prefix + name;\n }\n}\nvar reentry = false;\nvar componentFrameCache;\n\n{\n var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;\n componentFrameCache = new PossiblyWeakMap();\n}\n\nfunction describeNativeComponentFrame(fn, construct) {\n // If something asked for a stack inside a fake render, it should get ignored.\n if ( !fn || reentry) {\n return '';\n }\n\n {\n var frame = componentFrameCache.get(fn);\n\n if (frame !== undefined) {\n return frame;\n }\n }\n\n var control;\n reentry = true;\n var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined.\n\n Error.prepareStackTrace = undefined;\n var previousDispatcher;\n\n {\n previousDispatcher = ReactCurrentDispatcher.current; // Set the dispatcher in DEV because this might be call in the render function\n // for warnings.\n\n ReactCurrentDispatcher.current = null;\n disableLogs();\n }\n\n try {\n // This should throw.\n if (construct) {\n // Something should be setting the props in the constructor.\n var Fake = function () {\n throw Error();\n }; // $FlowFixMe\n\n\n Object.defineProperty(Fake.prototype, 'props', {\n set: function () {\n // We use a throwing setter instead of frozen or non-writable props\n // because that won't throw in a non-strict mode function.\n throw Error();\n }\n });\n\n if (typeof Reflect === 'object' && Reflect.construct) {\n // We construct a different control for this case to include any extra\n // frames added by the construct call.\n try {\n Reflect.construct(Fake, []);\n } catch (x) {\n control = x;\n }\n\n Reflect.construct(fn, [], Fake);\n } else {\n try {\n Fake.call();\n } catch (x) {\n control = x;\n }\n\n fn.call(Fake.prototype);\n }\n } else {\n try {\n throw Error();\n } catch (x) {\n control = x;\n }\n\n fn();\n }\n } catch (sample) {\n // This is inlined manually because closure doesn't do it for us.\n if (sample && control && typeof sample.stack === 'string') {\n // This extracts the first frame from the sample that isn't also in the control.\n // Skipping one frame that we assume is the frame that calls the two.\n var sampleLines = sample.stack.split('\\n');\n var controlLines = control.stack.split('\\n');\n var s = sampleLines.length - 1;\n var c = controlLines.length - 1;\n\n while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) {\n // We expect at least one stack frame to be shared.\n // Typically this will be the root most one. However, stack frames may be\n // cut off due to maximum stack limits. In this case, one maybe cut off\n // earlier than the other. We assume that the sample is longer or the same\n // and there for cut off earlier. So we should find the root most frame in\n // the sample somewhere in the control.\n c--;\n }\n\n for (; s >= 1 && c >= 0; s--, c--) {\n // Next we find the first one that isn't the same which should be the\n // frame that called our sample function and the control.\n if (sampleLines[s] !== controlLines[c]) {\n // In V8, the first line is describing the message but other VMs don't.\n // If we're about to return the first line, and the control is also on the same\n // line, that's a pretty good indicator that our sample threw at same line as\n // the control. I.e. before we entered the sample frame. So we ignore this result.\n // This can happen if you passed a class to function component, or non-function.\n if (s !== 1 || c !== 1) {\n do {\n s--;\n c--; // We may still have similar intermediate frames from the construct call.\n // The next one that isn't the same should be our match though.\n\n if (c < 0 || sampleLines[s] !== controlLines[c]) {\n // V8 adds a \"new\" prefix for native classes. Let's remove it to make it prettier.\n var _frame = '\\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled \"\"\n // but we have a user-provided \"displayName\"\n // splice it in to make the stack more readable.\n\n\n if (fn.displayName && _frame.includes('')) {\n _frame = _frame.replace('', fn.displayName);\n }\n\n {\n if (typeof fn === 'function') {\n componentFrameCache.set(fn, _frame);\n }\n } // Return the line we found.\n\n\n return _frame;\n }\n } while (s >= 1 && c >= 0);\n }\n\n break;\n }\n }\n }\n } finally {\n reentry = false;\n\n {\n ReactCurrentDispatcher.current = previousDispatcher;\n reenableLogs();\n }\n\n Error.prepareStackTrace = previousPrepareStackTrace;\n } // Fallback to just using the name if we couldn't make it throw.\n\n\n var name = fn ? fn.displayName || fn.name : '';\n var syntheticFrame = name ? describeBuiltInComponentFrame(name) : '';\n\n {\n if (typeof fn === 'function') {\n componentFrameCache.set(fn, syntheticFrame);\n }\n }\n\n return syntheticFrame;\n}\nfunction describeFunctionComponentFrame(fn, source, ownerFn) {\n {\n return describeNativeComponentFrame(fn, false);\n }\n}\n\nfunction shouldConstruct(Component) {\n var prototype = Component.prototype;\n return !!(prototype && prototype.isReactComponent);\n}\n\nfunction describeUnknownElementTypeFrameInDEV(type, source, ownerFn) {\n\n if (type == null) {\n return '';\n }\n\n if (typeof type === 'function') {\n {\n return describeNativeComponentFrame(type, shouldConstruct(type));\n }\n }\n\n if (typeof type === 'string') {\n return describeBuiltInComponentFrame(type);\n }\n\n switch (type) {\n case REACT_SUSPENSE_TYPE:\n return describeBuiltInComponentFrame('Suspense');\n\n case REACT_SUSPENSE_LIST_TYPE:\n return describeBuiltInComponentFrame('SuspenseList');\n }\n\n if (typeof type === 'object') {\n switch (type.$$typeof) {\n case REACT_FORWARD_REF_TYPE:\n return describeFunctionComponentFrame(type.render);\n\n case REACT_MEMO_TYPE:\n // Memo may contain any component type so we recursively resolve it.\n return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn);\n\n case REACT_LAZY_TYPE:\n {\n var lazyComponent = type;\n var payload = lazyComponent._payload;\n var init = lazyComponent._init;\n\n try {\n // Lazy may contain any component type so we recursively resolve it.\n return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn);\n } catch (x) {}\n }\n }\n }\n\n return '';\n}\n\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n\nvar loggedTypeFailures = {};\nvar ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;\n\nfunction setCurrentlyValidatingElement(element) {\n {\n if (element) {\n var owner = element._owner;\n var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);\n ReactDebugCurrentFrame.setExtraStackFrame(stack);\n } else {\n ReactDebugCurrentFrame.setExtraStackFrame(null);\n }\n }\n}\n\nfunction checkPropTypes(typeSpecs, values, location, componentName, element) {\n {\n // $FlowFixMe This is okay but Flow doesn't know it.\n var has = Function.call.bind(hasOwnProperty);\n\n for (var typeSpecName in typeSpecs) {\n if (has(typeSpecs, typeSpecName)) {\n var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to\n // fail the render phase where it didn't fail before. So we log it.\n // After these have been cleaned up, we'll let them throw.\n\n try {\n // This is intentionally an invariant that gets caught. It's the same\n // behavior as without this statement except with a better message.\n if (typeof typeSpecs[typeSpecName] !== 'function') {\n // eslint-disable-next-line react-internal/prod-error-codes\n var err = Error((componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.');\n err.name = 'Invariant Violation';\n throw err;\n }\n\n error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED');\n } catch (ex) {\n error$1 = ex;\n }\n\n if (error$1 && !(error$1 instanceof Error)) {\n setCurrentlyValidatingElement(element);\n\n error('%s: type specification of %s' + ' `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error$1);\n\n setCurrentlyValidatingElement(null);\n }\n\n if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) {\n // Only monitor this failure once because there tends to be a lot of the\n // same error.\n loggedTypeFailures[error$1.message] = true;\n setCurrentlyValidatingElement(element);\n\n error('Failed %s type: %s', location, error$1.message);\n\n setCurrentlyValidatingElement(null);\n }\n }\n }\n }\n}\n\nvar isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare\n\nfunction isArray(a) {\n return isArrayImpl(a);\n}\n\n/*\n * The `'' + value` pattern (used in in perf-sensitive code) throws for Symbol\n * and Temporal.* types. See https://github.com/facebook/react/pull/22064.\n *\n * The functions in this module will throw an easier-to-understand,\n * easier-to-debug exception with a clear errors message message explaining the\n * problem. (Instead of a confusing exception thrown inside the implementation\n * of the `value` object).\n */\n// $FlowFixMe only called in DEV, so void return is not possible.\nfunction typeName(value) {\n {\n // toStringTag is needed for namespaced types like Temporal.Instant\n var hasToStringTag = typeof Symbol === 'function' && Symbol.toStringTag;\n var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || 'Object';\n return type;\n }\n} // $FlowFixMe only called in DEV, so void return is not possible.\n\n\nfunction willCoercionThrow(value) {\n {\n try {\n testStringCoercion(value);\n return false;\n } catch (e) {\n return true;\n }\n }\n}\n\nfunction testStringCoercion(value) {\n // If you ended up here by following an exception call stack, here's what's\n // happened: you supplied an object or symbol value to React (as a prop, key,\n // DOM attribute, CSS property, string ref, etc.) and when React tried to\n // coerce it to a string using `'' + value`, an exception was thrown.\n //\n // The most common types that will cause this exception are `Symbol` instances\n // and Temporal objects like `Temporal.Instant`. But any object that has a\n // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this\n // exception. (Library authors do this to prevent users from using built-in\n // numeric operators like `+` or comparison operators like `>=` because custom\n // methods are needed to perform accurate arithmetic or comparison.)\n //\n // To fix the problem, coerce this object or symbol value to a string before\n // passing it to React. The most reliable way is usually `String(value)`.\n //\n // To find which value is throwing, check the browser or debugger console.\n // Before this exception was thrown, there should be `console.error` output\n // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the\n // problem and how that type was used: key, atrribute, input value prop, etc.\n // In most cases, this console output also shows the component and its\n // ancestor components where the exception happened.\n //\n // eslint-disable-next-line react-internal/safe-string-coercion\n return '' + value;\n}\nfunction checkKeyStringCoercion(value) {\n {\n if (willCoercionThrow(value)) {\n error('The provided key is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', typeName(value));\n\n return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n }\n }\n}\n\nvar ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;\nvar RESERVED_PROPS = {\n key: true,\n ref: true,\n __self: true,\n __source: true\n};\nvar specialPropKeyWarningShown;\nvar specialPropRefWarningShown;\nvar didWarnAboutStringRefs;\n\n{\n didWarnAboutStringRefs = {};\n}\n\nfunction hasValidRef(config) {\n {\n if (hasOwnProperty.call(config, 'ref')) {\n var getter = Object.getOwnPropertyDescriptor(config, 'ref').get;\n\n if (getter && getter.isReactWarning) {\n return false;\n }\n }\n }\n\n return config.ref !== undefined;\n}\n\nfunction hasValidKey(config) {\n {\n if (hasOwnProperty.call(config, 'key')) {\n var getter = Object.getOwnPropertyDescriptor(config, 'key').get;\n\n if (getter && getter.isReactWarning) {\n return false;\n }\n }\n }\n\n return config.key !== undefined;\n}\n\nfunction warnIfStringRefCannotBeAutoConverted(config, self) {\n {\n if (typeof config.ref === 'string' && ReactCurrentOwner.current && self && ReactCurrentOwner.current.stateNode !== self) {\n var componentName = getComponentNameFromType(ReactCurrentOwner.current.type);\n\n if (!didWarnAboutStringRefs[componentName]) {\n error('Component \"%s\" contains the string ref \"%s\". ' + 'Support for string refs will be removed in a future major release. ' + 'This case cannot be automatically converted to an arrow function. ' + 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-string-ref', getComponentNameFromType(ReactCurrentOwner.current.type), config.ref);\n\n didWarnAboutStringRefs[componentName] = true;\n }\n }\n }\n}\n\nfunction defineKeyPropWarningGetter(props, displayName) {\n {\n var warnAboutAccessingKey = function () {\n if (!specialPropKeyWarningShown) {\n specialPropKeyWarningShown = true;\n\n error('%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://reactjs.org/link/special-props)', displayName);\n }\n };\n\n warnAboutAccessingKey.isReactWarning = true;\n Object.defineProperty(props, 'key', {\n get: warnAboutAccessingKey,\n configurable: true\n });\n }\n}\n\nfunction defineRefPropWarningGetter(props, displayName) {\n {\n var warnAboutAccessingRef = function () {\n if (!specialPropRefWarningShown) {\n specialPropRefWarningShown = true;\n\n error('%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://reactjs.org/link/special-props)', displayName);\n }\n };\n\n warnAboutAccessingRef.isReactWarning = true;\n Object.defineProperty(props, 'ref', {\n get: warnAboutAccessingRef,\n configurable: true\n });\n }\n}\n/**\n * Factory method to create a new React element. This no longer adheres to\n * the class pattern, so do not use new to call it. Also, instanceof check\n * will not work. Instead test $$typeof field against Symbol.for('react.element') to check\n * if something is a React Element.\n *\n * @param {*} type\n * @param {*} props\n * @param {*} key\n * @param {string|object} ref\n * @param {*} owner\n * @param {*} self A *temporary* helper to detect places where `this` is\n * different from the `owner` when React.createElement is called, so that we\n * can warn. We want to get rid of owner and replace string `ref`s with arrow\n * functions, and as long as `this` and owner are the same, there will be no\n * change in behavior.\n * @param {*} source An annotation object (added by a transpiler or otherwise)\n * indicating filename, line number, and/or other information.\n * @internal\n */\n\n\nvar ReactElement = function (type, key, ref, self, source, owner, props) {\n var element = {\n // This tag allows us to uniquely identify this as a React Element\n $$typeof: REACT_ELEMENT_TYPE,\n // Built-in properties that belong on the element\n type: type,\n key: key,\n ref: ref,\n props: props,\n // Record the component responsible for creating this element.\n _owner: owner\n };\n\n {\n // The validation flag is currently mutative. We put it on\n // an external backing store so that we can freeze the whole object.\n // This can be replaced with a WeakMap once they are implemented in\n // commonly used development environments.\n element._store = {}; // To make comparing ReactElements easier for testing purposes, we make\n // the validation flag non-enumerable (where possible, which should\n // include every environment we run tests in), so the test framework\n // ignores it.\n\n Object.defineProperty(element._store, 'validated', {\n configurable: false,\n enumerable: false,\n writable: true,\n value: false\n }); // self and source are DEV only properties.\n\n Object.defineProperty(element, '_self', {\n configurable: false,\n enumerable: false,\n writable: false,\n value: self\n }); // Two elements created in two different places should be considered\n // equal for testing purposes and therefore we hide it from enumeration.\n\n Object.defineProperty(element, '_source', {\n configurable: false,\n enumerable: false,\n writable: false,\n value: source\n });\n\n if (Object.freeze) {\n Object.freeze(element.props);\n Object.freeze(element);\n }\n }\n\n return element;\n};\n/**\n * https://github.com/reactjs/rfcs/pull/107\n * @param {*} type\n * @param {object} props\n * @param {string} key\n */\n\nfunction jsxDEV(type, config, maybeKey, source, self) {\n {\n var propName; // Reserved names are extracted\n\n var props = {};\n var key = null;\n var ref = null; // Currently, key can be spread in as a prop. This causes a potential\n // issue if key is also explicitly declared (ie. \n // or ). We want to deprecate key spread,\n // but as an intermediary step, we will use jsxDEV for everything except\n // , because we aren't currently able to tell if\n // key is explicitly declared to be undefined or not.\n\n if (maybeKey !== undefined) {\n {\n checkKeyStringCoercion(maybeKey);\n }\n\n key = '' + maybeKey;\n }\n\n if (hasValidKey(config)) {\n {\n checkKeyStringCoercion(config.key);\n }\n\n key = '' + config.key;\n }\n\n if (hasValidRef(config)) {\n ref = config.ref;\n warnIfStringRefCannotBeAutoConverted(config, self);\n } // Remaining properties are added to a new props object\n\n\n for (propName in config) {\n if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {\n props[propName] = config[propName];\n }\n } // Resolve default props\n\n\n if (type && type.defaultProps) {\n var defaultProps = type.defaultProps;\n\n for (propName in defaultProps) {\n if (props[propName] === undefined) {\n props[propName] = defaultProps[propName];\n }\n }\n }\n\n if (key || ref) {\n var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;\n\n if (key) {\n defineKeyPropWarningGetter(props, displayName);\n }\n\n if (ref) {\n defineRefPropWarningGetter(props, displayName);\n }\n }\n\n return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);\n }\n}\n\nvar ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner;\nvar ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame;\n\nfunction setCurrentlyValidatingElement$1(element) {\n {\n if (element) {\n var owner = element._owner;\n var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);\n ReactDebugCurrentFrame$1.setExtraStackFrame(stack);\n } else {\n ReactDebugCurrentFrame$1.setExtraStackFrame(null);\n }\n }\n}\n\nvar propTypesMisspellWarningShown;\n\n{\n propTypesMisspellWarningShown = false;\n}\n/**\n * Verifies the object is a ReactElement.\n * See https://reactjs.org/docs/react-api.html#isvalidelement\n * @param {?object} object\n * @return {boolean} True if `object` is a ReactElement.\n * @final\n */\n\n\nfunction isValidElement(object) {\n {\n return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;\n }\n}\n\nfunction getDeclarationErrorAddendum() {\n {\n if (ReactCurrentOwner$1.current) {\n var name = getComponentNameFromType(ReactCurrentOwner$1.current.type);\n\n if (name) {\n return '\\n\\nCheck the render method of `' + name + '`.';\n }\n }\n\n return '';\n }\n}\n\nfunction getSourceInfoErrorAddendum(source) {\n {\n if (source !== undefined) {\n var fileName = source.fileName.replace(/^.*[\\\\\\/]/, '');\n var lineNumber = source.lineNumber;\n return '\\n\\nCheck your code at ' + fileName + ':' + lineNumber + '.';\n }\n\n return '';\n }\n}\n/**\n * Warn if there's no key explicitly set on dynamic arrays of children or\n * object keys are not valid. This allows us to keep track of children between\n * updates.\n */\n\n\nvar ownerHasKeyUseWarning = {};\n\nfunction getCurrentComponentErrorInfo(parentType) {\n {\n var info = getDeclarationErrorAddendum();\n\n if (!info) {\n var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name;\n\n if (parentName) {\n info = \"\\n\\nCheck the top-level render call using <\" + parentName + \">.\";\n }\n }\n\n return info;\n }\n}\n/**\n * Warn if the element doesn't have an explicit key assigned to it.\n * This element is in an array. The array could grow and shrink or be\n * reordered. All children that haven't already been validated are required to\n * have a \"key\" property assigned to it. Error statuses are cached so a warning\n * will only be shown once.\n *\n * @internal\n * @param {ReactElement} element Element that requires a key.\n * @param {*} parentType element's parent's type.\n */\n\n\nfunction validateExplicitKey(element, parentType) {\n {\n if (!element._store || element._store.validated || element.key != null) {\n return;\n }\n\n element._store.validated = true;\n var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);\n\n if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {\n return;\n }\n\n ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a\n // property, it may be the creator of the child that's responsible for\n // assigning it a key.\n\n var childOwner = '';\n\n if (element && element._owner && element._owner !== ReactCurrentOwner$1.current) {\n // Give the component that originally created this child.\n childOwner = \" It was passed a child from \" + getComponentNameFromType(element._owner.type) + \".\";\n }\n\n setCurrentlyValidatingElement$1(element);\n\n error('Each child in a list should have a unique \"key\" prop.' + '%s%s See https://reactjs.org/link/warning-keys for more information.', currentComponentErrorInfo, childOwner);\n\n setCurrentlyValidatingElement$1(null);\n }\n}\n/**\n * Ensure that every element either is passed in a static location, in an\n * array with an explicit keys property defined, or in an object literal\n * with valid key property.\n *\n * @internal\n * @param {ReactNode} node Statically passed child of any type.\n * @param {*} parentType node's parent's type.\n */\n\n\nfunction validateChildKeys(node, parentType) {\n {\n if (typeof node !== 'object') {\n return;\n }\n\n if (isArray(node)) {\n for (var i = 0; i < node.length; i++) {\n var child = node[i];\n\n if (isValidElement(child)) {\n validateExplicitKey(child, parentType);\n }\n }\n } else if (isValidElement(node)) {\n // This element was passed in a valid location.\n if (node._store) {\n node._store.validated = true;\n }\n } else if (node) {\n var iteratorFn = getIteratorFn(node);\n\n if (typeof iteratorFn === 'function') {\n // Entry iterators used to provide implicit keys,\n // but now we print a separate warning for them later.\n if (iteratorFn !== node.entries) {\n var iterator = iteratorFn.call(node);\n var step;\n\n while (!(step = iterator.next()).done) {\n if (isValidElement(step.value)) {\n validateExplicitKey(step.value, parentType);\n }\n }\n }\n }\n }\n }\n}\n/**\n * Given an element, validate that its props follow the propTypes definition,\n * provided by the type.\n *\n * @param {ReactElement} element\n */\n\n\nfunction validatePropTypes(element) {\n {\n var type = element.type;\n\n if (type === null || type === undefined || typeof type === 'string') {\n return;\n }\n\n var propTypes;\n\n if (typeof type === 'function') {\n propTypes = type.propTypes;\n } else if (typeof type === 'object' && (type.$$typeof === REACT_FORWARD_REF_TYPE || // Note: Memo only checks outer props here.\n // Inner props are checked in the reconciler.\n type.$$typeof === REACT_MEMO_TYPE)) {\n propTypes = type.propTypes;\n } else {\n return;\n }\n\n if (propTypes) {\n // Intentionally inside to avoid triggering lazy initializers:\n var name = getComponentNameFromType(type);\n checkPropTypes(propTypes, element.props, 'prop', name, element);\n } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {\n propTypesMisspellWarningShown = true; // Intentionally inside to avoid triggering lazy initializers:\n\n var _name = getComponentNameFromType(type);\n\n error('Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?', _name || 'Unknown');\n }\n\n if (typeof type.getDefaultProps === 'function' && !type.getDefaultProps.isReactClassApproved) {\n error('getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.');\n }\n }\n}\n/**\n * Given a fragment, validate that it can only be provided with fragment props\n * @param {ReactElement} fragment\n */\n\n\nfunction validateFragmentProps(fragment) {\n {\n var keys = Object.keys(fragment.props);\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n\n if (key !== 'children' && key !== 'key') {\n setCurrentlyValidatingElement$1(fragment);\n\n error('Invalid prop `%s` supplied to `React.Fragment`. ' + 'React.Fragment can only have `key` and `children` props.', key);\n\n setCurrentlyValidatingElement$1(null);\n break;\n }\n }\n\n if (fragment.ref !== null) {\n setCurrentlyValidatingElement$1(fragment);\n\n error('Invalid attribute `ref` supplied to `React.Fragment`.');\n\n setCurrentlyValidatingElement$1(null);\n }\n }\n}\n\nvar didWarnAboutKeySpread = {};\nfunction jsxWithValidation(type, props, key, isStaticChildren, source, self) {\n {\n var validType = isValidElementType(type); // We warn in this case but don't throw. We expect the element creation to\n // succeed and there will likely be errors in render.\n\n if (!validType) {\n var info = '';\n\n if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {\n info += ' You likely forgot to export your component from the file ' + \"it's defined in, or you might have mixed up default and named imports.\";\n }\n\n var sourceInfo = getSourceInfoErrorAddendum(source);\n\n if (sourceInfo) {\n info += sourceInfo;\n } else {\n info += getDeclarationErrorAddendum();\n }\n\n var typeString;\n\n if (type === null) {\n typeString = 'null';\n } else if (isArray(type)) {\n typeString = 'array';\n } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {\n typeString = \"<\" + (getComponentNameFromType(type.type) || 'Unknown') + \" />\";\n info = ' Did you accidentally export a JSX literal instead of a component?';\n } else {\n typeString = typeof type;\n }\n\n error('React.jsx: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', typeString, info);\n }\n\n var element = jsxDEV(type, props, key, source, self); // The result can be nullish if a mock or a custom function is used.\n // TODO: Drop this when these are no longer allowed as the type argument.\n\n if (element == null) {\n return element;\n } // Skip key warning if the type isn't valid since our key validation logic\n // doesn't expect a non-string/function type and can throw confusing errors.\n // We don't want exception behavior to differ between dev and prod.\n // (Rendering will throw with a helpful message and as soon as the type is\n // fixed, the key warnings will appear.)\n\n\n if (validType) {\n var children = props.children;\n\n if (children !== undefined) {\n if (isStaticChildren) {\n if (isArray(children)) {\n for (var i = 0; i < children.length; i++) {\n validateChildKeys(children[i], type);\n }\n\n if (Object.freeze) {\n Object.freeze(children);\n }\n } else {\n error('React.jsx: Static children should always be an array. ' + 'You are likely explicitly calling React.jsxs or React.jsxDEV. ' + 'Use the Babel transform instead.');\n }\n } else {\n validateChildKeys(children, type);\n }\n }\n }\n\n {\n if (hasOwnProperty.call(props, 'key')) {\n var componentName = getComponentNameFromType(type);\n var keys = Object.keys(props).filter(function (k) {\n return k !== 'key';\n });\n var beforeExample = keys.length > 0 ? '{key: someKey, ' + keys.join(': ..., ') + ': ...}' : '{key: someKey}';\n\n if (!didWarnAboutKeySpread[componentName + beforeExample]) {\n var afterExample = keys.length > 0 ? '{' + keys.join(': ..., ') + ': ...}' : '{}';\n\n error('A props object containing a \"key\" prop is being spread into JSX:\\n' + ' let props = %s;\\n' + ' <%s {...props} />\\n' + 'React keys must be passed directly to JSX without using spread:\\n' + ' let props = %s;\\n' + ' <%s key={someKey} {...props} />', beforeExample, componentName, afterExample, componentName);\n\n didWarnAboutKeySpread[componentName + beforeExample] = true;\n }\n }\n }\n\n if (type === REACT_FRAGMENT_TYPE) {\n validateFragmentProps(element);\n } else {\n validatePropTypes(element);\n }\n\n return element;\n }\n} // These two functions exist to still get child warnings in dev\n// even with the prod transform. This means that jsxDEV is purely\n// opt-in behavior for better messages but that we won't stop\n// giving you warnings if you use production apis.\n\nfunction jsxWithValidationStatic(type, props, key) {\n {\n return jsxWithValidation(type, props, key, true);\n }\n}\nfunction jsxWithValidationDynamic(type, props, key) {\n {\n return jsxWithValidation(type, props, key, false);\n }\n}\n\nvar jsx = jsxWithValidationDynamic ; // we may want to special case jsxs internally to take advantage of static children.\n// for now we can ship identical prod functions\n\nvar jsxs = jsxWithValidationStatic ;\n\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.jsx = jsx;\nexports.jsxs = jsxs;\n })();\n}\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.min.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","/*!\n* tabbable 6.2.0\n* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE\n*/\n// NOTE: separate `:not()` selectors has broader browser support than the newer\n// `:not([inert], [inert] *)` (Feb 2023)\n// CAREFUL: JSDom does not support `:not([inert] *)` as a selector; using it causes\n// the entire query to fail, resulting in no nodes found, which will break a lot\n// of things... so we have to rely on JS to identify nodes inside an inert container\nvar candidateSelectors = ['input:not([inert])', 'select:not([inert])', 'textarea:not([inert])', 'a[href]:not([inert])', 'button:not([inert])', '[tabindex]:not(slot):not([inert])', 'audio[controls]:not([inert])', 'video[controls]:not([inert])', '[contenteditable]:not([contenteditable=\"false\"]):not([inert])', 'details>summary:first-of-type:not([inert])', 'details:not([inert])'];\nvar candidateSelector = /* #__PURE__ */candidateSelectors.join(',');\nvar NoElement = typeof Element === 'undefined';\nvar matches = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;\nvar getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) {\n var _element$getRootNode;\n return element === null || element === void 0 ? void 0 : (_element$getRootNode = element.getRootNode) === null || _element$getRootNode === void 0 ? void 0 : _element$getRootNode.call(element);\n} : function (element) {\n return element === null || element === void 0 ? void 0 : element.ownerDocument;\n};\n\n/**\n * Determines if a node is inert or in an inert ancestor.\n * @param {Element} [node]\n * @param {boolean} [lookUp] If true and `node` is not inert, looks up at ancestors to\n * see if any of them are inert. If false, only `node` itself is considered.\n * @returns {boolean} True if inert itself or by way of being in an inert ancestor.\n * False if `node` is falsy.\n */\nvar isInert = function isInert(node, lookUp) {\n var _node$getAttribute;\n if (lookUp === void 0) {\n lookUp = true;\n }\n // CAREFUL: JSDom does not support inert at all, so we can't use the `HTMLElement.inert`\n // JS API property; we have to check the attribute, which can either be empty or 'true';\n // if it's `null` (not specified) or 'false', it's an active element\n var inertAtt = node === null || node === void 0 ? void 0 : (_node$getAttribute = node.getAttribute) === null || _node$getAttribute === void 0 ? void 0 : _node$getAttribute.call(node, 'inert');\n var inert = inertAtt === '' || inertAtt === 'true';\n\n // NOTE: this could also be handled with `node.matches('[inert], :is([inert] *)')`\n // if it weren't for `matches()` not being a function on shadow roots; the following\n // code works for any kind of node\n // CAREFUL: JSDom does not appear to support certain selectors like `:not([inert] *)`\n // so it likely would not support `:is([inert] *)` either...\n var result = inert || lookUp && node && isInert(node.parentNode); // recursive\n\n return result;\n};\n\n/**\n * Determines if a node's content is editable.\n * @param {Element} [node]\n * @returns True if it's content-editable; false if it's not or `node` is falsy.\n */\nvar isContentEditable = function isContentEditable(node) {\n var _node$getAttribute2;\n // CAREFUL: JSDom does not support the `HTMLElement.isContentEditable` API so we have\n // to use the attribute directly to check for this, which can either be empty or 'true';\n // if it's `null` (not specified) or 'false', it's a non-editable element\n var attValue = node === null || node === void 0 ? void 0 : (_node$getAttribute2 = node.getAttribute) === null || _node$getAttribute2 === void 0 ? void 0 : _node$getAttribute2.call(node, 'contenteditable');\n return attValue === '' || attValue === 'true';\n};\n\n/**\n * @param {Element} el container to check in\n * @param {boolean} includeContainer add container to check\n * @param {(node: Element) => boolean} filter filter candidates\n * @returns {Element[]}\n */\nvar getCandidates = function getCandidates(el, includeContainer, filter) {\n // even if `includeContainer=false`, we still have to check it for inertness because\n // if it's inert, all its children are inert\n if (isInert(el)) {\n return [];\n }\n var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector));\n if (includeContainer && matches.call(el, candidateSelector)) {\n candidates.unshift(el);\n }\n candidates = candidates.filter(filter);\n return candidates;\n};\n\n/**\n * @callback GetShadowRoot\n * @param {Element} element to check for shadow root\n * @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available.\n */\n\n/**\n * @callback ShadowRootFilter\n * @param {Element} shadowHostNode the element which contains shadow content\n * @returns {boolean} true if a shadow root could potentially contain valid candidates.\n */\n\n/**\n * @typedef {Object} CandidateScope\n * @property {Element} scopeParent contains inner candidates\n * @property {Element[]} candidates list of candidates found in the scope parent\n */\n\n/**\n * @typedef {Object} IterativeOptions\n * @property {GetShadowRoot|boolean} getShadowRoot true if shadow support is enabled; falsy if not;\n * if a function, implies shadow support is enabled and either returns the shadow root of an element\n * or a boolean stating if it has an undisclosed shadow root\n * @property {(node: Element) => boolean} filter filter candidates\n * @property {boolean} flatten if true then result will flatten any CandidateScope into the returned list\n * @property {ShadowRootFilter} shadowRootFilter filter shadow roots;\n */\n\n/**\n * @param {Element[]} elements list of element containers to match candidates from\n * @param {boolean} includeContainer add container list to check\n * @param {IterativeOptions} options\n * @returns {Array.}\n */\nvar getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) {\n var candidates = [];\n var elementsToCheck = Array.from(elements);\n while (elementsToCheck.length) {\n var element = elementsToCheck.shift();\n if (isInert(element, false)) {\n // no need to look up since we're drilling down\n // anything inside this container will also be inert\n continue;\n }\n if (element.tagName === 'SLOT') {\n // add shadow dom slot scope (slot itself cannot be focusable)\n var assigned = element.assignedElements();\n var content = assigned.length ? assigned : element.children;\n var nestedCandidates = getCandidatesIteratively(content, true, options);\n if (options.flatten) {\n candidates.push.apply(candidates, nestedCandidates);\n } else {\n candidates.push({\n scopeParent: element,\n candidates: nestedCandidates\n });\n }\n } else {\n // check candidate element\n var validCandidate = matches.call(element, candidateSelector);\n if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) {\n candidates.push(element);\n }\n\n // iterate over shadow content if possible\n var shadowRoot = element.shadowRoot ||\n // check for an undisclosed shadow\n typeof options.getShadowRoot === 'function' && options.getShadowRoot(element);\n\n // no inert look up because we're already drilling down and checking for inertness\n // on the way down, so all containers to this root node should have already been\n // vetted as non-inert\n var validShadowRoot = !isInert(shadowRoot, false) && (!options.shadowRootFilter || options.shadowRootFilter(element));\n if (shadowRoot && validShadowRoot) {\n // add shadow dom scope IIF a shadow root node was given; otherwise, an undisclosed\n // shadow exists, so look at light dom children as fallback BUT create a scope for any\n // child candidates found because they're likely slotted elements (elements that are\n // children of the web component element (which has the shadow), in the light dom, but\n // slotted somewhere _inside_ the undisclosed shadow) -- the scope is created below,\n // _after_ we return from this recursive call\n var _nestedCandidates = getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options);\n if (options.flatten) {\n candidates.push.apply(candidates, _nestedCandidates);\n } else {\n candidates.push({\n scopeParent: element,\n candidates: _nestedCandidates\n });\n }\n } else {\n // there's not shadow so just dig into the element's (light dom) children\n // __without__ giving the element special scope treatment\n elementsToCheck.unshift.apply(elementsToCheck, element.children);\n }\n }\n }\n return candidates;\n};\n\n/**\n * @private\n * Determines if the node has an explicitly specified `tabindex` attribute.\n * @param {HTMLElement} node\n * @returns {boolean} True if so; false if not.\n */\nvar hasTabIndex = function hasTabIndex(node) {\n return !isNaN(parseInt(node.getAttribute('tabindex'), 10));\n};\n\n/**\n * Determine the tab index of a given node.\n * @param {HTMLElement} node\n * @returns {number} Tab order (negative, 0, or positive number).\n * @throws {Error} If `node` is falsy.\n */\nvar getTabIndex = function getTabIndex(node) {\n if (!node) {\n throw new Error('No node provided');\n }\n if (node.tabIndex < 0) {\n // in Chrome, , and elements get a default\n // `tabIndex` of -1 when the 'tabindex' attribute isn't specified in the DOM,\n // yet they are still part of the regular tab order; in FF, they get a default\n // `tabIndex` of 0; since Chrome still puts those elements in the regular tab\n // order, consider their tab index to be 0.\n // Also browsers do not return `tabIndex` correctly for contentEditable nodes;\n // so if they don't have a tabindex attribute specifically set, assume it's 0.\n if ((/^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && !hasTabIndex(node)) {\n return 0;\n }\n }\n return node.tabIndex;\n};\n\n/**\n * Determine the tab index of a given node __for sort order purposes__.\n * @param {HTMLElement} node\n * @param {boolean} [isScope] True for a custom element with shadow root or slot that, by default,\n * has tabIndex -1, but needs to be sorted by document order in order for its content to be\n * inserted into the correct sort position.\n * @returns {number} Tab order (negative, 0, or positive number).\n */\nvar getSortOrderTabIndex = function getSortOrderTabIndex(node, isScope) {\n var tabIndex = getTabIndex(node);\n if (tabIndex < 0 && isScope && !hasTabIndex(node)) {\n return 0;\n }\n return tabIndex;\n};\nvar sortOrderedTabbables = function sortOrderedTabbables(a, b) {\n return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex;\n};\nvar isInput = function isInput(node) {\n return node.tagName === 'INPUT';\n};\nvar isHiddenInput = function isHiddenInput(node) {\n return isInput(node) && node.type === 'hidden';\n};\nvar isDetailsWithSummary = function isDetailsWithSummary(node) {\n var r = node.tagName === 'DETAILS' && Array.prototype.slice.apply(node.children).some(function (child) {\n return child.tagName === 'SUMMARY';\n });\n return r;\n};\nvar getCheckedRadio = function getCheckedRadio(nodes, form) {\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i].checked && nodes[i].form === form) {\n return nodes[i];\n }\n }\n};\nvar isTabbableRadio = function isTabbableRadio(node) {\n if (!node.name) {\n return true;\n }\n var radioScope = node.form || getRootNode(node);\n var queryRadios = function queryRadios(name) {\n return radioScope.querySelectorAll('input[type=\"radio\"][name=\"' + name + '\"]');\n };\n var radioSet;\n if (typeof window !== 'undefined' && typeof window.CSS !== 'undefined' && typeof window.CSS.escape === 'function') {\n radioSet = queryRadios(window.CSS.escape(node.name));\n } else {\n try {\n radioSet = queryRadios(node.name);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s', err.message);\n return false;\n }\n }\n var checked = getCheckedRadio(radioSet, node.form);\n return !checked || checked === node;\n};\nvar isRadio = function isRadio(node) {\n return isInput(node) && node.type === 'radio';\n};\nvar isNonTabbableRadio = function isNonTabbableRadio(node) {\n return isRadio(node) && !isTabbableRadio(node);\n};\n\n// determines if a node is ultimately attached to the window's document\nvar isNodeAttached = function isNodeAttached(node) {\n var _nodeRoot;\n // The root node is the shadow root if the node is in a shadow DOM; some document otherwise\n // (but NOT _the_ document; see second 'If' comment below for more).\n // If rootNode is shadow root, it'll have a host, which is the element to which the shadow\n // is attached, and the one we need to check if it's in the document or not (because the\n // shadow, and all nodes it contains, is never considered in the document since shadows\n // behave like self-contained DOMs; but if the shadow's HOST, which is part of the document,\n // is hidden, or is not in the document itself but is detached, it will affect the shadow's\n // visibility, including all the nodes it contains). The host could be any normal node,\n // or a custom element (i.e. web component). Either way, that's the one that is considered\n // part of the document, not the shadow root, nor any of its children (i.e. the node being\n // tested).\n // To further complicate things, we have to look all the way up until we find a shadow HOST\n // that is attached (or find none) because the node might be in nested shadows...\n // If rootNode is not a shadow root, it won't have a host, and so rootNode should be the\n // document (per the docs) and while it's a Document-type object, that document does not\n // appear to be the same as the node's `ownerDocument` for some reason, so it's safer\n // to ignore the rootNode at this point, and use `node.ownerDocument`. Otherwise,\n // using `rootNode.contains(node)` will _always_ be true we'll get false-positives when\n // node is actually detached.\n // NOTE: If `nodeRootHost` or `node` happens to be the `document` itself (which is possible\n // if a tabbable/focusable node was quickly added to the DOM, focused, and then removed\n // from the DOM as in https://github.com/focus-trap/focus-trap-react/issues/905), then\n // `ownerDocument` will be `null`, hence the optional chaining on it.\n var nodeRoot = node && getRootNode(node);\n var nodeRootHost = (_nodeRoot = nodeRoot) === null || _nodeRoot === void 0 ? void 0 : _nodeRoot.host;\n\n // in some cases, a detached node will return itself as the root instead of a document or\n // shadow root object, in which case, we shouldn't try to look further up the host chain\n var attached = false;\n if (nodeRoot && nodeRoot !== node) {\n var _nodeRootHost, _nodeRootHost$ownerDo, _node$ownerDocument;\n attached = !!((_nodeRootHost = nodeRootHost) !== null && _nodeRootHost !== void 0 && (_nodeRootHost$ownerDo = _nodeRootHost.ownerDocument) !== null && _nodeRootHost$ownerDo !== void 0 && _nodeRootHost$ownerDo.contains(nodeRootHost) || node !== null && node !== void 0 && (_node$ownerDocument = node.ownerDocument) !== null && _node$ownerDocument !== void 0 && _node$ownerDocument.contains(node));\n while (!attached && nodeRootHost) {\n var _nodeRoot2, _nodeRootHost2, _nodeRootHost2$ownerD;\n // since it's not attached and we have a root host, the node MUST be in a nested shadow DOM,\n // which means we need to get the host's host and check if that parent host is contained\n // in (i.e. attached to) the document\n nodeRoot = getRootNode(nodeRootHost);\n nodeRootHost = (_nodeRoot2 = nodeRoot) === null || _nodeRoot2 === void 0 ? void 0 : _nodeRoot2.host;\n attached = !!((_nodeRootHost2 = nodeRootHost) !== null && _nodeRootHost2 !== void 0 && (_nodeRootHost2$ownerD = _nodeRootHost2.ownerDocument) !== null && _nodeRootHost2$ownerD !== void 0 && _nodeRootHost2$ownerD.contains(nodeRootHost));\n }\n }\n return attached;\n};\nvar isZeroArea = function isZeroArea(node) {\n var _node$getBoundingClie = node.getBoundingClientRect(),\n width = _node$getBoundingClie.width,\n height = _node$getBoundingClie.height;\n return width === 0 && height === 0;\n};\nvar isHidden = function isHidden(node, _ref) {\n var displayCheck = _ref.displayCheck,\n getShadowRoot = _ref.getShadowRoot;\n // NOTE: visibility will be `undefined` if node is detached from the document\n // (see notes about this further down), which means we will consider it visible\n // (this is legacy behavior from a very long way back)\n // NOTE: we check this regardless of `displayCheck=\"none\"` because this is a\n // _visibility_ check, not a _display_ check\n if (getComputedStyle(node).visibility === 'hidden') {\n return true;\n }\n var isDirectSummary = matches.call(node, 'details>summary:first-of-type');\n var nodeUnderDetails = isDirectSummary ? node.parentElement : node;\n if (matches.call(nodeUnderDetails, 'details:not([open]) *')) {\n return true;\n }\n if (!displayCheck || displayCheck === 'full' || displayCheck === 'legacy-full') {\n if (typeof getShadowRoot === 'function') {\n // figure out if we should consider the node to be in an undisclosed shadow and use the\n // 'non-zero-area' fallback\n var originalNode = node;\n while (node) {\n var parentElement = node.parentElement;\n var rootNode = getRootNode(node);\n if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement) === true // check if there's an undisclosed shadow\n ) {\n // node has an undisclosed shadow which means we can only treat it as a black box, so we\n // fall back to a non-zero-area test\n return isZeroArea(node);\n } else if (node.assignedSlot) {\n // iterate up slot\n node = node.assignedSlot;\n } else if (!parentElement && rootNode !== node.ownerDocument) {\n // cross shadow boundary\n node = rootNode.host;\n } else {\n // iterate up normal dom\n node = parentElement;\n }\n }\n node = originalNode;\n }\n // else, `getShadowRoot` might be true, but all that does is enable shadow DOM support\n // (i.e. it does not also presume that all nodes might have undisclosed shadows); or\n // it might be a falsy value, which means shadow DOM support is disabled\n\n // Since we didn't find it sitting in an undisclosed shadow (or shadows are disabled)\n // now we can just test to see if it would normally be visible or not, provided it's\n // attached to the main document.\n // NOTE: We must consider case where node is inside a shadow DOM and given directly to\n // `isTabbable()` or `isFocusable()` -- regardless of `getShadowRoot` option setting.\n\n if (isNodeAttached(node)) {\n // this works wherever the node is: if there's at least one client rect, it's\n // somehow displayed; it also covers the CSS 'display: contents' case where the\n // node itself is hidden in place of its contents; and there's no need to search\n // up the hierarchy either\n return !node.getClientRects().length;\n }\n\n // Else, the node isn't attached to the document, which means the `getClientRects()`\n // API will __always__ return zero rects (this can happen, for example, if React\n // is used to render nodes onto a detached tree, as confirmed in this thread:\n // https://github.com/facebook/react/issues/9117#issuecomment-284228870)\n //\n // It also means that even window.getComputedStyle(node).display will return `undefined`\n // because styles are only computed for nodes that are in the document.\n //\n // NOTE: THIS HAS BEEN THE CASE FOR YEARS. It is not new, nor is it caused by tabbable\n // somehow. Though it was never stated officially, anyone who has ever used tabbable\n // APIs on nodes in detached containers has actually implicitly used tabbable in what\n // was later (as of v5.2.0 on Apr 9, 2021) called `displayCheck=\"none\"` mode -- essentially\n // considering __everything__ to be visible because of the innability to determine styles.\n //\n // v6.0.0: As of this major release, the default 'full' option __no longer treats detached\n // nodes as visible with the 'none' fallback.__\n if (displayCheck !== 'legacy-full') {\n return true; // hidden\n }\n // else, fallback to 'none' mode and consider the node visible\n } else if (displayCheck === 'non-zero-area') {\n // NOTE: Even though this tests that the node's client rect is non-zero to determine\n // whether it's displayed, and that a detached node will __always__ have a zero-area\n // client rect, we don't special-case for whether the node is attached or not. In\n // this mode, we do want to consider nodes that have a zero area to be hidden at all\n // times, and that includes attached or not.\n return isZeroArea(node);\n }\n\n // visible, as far as we can tell, or per current `displayCheck=none` mode, we assume\n // it's visible\n return false;\n};\n\n// form fields (nested) inside a disabled fieldset are not focusable/tabbable\n// unless they are in the _first_