Socket
Socket
Sign inDemoInstall

@react-aria/interactions

Package Overview
Dependencies
4
Maintainers
1
Versions
712
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.2.1 to 3.3.0

src/useMove.ts

695

dist/main.js

@@ -1,3 +0,1 @@

var _babelRuntimeHelpersExtends = $parcel$interopDefault(require("@babel/runtime/helpers/extends"));
var _react2 = require("react");

@@ -8,3 +6,2 @@

var {
useCallback,
useContext,

@@ -18,5 +15,6 @@ useEffect,

var {
mergeProps,
runAfterTransition,
focusWithoutScrolling,
mergeProps
useGlobalListeners
} = require("@react-aria/utils");

@@ -26,2 +24,4 @@

var _babelRuntimeHelpersExtends = $parcel$interopDefault(require("@babel/runtime/helpers/extends"));
function $parcel$interopDefault(a) {

@@ -158,15 +158,6 @@ return a && a.__esModule ? a.default : a;

});
let globalListeners = useRef(new Map());
let addGlobalListener = useCallback((eventTarget, type, listener, options) => {
globalListeners.current.set(listener, {
type,
eventTarget,
options
});
eventTarget.addEventListener(type, listener, options);
}, []);
let removeGlobalListener = useCallback((eventTarget, type, listener, options) => {
eventTarget.removeEventListener(type, listener, options);
globalListeners.current.delete(listener);
}, []);
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners();
let pressProps = useMemo(() => {

@@ -603,11 +594,8 @@ let state = ref.current;

return pressProps;
}, [isDisabled, onPressStart, onPressChange, onPressEnd, onPress, onPressUp, addGlobalListener, preventFocusOnPress, removeGlobalListener]); // eslint-disable-next-line arrow-body-style
}, [isDisabled, onPressStart, onPressChange, onPressEnd, onPress, onPressUp, addGlobalListener, preventFocusOnPress, removeGlobalListener]); // Remove user-select: none in case component unmounts immediately after pressStart
// eslint-disable-next-line arrow-body-style
useEffect(() => {
return () => {
globalListeners.current.forEach((value, key) => {
removeGlobalListener(value.eventTarget, value.type, key, value.options);
});
};
}, [removeGlobalListener]);
return () => $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection();
}, []);
return {

@@ -684,92 +672,5 @@ isPressed: isPressedProp || isPressed,

/**
* Example, used in components like Dialogs and Popovers so they can close
* when a user clicks outside them.
*/
function useInteractOutside(props) {
let {
ref,
onInteractOutside
} = props;
let stateRef = useRef({
isPointerDown: false,
ignoreEmulatedMouseEvents: false
});
let state = stateRef.current;
useEffect(() => {
let onPointerDown = e => {
if ($f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = true;
}
}; // Use pointer events if available. Otherwise, fall back to mouse and touch events.
const Pressable = _react.forwardRef((_ref, ref) => {
var _ref2;
if (typeof PointerEvent !== 'undefined') {
let onPointerUp = e => {
if (state.isPointerDown && onInteractOutside && $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
}
}; // changing these to capture phase fixed combobox
document.addEventListener('pointerdown', onPointerDown, true);
document.addEventListener('pointerup', onPointerUp, true);
return () => {
document.removeEventListener('pointerdown', onPointerDown, true);
document.removeEventListener('pointerup', onPointerUp, true);
};
} else {
let onMouseUp = e => {
if (state.ignoreEmulatedMouseEvents) {
state.ignoreEmulatedMouseEvents = false;
} else if (state.isPointerDown && onInteractOutside && $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
}
};
let onTouchEnd = e => {
state.ignoreEmulatedMouseEvents = true;
if (onInteractOutside && state.isPointerDown && $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
}
};
document.addEventListener('mousedown', onPointerDown, true);
document.addEventListener('mouseup', onMouseUp, true);
document.addEventListener('touchstart', onPointerDown, true);
document.addEventListener('touchend', onTouchEnd, true);
return () => {
document.removeEventListener('mousedown', onPointerDown, true);
document.removeEventListener('mouseup', onMouseUp, true);
document.removeEventListener('touchstart', onPointerDown, true);
document.removeEventListener('touchend', onTouchEnd, true);
};
}
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents, state.isPointerDown]);
}
exports.useInteractOutside = useInteractOutside;
function $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(event, ref) {
if (event.button > 0) {
return false;
} // if the event target is no longer in the document
if (event.target) {
const ownerDocument = event.target.ownerDocument;
if (!ownerDocument || !ownerDocument.body.contains(event.target)) {
return false;
}
}
return ref.current && !ref.current.contains(event.target);
}
const Pressable = _react.forwardRef((_ref, ref) => {
let {

@@ -780,3 +681,4 @@ children

ref = ref || useRef();
let newRef = useRef();
ref = (_ref2 = ref) != null ? _ref2 : newRef;
let {

@@ -830,53 +732,2 @@ pressProps

/**
* This function wraps a React event handler to make stopPropagation the default, and support continuePropagation instead.
*/
function $df2a10e65550e0fb9bbbe4a76eee490$export$createEventHandler(handler) {
if (!handler) {
return;
}
let shouldStopPropagation = true;
return e => {
let event = _babelRuntimeHelpersExtends({}, e, {
preventDefault() {
e.preventDefault();
},
isDefaultPrevented() {
return e.isDefaultPrevented();
},
stopPropagation() {
console.error('stopPropagation is now the default behavior for events in React Spectrum. You can use continuePropagation() to revert this behavior.');
},
continuePropagation() {
shouldStopPropagation = false;
}
});
handler(event);
if (shouldStopPropagation) {
e.stopPropagation();
}
};
}
/**
* Handles keyboard interactions for a focusable element.
*/
function useKeyboard(props) {
return {
keyboardProps: props.isDisabled ? {} : {
onKeyDown: $df2a10e65550e0fb9bbbe4a76eee490$export$createEventHandler(props.onKeyDown),
onKeyUp: $df2a10e65550e0fb9bbbe4a76eee490$export$createEventHandler(props.onKeyUp)
}
};
}
exports.useKeyboard = useKeyboard;
// NOTICE file in the root directory of this source tree.

@@ -935,57 +786,2 @@ // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions

exports.useFocus = useFocus;
/**
* Handles focus events for the target and its descendants.
*/
function useFocusWithin(props) {
let state = useRef({
isFocusWithin: false
}).current;
if (props.isDisabled) {
return {
focusWithinProps: {}
};
}
let onFocus = e => {
if (!state.isFocusWithin) {
if (props.onFocusWithin) {
props.onFocusWithin(e);
}
if (props.onFocusWithinChange) {
props.onFocusWithinChange(true);
}
state.isFocusWithin = true;
}
};
let onBlur = 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;
}
};
return {
focusWithinProps: {
onFocus: onFocus,
onBlur: onBlur
}
};
}
exports.useFocusWithin = useFocusWithin;
let $b83372066b2b4e1d9257843b2455c$var$currentModality = null;

@@ -1188,2 +984,57 @@ let $b83372066b2b4e1d9257843b2455c$var$changeHandlers = new Set();

exports.useFocusVisible = useFocusVisible;
/**
* Handles focus events for the target and its descendants.
*/
function useFocusWithin(props) {
let state = useRef({
isFocusWithin: false
}).current;
if (props.isDisabled) {
return {
focusWithinProps: {}
};
}
let onFocus = e => {
if (!state.isFocusWithin) {
if (props.onFocusWithin) {
props.onFocusWithin(e);
}
if (props.onFocusWithinChange) {
props.onFocusWithinChange(true);
}
state.isFocusWithin = true;
}
};
let onBlur = 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;
}
};
return {
focusWithinProps: {
onFocus: onFocus,
onBlur: onBlur
}
};
}
exports.useFocusWithin = useFocusWithin;
// iOS fires onPointerEnter twice: once with pointerType="touch" and again with pointerType="mouse".

@@ -1345,2 +1196,406 @@ // We want to ignore these emulated events so they do not trigger hover behavior.

exports.useHover = useHover;
/**
* Example, used in components like Dialogs and Popovers so they can close
* when a user clicks outside them.
*/
function useInteractOutside(props) {
let {
ref,
onInteractOutside
} = props;
let stateRef = useRef({
isPointerDown: false,
ignoreEmulatedMouseEvents: false
});
let state = stateRef.current;
useEffect(() => {
let onPointerDown = e => {
if ($f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = true; // Due to browser inconsistencies, we prevent
// default on pointer down. FF will otherwise try to start text selection.
if (e.button === 0) {
e.preventDefault();
}
}
}; // Use pointer events if available. Otherwise, fall back to mouse and touch events.
if (typeof PointerEvent !== 'undefined') {
let onPointerUp = e => {
if (state.isPointerDown && onInteractOutside && $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}
}; // changing these to capture phase fixed combobox
document.addEventListener('pointerdown', onPointerDown, true);
document.addEventListener('pointerup', onPointerUp, true);
return () => {
document.removeEventListener('pointerdown', onPointerDown, true);
document.removeEventListener('pointerup', onPointerUp, true);
};
} else {
let onMouseUp = e => {
if (state.ignoreEmulatedMouseEvents) {
state.ignoreEmulatedMouseEvents = false;
} else if (state.isPointerDown && onInteractOutside && $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}
};
let onTouchEnd = e => {
state.ignoreEmulatedMouseEvents = true;
if (onInteractOutside && state.isPointerDown && $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}
};
document.addEventListener('mousedown', onPointerDown, true);
document.addEventListener('mouseup', onMouseUp, true);
document.addEventListener('touchstart', onPointerDown, true);
document.addEventListener('touchend', onTouchEnd, true);
return () => {
document.removeEventListener('mousedown', onPointerDown, true);
document.removeEventListener('mouseup', onMouseUp, true);
document.removeEventListener('touchstart', onPointerDown, true);
document.removeEventListener('touchend', onTouchEnd, true);
};
}
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents, state.isPointerDown]);
}
exports.useInteractOutside = useInteractOutside;
function $f07e167670fb16f6a9d7f8a0eda7e156$var$isValidEvent(event, ref) {
if (event.button > 0) {
return false;
} // if the event target is no longer in the document
if (event.target) {
const ownerDocument = event.target.ownerDocument;
if (!ownerDocument || !ownerDocument.body.contains(event.target)) {
return false;
}
}
return ref.current && !ref.current.contains(event.target);
}
/**
* This function wraps a React event handler to make stopPropagation the default, and support continuePropagation instead.
*/
function $df2a10e65550e0fb9bbbe4a76eee490$export$createEventHandler(handler) {
if (!handler) {
return;
}
let shouldStopPropagation = true;
return e => {
let event = _babelRuntimeHelpersExtends({}, e, {
preventDefault() {
e.preventDefault();
},
isDefaultPrevented() {
return e.isDefaultPrevented();
},
stopPropagation() {
console.error('stopPropagation is now the default behavior for events in React Spectrum. You can use continuePropagation() to revert this behavior.');
},
continuePropagation() {
shouldStopPropagation = false;
}
});
handler(event);
if (shouldStopPropagation) {
e.stopPropagation();
}
};
}
/**
* Handles keyboard interactions for a focusable element.
*/
function useKeyboard(props) {
return {
keyboardProps: props.isDisabled ? {} : {
onKeyDown: $df2a10e65550e0fb9bbbe4a76eee490$export$createEventHandler(props.onKeyDown),
onKeyUp: $df2a10e65550e0fb9bbbe4a76eee490$export$createEventHandler(props.onKeyUp)
}
};
}
exports.useKeyboard = useKeyboard;
/**
* Handles move interactions across mouse, touch, and keyboard, including dragging with
* the mouse or touch, and using the arrow keys. Normalizes behavior across browsers and
* platforms, and ignores emulated mouse events on touch devices.
*/
function useMove(props) {
let {
onMoveStart,
onMove,
onMoveEnd
} = props;
let state = useRef({
didMove: false,
lastPosition: null,
id: null
});
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners();
let moveProps = useMemo(() => {
let moveProps = {};
let start = () => {
$ce801cc8e3ff24b95c928e0152c7b7f2$export$disableTextSelection();
state.current.didMove = false;
};
let move = (pointerType, deltaX, deltaY) => {
if (deltaX === 0 && deltaY === 0) {
return;
}
if (!state.current.didMove) {
state.current.didMove = true;
onMoveStart == null ? void 0 : onMoveStart({
type: 'movestart',
pointerType
});
}
onMove({
type: 'move',
pointerType,
deltaX: deltaX,
deltaY: deltaY
});
};
let end = pointerType => {
$ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection();
if (state.current.didMove) {
onMoveEnd == null ? void 0 : onMoveEnd({
type: 'moveend',
pointerType
});
}
};
if (typeof PointerEvent === 'undefined') {
let onMouseMove = e => {
if (e.button === 0) {
move('mouse', e.pageX - state.current.lastPosition.pageX, e.pageY - state.current.lastPosition.pageY);
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
}
};
let onMouseUp = e => {
if (e.button === 0) {
end('mouse');
removeGlobalListener(window, 'mousemove', onMouseMove, false);
removeGlobalListener(window, 'mouseup', onMouseUp, false);
}
};
moveProps.onMouseDown = e => {
if (e.button === 0) {
start();
e.stopPropagation();
e.preventDefault();
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
addGlobalListener(window, 'mousemove', onMouseMove, false);
addGlobalListener(window, 'mouseup', onMouseUp, false);
}
};
let onTouchMove = e => {
// @ts-ignore
let touch = [...e.changedTouches].findIndex((_ref) => {
let {
identifier
} = _ref;
return identifier === state.current.id;
});
if (touch >= 0) {
let {
pageX,
pageY
} = e.changedTouches[touch];
move('touch', pageX - state.current.lastPosition.pageX, pageY - state.current.lastPosition.pageY);
state.current.lastPosition = {
pageX,
pageY
};
}
};
let onTouchEnd = e => {
// @ts-ignore
let touch = [...e.changedTouches].findIndex((_ref2) => {
let {
identifier
} = _ref2;
return identifier === state.current.id;
});
if (touch >= 0) {
end('touch');
state.current.id = null;
removeGlobalListener(window, 'touchmove', onTouchMove);
removeGlobalListener(window, 'touchend', onTouchEnd);
removeGlobalListener(window, 'touchcancel', onTouchEnd);
}
};
moveProps.onTouchStart = e => {
if (e.changedTouches.length === 0 || state.current.id != null) {
return;
}
let {
pageX,
pageY,
identifier
} = e.changedTouches[0];
start();
e.stopPropagation();
e.preventDefault();
state.current.lastPosition = {
pageX,
pageY
};
state.current.id = identifier;
addGlobalListener(window, 'touchmove', onTouchMove, false);
addGlobalListener(window, 'touchend', onTouchEnd, false);
addGlobalListener(window, 'touchcancel', onTouchEnd, false);
};
} else {
let onPointerMove = e => {
if (e.pointerId === state.current.id) {
// @ts-ignore
let pointerType = e.pointerType || 'mouse'; // Problems with PointerEvent#movementX/movementY:
// 1. it is always 0 on macOS Safari.
// 2. On Chrome Android, it's scaled by devicePixelRatio, but not on Chrome macOS
move(pointerType, e.pageX - state.current.lastPosition.pageX, e.pageY - state.current.lastPosition.pageY);
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
}
};
let onPointerUp = e => {
if (e.pointerId === state.current.id) {
// @ts-ignore
let pointerType = e.pointerType || 'mouse';
end(pointerType);
state.current.id = null;
removeGlobalListener(window, 'pointermove', onPointerMove, false);
removeGlobalListener(window, 'pointerup', onPointerUp, false);
removeGlobalListener(window, 'pointercancel', onPointerUp, false);
}
};
moveProps.onPointerDown = e => {
if (e.button === 0 && state.current.id == null) {
start();
e.stopPropagation();
e.preventDefault();
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
state.current.id = e.pointerId;
addGlobalListener(window, 'pointermove', onPointerMove, false);
addGlobalListener(window, 'pointerup', onPointerUp, false);
addGlobalListener(window, 'pointercancel', onPointerUp, false);
}
};
}
let triggetKeyboardMove = (deltaX, deltaY) => {
start();
move('keyboard', deltaX, deltaY);
end('keyboard');
};
moveProps.onKeyDown = e => {
switch (e.key) {
case 'Left':
case 'ArrowLeft':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(-1, 0);
break;
case 'Right':
case 'ArrowRight':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(1, 0);
break;
case 'Up':
case 'ArrowUp':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(0, -1);
break;
case 'Down':
case 'ArrowDown':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(0, 1);
break;
}
};
return moveProps;
}, [state, onMoveStart, onMove, onMoveEnd, addGlobalListener, removeGlobalListener]);
return {
moveProps
};
}
exports.useMove = useMove;
//# sourceMappingURL=main.js.map

@@ -0,5 +1,5 @@

import _react, { useContext, useEffect, useMemo, useRef, useState } from "react";
import { mergeProps, runAfterTransition, focusWithoutScrolling, useGlobalListeners } from "@react-aria/utils";
import _babelRuntimeHelpersEsmObjectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
import _babelRuntimeHelpersEsmExtends from "@babel/runtime/helpers/esm/extends";
import _react, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import { runAfterTransition, focusWithoutScrolling, mergeProps } from "@react-aria/utils";
import _babelRuntimeHelpersEsmObjectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
let $e17c9db826984f8ab8e5d837bf0b8$var$state = 'default';

@@ -132,15 +132,6 @@ let $e17c9db826984f8ab8e5d837bf0b8$var$savedUserSelect = '';

});
let globalListeners = useRef(new Map());
let addGlobalListener = useCallback((eventTarget, type, listener, options) => {
globalListeners.current.set(listener, {
type,
eventTarget,
options
});
eventTarget.addEventListener(type, listener, options);
}, []);
let removeGlobalListener = useCallback((eventTarget, type, listener, options) => {
eventTarget.removeEventListener(type, listener, options);
globalListeners.current.delete(listener);
}, []);
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners();
let pressProps = useMemo(() => {

@@ -577,11 +568,8 @@ let state = ref.current;

return pressProps;
}, [isDisabled, onPressStart, onPressChange, onPressEnd, onPress, onPressUp, addGlobalListener, preventFocusOnPress, removeGlobalListener]); // eslint-disable-next-line arrow-body-style
}, [isDisabled, onPressStart, onPressChange, onPressEnd, onPress, onPressUp, addGlobalListener, preventFocusOnPress, removeGlobalListener]); // Remove user-select: none in case component unmounts immediately after pressStart
// eslint-disable-next-line arrow-body-style
useEffect(() => {
return () => {
globalListeners.current.forEach((value, key) => {
removeGlobalListener(value.eventTarget, value.type, key, value.options);
});
};
}, [removeGlobalListener]);
return () => $e17c9db826984f8ab8e5d837bf0b8$export$restoreTextSelection();
}, []);
return {

@@ -656,90 +644,5 @@ isPressed: isPressedProp || isPressed,

/**
* Example, used in components like Dialogs and Popovers so they can close
* when a user clicks outside them.
*/
export function useInteractOutside(props) {
let {
ref,
onInteractOutside
} = props;
let stateRef = useRef({
isPointerDown: false,
ignoreEmulatedMouseEvents: false
});
let state = stateRef.current;
useEffect(() => {
let onPointerDown = e => {
if ($e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = true;
}
}; // Use pointer events if available. Otherwise, fall back to mouse and touch events.
export const Pressable = _react.forwardRef((_ref, ref) => {
var _ref2;
if (typeof PointerEvent !== 'undefined') {
let onPointerUp = e => {
if (state.isPointerDown && onInteractOutside && $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
}
}; // changing these to capture phase fixed combobox
document.addEventListener('pointerdown', onPointerDown, true);
document.addEventListener('pointerup', onPointerUp, true);
return () => {
document.removeEventListener('pointerdown', onPointerDown, true);
document.removeEventListener('pointerup', onPointerUp, true);
};
} else {
let onMouseUp = e => {
if (state.ignoreEmulatedMouseEvents) {
state.ignoreEmulatedMouseEvents = false;
} else if (state.isPointerDown && onInteractOutside && $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
}
};
let onTouchEnd = e => {
state.ignoreEmulatedMouseEvents = true;
if (onInteractOutside && state.isPointerDown && $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
}
};
document.addEventListener('mousedown', onPointerDown, true);
document.addEventListener('mouseup', onMouseUp, true);
document.addEventListener('touchstart', onPointerDown, true);
document.addEventListener('touchend', onTouchEnd, true);
return () => {
document.removeEventListener('mousedown', onPointerDown, true);
document.removeEventListener('mouseup', onMouseUp, true);
document.removeEventListener('touchstart', onPointerDown, true);
document.removeEventListener('touchend', onTouchEnd, true);
};
}
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents, state.isPointerDown]);
}
function $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(event, ref) {
if (event.button > 0) {
return false;
} // if the event target is no longer in the document
if (event.target) {
const ownerDocument = event.target.ownerDocument;
if (!ownerDocument || !ownerDocument.body.contains(event.target)) {
return false;
}
}
return ref.current && !ref.current.contains(event.target);
}
export const Pressable = _react.forwardRef((_ref, ref) => {
let {

@@ -750,3 +653,4 @@ children

ref = ref || useRef();
let newRef = useRef();
ref = (_ref2 = ref) != null ? _ref2 : newRef;
let {

@@ -794,51 +698,2 @@ pressProps

});
/**
* This function wraps a React event handler to make stopPropagation the default, and support continuePropagation instead.
*/
function $dc0d75166de722fbf58eb6c3552$export$createEventHandler(handler) {
if (!handler) {
return;
}
let shouldStopPropagation = true;
return e => {
let event = _babelRuntimeHelpersEsmExtends({}, e, {
preventDefault() {
e.preventDefault();
},
isDefaultPrevented() {
return e.isDefaultPrevented();
},
stopPropagation() {
console.error('stopPropagation is now the default behavior for events in React Spectrum. You can use continuePropagation() to revert this behavior.');
},
continuePropagation() {
shouldStopPropagation = false;
}
});
handler(event);
if (shouldStopPropagation) {
e.stopPropagation();
}
};
}
/**
* Handles keyboard interactions for a focusable element.
*/
export function useKeyboard(props) {
return {
keyboardProps: props.isDisabled ? {} : {
onKeyDown: $dc0d75166de722fbf58eb6c3552$export$createEventHandler(props.onKeyDown),
onKeyUp: $dc0d75166de722fbf58eb6c3552$export$createEventHandler(props.onKeyUp)
}
};
}
// NOTICE file in the root directory of this source tree.

@@ -895,55 +750,2 @@ // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions

}
/**
* Handles focus events for the target and its descendants.
*/
export function useFocusWithin(props) {
let state = useRef({
isFocusWithin: false
}).current;
if (props.isDisabled) {
return {
focusWithinProps: {}
};
}
let onFocus = e => {
if (!state.isFocusWithin) {
if (props.onFocusWithin) {
props.onFocusWithin(e);
}
if (props.onFocusWithinChange) {
props.onFocusWithinChange(true);
}
state.isFocusWithin = true;
}
};
let onBlur = 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;
}
};
return {
focusWithinProps: {
onFocus: onFocus,
onBlur: onBlur
}
};
}
let $d01f69bb2ab5f70dfd0005370a2a2cbc$var$currentModality = null;

@@ -1132,2 +934,55 @@ let $d01f69bb2ab5f70dfd0005370a2a2cbc$var$changeHandlers = new Set();

}
/**
* Handles focus events for the target and its descendants.
*/
export function useFocusWithin(props) {
let state = useRef({
isFocusWithin: false
}).current;
if (props.isDisabled) {
return {
focusWithinProps: {}
};
}
let onFocus = e => {
if (!state.isFocusWithin) {
if (props.onFocusWithin) {
props.onFocusWithin(e);
}
if (props.onFocusWithinChange) {
props.onFocusWithinChange(true);
}
state.isFocusWithin = true;
}
};
let onBlur = 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;
}
};
return {
focusWithinProps: {
onFocus: onFocus,
onBlur: onBlur
}
};
}
// iOS fires onPointerEnter twice: once with pointerType="touch" and again with pointerType="mouse".

