UNPKG

@react-aria/interactions

Version:
965 lines (939 loc) • 80.6 kB
import {mergeProps as $bx7SL$mergeProps, useSyncRef as $bx7SL$useSyncRef, useGlobalListeners as $bx7SL$useGlobalListeners, isVirtualClick as $bx7SL$isVirtualClick, focusWithoutScrolling as $bx7SL$focusWithoutScrolling, isVirtualPointerEvent as $bx7SL$isVirtualPointerEvent, isIOS as $bx7SL$isIOS, runAfterTransition as $bx7SL$runAfterTransition, useLayoutEffect as $bx7SL$useLayoutEffect, isMac as $bx7SL$isMac, useEvent as $bx7SL$useEvent, useDescription as $bx7SL$useDescription} from "@react-aria/utils"; import $bx7SL$react, {useRef as $bx7SL$useRef, useContext as $bx7SL$useContext, useState as $bx7SL$useState, useMemo as $bx7SL$useMemo, useEffect as $bx7SL$useEffect, useCallback as $bx7SL$useCallback} from "react"; /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ // Portions of the code in this file are based on code from react. // Original licensing for the following can be found in the // NOTICE file in the root directory of this source tree. // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ // Note that state only matters here for iOS. Non-iOS gets user-select: none applied to the target element // rather than at the document level so we just need to apply/remove user-select: none for each pressed element individually let $14c0b72509d70225$var$state = "default"; let $14c0b72509d70225$var$savedUserSelect = ""; let $14c0b72509d70225$var$modifiedElementMap = new WeakMap(); function $14c0b72509d70225$export$16a4697467175487(target) { if ((0, $bx7SL$isIOS)()) { if ($14c0b72509d70225$var$state === "default") { $14c0b72509d70225$var$savedUserSelect = document.documentElement.style.webkitUserSelect; document.documentElement.style.webkitUserSelect = "none"; } $14c0b72509d70225$var$state = "disabled"; } else if (target instanceof HTMLElement || target instanceof SVGElement) { // If not iOS, store the target's original user-select and change to user-select: none // Ignore state since it doesn't apply for non iOS $14c0b72509d70225$var$modifiedElementMap.set(target, target.style.userSelect); target.style.userSelect = "none"; } } function $14c0b72509d70225$export$b0d6fa1ab32e3295(target) { if ((0, $bx7SL$isIOS)()) { // If the state is already default, there's nothing to do. // If it is restoring, then there's no need to queue a second restore. if ($14c0b72509d70225$var$state !== "disabled") return; $14c0b72509d70225$var$state = "restoring"; // There appears to be a delay on iOS where selection still might occur // after pointer up, so wait a bit before removing user-select. setTimeout(()=>{ // Wait for any CSS transitions to complete so we don't recompute style // for the whole page in the middle of the animation and cause jank. (0, $bx7SL$runAfterTransition)(()=>{ // Avoid race conditions if ($14c0b72509d70225$var$state === "restoring") { if (document.documentElement.style.webkitUserSelect === "none") document.documentElement.style.webkitUserSelect = $14c0b72509d70225$var$savedUserSelect || ""; $14c0b72509d70225$var$savedUserSelect = ""; $14c0b72509d70225$var$state = "default"; } }); }, 300); } else if (target instanceof HTMLElement || target instanceof SVGElement) // If not iOS, restore the target's original user-select if any // Ignore state since it doesn't apply for non iOS { if (target && $14c0b72509d70225$var$modifiedElementMap.has(target)) { let targetOldUserSelect = $14c0b72509d70225$var$modifiedElementMap.get(target); if (target.style.userSelect === "none") target.style.userSelect = targetOldUserSelect; if (target.getAttribute("style") === "") target.removeAttribute("style"); $14c0b72509d70225$var$modifiedElementMap.delete(target); } } } /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ const $ae1eeba8b9eafd08$export$5165eccb35aaadb5 = (0, $bx7SL$react).createContext(null); $ae1eeba8b9eafd08$export$5165eccb35aaadb5.displayName = "PressResponderContext"; function $f6c31cce2adf654f$var$usePressResponderContext(props) { // Consume context from <PressResponder> and merge with props. let context = (0, $bx7SL$useContext)((0, $ae1eeba8b9eafd08$export$5165eccb35aaadb5)); if (context) { let { register: register , ...contextProps } = context; props = (0, $bx7SL$mergeProps)(contextProps, props); register(); } (0, $bx7SL$useSyncRef)(context, props.ref); return props; } function $f6c31cce2adf654f$export$45712eceda6fad21(props) { let { onPress: onPress , onPressChange: onPressChange , onPressStart: onPressStart , onPressEnd: onPressEnd , onPressUp: onPressUp , isDisabled: isDisabled , isPressed: isPressedProp , preventFocusOnPress: preventFocusOnPress , shouldCancelOnPointerExit: shouldCancelOnPointerExit , allowTextSelectionOnPress: allowTextSelectionOnPress , // eslint-disable-next-line @typescript-eslint/no-unused-vars ref: _ , ...domProps } = $f6c31cce2adf654f$var$usePressResponderContext(props); let propsRef = (0, $bx7SL$useRef)(null); propsRef.current = { onPress: onPress, onPressChange: onPressChange, onPressStart: onPressStart, onPressEnd: onPressEnd, onPressUp: onPressUp, isDisabled: isDisabled, shouldCancelOnPointerExit: shouldCancelOnPointerExit }; let [isPressed, setPressed] = (0, $bx7SL$useState)(false); let ref = (0, $bx7SL$useRef)({ isPressed: false, ignoreEmulatedMouseEvents: false, ignoreClickAfterPress: false, didFirePressStart: false, activePointerId: null, target: null, isOverTarget: false, pointerType: null }); let { addGlobalListener: addGlobalListener , removeAllGlobalListeners: removeAllGlobalListeners } = (0, $bx7SL$useGlobalListeners)(); let pressProps = (0, $bx7SL$useMemo)(()=>{ let state = ref.current; let triggerPressStart = (originalEvent, pointerType)=>{ let { onPressStart: onPressStart , onPressChange: onPressChange , isDisabled: isDisabled } = propsRef.current; if (isDisabled || state.didFirePressStart) return; if (onPressStart) onPressStart({ type: "pressstart", pointerType: pointerType, target: originalEvent.currentTarget, shiftKey: originalEvent.shiftKey, metaKey: originalEvent.metaKey, ctrlKey: originalEvent.ctrlKey, altKey: originalEvent.altKey }); if (onPressChange) onPressChange(true); state.didFirePressStart = true; setPressed(true); }; let triggerPressEnd = (originalEvent, pointerType, wasPressed = true)=>{ let { onPressEnd: onPressEnd , onPressChange: onPressChange , onPress: onPress , isDisabled: isDisabled } = propsRef.current; if (!state.didFirePressStart) return; state.ignoreClickAfterPress = true; state.didFirePressStart = false; if (onPressEnd) onPressEnd({ type: "pressend", pointerType: pointerType, target: originalEvent.currentTarget, shiftKey: originalEvent.shiftKey, metaKey: originalEvent.metaKey, ctrlKey: originalEvent.ctrlKey, altKey: originalEvent.altKey }); if (onPressChange) onPressChange(false); setPressed(false); if (onPress && wasPressed && !isDisabled) onPress({ type: "press", pointerType: pointerType, target: originalEvent.currentTarget, shiftKey: originalEvent.shiftKey, metaKey: originalEvent.metaKey, ctrlKey: originalEvent.ctrlKey, altKey: originalEvent.altKey }); }; let triggerPressUp = (originalEvent, pointerType)=>{ let { onPressUp: onPressUp , isDisabled: isDisabled } = propsRef.current; if (isDisabled) return; if (onPressUp) onPressUp({ type: "pressup", pointerType: pointerType, target: originalEvent.currentTarget, shiftKey: originalEvent.shiftKey, metaKey: originalEvent.metaKey, ctrlKey: originalEvent.ctrlKey, altKey: originalEvent.altKey }); }; let cancel = (e)=>{ if (state.isPressed) { if (state.isOverTarget) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false); state.isPressed = false; state.isOverTarget = false; state.activePointerId = null; state.pointerType = null; removeAllGlobalListeners(); if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)(state.target); } }; let pressProps = { onKeyDown (e) { if ($f6c31cce2adf654f$var$isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && e.currentTarget.contains(e.target)) { if ($f6c31cce2adf654f$var$shouldPreventDefaultKeyboard(e.target, e.key)) e.preventDefault(); e.stopPropagation(); // If the event is repeating, it may have started on a different element // after which focus moved to the current element. Ignore these events and // only handle the first key down event. if (!state.isPressed && !e.repeat) { state.target = e.currentTarget; state.isPressed = true; triggerPressStart(e, "keyboard"); // Focus may move before the key up event, so register the event on the document // instead of the same element where the key down event occurred. addGlobalListener(document, "keyup", onKeyUp, false); } } else if (e.key === "Enter" && $f6c31cce2adf654f$var$isHTMLAnchorLink(e.currentTarget)) // If the target is a link, we won't have handled this above because we want the default // browser behavior to open the link when pressing Enter. But we still need to prevent // default so that elements above do not also handle it (e.g. table row). e.stopPropagation(); }, onKeyUp (e) { if ($f6c31cce2adf654f$var$isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && !e.repeat && e.currentTarget.contains(e.target)) triggerPressUp($f6c31cce2adf654f$var$createEvent(state.target, e), "keyboard"); }, onClick (e) { if (e && !e.currentTarget.contains(e.target)) return; if (e && e.button === 0) { e.stopPropagation(); if (isDisabled) e.preventDefault(); // If triggered from a screen reader or by using element.click(), // trigger as if it were a keyboard click. if (!state.ignoreClickAfterPress && !state.ignoreEmulatedMouseEvents && (state.pointerType === "virtual" || (0, $bx7SL$isVirtualClick)(e.nativeEvent))) { // Ensure the element receives focus (VoiceOver on iOS does not do this) if (!isDisabled && !preventFocusOnPress) (0, $bx7SL$focusWithoutScrolling)(e.currentTarget); triggerPressStart(e, "virtual"); triggerPressUp(e, "virtual"); triggerPressEnd(e, "virtual"); } state.ignoreEmulatedMouseEvents = false; state.ignoreClickAfterPress = false; } } }; let onKeyUp = (e)=>{ if (state.isPressed && $f6c31cce2adf654f$var$isValidKeyboardEvent(e, state.target)) { if ($f6c31cce2adf654f$var$shouldPreventDefaultKeyboard(e.target, e.key)) e.preventDefault(); e.stopPropagation(); state.isPressed = false; let target = e.target; triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), "keyboard", state.target.contains(target)); removeAllGlobalListeners(); // If the target is a link, trigger the click method to open the URL, // but defer triggering pressEnd until onClick event handler. if (state.target instanceof HTMLElement && state.target.contains(target) && ($f6c31cce2adf654f$var$isHTMLAnchorLink(state.target) || state.target.getAttribute("role") === "link")) state.target.click(); } }; if (typeof PointerEvent !== "undefined") { pressProps.onPointerDown = (e)=>{ // Only handle left clicks, and ignore events that bubbled through portals. if (e.button !== 0 || !e.currentTarget.contains(e.target)) return; // iOS safari fires pointer events from VoiceOver with incorrect coordinates/target. // Ignore and let the onClick handler take care of it instead. // https://bugs.webkit.org/show_bug.cgi?id=222627 // https://bugs.webkit.org/show_bug.cgi?id=223202 if ((0, $bx7SL$isVirtualPointerEvent)(e.nativeEvent)) { state.pointerType = "virtual"; return; } // Due to browser inconsistencies, especially on mobile browsers, we prevent // default on pointer down and handle focusing the pressable element ourselves. if ($f6c31cce2adf654f$var$shouldPreventDefault(e.currentTarget)) e.preventDefault(); state.pointerType = e.pointerType; e.stopPropagation(); if (!state.isPressed) { state.isPressed = true; state.isOverTarget = true; state.activePointerId = e.pointerId; state.target = e.currentTarget; if (!isDisabled && !preventFocusOnPress) (0, $bx7SL$focusWithoutScrolling)(e.currentTarget); if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$16a4697467175487)(state.target); triggerPressStart(e, state.pointerType); addGlobalListener(document, "pointermove", onPointerMove, false); addGlobalListener(document, "pointerup", onPointerUp, false); addGlobalListener(document, "pointercancel", onPointerCancel, false); } }; pressProps.onMouseDown = (e)=>{ if (!e.currentTarget.contains(e.target)) return; if (e.button === 0) { // Chrome and Firefox on touch Windows devices require mouse down events // to be canceled in addition to pointer events, or an extra asynchronous // focus event will be fired. if ($f6c31cce2adf654f$var$shouldPreventDefault(e.currentTarget)) e.preventDefault(); e.stopPropagation(); } }; pressProps.onPointerUp = (e)=>{ // iOS fires pointerup with zero width and height, so check the pointerType recorded during pointerdown. if (!e.currentTarget.contains(e.target) || state.pointerType === "virtual") return; // Only handle left clicks // Safari on iOS sometimes fires pointerup events, even // when the touch isn't over the target, so double check. if (e.button === 0 && $f6c31cce2adf654f$var$isOverTarget(e, e.currentTarget)) triggerPressUp(e, state.pointerType || e.pointerType); }; // Safari on iOS < 13.2 does not implement pointerenter/pointerleave events correctly. // Use pointer move events instead to implement our own hit testing. // See https://bugs.webkit.org/show_bug.cgi?id=199803 let onPointerMove = (e)=>{ if (e.pointerId !== state.activePointerId) return; if ($f6c31cce2adf654f$var$isOverTarget(e, state.target)) { if (!state.isOverTarget) { state.isOverTarget = true; triggerPressStart($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType); } } else if (state.isOverTarget) { state.isOverTarget = false; triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false); if (propsRef.current.shouldCancelOnPointerExit) cancel(e); } }; let onPointerUp = (e)=>{ if (e.pointerId === state.activePointerId && state.isPressed && e.button === 0) { if ($f6c31cce2adf654f$var$isOverTarget(e, state.target)) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType); else if (state.isOverTarget) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false); state.isPressed = false; state.isOverTarget = false; state.activePointerId = null; state.pointerType = null; removeAllGlobalListeners(); if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)(state.target); } }; let onPointerCancel = (e)=>{ cancel(e); }; pressProps.onDragStart = (e)=>{ if (!e.currentTarget.contains(e.target)) return; // Safari does not call onPointerCancel when a drag starts, whereas Chrome and Firefox do. cancel(e); }; } else { pressProps.onMouseDown = (e)=>{ // Only handle left clicks if (e.button !== 0 || !e.currentTarget.contains(e.target)) return; // Due to browser inconsistencies, especially on mobile browsers, we prevent // default on mouse down and handle focusing the pressable element ourselves. if ($f6c31cce2adf654f$var$shouldPreventDefault(e.currentTarget)) e.preventDefault(); e.stopPropagation(); if (state.ignoreEmulatedMouseEvents) return; state.isPressed = true; state.isOverTarget = true; state.target = e.currentTarget; state.pointerType = (0, $bx7SL$isVirtualClick)(e.nativeEvent) ? "virtual" : "mouse"; if (!isDisabled && !preventFocusOnPress) (0, $bx7SL$focusWithoutScrolling)(e.currentTarget); triggerPressStart(e, state.pointerType); addGlobalListener(document, "mouseup", onMouseUp, false); }; pressProps.onMouseEnter = (e)=>{ if (!e.currentTarget.contains(e.target)) return; e.stopPropagation(); if (state.isPressed && !state.ignoreEmulatedMouseEvents) { state.isOverTarget = true; triggerPressStart(e, state.pointerType); } }; pressProps.onMouseLeave = (e)=>{ if (!e.currentTarget.contains(e.target)) return; e.stopPropagation(); if (state.isPressed && !state.ignoreEmulatedMouseEvents) { state.isOverTarget = false; triggerPressEnd(e, state.pointerType, false); if (propsRef.current.shouldCancelOnPointerExit) cancel(e); } }; pressProps.onMouseUp = (e)=>{ if (!e.currentTarget.contains(e.target)) return; if (!state.ignoreEmulatedMouseEvents && e.button === 0) triggerPressUp(e, state.pointerType); }; let onMouseUp = (e)=>{ // Only handle left clicks if (e.button !== 0) return; state.isPressed = false; removeAllGlobalListeners(); if (state.ignoreEmulatedMouseEvents) { state.ignoreEmulatedMouseEvents = false; return; } if ($f6c31cce2adf654f$var$isOverTarget(e, state.target)) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType); else if (state.isOverTarget) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false); state.isOverTarget = false; }; pressProps.onTouchStart = (e)=>{ if (!e.currentTarget.contains(e.target)) return; e.stopPropagation(); let touch = $f6c31cce2adf654f$var$getTouchFromEvent(e.nativeEvent); if (!touch) return; state.activePointerId = touch.identifier; state.ignoreEmulatedMouseEvents = true; state.isOverTarget = true; state.isPressed = true; state.target = e.currentTarget; state.pointerType = "touch"; // Due to browser inconsistencies, especially on mobile browsers, we prevent default // on the emulated mouse event and handle focusing the pressable element ourselves. if (!isDisabled && !preventFocusOnPress) (0, $bx7SL$focusWithoutScrolling)(e.currentTarget); if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$16a4697467175487)(state.target); triggerPressStart(e, state.pointerType); addGlobalListener(window, "scroll", onScroll, true); }; pressProps.onTouchMove = (e)=>{ if (!e.currentTarget.contains(e.target)) return; e.stopPropagation(); if (!state.isPressed) return; let touch = $f6c31cce2adf654f$var$getTouchById(e.nativeEvent, state.activePointerId); if (touch && $f6c31cce2adf654f$var$isOverTarget(touch, e.currentTarget)) { if (!state.isOverTarget) { state.isOverTarget = true; triggerPressStart(e, state.pointerType); } } else if (state.isOverTarget) { state.isOverTarget = false; triggerPressEnd(e, state.pointerType, false); if (propsRef.current.shouldCancelOnPointerExit) cancel(e); } }; pressProps.onTouchEnd = (e)=>{ if (!e.currentTarget.contains(e.target)) return; e.stopPropagation(); if (!state.isPressed) return; let touch = $f6c31cce2adf654f$var$getTouchById(e.nativeEvent, state.activePointerId); if (touch && $f6c31cce2adf654f$var$isOverTarget(touch, e.currentTarget)) { triggerPressUp(e, state.pointerType); triggerPressEnd(e, state.pointerType); } else if (state.isOverTarget) triggerPressEnd(e, state.pointerType, false); state.isPressed = false; state.activePointerId = null; state.isOverTarget = false; state.ignoreEmulatedMouseEvents = true; if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)(state.target); removeAllGlobalListeners(); }; pressProps.onTouchCancel = (e)=>{ if (!e.currentTarget.contains(e.target)) return; e.stopPropagation(); if (state.isPressed) cancel(e); }; let onScroll = (e)=>{ if (state.isPressed && e.target.contains(state.target)) cancel({ currentTarget: state.target, shiftKey: false, ctrlKey: false, metaKey: false, altKey: false }); }; pressProps.onDragStart = (e)=>{ if (!e.currentTarget.contains(e.target)) return; cancel(e); }; } return pressProps; }, [ addGlobalListener, isDisabled, preventFocusOnPress, removeAllGlobalListeners, allowTextSelectionOnPress ]); // Remove user-select: none in case component unmounts immediately after pressStart // eslint-disable-next-line arrow-body-style (0, $bx7SL$useEffect)(()=>{ return ()=>{ if (!allowTextSelectionOnPress) // eslint-disable-next-line react-hooks/exhaustive-deps (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)(ref.current.target); }; }, [ allowTextSelectionOnPress ]); return { isPressed: isPressedProp || isPressed, pressProps: (0, $bx7SL$mergeProps)(domProps, pressProps) }; } function $f6c31cce2adf654f$var$isHTMLAnchorLink(target) { return target.tagName === "A" && target.hasAttribute("href"); } function $f6c31cce2adf654f$var$isValidKeyboardEvent(event, currentTarget) { const { key: key , code: code } = event; const element = currentTarget; const role = element.getAttribute("role"); // Accessibility for keyboards. Space and Enter only. // "Spacebar" is for IE 11 return (key === "Enter" || key === " " || key === "Spacebar" || code === "Space") && !(element instanceof HTMLInputElement && !$f6c31cce2adf654f$var$isValidInputKey(element, key) || element instanceof HTMLTextAreaElement || element.isContentEditable) && // A link with a valid href should be handled natively, // unless it also has role='button' and was triggered using Space. (!$f6c31cce2adf654f$var$isHTMLAnchorLink(element) || role === "button" && key !== "Enter") && // An element with role='link' should only trigger with Enter key !(role === "link" && key !== "Enter"); } function $f6c31cce2adf654f$var$getTouchFromEvent(event) { const { targetTouches: targetTouches } = event; if (targetTouches.length > 0) return targetTouches[0]; return null; } function $f6c31cce2adf654f$var$getTouchById(event, pointerId) { const changedTouches = event.changedTouches; for(let i = 0; i < changedTouches.length; i++){ const touch = changedTouches[i]; if (touch.identifier === pointerId) return touch; } return null; } function $f6c31cce2adf654f$var$createEvent(target, e) { return { currentTarget: target, shiftKey: e.shiftKey, ctrlKey: e.ctrlKey, metaKey: e.metaKey, altKey: e.altKey }; } function $f6c31cce2adf654f$var$getPointClientRect(point) { let offsetX = point.width / 2 || point.radiusX || 0; let offsetY = point.height / 2 || point.radiusY || 0; return { top: point.clientY - offsetY, right: point.clientX + offsetX, bottom: point.clientY + offsetY, left: point.clientX - offsetX }; } function $f6c31cce2adf654f$var$areRectanglesOverlapping(a, b) { // check if they cannot overlap on x axis if (a.left > b.right || b.left > a.right) return false; // check if they cannot overlap on y axis if (a.top > b.bottom || b.top > a.bottom) return false; return true; } function $f6c31cce2adf654f$var$isOverTarget(point, target) { let rect = target.getBoundingClientRect(); let pointRect = $f6c31cce2adf654f$var$getPointClientRect(point); return $f6c31cce2adf654f$var$areRectanglesOverlapping(rect, pointRect); } function $f6c31cce2adf654f$var$shouldPreventDefault(target) { // We cannot prevent default if the target is a draggable element. return !(target instanceof HTMLElement) || !target.draggable; } function $f6c31cce2adf654f$var$shouldPreventDefaultKeyboard(target, key) { if (target instanceof HTMLInputElement) return !$f6c31cce2adf654f$var$isValidInputKey(target, key); if (target instanceof HTMLButtonElement) return target.type !== "submit"; return true; } const $f6c31cce2adf654f$var$nonTextInputTypes = new Set([ "checkbox", "radio", "range", "color", "file", "image", "button", "submit", "reset" ]); function $f6c31cce2adf654f$var$isValidInputKey(target, key) { // Only space should toggle checkboxes and radios, not enter. return target.type === "checkbox" || target.type === "radio" ? key === " " : $f6c31cce2adf654f$var$nonTextInputTypes.has(target.type); } const $3b117e43dc0ca95d$export$27c701ed9e449e99 = /*#__PURE__*/ (0, $bx7SL$react).forwardRef(({ children: children , ...props }, ref)=>{ let newRef = (0, $bx7SL$useRef)(); ref = ref !== null && ref !== void 0 ? ref : newRef; let { pressProps: pressProps } = (0, $f6c31cce2adf654f$export$45712eceda6fad21)({ ...props, ref: ref }); let child = (0, $bx7SL$react).Children.only(children); return /*#__PURE__*/ (0, $bx7SL$react).cloneElement(child, // @ts-ignore { ref: ref, ...(0, $bx7SL$mergeProps)(child.props, pressProps) }); }); /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ const $f1ab8c75478c6f73$export$3351871ee4b288b8 = /*#__PURE__*/ (0, $bx7SL$react).forwardRef(({ children: children , ...props }, ref)=>{ let isRegistered = (0, $bx7SL$useRef)(false); let prevContext = (0, $bx7SL$useContext)((0, $ae1eeba8b9eafd08$export$5165eccb35aaadb5)); let context = (0, $bx7SL$mergeProps)(prevContext || {}, { ...props, ref: ref || (prevContext === null || prevContext === void 0 ? void 0 : prevContext.ref), register () { isRegistered.current = true; if (prevContext) prevContext.register(); } }); (0, $bx7SL$useSyncRef)(prevContext, ref); (0, $bx7SL$useEffect)(()=>{ if (!isRegistered.current) console.warn("A PressResponder was rendered without a pressable child. Either call the usePress hook, or wrap your DOM node with <Pressable> component."); }, []); return /*#__PURE__*/ (0, $bx7SL$react).createElement((0, $ae1eeba8b9eafd08$export$5165eccb35aaadb5).Provider, { value: context }, children); }); /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ // Portions of the code in this file are based on code from react. // Original licensing for the following can be found in the // NOTICE file in the root directory of this source tree. // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ class $8a9cb279dc87e130$export$905e7fc544a71f36 { isDefaultPrevented() { return this.nativeEvent.defaultPrevented; } preventDefault() { this.defaultPrevented = true; this.nativeEvent.preventDefault(); } stopPropagation() { this.nativeEvent.stopPropagation(); this.isPropagationStopped = ()=>true; } isPropagationStopped() { return false; } persist() {} constructor(type, nativeEvent){ this.nativeEvent = nativeEvent; this.target = nativeEvent.target; this.currentTarget = nativeEvent.currentTarget; this.relatedTarget = nativeEvent.relatedTarget; this.bubbles = nativeEvent.bubbles; this.cancelable = nativeEvent.cancelable; this.defaultPrevented = nativeEvent.defaultPrevented; this.eventPhase = nativeEvent.eventPhase; this.isTrusted = nativeEvent.isTrusted; this.timeStamp = nativeEvent.timeStamp; this.type = type; } } function $8a9cb279dc87e130$export$715c682d09d639cc(onBlur) { let stateRef = (0, $bx7SL$useRef)({ isFocused: false, onBlur: onBlur, observer: null }); stateRef.current.onBlur = onBlur; // Clean up MutationObserver on unmount. See below. // eslint-disable-next-line arrow-body-style (0, $bx7SL$useLayoutEffect)(()=>{ const state = stateRef.current; return ()=>{ if (state.observer) { state.observer.disconnect(); state.observer = null; } }; }, []); // This function is called during a React onFocus event. return (0, $bx7SL$useCallback)((e)=>{ // React does not fire onBlur when an element is disabled. https://github.com/facebook/react/issues/9142 // Most browsers fire a native focusout event in this case, except for Firefox. In that case, we use a // MutationObserver to watch for the disabled attribute, and dispatch these events ourselves. // For browsers that do, focusout fires before the MutationObserver, so onBlur should not fire twice. if (e.target instanceof HTMLButtonElement || e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement) { stateRef.current.isFocused = true; let target = e.target; let onBlurHandler = (e)=>{ var // For backward compatibility, dispatch a (fake) React synthetic event. _stateRef_current, _stateRef_current_onBlur; stateRef.current.isFocused = false; if (target.disabled) (_stateRef_current_onBlur = (_stateRef_current = stateRef.current).onBlur) === null || _stateRef_current_onBlur === void 0 ? void 0 : _stateRef_current_onBlur.call(_stateRef_current, new $8a9cb279dc87e130$export$905e7fc544a71f36("blur", e)); // We no longer need the MutationObserver once the target is blurred. if (stateRef.current.observer) { stateRef.current.observer.disconnect(); stateRef.current.observer = null; } }; target.addEventListener("focusout", onBlurHandler, { once: true }); stateRef.current.observer = new MutationObserver(()=>{ if (stateRef.current.isFocused && target.disabled) { stateRef.current.observer.disconnect(); target.dispatchEvent(new FocusEvent("blur")); target.dispatchEvent(new FocusEvent("focusout", { bubbles: true })); } }); stateRef.current.observer.observe(target, { attributes: true, attributeFilter: [ "disabled" ] }); } }, []); } function $a1ea59d68270f0dd$export$f8168d8dd8fd66e6(props) { let { isDisabled: isDisabled , onFocus: onFocusProp , onBlur: onBlurProp , onFocusChange: onFocusChange } = props; const onBlur = (0, $bx7SL$useCallback)((e)=>{ if (e.target === e.currentTarget) { if (onBlurProp) onBlurProp(e); if (onFocusChange) onFocusChange(false); return true; } }, [ onBlurProp, onFocusChange ]); const onSyntheticFocus = (0, $8a9cb279dc87e130$export$715c682d09d639cc)(onBlur); const onFocus = (0, $bx7SL$useCallback)((e)=>{ if (e.target === e.currentTarget) { if (onFocusProp) onFocusProp(e); if (onFocusChange) onFocusChange(true); onSyntheticFocus(e); } }, [ onFocusChange, onFocusProp, onSyntheticFocus ]); return { focusProps: { onFocus: !isDisabled && (onFocusProp || onFocusChange || onBlurProp) ? onFocus : undefined, onBlur: !isDisabled && (onBlurProp || onFocusChange) ? onBlur : undefined } }; } /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ // Portions of the code in this file are based on code from react. // Original licensing for the following can be found in the // NOTICE file in the root directory of this source tree. // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions let $507fabe10e71c6fb$var$currentModality = null; let $507fabe10e71c6fb$var$changeHandlers = new Set(); let $507fabe10e71c6fb$var$hasSetupGlobalListeners = false; let $507fabe10e71c6fb$var$hasEventBeforeFocus = false; let $507fabe10e71c6fb$var$hasBlurredWindowRecently = false; // Only Tab or Esc keys will make focus visible on text input elements const $507fabe10e71c6fb$var$FOCUS_VISIBLE_INPUT_KEYS = { Tab: true, Escape: true }; function $507fabe10e71c6fb$var$triggerChangeHandlers(modality, e) { for (let handler of $507fabe10e71c6fb$var$changeHandlers)handler(modality, e); } /** * Helper function to determine if a KeyboardEvent is unmodified and could make keyboard focus styles visible. */ function $507fabe10e71c6fb$var$isValidKey(e) { // Control and Shift keys trigger when navigating back to the tab with keyboard. return !(e.metaKey || !(0, $bx7SL$isMac)() && e.altKey || e.ctrlKey || e.key === "Control" || e.key === "Shift" || e.key === "Meta"); } function $507fabe10e71c6fb$var$handleKeyboardEvent(e) { $507fabe10e71c6fb$var$hasEventBeforeFocus = true; if ($507fabe10e71c6fb$var$isValidKey(e)) { $507fabe10e71c6fb$var$currentModality = "keyboard"; $507fabe10e71c6fb$var$triggerChangeHandlers("keyboard", e); } } function $507fabe10e71c6fb$var$handlePointerEvent(e) { $507fabe10e71c6fb$var$currentModality = "pointer"; if (e.type === "mousedown" || e.type === "pointerdown") { $507fabe10e71c6fb$var$hasEventBeforeFocus = true; $507fabe10e71c6fb$var$triggerChangeHandlers("pointer", e); } } function $507fabe10e71c6fb$var$handleClickEvent(e) { if ((0, $bx7SL$isVirtualClick)(e)) { $507fabe10e71c6fb$var$hasEventBeforeFocus = true; $507fabe10e71c6fb$var$currentModality = "virtual"; } } function $507fabe10e71c6fb$var$handleFocusEvent(e) { // Firefox fires two extra focus events when the user first clicks into an iframe: // first on the window, then on the document. We ignore these events so they don't // cause keyboard focus rings to appear. if (e.target === window || e.target === document) return; // If a focus event occurs without a preceding keyboard or pointer event, switch to virtual modality. // This occurs, for example, when navigating a form with the next/previous buttons on iOS. if (!$507fabe10e71c6fb$var$hasEventBeforeFocus && !$507fabe10e71c6fb$var$hasBlurredWindowRecently) { $507fabe10e71c6fb$var$currentModality = "virtual"; $507fabe10e71c6fb$var$triggerChangeHandlers("virtual", e); } $507fabe10e71c6fb$var$hasEventBeforeFocus = false; $507fabe10e71c6fb$var$hasBlurredWindowRecently = false; } function $507fabe10e71c6fb$var$handleWindowBlur() { // When the window is blurred, reset state. This is necessary when tabbing out of the window, // for example, since a subsequent focus event won't be fired. $507fabe10e71c6fb$var$hasEventBeforeFocus = false; $507fabe10e71c6fb$var$hasBlurredWindowRecently = true; } /** * Setup global event listeners to control when keyboard focus style should be visible. */ function $507fabe10e71c6fb$var$setupGlobalFocusEvents() { if (typeof window === "undefined" || $507fabe10e71c6fb$var$hasSetupGlobalListeners) return; // Programmatic focus() calls shouldn't affect the current input modality. // However, we need to detect other cases when a focus event occurs without // a preceding user event (e.g. screen reader focus). Overriding the focus // method on HTMLElement.prototype is a bit hacky, but works. let focus = HTMLElement.prototype.focus; HTMLElement.prototype.focus = function() { $507fabe10e71c6fb$var$hasEventBeforeFocus = true; focus.apply(this, arguments); }; document.addEventListener("keydown", $507fabe10e71c6fb$var$handleKeyboardEvent, true); document.addEventListener("keyup", $507fabe10e71c6fb$var$handleKeyboardEvent, true); document.addEventListener("click", $507fabe10e71c6fb$var$handleClickEvent, true); // Register focus events on the window so they are sure to happen // before React's event listeners (registered on the document). window.addEventListener("focus", $507fabe10e71c6fb$var$handleFocusEvent, true); window.addEventListener("blur", $507fabe10e71c6fb$var$handleWindowBlur, false); if (typeof PointerEvent !== "undefined") { document.addEventListener("pointerdown", $507fabe10e71c6fb$var$handlePointerEvent, true); document.addEventListener("pointermove", $507fabe10e71c6fb$var$handlePointerEvent, true); document.addEventListener("pointerup", $507fabe10e71c6fb$var$handlePointerEvent, true); } else { document.addEventListener("mousedown", $507fabe10e71c6fb$var$handlePointerEvent, true); document.addEventListener("mousemove", $507fabe10e71c6fb$var$handlePointerEvent, true); document.addEventListener("mouseup", $507fabe10e71c6fb$var$handlePointerEvent, true); } $507fabe10e71c6fb$var$hasSetupGlobalListeners = true; } if (typeof document !== "undefined") { if (document.readyState !== "loading") $507fabe10e71c6fb$var$setupGlobalFocusEvents(); else document.addEventListener("DOMContentLoaded", $507fabe10e71c6fb$var$setupGlobalFocusEvents); } function $507fabe10e71c6fb$export$b9b3dfddab17db27() { return $507fabe10e71c6fb$var$currentModality !== "pointer"; } function $507fabe10e71c6fb$export$630ff653c5ada6a9() { return $507fabe10e71c6fb$var$currentModality; } function $507fabe10e71c6fb$export$8397ddfc504fdb9a(modality) { $507fabe10e71c6fb$var$currentModality = modality; $507fabe10e71c6fb$var$triggerChangeHandlers(modality, null); } function $507fabe10e71c6fb$export$98e20ec92f614cfe() { $507fabe10e71c6fb$var$setupGlobalFocusEvents(); let [modality, setModality] = (0, $bx7SL$useState)($507fabe10e71c6fb$var$currentModality); (0, $bx7SL$useEffect)(()=>{ let handler = ()=>{ setModality($507fabe10e71c6fb$var$currentModality); }; $507fabe10e71c6fb$var$changeHandlers.add(handler); return ()=>{ $507fabe10e71c6fb$var$changeHandlers.delete(handler); }; }, []); return modality; } /** * If this is attached to text input component, return if the event is a focus event (Tab/Escape keys pressed) so that * focus visible style can be properly set. */ function $507fabe10e71c6fb$var$isKeyboardFocusEvent(isTextInput, modality, e) { return !(isTextInput && modality === "keyboard" && e instanceof KeyboardEvent && !$507fabe10e71c6fb$var$FOCUS_VISIBLE_INPUT_KEYS[e.key]); } function $507fabe10e71c6fb$export$ffd9e5021c1fb2d6(props = {}) { let { isTextInput: isTextInput , autoFocus: autoFocus } = props; let [isFocusVisibleState, setFocusVisible] = (0, $bx7SL$useState)(autoFocus || $507fabe10e71c6fb$export$b9b3dfddab17db27()); $507fabe10e71c6fb$export$ec71b4b83ac08ec3((isFocusVisible)=>{ setFocusVisible(isFocusVisible); }, [ isTextInput ], { isTextInput: isTextInput }); return { isFocusVisible: isFocusVisibleState }; } function $507fabe10e71c6fb$export$ec71b4b83ac08ec3(fn, deps, opts) { $507fabe10e71c6fb$var$setupGlobalFocusEvents(); (0, $bx7SL$useEffect)(()=>{ let handler = (modality, e)=>{ if (!$507fabe10e71c6fb$var$isKeyboardFocusEvent(opts === null || opts === void 0 ? void 0 : opts.isTextInput, modality, e)) return; fn($507fabe10e71c6fb$export$b9b3dfddab17db27()); }; $507fabe10e71c6fb$var$changeHandlers.add(handler); return ()=>{ $507fabe10e71c6fb$var$changeHandlers.delete(handler); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); } /* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You