@react-aria/interactions
Advanced tools
Comparing version 3.0.0-rc.1 to 3.0.0-rc.2
722
dist/main.js
@@ -1,5 +0,10 @@ | ||
var _babelRuntimeHelpersEsmSlicedToArray = $parcel$interopDefault(require("@babel/runtime/helpers/esm/slicedToArray")); | ||
var _babelRuntimeHelpersSlicedToArray = $parcel$interopDefault(require("@babel/runtime/helpers/slicedToArray")); | ||
var _babelRuntimeHelpersEsmObjectWithoutProperties = $parcel$interopDefault(require("@babel/runtime/helpers/esm/objectWithoutProperties")); | ||
var _babelRuntimeHelpersObjectWithoutProperties = $parcel$interopDefault(require("@babel/runtime/helpers/objectWithoutProperties")); | ||
var _temp = require("@react-aria/utils"); | ||
var focusWithoutScrolling = _temp.focusWithoutScrolling; | ||
var mergeProps = _temp.mergeProps; | ||
var _react2 = require("react"); | ||
@@ -15,6 +20,4 @@ | ||
var mergeProps = require("@react-aria/utils").mergeProps; | ||
var _babelRuntimeHelpersObjectSpread = $parcel$interopDefault(require("@babel/runtime/helpers/objectSpread2")); | ||
var _babelRuntimeHelpersEsmObjectSpread = $parcel$interopDefault(require("@babel/runtime/helpers/esm/objectSpread2")); | ||
function $parcel$interopDefault(a) { | ||
@@ -26,2 +29,4 @@ return a && a.__esModule ? a.default : a; | ||
$f0c946772fda863393a370b793f7614$export$PressResponderContext.displayName = 'PressResponderContext'; | ||
function $d96e234a33d0fc61c9867cbf1a711$var$usePressResponderContext(props) { | ||
@@ -33,3 +38,3 @@ // Consume context from <PressResponder> and merge with props. | ||
var register = context.register, | ||
contextProps = _babelRuntimeHelpersEsmObjectWithoutProperties(context, ["register"]); | ||
contextProps = _babelRuntimeHelpersObjectWithoutProperties(context, ["register"]); | ||
@@ -58,9 +63,10 @@ props = mergeProps(contextProps, props); | ||
onPressEnd = _usePressResponderCon.onPressEnd, | ||
onPressUp = _usePressResponderCon.onPressUp, | ||
isDisabled = _usePressResponderCon.isDisabled, | ||
isPressedProp = _usePressResponderCon.isPressed, | ||
_ = _usePressResponderCon.ref, | ||
domProps = _babelRuntimeHelpersEsmObjectWithoutProperties(_usePressResponderCon, ["onPress", "onPressChange", "onPressStart", "onPressEnd", "isDisabled", "isPressed", "ref"]); | ||
domProps = _babelRuntimeHelpersObjectWithoutProperties(_usePressResponderCon, ["onPress", "onPressChange", "onPressStart", "onPressEnd", "onPressUp", "isDisabled", "isPressed", "ref"]); | ||
var _useState = useState(false), | ||
_useState2 = _babelRuntimeHelpersEsmSlicedToArray(_useState, 2), | ||
_useState2 = _babelRuntimeHelpersSlicedToArray(_useState, 2), | ||
isPressed = _useState2[0], | ||
@@ -72,2 +78,3 @@ setPressed = _useState2[1]; | ||
ignoreEmulatedMouseEvents: false, | ||
ignoreClickAfterPress: false, | ||
activePointerId: null, | ||
@@ -89,3 +96,3 @@ target: null, | ||
pointerType: pointerType, | ||
target: originalEvent.target, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
@@ -111,2 +118,4 @@ metaKey: originalEvent.metaKey, | ||
state.ignoreClickAfterPress = true; | ||
if (onPressEnd) { | ||
@@ -116,3 +125,3 @@ onPressEnd({ | ||
pointerType: pointerType, | ||
target: originalEvent.target, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
@@ -134,3 +143,3 @@ metaKey: originalEvent.metaKey, | ||
pointerType: pointerType, | ||
target: originalEvent.target, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
@@ -143,17 +152,65 @@ metaKey: originalEvent.metaKey, | ||
var triggerPressUp = function triggerPressUp(originalEvent, pointerType) { | ||
if (isDisabled) { | ||
return; | ||
} | ||
if (onPressUp) { | ||
onPressUp({ | ||
type: 'pressup', | ||
pointerType: pointerType, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
metaKey: originalEvent.metaKey, | ||
ctrlKey: originalEvent.ctrlKey | ||
}); | ||
} | ||
}; | ||
var pressProps = { | ||
onKeyDown: function onKeyDown(e) { | ||
if (!state.isPressed && $d96e234a33d0fc61c9867cbf1a711$var$isValidKeyboardEvent(e.nativeEvent)) { | ||
if ($d96e234a33d0fc61c9867cbf1a711$var$isValidKeyboardEvent(e.nativeEvent)) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
state.isPressed = true; | ||
triggerPressStart(e, 'keyboard'); | ||
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. | ||
document.addEventListener('keyup', onKeyUp, false); | ||
} | ||
} | ||
}, | ||
onKeyUp: function onKeyUp(e) { | ||
if (state.isPressed && $d96e234a33d0fc61c9867cbf1a711$var$isValidKeyboardEvent(e.nativeEvent)) { | ||
e.preventDefault(); | ||
if ($d96e234a33d0fc61c9867cbf1a711$var$isValidKeyboardEvent(e.nativeEvent) && !e.repeat) { | ||
triggerPressUp($d96e234a33d0fc61c9867cbf1a711$var$createEvent(state.target, e), 'keyboard'); | ||
} | ||
}, | ||
onClick: function onClick(e) { | ||
if (e && e.button === 0) { | ||
e.stopPropagation(); | ||
state.isPressed = false; | ||
triggerPressEnd(e, 'keyboard'); | ||
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 && $d96e234a33d0fc61c9867cbf1a711$var$isVirtualClick(e.nativeEvent)) { | ||
// Ensure the element receives focus (VoiceOver on iOS does not do this) | ||
if (!isDisabled) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
triggerPressStart(e, 'virtual'); | ||
triggerPressUp(e, 'virtual'); | ||
triggerPressEnd(e, 'virtual'); | ||
} | ||
state.ignoreEmulatedMouseEvents = false; | ||
state.ignoreClickAfterPress = false; | ||
} | ||
@@ -163,4 +220,48 @@ } | ||
var onKeyUp = function onKeyUp(e) { | ||
if (state.isPressed && $d96e234a33d0fc61c9867cbf1a711$var$isValidKeyboardEvent(e)) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
state.isPressed = false; | ||
triggerPressEnd($d96e234a33d0fc61c9867cbf1a711$var$createEvent(state.target, e), 'keyboard', e.target === state.target); | ||
document.removeEventListener('keyup', onKeyUp, false); // If the target is a link, trigger the click method to open the URL, | ||
// but defer triggering pressEnd until onClick event handler. | ||
if (e.target === state.target && $d96e234a33d0fc61c9867cbf1a711$var$isHTMLAnchorLink(state.target) || state.target.getAttribute('role') === 'link') { | ||
state.target.click(); | ||
} | ||
} | ||
}; // Safari on iOS starts selecting text on long press. The only way to avoid this, it seems, | ||
// is to add user-select: none to the entire page. Adding it to the pressable element prevents | ||
// that element from being selected, but nearby elements may still receive selection. We add | ||
// user-select: none on touch start, and remove it again on touch end to prevent this. | ||
var disableTextSelection = function disableTextSelection() { | ||
state.userSelect = document.documentElement.style.webkitUserSelect; | ||
document.documentElement.style.webkitUserSelect = 'none'; | ||
}; | ||
var restoreTextSelection = function restoreTextSelection() { | ||
// 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(function () { | ||
// Avoid race conditions | ||
if (!state.isPressed && document.documentElement.style.webkitUserSelect === 'none') { | ||
document.documentElement.style.webkitUserSelect = state.userSelect || ''; | ||
state.userSelect = null; | ||
} | ||
}, 300); | ||
}; | ||
if (typeof PointerEvent !== 'undefined') { | ||
pressProps.onPointerDown = function (e) { | ||
// Only handle left clicks | ||
if (e.button !== 0) { | ||
return; | ||
} // Due to browser inconsistencies, especially on mobile browsers, we prevent | ||
// default on pointer down and handle focusing the pressable element ourselves. | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
@@ -173,2 +274,8 @@ | ||
state.target = e.currentTarget; | ||
if (!isDisabled) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
disableTextSelection(); | ||
triggerPressStart(e, e.pointerType); | ||
@@ -181,2 +288,11 @@ document.addEventListener('pointermove', onPointerMove, false); | ||
pressProps.onMouseDown = function (e) { | ||
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. | ||
e.preventDefault(); | ||
} | ||
}; | ||
var unbindEvents = function unbindEvents() { | ||
@@ -186,2 +302,11 @@ document.removeEventListener('pointermove', onPointerMove, false); | ||
document.removeEventListener('pointercancel', onPointerCancel, false); | ||
}; | ||
pressProps.onPointerUp = function (e) { | ||
// 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 && $d96e234a33d0fc61c9867cbf1a711$var$isOverTarget(e, e.currentTarget)) { | ||
triggerPressUp(e, e.pointerType); | ||
} | ||
}; // Safari on iOS < 13.2 does not implement pointerenter/pointerleave events correctly. | ||
@@ -197,5 +322,3 @@ // Use pointer move events instead to implement our own hit testing. | ||
var rect = state.target.getBoundingClientRect(); | ||
if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) { | ||
if ($d96e234a33d0fc61c9867cbf1a711$var$isOverTarget(e, state.target)) { | ||
if (!state.isOverTarget) { | ||
@@ -212,6 +335,4 @@ state.isOverTarget = true; | ||
var onPointerUp = function onPointerUp(e) { | ||
if (e.pointerId === state.activePointerId && state.isPressed) { | ||
var rect = state.target.getBoundingClientRect(); | ||
if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) { | ||
if (e.pointerId === state.activePointerId && state.isPressed && e.button === 0) { | ||
if ($d96e234a33d0fc61c9867cbf1a711$var$isOverTarget(e, state.target)) { | ||
triggerPressEnd($d96e234a33d0fc61c9867cbf1a711$var$createEvent(state.target, e), e.pointerType); | ||
@@ -226,2 +347,3 @@ } else if (state.isOverTarget) { | ||
unbindEvents(); | ||
restoreTextSelection(); | ||
} | ||
@@ -240,2 +362,3 @@ }; | ||
unbindEvents(); | ||
restoreTextSelection(); | ||
} | ||
@@ -245,6 +368,13 @@ }; | ||
pressProps.onMouseDown = function (e) { | ||
// Only handle left clicks | ||
if (e.button !== 0) { | ||
return; | ||
} // Due to browser inconsistencies, especially on mobile browsers, we prevent | ||
// default on mouse down and handle focusing the pressable element ourselves. | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
if (state.ignoreEmulatedMouseEvents) { | ||
e.nativeEvent.preventDefault(); | ||
return; | ||
@@ -254,3 +384,9 @@ } | ||
state.isPressed = true; | ||
state.isOverTarget = true; | ||
state.target = e.currentTarget; | ||
if (!isDisabled) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
triggerPressStart(e, 'mouse'); | ||
@@ -264,2 +400,3 @@ document.addEventListener('mouseup', onMouseUp, false); | ||
if (state.isPressed && !state.ignoreEmulatedMouseEvents) { | ||
state.isOverTarget = true; | ||
triggerPressStart(e, 'mouse'); | ||
@@ -273,2 +410,3 @@ } | ||
if (state.isPressed && !state.ignoreEmulatedMouseEvents) { | ||
state.isOverTarget = false; | ||
triggerPressEnd(e, 'mouse', false); | ||
@@ -278,7 +416,18 @@ } | ||
pressProps.onMouseUp = function (e) { | ||
if (!state.ignoreEmulatedMouseEvents && e.button === 0) { | ||
triggerPressUp(e, 'mouse'); | ||
} | ||
}; | ||
var onMouseUp = function onMouseUp(e) { | ||
// Only handle left clicks | ||
if (e.button !== 0) { | ||
return; | ||
} | ||
state.isPressed = false; | ||
document.removeEventListener('mouseup', onMouseUp, false); | ||
if (state.ignoreEmulatedMouseEvents || !state.target || !state.target.contains(e.target)) { | ||
if (state.ignoreEmulatedMouseEvents) { | ||
state.ignoreEmulatedMouseEvents = false; | ||
@@ -288,3 +437,9 @@ return; | ||
triggerPressEnd($d96e234a33d0fc61c9867cbf1a711$var$createEvent(state.target, e), 'mouse'); | ||
if ($d96e234a33d0fc61c9867cbf1a711$var$isOverTarget(e, state.target)) { | ||
triggerPressEnd($d96e234a33d0fc61c9867cbf1a711$var$createEvent(state.target, e), 'mouse'); | ||
} else if (state.isOverTarget) { | ||
triggerPressEnd($d96e234a33d0fc61c9867cbf1a711$var$createEvent(state.target, e), 'mouse', false); | ||
} | ||
state.isOverTarget = false; | ||
}; | ||
@@ -304,3 +459,12 @@ | ||
state.isPressed = true; | ||
state.target = e.currentTarget; // 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) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
disableTextSelection(); | ||
triggerPressStart(e, 'touch'); | ||
window.addEventListener('scroll', onScroll, true); | ||
}; | ||
@@ -310,6 +474,10 @@ | ||
e.stopPropagation(); | ||
var rect = e.currentTarget.getBoundingClientRect(); | ||
if (!state.isPressed) { | ||
return; | ||
} | ||
var touch = $d96e234a33d0fc61c9867cbf1a711$var$getTouchById(e.nativeEvent, state.activePointerId); | ||
if (touch && touch.clientX >= rect.left && touch.clientX <= rect.right && touch.clientY >= rect.top && touch.clientY <= rect.bottom) { | ||
if (touch && $d96e234a33d0fc61c9867cbf1a711$var$isOverTarget(touch, e.currentTarget)) { | ||
if (!state.isOverTarget) { | ||
@@ -327,6 +495,11 @@ state.isOverTarget = true; | ||
e.stopPropagation(); | ||
var rect = e.currentTarget.getBoundingClientRect(); | ||
if (!state.isPressed) { | ||
return; | ||
} | ||
var touch = $d96e234a33d0fc61c9867cbf1a711$var$getTouchById(e.nativeEvent, state.activePointerId); | ||
if (touch && touch.clientX >= rect.left && touch.clientX <= rect.right && touch.clientY >= rect.top && touch.clientY <= rect.bottom) { | ||
if (touch && $d96e234a33d0fc61c9867cbf1a711$var$isOverTarget(touch, e.currentTarget)) { | ||
triggerPressUp(e, 'touch'); | ||
triggerPressEnd(e, 'touch'); | ||
@@ -340,2 +513,5 @@ } else if (state.isOverTarget) { | ||
state.isOverTarget = false; | ||
state.ignoreEmulatedMouseEvents = true; | ||
restoreTextSelection(); | ||
window.removeEventListener('scroll', onScroll, true); | ||
}; | ||
@@ -347,19 +523,27 @@ | ||
if (state.isPressed) { | ||
if (state.isOverTarget) { | ||
triggerPressEnd(e, 'touch', false); | ||
} | ||
cancelTouchEvent(e, 'touch'); | ||
} | ||
}; | ||
state.isPressed = false; | ||
state.activePointerId = null; | ||
state.isOverTarget = false; | ||
var onScroll = function onScroll(e) { | ||
if (state.isPressed && e.target.contains(state.target)) { | ||
cancelTouchEvent({ | ||
currentTarget: state.target, | ||
shiftKey: false, | ||
ctrlKey: false, | ||
metaKey: false | ||
}, 'touch'); | ||
} | ||
}; | ||
pressProps.onClick = function (e) { | ||
e.stopPropagation(); | ||
state.ignoreEmulatedMouseEvents = false; | ||
var cancelTouchEvent = function cancelTouchEvent(e, pointerType) { | ||
if (state.isOverTarget) { | ||
triggerPressEnd(e, pointerType, false); | ||
} | ||
if (isDisabled) { | ||
e.preventDefault(); | ||
} | ||
state.isPressed = false; | ||
state.activePointerId = null; | ||
state.isOverTarget = false; | ||
restoreTextSelection(); | ||
window.removeEventListener('scroll', onScroll, true); | ||
}; | ||
@@ -369,3 +553,3 @@ } | ||
return pressProps; | ||
}, [onPress, onPressStart, onPressEnd, onPressChange, isDisabled]); | ||
}, [onPress, onPressStart, onPressEnd, onPressChange, onPressUp, isDisabled]); | ||
return { | ||
@@ -379,11 +563,35 @@ isPressed: isPressedProp || isPressed, | ||
function $d96e234a33d0fc61c9867cbf1a711$var$isHTMLAnchorLink(target) { | ||
return target.tagName === 'A' && target.hasAttribute('href'); | ||
} | ||
function $d96e234a33d0fc61c9867cbf1a711$var$isValidKeyboardEvent(event) { | ||
var key = event.key, | ||
target = event.target; | ||
var _ref = target, | ||
tagName = _ref.tagName, | ||
isContentEditable = _ref.isContentEditable; // Accessibility for keyboards. Space and Enter only. | ||
var element = target; | ||
var tagName = element.tagName, | ||
isContentEditable = element.isContentEditable; | ||
var role = element.getAttribute('role'); // Accessibility for keyboards. Space and Enter only. | ||
// "Spacebar" is for IE 11 | ||
return (key === 'Enter' || key === ' ' || key === 'Spacebar') && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && isContentEditable !== true; | ||
return (key === 'Enter' || key === ' ' || key === 'Spacebar') && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && isContentEditable !== true && ( // A link with a valid href should be handled natively, | ||
// unless it also has role='button' and was triggered using Space. | ||
!$d96e234a33d0fc61c9867cbf1a711$var$isHTMLAnchorLink(element) || role === 'button' && key !== 'Enter') && // An element with role='link' should only trigger with Enter key | ||
!(role === 'link' && key !== 'Enter'); | ||
} // Per: https://github.com/facebook/react/blob/3c713d513195a53788b3f8bb4b70279d68b15bcc/packages/react-interactions/events/src/dom/shared/index.js#L74-L87 | ||
// Keyboards, Assitive Technologies, and element.click() all produce a "virtual" | ||
// click event. This is a method of inferring such clicks. Every browser except | ||
// IE 11 only sets a zero value of "detail" for click events that are "virtual". | ||
// However, IE 11 uses a zero value for all click events. For IE 11 we rely on | ||
// the quirk that it produces click events that are of type PointerEvent, and | ||
// where only the "virtual" click lacks a pointerType field. | ||
function $d96e234a33d0fc61c9867cbf1a711$var$isVirtualClick(event) { | ||
// JAWS/NVDA with Firefox. | ||
if (event.mozInputSource === 0 && event.isTrusted) { | ||
return true; | ||
} | ||
return event.detail === 0 && !event.pointerType; | ||
} | ||
@@ -417,3 +625,3 @@ | ||
return { | ||
target: target, | ||
currentTarget: target, | ||
shiftKey: e.shiftKey, | ||
@@ -425,2 +633,7 @@ ctrlKey: e.ctrlKey, | ||
function $d96e234a33d0fc61c9867cbf1a711$var$isOverTarget(point, target) { | ||
var rect = target.getBoundingClientRect(); | ||
return (point.clientX || 0) >= (rect.left || 0) && (point.clientX || 0) <= (rect.right || 0) && (point.clientY || 0) >= (rect.top || 0) && (point.clientY || 0) <= (rect.bottom || 0); | ||
} | ||
function useInteractOutside(props) { | ||
@@ -430,2 +643,3 @@ var ref = props.ref, | ||
var stateRef = useRef({ | ||
isPointerDown: false, | ||
ignoreEmulatedMouseEvents: false | ||
@@ -435,6 +649,13 @@ }); | ||
useEffect(function () { | ||
// Use pointer events if available. Otherwise, fall back to mouse and touch events. | ||
var onPointerDown = function onPointerDown(e) { | ||
if ($d4a49544db7051e6fc4a9e0a16b$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = true; | ||
} | ||
}; // Use pointer events if available. Otherwise, fall back to mouse and touch events. | ||
if (typeof PointerEvent !== 'undefined') { | ||
var onPointerUp = function onPointerUp(e) { | ||
if (onInteractOutside && $d4a49544db7051e6fc4a9e0a16b$var$isValidEvent(e, ref)) { | ||
if (state.isPointerDown && onInteractOutside && $d4a49544db7051e6fc4a9e0a16b$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = false; | ||
onInteractOutside(e); | ||
@@ -444,4 +665,6 @@ } | ||
document.addEventListener('pointerdown', onPointerDown, false); | ||
document.addEventListener('pointerup', onPointerUp, false); | ||
return function () { | ||
document.removeEventListener('pointerdown', onPointerDown, false); | ||
document.removeEventListener('pointerup', onPointerUp, false); | ||
@@ -453,3 +676,4 @@ }; | ||
state.ignoreEmulatedMouseEvents = false; | ||
} else if (onInteractOutside && $d4a49544db7051e6fc4a9e0a16b$var$isValidEvent(e, ref)) { | ||
} else if (state.isPointerDown && onInteractOutside && $d4a49544db7051e6fc4a9e0a16b$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = false; | ||
onInteractOutside(e); | ||
@@ -462,3 +686,4 @@ } | ||
if (onInteractOutside && $d4a49544db7051e6fc4a9e0a16b$var$isValidEvent(e, ref)) { | ||
if (onInteractOutside && state.isPointerDown && $d4a49544db7051e6fc4a9e0a16b$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = false; | ||
onInteractOutside(e); | ||
@@ -468,10 +693,14 @@ } | ||
document.addEventListener('mousedown', onPointerDown, false); | ||
document.addEventListener('mouseup', onMouseUp, false); | ||
document.addEventListener('touchstart', onPointerDown, false); | ||
document.addEventListener('touchend', onTouchEnd, false); | ||
return function () { | ||
document.removeEventListener('mousedown', onPointerDown, false); | ||
document.removeEventListener('mouseup', onMouseUp, false); | ||
document.removeEventListener('touchstart', onPointerDown, false); | ||
document.removeEventListener('touchend', onTouchEnd, false); | ||
}; | ||
} | ||
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents]); | ||
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents, state.isPointerDown]); | ||
} | ||
@@ -491,7 +720,7 @@ | ||
var children = _ref.children, | ||
props = _babelRuntimeHelpersEsmObjectWithoutProperties(_ref, ["children"]); | ||
props = _babelRuntimeHelpersObjectWithoutProperties(_ref, ["children"]); | ||
ref = ref || useRef(); | ||
var _usePress = usePress(_babelRuntimeHelpersEsmObjectSpread({}, props, { | ||
var _usePress = usePress(_babelRuntimeHelpersObjectSpread({}, props, { | ||
ref: ref | ||
@@ -504,3 +733,3 @@ })), | ||
return _react.cloneElement(child, // @ts-ignore | ||
_babelRuntimeHelpersEsmObjectSpread({ | ||
_babelRuntimeHelpersObjectSpread({ | ||
ref: ref | ||
@@ -514,7 +743,7 @@ }, mergeProps(child.props, pressProps))); | ||
var children = _ref.children, | ||
props = _babelRuntimeHelpersEsmObjectWithoutProperties(_ref, ["children"]); | ||
props = _babelRuntimeHelpersObjectWithoutProperties(_ref, ["children"]); | ||
var isRegistered = useRef(false); | ||
var context = _babelRuntimeHelpersEsmObjectSpread({}, props, { | ||
var context = _babelRuntimeHelpersObjectSpread({}, props, { | ||
ref: ref, | ||
@@ -531,5 +760,6 @@ register: function register() { | ||
}, []); | ||
return _react.createElement($f0c946772fda863393a370b793f7614$export$PressResponderContext.Provider, { | ||
value: context | ||
}, children); | ||
return (/*#__PURE__*/_react.createElement($f0c946772fda863393a370b793f7614$export$PressResponderContext.Provider, { | ||
value: context | ||
}, children) | ||
); | ||
}); | ||
@@ -544,2 +774,3 @@ | ||
* 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 | ||
@@ -558,3 +789,3 @@ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
return function (e) { | ||
var event = _babelRuntimeHelpersEsmObjectSpread({}, e, { | ||
var event = _babelRuntimeHelpersObjectSpread({}, e, { | ||
preventDefault: function preventDefault() { | ||
@@ -657,39 +888,31 @@ e.preventDefault(); | ||
var onFocus, onBlur; | ||
var onFocus = $d3f751924ed6dd36b5df9e3d348e5194$export$createEventHandler(function (e) { | ||
if (props.onFocusWithin) { | ||
props.onFocusWithin(e); | ||
} | ||
if (props.onFocusWithin || props.onFocusWithinChange) { | ||
onFocus = $d3f751924ed6dd36b5df9e3d348e5194$export$createEventHandler(function (e) { | ||
if (props.onFocusWithin) { | ||
props.onFocusWithin(e); | ||
if (!state.isFocusWithin) { | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(true); | ||
} | ||
if (!state.isFocusWithin) { | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(true); | ||
} | ||
state.isFocusWithin = true; | ||
state.isFocusWithin = true; | ||
} | ||
}); | ||
var onBlur = $d3f751924ed6dd36b5df9e3d348e5194$export$createEventHandler(function (e) { | ||
// We don't want to trigger onBlurWithin and then immediately onFocusWithin again | ||
// when moving focus inside the element. Only trigger if the currentTarget doesn't | ||
// include the relatedTarget (where focus is moving). | ||
if (state.isFocusWithin && !e.currentTarget.contains(e.relatedTarget)) { | ||
if (props.onBlurWithin) { | ||
props.onBlurWithin(e); | ||
} | ||
}); | ||
} | ||
if (props.onBlurWithin || props.onFocusWithinChange) { | ||
onBlur = $d3f751924ed6dd36b5df9e3d348e5194$export$createEventHandler(function (e) { | ||
// We don't want to trigger onBlurWithin and then immediately onFocusWithin again | ||
// when moving focus inside the element. Only trigger if the currentTarget doesn't | ||
// include the relatedTarget (where focus is moving). | ||
if (state.isFocusWithin && !e.currentTarget.contains(e.relatedTarget)) { | ||
if (props.onBlurWithin) { | ||
props.onBlurWithin(e); | ||
} | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(false); | ||
} | ||
state.isFocusWithin = false; | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(false); | ||
} | ||
}); | ||
} | ||
state.isFocusWithin = false; | ||
} | ||
}); | ||
return { | ||
@@ -704,5 +927,101 @@ focusWithinProps: { | ||
exports.useFocusWithin = useFocusWithin; | ||
function $cdeee53b9efe306c5345d332eb79788$var$_createForOfIteratorHelper(o) { | ||
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { | ||
if (Array.isArray(o) || (o = $cdeee53b9efe306c5345d332eb79788$var$_unsupportedIterableToArray(o))) { | ||
var i = 0; | ||
var F = function F() {}; | ||
return { | ||
s: F, | ||
n: function n() { | ||
if (i >= o.length) return { | ||
done: true | ||
}; | ||
return { | ||
done: false, | ||
value: o[i++] | ||
}; | ||
}, | ||
e: function (_e) { | ||
function e(_x) { | ||
return _e.apply(this, arguments); | ||
} | ||
e.toString = function () { | ||
return _e.toString(); | ||
}; | ||
return e; | ||
}(function (e) { | ||
throw e; | ||
}), | ||
f: F | ||
}; | ||
} | ||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); | ||
} | ||
var it, | ||
normalCompletion = true, | ||
didErr = false, | ||
err; | ||
return { | ||
s: function s() { | ||
it = o[Symbol.iterator](); | ||
}, | ||
n: function n() { | ||
var step = it.next(); | ||
normalCompletion = step.done; | ||
return step; | ||
}, | ||
e: function (_e2) { | ||
function e(_x2) { | ||
return _e2.apply(this, arguments); | ||
} | ||
e.toString = function () { | ||
return _e2.toString(); | ||
}; | ||
return e; | ||
}(function (e) { | ||
didErr = true; | ||
err = e; | ||
}), | ||
f: function f() { | ||
try { | ||
if (!normalCompletion && it.return != null) it.return(); | ||
} finally { | ||
if (didErr) throw err; | ||
} | ||
} | ||
}; | ||
} | ||
function $cdeee53b9efe306c5345d332eb79788$var$_unsupportedIterableToArray(o, minLen) { | ||
if (!o) return; | ||
if (typeof o === "string") return $cdeee53b9efe306c5345d332eb79788$var$_arrayLikeToArray(o, minLen); | ||
var n = Object.prototype.toString.call(o).slice(8, -1); | ||
if (n === "Object" && o.constructor) n = o.constructor.name; | ||
if (n === "Map" || n === "Set") return Array.from(n); | ||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return $cdeee53b9efe306c5345d332eb79788$var$_arrayLikeToArray(o, minLen); | ||
} | ||
function $cdeee53b9efe306c5345d332eb79788$var$_arrayLikeToArray(arr, len) { | ||
if (len == null || len > arr.length) len = arr.length; | ||
for (var i = 0, arr2 = new Array(len); i < len; i++) { | ||
arr2[i] = arr[i]; | ||
} | ||
return arr2; | ||
} | ||
var $cdeee53b9efe306c5345d332eb79788$var$isGlobalFocusVisible = true; | ||
var $cdeee53b9efe306c5345d332eb79788$var$changeHandlers = new Set(); | ||
var $cdeee53b9efe306c5345d332eb79788$var$hasSetupGlobalListeners = false; | ||
var $cdeee53b9efe306c5345d332eb79788$var$hasEventBeforeFocus = false; | ||
var $cdeee53b9efe306c5345d332eb79788$var$isMac = typeof window !== 'undefined' && window.navigator != null ? /^Mac/.test(window.navigator.platform) : false; // Only Tab or Esc keys will make focus visible on text input elements | ||
@@ -716,8 +1035,7 @@ | ||
function $cdeee53b9efe306c5345d332eb79788$var$triggerChangeHandlers(modality, e) { | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
var _iterator = $cdeee53b9efe306c5345d332eb79788$var$_createForOfIteratorHelper($cdeee53b9efe306c5345d332eb79788$var$changeHandlers), | ||
_step; | ||
try { | ||
for (var _iterator = $cdeee53b9efe306c5345d332eb79788$var$changeHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var handler = _step.value; | ||
@@ -727,14 +1045,5 @@ handler(modality, e); | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
_iterator.e(err); | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
_iterator.f(); | ||
} | ||
@@ -749,2 +1058,4 @@ } // Helper function to determine if a KeyboardEvent is unmodified and could make keyboard focus styles visible | ||
function $cdeee53b9efe306c5345d332eb79788$var$handleKeyboardEvent(e) { | ||
$cdeee53b9efe306c5345d332eb79788$var$hasEventBeforeFocus = true; | ||
if ($cdeee53b9efe306c5345d332eb79788$var$isValidKey(e)) { | ||
@@ -760,4 +1071,16 @@ $cdeee53b9efe306c5345d332eb79788$var$isGlobalFocusVisible = true; | ||
if (e.type === 'mousedown' || e.type === 'pointerdown') { | ||
$cdeee53b9efe306c5345d332eb79788$var$hasEventBeforeFocus = true; | ||
$cdeee53b9efe306c5345d332eb79788$var$triggerChangeHandlers('pointer', e); | ||
} | ||
} | ||
function $cdeee53b9efe306c5345d332eb79788$var$handleFocusEvent(e) { | ||
// If a focus event occurs without a preceding keyboard or pointer event, switch to keyboard modality. | ||
// This occurs, for example, when navigating a form with the next/previous buttons on iOS. | ||
if (!$cdeee53b9efe306c5345d332eb79788$var$hasEventBeforeFocus) { | ||
$cdeee53b9efe306c5345d332eb79788$var$isGlobalFocusVisible = true; | ||
$cdeee53b9efe306c5345d332eb79788$var$triggerChangeHandlers('keyboard', e); | ||
} | ||
$cdeee53b9efe306c5345d332eb79788$var$hasEventBeforeFocus = false; | ||
} // Setup global event listeners to control when keyboard focus style should be visible | ||
@@ -769,6 +1092,18 @@ | ||
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. | ||
var focus = HTMLElement.prototype.focus; | ||
HTMLElement.prototype.focus = function () { | ||
$cdeee53b9efe306c5345d332eb79788$var$hasEventBeforeFocus = true; | ||
focus.apply(this, arguments); | ||
}; | ||
document.addEventListener('keydown', $cdeee53b9efe306c5345d332eb79788$var$handleKeyboardEvent, true); | ||
document.addEventListener('keyup', $cdeee53b9efe306c5345d332eb79788$var$handleKeyboardEvent, true); | ||
document.addEventListener('focus', $cdeee53b9efe306c5345d332eb79788$var$handleFocusEvent, true); | ||
@@ -798,3 +1133,3 @@ if (typeof PointerEvent !== 'undefined') { | ||
var _useState = useState(autoFocus || $cdeee53b9efe306c5345d332eb79788$var$isGlobalFocusVisible), | ||
_useState2 = _babelRuntimeHelpersEsmSlicedToArray(_useState, 2), | ||
_useState2 = _babelRuntimeHelpersSlicedToArray(_useState, 2), | ||
isFocusVisible = _useState2[0], | ||
@@ -824,2 +1159,163 @@ setFocusVisible = _useState2[1]; | ||
exports.useFocusVisible = useFocusVisible; | ||
exports.useFocusVisible = useFocusVisible; | ||
function useHover(props) { | ||
var onHover = props.onHover, | ||
onHoverChange = props.onHoverChange, | ||
onHoverEnd = props.onHoverEnd, | ||
isDisabled = props.isDisabled, | ||
domProps = _babelRuntimeHelpersObjectWithoutProperties(props, ["onHover", "onHoverChange", "onHoverEnd", "isDisabled"]); | ||
var hoverProps = useMemo(function () { | ||
var triggerHoverStart = function triggerHoverStart(event, pointerType) { | ||
if (isDisabled) { | ||
return; | ||
} | ||
if (pointerType === 'touch') { | ||
return; | ||
} | ||
var target = event.target; | ||
if (onHover) { | ||
onHover({ | ||
type: 'hover', | ||
target: target, | ||
pointerType: pointerType | ||
}); | ||
} | ||
if (onHoverChange) { | ||
onHoverChange(true); | ||
} | ||
}; | ||
var triggerHoverEnd = function triggerHoverEnd(event, pointerType) { | ||
if (isDisabled) { | ||
return; | ||
} | ||
if (pointerType === 'touch') { | ||
return; | ||
} | ||
var target = event.target; | ||
if (onHoverEnd) { | ||
onHoverEnd({ | ||
type: 'hoverend', | ||
target: target, | ||
pointerType: pointerType | ||
}); | ||
} | ||
if (onHoverChange) { | ||
onHoverChange(false); | ||
} | ||
}; | ||
var hoverProps = {}; | ||
if (typeof PointerEvent !== 'undefined') { | ||
hoverProps.onPointerEnter = function (e) { | ||
triggerHoverStart(e, e.pointerType); | ||
}; | ||
hoverProps.onPointerLeave = function (e) { | ||
triggerHoverEnd(e, e.pointerType); | ||
}; | ||
} else { | ||
hoverProps.onMouseEnter = function (e) { | ||
triggerHoverStart(e, 'mouse'); | ||
}; | ||
hoverProps.onMouseLeave = function (e) { | ||
triggerHoverEnd(e, 'mouse'); | ||
}; | ||
} | ||
return hoverProps; | ||
}, [onHover, onHoverChange, onHoverEnd, isDisabled]); | ||
return { | ||
hoverProps: mergeProps(domProps, hoverProps) | ||
}; | ||
} | ||
exports.useHover = useHover; | ||
var DOMPropsResponderContext = _react.createContext(null); | ||
exports.DOMPropsResponderContext = DOMPropsResponderContext; | ||
function useDOMPropsResponderContext(props) { | ||
// Consume context from <DOMPropsResponder> and merge with props. | ||
var context = useContext(DOMPropsResponderContext); | ||
if (context) { | ||
var _register = context.register, | ||
contextProps = _babelRuntimeHelpersObjectWithoutProperties(context, ["register"]); | ||
props = mergeProps(contextProps, props); | ||
_register(); | ||
} // Sync ref from <DOMPropsResponder> with ref passed to the useHover hook. | ||
useEffect(function () { | ||
if (context && context.ref) { | ||
context.ref.current = props.ref.current; | ||
return function () { | ||
context.ref.current = null; | ||
}; | ||
} | ||
}, [context, props.ref]); | ||
return props; | ||
} | ||
exports.useDOMPropsResponderContext = useDOMPropsResponderContext; | ||
var DOMPropsResponder = _react.forwardRef(function (_ref, ref) { | ||
var children = _ref.children, | ||
props = _babelRuntimeHelpersObjectWithoutProperties(_ref, ["children"]); | ||
var isRegistered = useRef(false); | ||
var context = _babelRuntimeHelpersObjectSpread({}, props, { | ||
ref: ref, | ||
register: function register() { | ||
isRegistered.current = true; | ||
} | ||
}); // TODO: Think of a more generic message when this replaces the PressResponder as well | ||
useEffect(function () { | ||
if (!isRegistered.current) { | ||
console.warn('A DOMPropsResponder was ultilized without a hoverable DOM node.'); | ||
} | ||
}, []); | ||
return (/*#__PURE__*/_react.createElement(DOMPropsResponderContext.Provider, { | ||
value: context | ||
}, children) | ||
); | ||
}); | ||
exports.DOMPropsResponder = DOMPropsResponder; | ||
function useDOMPropsResponder(domRef) { | ||
var domProps = useDOMPropsResponderContext({ | ||
ref: domRef | ||
}) || {}; // @ts-ignore | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
var register = domProps.register, | ||
isDisabled = domProps.isDisabled, | ||
onPress = domProps.onPress, | ||
partialDomProps = _babelRuntimeHelpersObjectWithoutProperties(domProps, ["register", "isDisabled", "onPress"]); | ||
return { | ||
contextProps: partialDomProps | ||
}; | ||
} | ||
exports.useDOMPropsResponder = useDOMPropsResponder; |
import _babelRuntimeHelpersEsmObjectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; | ||
import { focusWithoutScrolling, mergeProps } from "@react-aria/utils"; | ||
import _react, { useContext, useEffect, useMemo, useRef, useState } from "react"; | ||
import { mergeProps } from "@react-aria/utils"; | ||
import _babelRuntimeHelpersEsmObjectSpread from "@babel/runtime/helpers/esm/objectSpread2"; | ||
@@ -8,2 +8,4 @@ | ||
$dfb1afd42bc5ba853feb46619fe4852d$export$PressResponderContext.displayName = 'PressResponderContext'; | ||
function $d4f8c4e5fbfabc3f0b106b817fa442a7$var$usePressResponderContext(props) { | ||
@@ -42,2 +44,3 @@ // Consume context from <PressResponder> and merge with props. | ||
onPressEnd, | ||
onPressUp, | ||
isDisabled, | ||
@@ -48,3 +51,3 @@ isPressed: isPressedProp, | ||
} = _usePressResponderCon, | ||
domProps = _babelRuntimeHelpersEsmObjectWithoutProperties(_usePressResponderCon, ["onPress", "onPressChange", "onPressStart", "onPressEnd", "isDisabled", "isPressed", "ref"]); | ||
domProps = _babelRuntimeHelpersEsmObjectWithoutProperties(_usePressResponderCon, ["onPress", "onPressChange", "onPressStart", "onPressEnd", "onPressUp", "isDisabled", "isPressed", "ref"]); | ||
@@ -55,2 +58,3 @@ let [isPressed, setPressed] = useState(false); | ||
ignoreEmulatedMouseEvents: false, | ||
ignoreClickAfterPress: false, | ||
activePointerId: null, | ||
@@ -72,3 +76,3 @@ target: null, | ||
pointerType, | ||
target: originalEvent.target, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
@@ -92,2 +96,4 @@ metaKey: originalEvent.metaKey, | ||
state.ignoreClickAfterPress = true; | ||
if (onPressEnd) { | ||
@@ -97,3 +103,3 @@ onPressEnd({ | ||
pointerType, | ||
target: originalEvent.target, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
@@ -115,3 +121,3 @@ metaKey: originalEvent.metaKey, | ||
pointerType, | ||
target: originalEvent.target, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
@@ -124,9 +130,35 @@ metaKey: originalEvent.metaKey, | ||
let triggerPressUp = (originalEvent, pointerType) => { | ||
if (isDisabled) { | ||
return; | ||
} | ||
if (onPressUp) { | ||
onPressUp({ | ||
type: 'pressup', | ||
pointerType, | ||
target: originalEvent.currentTarget, | ||
shiftKey: originalEvent.shiftKey, | ||
metaKey: originalEvent.metaKey, | ||
ctrlKey: originalEvent.ctrlKey | ||
}); | ||
} | ||
}; | ||
let pressProps = { | ||
onKeyDown(e) { | ||
if (!state.isPressed && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isValidKeyboardEvent(e.nativeEvent)) { | ||
if ($d4f8c4e5fbfabc3f0b106b817fa442a7$var$isValidKeyboardEvent(e.nativeEvent)) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
state.isPressed = true; | ||
triggerPressStart(e, 'keyboard'); | ||
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. | ||
document.addEventListener('keyup', onKeyUp, false); | ||
} | ||
} | ||
@@ -136,7 +168,30 @@ }, | ||
onKeyUp(e) { | ||
if (state.isPressed && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isValidKeyboardEvent(e.nativeEvent)) { | ||
e.preventDefault(); | ||
if ($d4f8c4e5fbfabc3f0b106b817fa442a7$var$isValidKeyboardEvent(e.nativeEvent) && !e.repeat) { | ||
triggerPressUp($d4f8c4e5fbfabc3f0b106b817fa442a7$var$createEvent(state.target, e), 'keyboard'); | ||
} | ||
}, | ||
onClick(e) { | ||
if (e && e.button === 0) { | ||
e.stopPropagation(); | ||
state.isPressed = false; | ||
triggerPressEnd(e, 'keyboard'); | ||
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 && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isVirtualClick(e.nativeEvent)) { | ||
// Ensure the element receives focus (VoiceOver on iOS does not do this) | ||
if (!isDisabled) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
triggerPressStart(e, 'virtual'); | ||
triggerPressUp(e, 'virtual'); | ||
triggerPressEnd(e, 'virtual'); | ||
} | ||
state.ignoreEmulatedMouseEvents = false; | ||
state.ignoreClickAfterPress = false; | ||
} | ||
@@ -147,4 +202,48 @@ } | ||
let onKeyUp = e => { | ||
if (state.isPressed && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isValidKeyboardEvent(e)) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
state.isPressed = false; | ||
triggerPressEnd($d4f8c4e5fbfabc3f0b106b817fa442a7$var$createEvent(state.target, e), 'keyboard', e.target === state.target); | ||
document.removeEventListener('keyup', onKeyUp, false); // If the target is a link, trigger the click method to open the URL, | ||
// but defer triggering pressEnd until onClick event handler. | ||
if (e.target === state.target && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isHTMLAnchorLink(state.target) || state.target.getAttribute('role') === 'link') { | ||
state.target.click(); | ||
} | ||
} | ||
}; // Safari on iOS starts selecting text on long press. The only way to avoid this, it seems, | ||
// is to add user-select: none to the entire page. Adding it to the pressable element prevents | ||
// that element from being selected, but nearby elements may still receive selection. We add | ||
// user-select: none on touch start, and remove it again on touch end to prevent this. | ||
let disableTextSelection = () => { | ||
state.userSelect = document.documentElement.style.webkitUserSelect; | ||
document.documentElement.style.webkitUserSelect = 'none'; | ||
}; | ||
let restoreTextSelection = () => { | ||
// 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(() => { | ||
// Avoid race conditions | ||
if (!state.isPressed && document.documentElement.style.webkitUserSelect === 'none') { | ||
document.documentElement.style.webkitUserSelect = state.userSelect || ''; | ||
state.userSelect = null; | ||
} | ||
}, 300); | ||
}; | ||
if (typeof PointerEvent !== 'undefined') { | ||
pressProps.onPointerDown = e => { | ||
// Only handle left clicks | ||
if (e.button !== 0) { | ||
return; | ||
} // Due to browser inconsistencies, especially on mobile browsers, we prevent | ||
// default on pointer down and handle focusing the pressable element ourselves. | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
@@ -157,2 +256,8 @@ | ||
state.target = e.currentTarget; | ||
if (!isDisabled) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
disableTextSelection(); | ||
triggerPressStart(e, e.pointerType); | ||
@@ -165,2 +270,11 @@ document.addEventListener('pointermove', onPointerMove, false); | ||
pressProps.onMouseDown = e => { | ||
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. | ||
e.preventDefault(); | ||
} | ||
}; | ||
let unbindEvents = () => { | ||
@@ -170,2 +284,11 @@ document.removeEventListener('pointermove', onPointerMove, false); | ||
document.removeEventListener('pointercancel', onPointerCancel, false); | ||
}; | ||
pressProps.onPointerUp = e => { | ||
// 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 && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isOverTarget(e, e.currentTarget)) { | ||
triggerPressUp(e, e.pointerType); | ||
} | ||
}; // Safari on iOS < 13.2 does not implement pointerenter/pointerleave events correctly. | ||
@@ -181,5 +304,3 @@ // Use pointer move events instead to implement our own hit testing. | ||
let rect = state.target.getBoundingClientRect(); | ||
if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) { | ||
if ($d4f8c4e5fbfabc3f0b106b817fa442a7$var$isOverTarget(e, state.target)) { | ||
if (!state.isOverTarget) { | ||
@@ -196,6 +317,4 @@ state.isOverTarget = true; | ||
let onPointerUp = e => { | ||
if (e.pointerId === state.activePointerId && state.isPressed) { | ||
let rect = state.target.getBoundingClientRect(); | ||
if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) { | ||
if (e.pointerId === state.activePointerId && state.isPressed && e.button === 0) { | ||
if ($d4f8c4e5fbfabc3f0b106b817fa442a7$var$isOverTarget(e, state.target)) { | ||
triggerPressEnd($d4f8c4e5fbfabc3f0b106b817fa442a7$var$createEvent(state.target, e), e.pointerType); | ||
@@ -210,2 +329,3 @@ } else if (state.isOverTarget) { | ||
unbindEvents(); | ||
restoreTextSelection(); | ||
} | ||
@@ -224,2 +344,3 @@ }; | ||
unbindEvents(); | ||
restoreTextSelection(); | ||
} | ||
@@ -229,6 +350,13 @@ }; | ||
pressProps.onMouseDown = e => { | ||
// Only handle left clicks | ||
if (e.button !== 0) { | ||
return; | ||
} // Due to browser inconsistencies, especially on mobile browsers, we prevent | ||
// default on mouse down and handle focusing the pressable element ourselves. | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
if (state.ignoreEmulatedMouseEvents) { | ||
e.nativeEvent.preventDefault(); | ||
return; | ||
@@ -238,3 +366,9 @@ } | ||
state.isPressed = true; | ||
state.isOverTarget = true; | ||
state.target = e.currentTarget; | ||
if (!isDisabled) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
triggerPressStart(e, 'mouse'); | ||
@@ -248,2 +382,3 @@ document.addEventListener('mouseup', onMouseUp, false); | ||
if (state.isPressed && !state.ignoreEmulatedMouseEvents) { | ||
state.isOverTarget = true; | ||
triggerPressStart(e, 'mouse'); | ||
@@ -257,2 +392,3 @@ } | ||
if (state.isPressed && !state.ignoreEmulatedMouseEvents) { | ||
state.isOverTarget = false; | ||
triggerPressEnd(e, 'mouse', false); | ||
@@ -262,7 +398,18 @@ } | ||
pressProps.onMouseUp = e => { | ||
if (!state.ignoreEmulatedMouseEvents && e.button === 0) { | ||
triggerPressUp(e, 'mouse'); | ||
} | ||
}; | ||
let onMouseUp = e => { | ||
// Only handle left clicks | ||
if (e.button !== 0) { | ||
return; | ||
} | ||
state.isPressed = false; | ||
document.removeEventListener('mouseup', onMouseUp, false); | ||
if (state.ignoreEmulatedMouseEvents || !state.target || !state.target.contains(e.target)) { | ||
if (state.ignoreEmulatedMouseEvents) { | ||
state.ignoreEmulatedMouseEvents = false; | ||
@@ -272,3 +419,9 @@ return; | ||
triggerPressEnd($d4f8c4e5fbfabc3f0b106b817fa442a7$var$createEvent(state.target, e), 'mouse'); | ||
if ($d4f8c4e5fbfabc3f0b106b817fa442a7$var$isOverTarget(e, state.target)) { | ||
triggerPressEnd($d4f8c4e5fbfabc3f0b106b817fa442a7$var$createEvent(state.target, e), 'mouse'); | ||
} else if (state.isOverTarget) { | ||
triggerPressEnd($d4f8c4e5fbfabc3f0b106b817fa442a7$var$createEvent(state.target, e), 'mouse', false); | ||
} | ||
state.isOverTarget = false; | ||
}; | ||
@@ -288,3 +441,12 @@ | ||
state.isPressed = true; | ||
state.target = e.currentTarget; // 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) { | ||
focusWithoutScrolling(e.currentTarget); | ||
} | ||
disableTextSelection(); | ||
triggerPressStart(e, 'touch'); | ||
window.addEventListener('scroll', onScroll, true); | ||
}; | ||
@@ -294,6 +456,10 @@ | ||
e.stopPropagation(); | ||
let rect = e.currentTarget.getBoundingClientRect(); | ||
if (!state.isPressed) { | ||
return; | ||
} | ||
let touch = $d4f8c4e5fbfabc3f0b106b817fa442a7$var$getTouchById(e.nativeEvent, state.activePointerId); | ||
if (touch && touch.clientX >= rect.left && touch.clientX <= rect.right && touch.clientY >= rect.top && touch.clientY <= rect.bottom) { | ||
if (touch && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isOverTarget(touch, e.currentTarget)) { | ||
if (!state.isOverTarget) { | ||
@@ -311,6 +477,11 @@ state.isOverTarget = true; | ||
e.stopPropagation(); | ||
let rect = e.currentTarget.getBoundingClientRect(); | ||
if (!state.isPressed) { | ||
return; | ||
} | ||
let touch = $d4f8c4e5fbfabc3f0b106b817fa442a7$var$getTouchById(e.nativeEvent, state.activePointerId); | ||
if (touch && touch.clientX >= rect.left && touch.clientX <= rect.right && touch.clientY >= rect.top && touch.clientY <= rect.bottom) { | ||
if (touch && $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isOverTarget(touch, e.currentTarget)) { | ||
triggerPressUp(e, 'touch'); | ||
triggerPressEnd(e, 'touch'); | ||
@@ -324,2 +495,5 @@ } else if (state.isOverTarget) { | ||
state.isOverTarget = false; | ||
state.ignoreEmulatedMouseEvents = true; | ||
restoreTextSelection(); | ||
window.removeEventListener('scroll', onScroll, true); | ||
}; | ||
@@ -331,19 +505,27 @@ | ||
if (state.isPressed) { | ||
if (state.isOverTarget) { | ||
triggerPressEnd(e, 'touch', false); | ||
} | ||
cancelTouchEvent(e, 'touch'); | ||
} | ||
}; | ||
state.isPressed = false; | ||
state.activePointerId = null; | ||
state.isOverTarget = false; | ||
let onScroll = e => { | ||
if (state.isPressed && e.target.contains(state.target)) { | ||
cancelTouchEvent({ | ||
currentTarget: state.target, | ||
shiftKey: false, | ||
ctrlKey: false, | ||
metaKey: false | ||
}, 'touch'); | ||
} | ||
}; | ||
pressProps.onClick = e => { | ||
e.stopPropagation(); | ||
state.ignoreEmulatedMouseEvents = false; | ||
let cancelTouchEvent = (e, pointerType) => { | ||
if (state.isOverTarget) { | ||
triggerPressEnd(e, pointerType, false); | ||
} | ||
if (isDisabled) { | ||
e.preventDefault(); | ||
} | ||
state.isPressed = false; | ||
state.activePointerId = null; | ||
state.isOverTarget = false; | ||
restoreTextSelection(); | ||
window.removeEventListener('scroll', onScroll, true); | ||
}; | ||
@@ -353,3 +535,3 @@ } | ||
return pressProps; | ||
}, [onPress, onPressStart, onPressEnd, onPressChange, isDisabled]); | ||
}, [onPress, onPressStart, onPressEnd, onPressChange, onPressUp, isDisabled]); | ||
return { | ||
@@ -361,2 +543,6 @@ isPressed: isPressedProp || isPressed, | ||
function $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isHTMLAnchorLink(target) { | ||
return target.tagName === 'A' && target.hasAttribute('href'); | ||
} | ||
function $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isValidKeyboardEvent(event) { | ||
@@ -367,9 +553,30 @@ const { | ||
} = event; | ||
const element = target; | ||
const { | ||
tagName, | ||
isContentEditable | ||
} = target; // Accessibility for keyboards. Space and Enter only. | ||
} = element; | ||
const role = element.getAttribute('role'); // Accessibility for keyboards. Space and Enter only. | ||
// "Spacebar" is for IE 11 | ||
return (key === 'Enter' || key === ' ' || key === 'Spacebar') && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && isContentEditable !== true; | ||
return (key === 'Enter' || key === ' ' || key === 'Spacebar') && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && isContentEditable !== true && ( // A link with a valid href should be handled natively, | ||
// unless it also has role='button' and was triggered using Space. | ||
!$d4f8c4e5fbfabc3f0b106b817fa442a7$var$isHTMLAnchorLink(element) || role === 'button' && key !== 'Enter') && // An element with role='link' should only trigger with Enter key | ||
!(role === 'link' && key !== 'Enter'); | ||
} // Per: https://github.com/facebook/react/blob/3c713d513195a53788b3f8bb4b70279d68b15bcc/packages/react-interactions/events/src/dom/shared/index.js#L74-L87 | ||
// Keyboards, Assitive Technologies, and element.click() all produce a "virtual" | ||
// click event. This is a method of inferring such clicks. Every browser except | ||
// IE 11 only sets a zero value of "detail" for click events that are "virtual". | ||
// However, IE 11 uses a zero value for all click events. For IE 11 we rely on | ||
// the quirk that it produces click events that are of type PointerEvent, and | ||
// where only the "virtual" click lacks a pointerType field. | ||
function $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isVirtualClick(event) { | ||
// JAWS/NVDA with Firefox. | ||
if (event.mozInputSource === 0 && event.isTrusted) { | ||
return true; | ||
} | ||
return event.detail === 0 && !event.pointerType; | ||
} | ||
@@ -405,3 +612,3 @@ | ||
return { | ||
target, | ||
currentTarget: target, | ||
shiftKey: e.shiftKey, | ||
@@ -413,2 +620,7 @@ ctrlKey: e.ctrlKey, | ||
function $d4f8c4e5fbfabc3f0b106b817fa442a7$var$isOverTarget(point, target) { | ||
let rect = target.getBoundingClientRect(); | ||
return (point.clientX || 0) >= (rect.left || 0) && (point.clientX || 0) <= (rect.right || 0) && (point.clientY || 0) >= (rect.top || 0) && (point.clientY || 0) <= (rect.bottom || 0); | ||
} | ||
export function useInteractOutside(props) { | ||
@@ -420,2 +632,3 @@ let { | ||
let stateRef = useRef({ | ||
isPointerDown: false, | ||
ignoreEmulatedMouseEvents: false | ||
@@ -425,6 +638,13 @@ }); | ||
useEffect(() => { | ||
// Use pointer events if available. Otherwise, fall back to mouse and touch events. | ||
let onPointerDown = e => { | ||
if ($aa0c64dcd7f02ca42a7bfa03164e6$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = true; | ||
} | ||
}; // Use pointer events if available. Otherwise, fall back to mouse and touch events. | ||
if (typeof PointerEvent !== 'undefined') { | ||
let onPointerUp = e => { | ||
if (onInteractOutside && $aa0c64dcd7f02ca42a7bfa03164e6$var$isValidEvent(e, ref)) { | ||
if (state.isPointerDown && onInteractOutside && $aa0c64dcd7f02ca42a7bfa03164e6$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = false; | ||
onInteractOutside(e); | ||
@@ -434,4 +654,6 @@ } | ||
document.addEventListener('pointerdown', onPointerDown, false); | ||
document.addEventListener('pointerup', onPointerUp, false); | ||
return () => { | ||
document.removeEventListener('pointerdown', onPointerDown, false); | ||
document.removeEventListener('pointerup', onPointerUp, false); | ||
@@ -443,3 +665,4 @@ }; | ||
state.ignoreEmulatedMouseEvents = false; | ||
} else if (onInteractOutside && $aa0c64dcd7f02ca42a7bfa03164e6$var$isValidEvent(e, ref)) { | ||
} else if (state.isPointerDown && onInteractOutside && $aa0c64dcd7f02ca42a7bfa03164e6$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = false; | ||
onInteractOutside(e); | ||
@@ -452,3 +675,4 @@ } | ||
if (onInteractOutside && $aa0c64dcd7f02ca42a7bfa03164e6$var$isValidEvent(e, ref)) { | ||
if (onInteractOutside && state.isPointerDown && $aa0c64dcd7f02ca42a7bfa03164e6$var$isValidEvent(e, ref)) { | ||
state.isPointerDown = false; | ||
onInteractOutside(e); | ||
@@ -458,10 +682,14 @@ } | ||
document.addEventListener('mousedown', onPointerDown, false); | ||
document.addEventListener('mouseup', onMouseUp, false); | ||
document.addEventListener('touchstart', onPointerDown, false); | ||
document.addEventListener('touchend', onTouchEnd, false); | ||
return () => { | ||
document.removeEventListener('mousedown', onPointerDown, false); | ||
document.removeEventListener('mouseup', onMouseUp, false); | ||
document.removeEventListener('touchstart', onPointerDown, false); | ||
document.removeEventListener('touchend', onTouchEnd, false); | ||
}; | ||
} | ||
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents]); | ||
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents, state.isPointerDown]); | ||
} | ||
@@ -519,5 +747,6 @@ | ||
}, []); | ||
return _react.createElement($dfb1afd42bc5ba853feb46619fe4852d$export$PressResponderContext.Provider, { | ||
value: context | ||
}, children); | ||
return (/*#__PURE__*/_react.createElement($dfb1afd42bc5ba853feb46619fe4852d$export$PressResponderContext.Provider, { | ||
value: context | ||
}, children) | ||
); | ||
}); | ||
@@ -530,2 +759,3 @@ | ||
* 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 | ||
@@ -642,39 +872,31 @@ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
let onFocus, onBlur; | ||
let onFocus = $bf0ab9e2de2515781be699d1ec74e486$export$createEventHandler(e => { | ||
if (props.onFocusWithin) { | ||
props.onFocusWithin(e); | ||
} | ||
if (props.onFocusWithin || props.onFocusWithinChange) { | ||
onFocus = $bf0ab9e2de2515781be699d1ec74e486$export$createEventHandler(e => { | ||
if (props.onFocusWithin) { | ||
props.onFocusWithin(e); | ||
if (!state.isFocusWithin) { | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(true); | ||
} | ||
if (!state.isFocusWithin) { | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(true); | ||
} | ||
state.isFocusWithin = true; | ||
state.isFocusWithin = true; | ||
} | ||
}); | ||
let onBlur = $bf0ab9e2de2515781be699d1ec74e486$export$createEventHandler(e => { | ||
// We don't want to trigger onBlurWithin and then immediately onFocusWithin again | ||
// when moving focus inside the element. Only trigger if the currentTarget doesn't | ||
// include the relatedTarget (where focus is moving). | ||
if (state.isFocusWithin && !e.currentTarget.contains(e.relatedTarget)) { | ||
if (props.onBlurWithin) { | ||
props.onBlurWithin(e); | ||
} | ||
}); | ||
} | ||
if (props.onBlurWithin || props.onFocusWithinChange) { | ||
onBlur = $bf0ab9e2de2515781be699d1ec74e486$export$createEventHandler(e => { | ||
// We don't want to trigger onBlurWithin and then immediately onFocusWithin again | ||
// when moving focus inside the element. Only trigger if the currentTarget doesn't | ||
// include the relatedTarget (where focus is moving). | ||
if (state.isFocusWithin && !e.currentTarget.contains(e.relatedTarget)) { | ||
if (props.onBlurWithin) { | ||
props.onBlurWithin(e); | ||
} | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(false); | ||
} | ||
state.isFocusWithin = false; | ||
if (props.onFocusWithinChange) { | ||
props.onFocusWithinChange(false); | ||
} | ||
}); | ||
} | ||
state.isFocusWithin = false; | ||
} | ||
}); | ||
return { | ||
@@ -690,2 +912,3 @@ focusWithinProps: { | ||
let $d51c87ad858c3af15dd5d3656d9d713$var$hasSetupGlobalListeners = false; | ||
let $d51c87ad858c3af15dd5d3656d9d713$var$hasEventBeforeFocus = false; | ||
const $d51c87ad858c3af15dd5d3656d9d713$var$isMac = typeof window !== 'undefined' && window.navigator != null ? /^Mac/.test(window.navigator.platform) : false; // Only Tab or Esc keys will make focus visible on text input elements | ||
@@ -710,2 +933,4 @@ | ||
function $d51c87ad858c3af15dd5d3656d9d713$var$handleKeyboardEvent(e) { | ||
$d51c87ad858c3af15dd5d3656d9d713$var$hasEventBeforeFocus = true; | ||
if ($d51c87ad858c3af15dd5d3656d9d713$var$isValidKey(e)) { | ||
@@ -721,4 +946,16 @@ $d51c87ad858c3af15dd5d3656d9d713$var$isGlobalFocusVisible = true; | ||
if (e.type === 'mousedown' || e.type === 'pointerdown') { | ||
$d51c87ad858c3af15dd5d3656d9d713$var$hasEventBeforeFocus = true; | ||
$d51c87ad858c3af15dd5d3656d9d713$var$triggerChangeHandlers('pointer', e); | ||
} | ||
} | ||
function $d51c87ad858c3af15dd5d3656d9d713$var$handleFocusEvent(e) { | ||
// If a focus event occurs without a preceding keyboard or pointer event, switch to keyboard modality. | ||
// This occurs, for example, when navigating a form with the next/previous buttons on iOS. | ||
if (!$d51c87ad858c3af15dd5d3656d9d713$var$hasEventBeforeFocus) { | ||
$d51c87ad858c3af15dd5d3656d9d713$var$isGlobalFocusVisible = true; | ||
$d51c87ad858c3af15dd5d3656d9d713$var$triggerChangeHandlers('keyboard', e); | ||
} | ||
$d51c87ad858c3af15dd5d3656d9d713$var$hasEventBeforeFocus = false; | ||
} // Setup global event listeners to control when keyboard focus style should be visible | ||
@@ -730,6 +967,18 @@ | ||
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 () { | ||
$d51c87ad858c3af15dd5d3656d9d713$var$hasEventBeforeFocus = true; | ||
focus.apply(this, arguments); | ||
}; | ||
document.addEventListener('keydown', $d51c87ad858c3af15dd5d3656d9d713$var$handleKeyboardEvent, true); | ||
document.addEventListener('keyup', $d51c87ad858c3af15dd5d3656d9d713$var$handleKeyboardEvent, true); | ||
document.addEventListener('focus', $d51c87ad858c3af15dd5d3656d9d713$var$handleFocusEvent, true); | ||
@@ -779,2 +1028,157 @@ if (typeof PointerEvent !== 'undefined') { | ||
}; | ||
} | ||
export function useHover(props) { | ||
let { | ||
onHover, | ||
onHoverChange, | ||
onHoverEnd, | ||
isDisabled | ||
} = props, | ||
domProps = _babelRuntimeHelpersEsmObjectWithoutProperties(props, ["onHover", "onHoverChange", "onHoverEnd", "isDisabled"]); | ||
let hoverProps = useMemo(() => { | ||
let triggerHoverStart = (event, pointerType) => { | ||
if (isDisabled) { | ||
return; | ||
} | ||
if (pointerType === 'touch') { | ||
return; | ||
} | ||
let target = event.target; | ||
if (onHover) { | ||
onHover({ | ||
type: 'hover', | ||
target, | ||
pointerType | ||
}); | ||
} | ||
if (onHoverChange) { | ||
onHoverChange(true); | ||
} | ||
}; | ||
let triggerHoverEnd = (event, pointerType) => { | ||
if (isDisabled) { | ||
return; | ||
} | ||
if (pointerType === 'touch') { | ||
return; | ||
} | ||
let target = event.target; | ||
if (onHoverEnd) { | ||
onHoverEnd({ | ||
type: 'hoverend', | ||
target, | ||
pointerType | ||
}); | ||
} | ||
if (onHoverChange) { | ||
onHoverChange(false); | ||
} | ||
}; | ||
let hoverProps = {}; | ||
if (typeof PointerEvent !== 'undefined') { | ||
hoverProps.onPointerEnter = e => { | ||
triggerHoverStart(e, e.pointerType); | ||
}; | ||
hoverProps.onPointerLeave = e => { | ||
triggerHoverEnd(e, e.pointerType); | ||
}; | ||
} else { | ||
hoverProps.onMouseEnter = e => { | ||
triggerHoverStart(e, 'mouse'); | ||
}; | ||
hoverProps.onMouseLeave = e => { | ||
triggerHoverEnd(e, 'mouse'); | ||
}; | ||
} | ||
return hoverProps; | ||
}, [onHover, onHoverChange, onHoverEnd, isDisabled]); | ||
return { | ||
hoverProps: mergeProps(domProps, hoverProps) | ||
}; | ||
} | ||
export const DOMPropsResponderContext = _react.createContext(null); | ||
export function useDOMPropsResponderContext(props) { | ||
// Consume context from <DOMPropsResponder> and merge with props. | ||
let context = useContext(DOMPropsResponderContext); | ||
if (context) { | ||
let { | ||
register | ||
} = context, | ||
contextProps = _babelRuntimeHelpersEsmObjectWithoutProperties(context, ["register"]); | ||
props = mergeProps(contextProps, props); | ||
register(); | ||
} // Sync ref from <DOMPropsResponder> with ref passed to the useHover hook. | ||
useEffect(() => { | ||
if (context && context.ref) { | ||
context.ref.current = props.ref.current; | ||
return () => { | ||
context.ref.current = null; | ||
}; | ||
} | ||
}, [context, props.ref]); | ||
return props; | ||
} | ||
export const DOMPropsResponder = _react.forwardRef((_ref, ref) => { | ||
let { | ||
children | ||
} = _ref, | ||
props = _babelRuntimeHelpersEsmObjectWithoutProperties(_ref, ["children"]); | ||
let isRegistered = useRef(false); | ||
let context = _babelRuntimeHelpersEsmObjectSpread({}, props, { | ||
ref, | ||
register() { | ||
isRegistered.current = true; | ||
} | ||
}); // TODO: Think of a more generic message when this replaces the PressResponder as well | ||
useEffect(() => { | ||
if (!isRegistered.current) { | ||
console.warn('A DOMPropsResponder was ultilized without a hoverable DOM node.'); | ||
} | ||
}, []); | ||
return (/*#__PURE__*/_react.createElement(DOMPropsResponderContext.Provider, { | ||
value: context | ||
}, children) | ||
); | ||
}); | ||
export function useDOMPropsResponder(domRef) { | ||
let domProps = useDOMPropsResponderContext({ | ||
ref: domRef | ||
}) || {}; // @ts-ignore | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const { | ||
register, | ||
isDisabled, | ||
onPress | ||
} = domProps, | ||
partialDomProps = _babelRuntimeHelpersEsmObjectWithoutProperties(domProps, ["register", "isDisabled", "onPress"]); | ||
return { | ||
contextProps: partialDomProps | ||
}; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { DOMProps, PressEvents, KeyboardEvents, FocusEvents, FocusEvent } from "@react-types/shared"; | ||
import { DOMProps, PressEvents, KeyboardEvents, FocusEvents, FocusEvent, HoverEvents } from "@react-types/shared"; | ||
import { HTMLAttributes, RefObject, SyntheticEvent, ReactElement, ReactNode } from "react"; | ||
@@ -10,3 +10,3 @@ export interface PressProps extends PressEvents { | ||
} | ||
interface PressResult { | ||
export interface PressResult { | ||
isPressed: boolean; | ||
@@ -70,3 +70,44 @@ pressProps: HTMLAttributes<HTMLElement>; | ||
export function useFocusVisible(props: FocusVisibleProps): FocusVisibleResult; | ||
export interface HoverProps extends HoverEvents, DOMProps { | ||
isDisabled?: boolean; | ||
} | ||
export interface HoverHookProps extends HoverProps, DOMProps { | ||
ref?: RefObject<HTMLElement>; | ||
} | ||
interface HoverResult { | ||
hoverProps: HTMLAttributes<HTMLElement>; | ||
} | ||
export function useHover(props: HoverHookProps): HoverResult; | ||
export interface DOMPropsResponderContext extends HoverProps { | ||
register(): void; | ||
ref?: MutableRefObject<HTMLElement>; | ||
onMouseEnter?: () => void; | ||
onMouseLeave?: () => void; | ||
onPointerEnter?: () => void; | ||
onPointerLeave?: () => void; | ||
} | ||
export const DOMPropsResponderContext: React.Context<DOMPropsResponderContext>; | ||
export function useDOMPropsResponderContext(props: HoverHookProps): HoverHookProps; | ||
interface DOMPropsResponderProps extends HoverProps { | ||
children: ReactNode; | ||
} | ||
export const DOMPropsResponder: React.ForwardRefExoticComponent<DOMPropsResponderProps & React.RefAttributes<HTMLElement>>; | ||
export function useDOMPropsResponder(domRef: RefObject<HTMLElement>): { | ||
contextProps: { | ||
ref?: RefObject<HTMLElement>; | ||
onHover?: (e: import("@react-types/shared").HoverEvent) => void; | ||
onHoverEnd?: (e: import("@react-types/shared").HoverEvent) => void; | ||
onHoverChange?: (isHovering: boolean) => void; | ||
id?: string; | ||
tabIndex?: number; | ||
role?: string; | ||
'aria-label'?: string; | ||
'aria-labelledby'?: string; | ||
'aria-describedby'?: string; | ||
'aria-controls'?: string; | ||
'aria-owns'?: string; | ||
'aria-hidden'?: boolean | "false" | "true"; | ||
}; | ||
}; | ||
//# sourceMappingURL=types.d.ts.map |
{ | ||
"name": "@react-aria/interactions", | ||
"version": "3.0.0-rc.1", | ||
"version": "3.0.0-rc.2", | ||
"description": "Spectrum UI components in React", | ||
@@ -20,4 +20,4 @@ "license": "Apache-2.0", | ||
"@babel/runtime": "^7.6.2", | ||
"@react-aria/utils": "^3.0.0-rc.1", | ||
"@react-types/shared": "^3.0.0-rc.1" | ||
"@react-aria/utils": "^3.0.0-rc.2", | ||
"@react-types/shared": "^3.0.0-rc.2" | ||
}, | ||
@@ -30,3 +30,3 @@ "peerDependencies": { | ||
}, | ||
"gitHead": "5a9784f0bb6c25af7422215efb31ef72caeb9600" | ||
"gitHead": "207e6ee9076905c96638a7f81a367758872e1410" | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
98239
7
2086