@@ -1287,2 +1142,400 @@ // We want to ignore these emulated events so they do not trigger hover behavior.

}
/**
* Example, used in components like Dialogs and Popovers so they can close
* when a user clicks outside them.
*/
export function useInteractOutside(props) {
let {
ref,
onInteractOutside
} = props;
let stateRef = useRef({
isPointerDown: false,
ignoreEmulatedMouseEvents: false
});
let state = stateRef.current;
useEffect(() => {
let onPointerDown = e => {
if ($e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = true; // Due to browser inconsistencies, we prevent
// default on pointer down. FF will otherwise try to start text selection.
if (e.button === 0) {
e.preventDefault();
}
}
}; // Use pointer events if available. Otherwise, fall back to mouse and touch events.
if (typeof PointerEvent !== 'undefined') {
let onPointerUp = e => {
if (state.isPointerDown && onInteractOutside && $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}
}; // changing these to capture phase fixed combobox
document.addEventListener('pointerdown', onPointerDown, true);
document.addEventListener('pointerup', onPointerUp, true);
return () => {
document.removeEventListener('pointerdown', onPointerDown, true);
document.removeEventListener('pointerup', onPointerUp, true);
};
} else {
let onMouseUp = e => {
if (state.ignoreEmulatedMouseEvents) {
state.ignoreEmulatedMouseEvents = false;
} else if (state.isPointerDown && onInteractOutside && $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}
};
let onTouchEnd = e => {
state.ignoreEmulatedMouseEvents = true;
if (onInteractOutside && state.isPointerDown && $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(e, ref)) {
state.isPointerDown = false;
onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}
};
document.addEventListener('mousedown', onPointerDown, true);
document.addEventListener('mouseup', onMouseUp, true);
document.addEventListener('touchstart', onPointerDown, true);
document.addEventListener('touchend', onTouchEnd, true);
return () => {
document.removeEventListener('mousedown', onPointerDown, true);
document.removeEventListener('mouseup', onMouseUp, true);
document.removeEventListener('touchstart', onPointerDown, true);
document.removeEventListener('touchend', onTouchEnd, true);
};
}
}, [onInteractOutside, ref, state.ignoreEmulatedMouseEvents, state.isPointerDown]);
}
function $e415bb64ab27cb8fbfac2f417412022f$var$isValidEvent(event, ref) {
if (event.button > 0) {
return false;
} // if the event target is no longer in the document
if (event.target) {
const ownerDocument = event.target.ownerDocument;
if (!ownerDocument || !ownerDocument.body.contains(event.target)) {
return false;
}
}
return ref.current && !ref.current.contains(event.target);
}
/**
* This function wraps a React event handler to make stopPropagation the default, and support continuePropagation instead.
*/
function $dc0d75166de722fbf58eb6c3552$export$createEventHandler(handler) {
if (!handler) {
return;
}
let shouldStopPropagation = true;
return e => {
let event = _babelRuntimeHelpersEsmExtends({}, e, {
preventDefault() {
e.preventDefault();
},
isDefaultPrevented() {
return e.isDefaultPrevented();
},
stopPropagation() {
console.error('stopPropagation is now the default behavior for events in React Spectrum. You can use continuePropagation() to revert this behavior.');
},
continuePropagation() {
shouldStopPropagation = false;
}
});
handler(event);
if (shouldStopPropagation) {
e.stopPropagation();
}
};
}
/**
* Handles keyboard interactions for a focusable element.
*/
export function useKeyboard(props) {
return {
keyboardProps: props.isDisabled ? {} : {
onKeyDown: $dc0d75166de722fbf58eb6c3552$export$createEventHandler(props.onKeyDown),
onKeyUp: $dc0d75166de722fbf58eb6c3552$export$createEventHandler(props.onKeyUp)
}
};
}
/**
* Handles move interactions across mouse, touch, and keyboard, including dragging with
* the mouse or touch, and using the arrow keys. Normalizes behavior across browsers and
* platforms, and ignores emulated mouse events on touch devices.
*/
export function useMove(props) {
let {
onMoveStart,
onMove,
onMoveEnd
} = props;
let state = useRef({
didMove: false,
lastPosition: null,
id: null
});
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners();
let moveProps = useMemo(() => {
let moveProps = {};
let start = () => {
$e17c9db826984f8ab8e5d837bf0b8$export$disableTextSelection();
state.current.didMove = false;
};
let move = (pointerType, deltaX, deltaY) => {
if (deltaX === 0 && deltaY === 0) {
return;
}
if (!state.current.didMove) {
state.current.didMove = true;
onMoveStart == null ? void 0 : onMoveStart({
type: 'movestart',
pointerType
});
}
onMove({
type: 'move',
pointerType,
deltaX: deltaX,
deltaY: deltaY
});
};
let end = pointerType => {
$e17c9db826984f8ab8e5d837bf0b8$export$restoreTextSelection();
if (state.current.didMove) {
onMoveEnd == null ? void 0 : onMoveEnd({
type: 'moveend',
pointerType
});
}
};
if (typeof PointerEvent === 'undefined') {
let onMouseMove = e => {
if (e.button === 0) {
move('mouse', e.pageX - state.current.lastPosition.pageX, e.pageY - state.current.lastPosition.pageY);
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
}
};
let onMouseUp = e => {
if (e.button === 0) {
end('mouse');
removeGlobalListener(window, 'mousemove', onMouseMove, false);
removeGlobalListener(window, 'mouseup', onMouseUp, false);
}
};
moveProps.onMouseDown = e => {
if (e.button === 0) {
start();
e.stopPropagation();
e.preventDefault();
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
addGlobalListener(window, 'mousemove', onMouseMove, false);
addGlobalListener(window, 'mouseup', onMouseUp, false);
}
};
let onTouchMove = e => {
// @ts-ignore
let touch = [...e.changedTouches].findIndex((_ref) => {
let {
identifier
} = _ref;
return identifier === state.current.id;
});
if (touch >= 0) {
let {
pageX,
pageY
} = e.changedTouches[touch];
move('touch', pageX - state.current.lastPosition.pageX, pageY - state.current.lastPosition.pageY);
state.current.lastPosition = {
pageX,
pageY
};
}
};
let onTouchEnd = e => {
// @ts-ignore
let touch = [...e.changedTouches].findIndex((_ref2) => {
let {
identifier
} = _ref2;
return identifier === state.current.id;
});
if (touch >= 0) {
end('touch');
state.current.id = null;
removeGlobalListener(window, 'touchmove', onTouchMove);
removeGlobalListener(window, 'touchend', onTouchEnd);
removeGlobalListener(window, 'touchcancel', onTouchEnd);
}
};
moveProps.onTouchStart = e => {
if (e.changedTouches.length === 0 || state.current.id != null) {
return;
}
let {
pageX,
pageY,
identifier
} = e.changedTouches[0];
start();
e.stopPropagation();
e.preventDefault();
state.current.lastPosition = {
pageX,
pageY
};
state.current.id = identifier;
addGlobalListener(window, 'touchmove', onTouchMove, false);
addGlobalListener(window, 'touchend', onTouchEnd, false);
addGlobalListener(window, 'touchcancel', onTouchEnd, false);
};
} else {
let onPointerMove = e => {
if (e.pointerId === state.current.id) {
// @ts-ignore
let pointerType = e.pointerType || 'mouse'; // Problems with PointerEvent#movementX/movementY:
// 1. it is always 0 on macOS Safari.
// 2. On Chrome Android, it's scaled by devicePixelRatio, but not on Chrome macOS
move(pointerType, e.pageX - state.current.lastPosition.pageX, e.pageY - state.current.lastPosition.pageY);
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
}
};
let onPointerUp = e => {
if (e.pointerId === state.current.id) {
// @ts-ignore
let pointerType = e.pointerType || 'mouse';
end(pointerType);
state.current.id = null;
removeGlobalListener(window, 'pointermove', onPointerMove, false);
removeGlobalListener(window, 'pointerup', onPointerUp, false);
removeGlobalListener(window, 'pointercancel', onPointerUp, false);
}
};
moveProps.onPointerDown = e => {
if (e.button === 0 && state.current.id == null) {
start();
e.stopPropagation();
e.preventDefault();
state.current.lastPosition = {
pageX: e.pageX,
pageY: e.pageY
};
state.current.id = e.pointerId;
addGlobalListener(window, 'pointermove', onPointerMove, false);
addGlobalListener(window, 'pointerup', onPointerUp, false);
addGlobalListener(window, 'pointercancel', onPointerUp, false);
}
};
}
let triggetKeyboardMove = (deltaX, deltaY) => {
start();
move('keyboard', deltaX, deltaY);
end('keyboard');
};
moveProps.onKeyDown = e => {
switch (e.key) {
case 'Left':
case 'ArrowLeft':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(-1, 0);
break;
case 'Right':
case 'ArrowRight':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(1, 0);
break;
case 'Up':
case 'ArrowUp':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(0, -1);
break;
case 'Down':
case 'ArrowDown':
e.preventDefault();
e.stopPropagation();
triggetKeyboardMove(0, 1);
break;
}
};
return moveProps;
}, [state, onMoveStart, onMove, onMoveEnd, addGlobalListener, removeGlobalListener]);
return {
moveProps
};
}
//# sourceMappingURL=module.js.map

@@ -1,3 +0,3 @@

import React, { HTMLAttributes, RefObject, SyntheticEvent, ReactElement, ReactNode, FocusEvent } from "react";
import { PressEvents, KeyboardEvents, FocusEvents, HoverEvents } from "@react-types/shared";
import React, { HTMLAttributes, RefObject, ReactElement, ReactNode, FocusEvent, SyntheticEvent } from "react";
import { PressEvents, FocusEvents, HoverEvents, KeyboardEvents, MoveEvents } from "@react-types/shared";
export interface PressProps extends PressEvents {

@@ -27,11 +27,2 @@ /** Whether the target is in a controlled press state (e.g. an overlay it triggers is open). */

export function usePress(props: PressHookProps): PressResult;
interface InteractOutsideProps {
ref: RefObject<Element>;
onInteractOutside?: (e: SyntheticEvent) => void;
}
/**
* Example, used in components like Dialogs and Popovers so they can close
* when a user clicks outside them.
*/
export function useInteractOutside(props: InteractOutsideProps): void;
interface PressableProps extends PressProps {

@@ -45,14 +36,2 @@ children: ReactElement<HTMLAttributes<HTMLElement>, string>;

export const PressResponder: React.ForwardRefExoticComponent<PressResponderProps & React.RefAttributes<HTMLElement>>;
export interface KeyboardProps extends KeyboardEvents {
/** Whether the keyboard events should be disabled. */
isDisabled?: boolean;
}
interface KeyboardResult {
/** Props to spread onto the target element. */
keyboardProps: HTMLAttributes<HTMLElement>;
}
/**
* Handles keyboard interactions for a focusable element.
*/
export function useKeyboard(props: KeyboardProps): KeyboardResult;
interface FocusProps extends FocusEvents {

@@ -71,20 +50,2 @@ /** Whether the focus events should be disabled. */

export function useFocus(props: FocusProps): FocusResult;
interface FocusWithinProps {
/** Whether the focus within events should be disabled. */
isDisabled?: boolean;
/** Handler that is called when the target element or a descendant receives focus. */
onFocusWithin?: (e: FocusEvent) => void;
/** Handler that is called when the target element and all descendants lose focus. */
onBlurWithin?: (e: FocusEvent) => void;
/** Handler that is called when the the focus within state changes. */
onFocusWithinChange?: (isFocusWithin: boolean) => void;
}
interface FocusWithinResult {
/** Props to spread onto the target element. */
focusWithinProps: HTMLAttributes<HTMLElement>;
}
/**
* Handles focus events for the target and its descendants.
*/
export function useFocusWithin(props: FocusWithinProps): FocusWithinResult;
type Modality = 'keyboard' | 'pointer' | 'virtual';

@@ -115,2 +76,20 @@ interface FocusVisibleProps {

export function useFocusVisible(props?: FocusVisibleProps): FocusVisibleResult;
interface FocusWithinProps {
/** Whether the focus within events should be disabled. */
isDisabled?: boolean;
/** Handler that is called when the target element or a descendant receives focus. */
onFocusWithin?: (e: FocusEvent) => void;
/** Handler that is called when the target element and all descendants lose focus. */
onBlurWithin?: (e: FocusEvent) => void;
/** Handler that is called when the the focus within state changes. */
onFocusWithinChange?: (isFocusWithin: boolean) => void;
}
interface FocusWithinResult {
/** Props to spread onto the target element. */
focusWithinProps: HTMLAttributes<HTMLElement>;
}
/**
* Handles focus events for the target and its descendants.
*/
export function useFocusWithin(props: FocusWithinProps): FocusWithinResult;
export interface HoverProps extends HoverEvents {

@@ -130,3 +109,34 @@ /** Whether the hover events should be disabled. */

export function useHover(props: HoverProps): HoverResult;
interface InteractOutsideProps {
ref: RefObject<Element>;
onInteractOutside?: (e: SyntheticEvent) => void;
}
/**
* Example, used in components like Dialogs and Popovers so they can close
* when a user clicks outside them.
*/
export function useInteractOutside(props: InteractOutsideProps): void;
export interface KeyboardProps extends KeyboardEvents {
/** Whether the keyboard events should be disabled. */
isDisabled?: boolean;
}
interface KeyboardResult {
/** Props to spread onto the target element. */
keyboardProps: HTMLAttributes<HTMLElement>;
}
/**
* Handles keyboard interactions for a focusable element.
*/
export function useKeyboard(props: KeyboardProps): KeyboardResult;
interface MoveResult {
/** Props to spread on the target element. */
moveProps: HTMLAttributes<HTMLElement>;
}
/**
* Handles move interactions across mouse, touch, and keyboard, including dragging with
* the mouse or touch, and using the arrow keys. Normalizes behavior across browsers and
* platforms, and ignores emulated mouse events on touch devices.
*/
export function useMove(props: MoveEvents): MoveResult;
//# sourceMappingURL=types.d.ts.map
{
"name": "@react-aria/interactions",
"version": "3.2.1",
"version": "3.3.0",
"description": "Spectrum UI components in React",

@@ -21,4 +21,4 @@ "license": "Apache-2.0",

"@babel/runtime": "^7.6.2",
"@react-aria/utils": "^3.3.0",
"@react-types/shared": "^3.2.1"
"@react-aria/utils": "^3.4.0",
"@react-types/shared": "^3.3.0"
},

@@ -31,3 +31,3 @@ "peerDependencies": {

},
"gitHead": "0778f71a3c13e1e24388a23b6d525e3b9f5b98f1"
"gitHead": "9f738a06ea4e256c8d975f00502b4b0bbabb8f65"
}

@@ -16,3 +16,3 @@ /*

interface PressResponderContext extends PressProps {
interface IPressResponderContext extends PressProps {
register(): void,

@@ -22,3 +22,3 @@ ref?: MutableRefObject<HTMLElement>

export const PressResponderContext = React.createContext<PressResponderContext>(null);
export const PressResponderContext = React.createContext<IPressResponderContext>(null);
PressResponderContext.displayName = 'PressResponderContext';

@@ -20,3 +20,3 @@ /*

interface DOMPropsResponderContext extends HTMLAttributes<HTMLElement> {
interface IDOMPropsResponderContext extends HTMLAttributes<HTMLElement> {
register(): void,

@@ -26,3 +26,3 @@ ref?: MutableRefObject<HTMLElement>

export const DOMPropsResponderContext = React.createContext<DOMPropsResponderContext>(null);
export const DOMPropsResponderContext = React.createContext<IDOMPropsResponderContext>(null);

@@ -29,0 +29,0 @@ export function useDOMPropsResponderContext(props: DOMPropsResponderProps): DOMPropsResponderProps {

@@ -13,10 +13,11 @@ /*

export * from './usePress';
export * from './useInteractOutside';
export * from './Pressable';
export * from './PressResponder';
export * from './useKeyboard';
export * from './useFocus';
export * from './useFocusVisible';
export * from './useFocusWithin';
export * from './useFocusVisible';
export * from './useHover';
export * from './useInteractOutside';
export * from './useKeyboard';
export * from './useMove';
export * from './usePress';

@@ -41,2 +41,7 @@ /*

state.isPointerDown = true;
// Due to browser inconsistencies, we prevent
// default on pointer down. FF will otherwise try to start text selection.
if (e.button === 0) {
e.preventDefault();
}
}

@@ -51,2 +56,5 @@ };

onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}

@@ -70,2 +78,5 @@ };

onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}

@@ -79,2 +90,5 @@ };

onInteractOutside(e);
if (e.button === 0) {
e.preventDefault();
}
}

@@ -81,0 +95,0 @@ };

@@ -20,6 +20,7 @@ /*

import {focusWithoutScrolling, mergeProps} from '@react-aria/utils';
import {HTMLAttributes, RefObject, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {HTMLAttributes, RefObject, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {isVirtualClick} from './utils';
import {PointerType, PressEvents} from '@react-types/shared';
import {PressResponderContext} from './context';
import {useGlobalListeners} from '@react-aria/utils';

@@ -102,3 +103,3 @@ export interface PressProps extends PressEvents {

// eslint-disable-next-line @typescript-eslint/no-unused-vars
ref: _, // Removing `ref` from `domProps` because TypeScript is dumb
ref: _, // Removing `ref` from `domProps` because TypeScript is dumb,
...domProps

@@ -117,11 +118,3 @@ } = usePressResponderContext(props);

let globalListeners = useRef(new Map());
let addGlobalListener = useCallback((eventTarget, type, listener, options) => {
globalListeners.current.set(listener, {type, eventTarget, options});
eventTarget.addEventListener(type, listener, options);
}, []);
let removeGlobalListener = useCallback((eventTarget, type, listener, options) => {
eventTarget.removeEventListener(type, listener, options);
globalListeners.current.delete(listener);
}, []);
let {addGlobalListener, removeGlobalListener} = useGlobalListeners();

@@ -548,10 +541,7 @@ let pressProps = useMemo(() => {

// Remove user-select: none in case component unmounts immediately after pressStart
// eslint-disable-next-line arrow-body-style
useEffect(() => {
return () => {
globalListeners.current.forEach((value, key) => {
removeGlobalListener(value.eventTarget, value.type, key, value.options);
});
};
}, [removeGlobalListener]);
return () => restoreTextSelection();
}, []);

@@ -558,0 +548,0 @@ return {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc