Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@react-aria/numberfield

Package Overview
Dependencies
Maintainers
2
Versions
708
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@react-aria/numberfield - npm Package Compare versions

Comparing version 3.0.0-nightly.992 to 3.0.0-nightly.994

178

dist/main.js
var {
useTextField
} = require("@react-aria/textfield");
var {
useSpinButton

@@ -15,4 +11,9 @@ } = require("@react-aria/spinbutton");

var {
useFormattedTextField
} = require("@react-aria/textfield");
var {
useFocus,
useFocusWithin
useFocusWithin,
useScrollWheel
} = require("@react-aria/interactions");

@@ -30,5 +31,3 @@

useCallback,
useEffect,
useMemo,
useRef,
useState

@@ -185,6 +184,2 @@ } = require("react");

function $ebb253b0ca493f114f41772a028a$var$supportsNativeBeforeInputEvent() {
return typeof window !== 'undefined' && window.InputEvent && // @ts-ignore
typeof InputEvent.prototype.getTargetRanges === 'function';
}
/**

@@ -194,4 +189,2 @@ * Provides the behavior and accessibility implementation for a number field component.

*/
function useNumberField(props, state, inputRef) {

@@ -255,10 +248,2 @@ let {

let onWheel = useCallback(e => {
// If the ctrlKey is pressed, this is a zoom event, do nothing.
if (e.ctrlKey) {
return;
} // stop scrolling the page
e.preventDefault();
if (e.deltaY > 0) {

@@ -272,5 +257,4 @@ increment();

let scrollingDisabled = isDisabled || isReadOnly || !focusWithin;
$ebb253b0ca493f114f41772a028a$var$useScrollWheel({
useScrollWheel({
onScroll: onWheel,
capture: false,
isDisabled: scrollingDisabled

@@ -307,77 +291,2 @@ }, inputRef); // The inputMode attribute influences the software keyboard that is shown on touch devices.

let stateRef = useRef(state);
stateRef.current = state; // All browsers implement the 'beforeinput' event natively except Firefox
// (currently behind a flag as of Firefox 84). React's polyfill does not
// run in all cases that the native event fires, e.g. when deleting text.
// Use the native event if available so that we can prevent invalid deletions.
// We do not attempt to polyfill this in Firefox since it would be very complicated,
// the benefit of doing so is fairly minor, and it's going to be natively supported soon.
useEffect(() => {
if (!$ebb253b0ca493f114f41772a028a$var$supportsNativeBeforeInputEvent()) {
return;
}
let input = inputRef.current;
let onBeforeInput = e => {
let state = stateRef.current; // Compute the next value of the input if the event is allowed to proceed.
// See https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes for a full list of input types.
let nextValue;
switch (e.inputType) {
case 'historyUndo':
case 'historyRedo':
// Explicitly allow undo/redo. e.data is null in this case, but there's no need to validate,
// because presumably the input would have already been validated previously.
return;
case 'deleteContent':
case 'deleteByCut':
case 'deleteByDrag':
nextValue = input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
case 'deleteContentForward':
// This is potentially incorrect, since the browser may actually delete more than a single UTF-16
// character. In reality, a full Unicode grapheme cluster consisting of multiple UTF-16 characters
// or code points may be deleted. However, in our currently supported locales, there are no such cases.
// If we support additional locales in the future, this may need to change.
nextValue = input.selectionEnd === input.selectionStart ? input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd + 1) : input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
case 'deleteContentBackward':
nextValue = input.selectionEnd === input.selectionStart ? input.value.slice(0, input.selectionStart - 1) + input.value.slice(input.selectionStart) : input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
default:
if (e.data != null) {
nextValue = input.value.slice(0, input.selectionStart) + e.data + input.value.slice(input.selectionEnd);
}
break;
} // If we did not compute a value, or the new value is invalid, prevent the event
// so that the browser does not update the input text, move the selection, or add to
// the undo/redo stack.
if (nextValue == null || !state.validate(nextValue)) {
e.preventDefault();
}
};
input.addEventListener('beforeinput', onBeforeInput, false);
return () => {
input.removeEventListener('beforeinput', onBeforeInput, false);
};
}, [inputRef, stateRef]);
let onBeforeInput = !$ebb253b0ca493f114f41772a028a$var$supportsNativeBeforeInputEvent() ? e => {
let nextValue = e.target.value.slice(0, e.target.selectionStart) + e.data + e.target.value.slice(e.target.selectionEnd);
if (!state.validate(nextValue)) {
e.preventDefault();
}
} : null;
let onChange = value => {

@@ -387,7 +296,6 @@ state.setInputValue(value);

let compositionStartState = useRef(null);
let {
labelProps,
inputProps: textFieldProps
} = useTextField({
} = useFormattedTextField({
label,

@@ -407,46 +315,4 @@ autoFocus,

inputMode,
onChange,
onBeforeInput,
onCompositionStart() {
// Chrome does not implement Input Events Level 2, which specifies the insertFromComposition
// and deleteByComposition inputType values for the beforeinput event. These are meant to occur
// at the end of a composition (e.g. Pinyin IME, Android auto correct, etc.), and crucially, are
// cancelable. The insertCompositionText and deleteCompositionText input types are not cancelable,
// nor would we want to cancel them because the input from the user is incomplete at that point.
// In Safari, insertFromComposition/deleteFromComposition will fire, however, allowing us to cancel
// the final composition result if it is invalid. As a fallback for Chrome and Firefox, which either
// don't support Input Events Level 2, or beforeinput at all, we store the state of the input when
// the compositionstart event fires, and undo the changes in compositionend (below) if it is invalid.
// Unfortunately, this messes up the undo/redo stack, but until insertFromComposition/deleteByComposition
// are implemented, there is no other way to prevent composed input.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1022204
let {
value,
selectionStart,
selectionEnd
} = inputRef.current;
compositionStartState.current = {
value,
selectionStart,
selectionEnd
};
},
onCompositionEnd() {
if (!state.validate(inputRef.current.value)) {
// Restore the input value in the DOM immediately so we can synchronously update the selection position.
// But also update the value in React state as well so it is correct for future updates.
let {
value,
selectionStart,
selectionEnd
} = compositionStartState.current;
inputRef.current.value = value;
inputRef.current.setSelectionRange(selectionStart, selectionEnd);
state.setInputValue(value);
}
}
}, inputRef);
onChange
}, state, inputRef);
let inputProps = mergeProps(spinButtonProps, textFieldProps, focusProps, {

@@ -536,27 +402,5 @@ // override the spinbutton role, we can't focus a spin button with VO

};
} // scroll wheel needs to be added not passively so it's cancelable, small helper hook to remember that
}
exports.useNumberField = useNumberField;
function $ebb253b0ca493f114f41772a028a$var$useScrollWheel(_ref, ref) {
let {
onScroll,
capture,
isDisabled
} = _ref;
useEffect(() => {
let elem = ref.current;
if (!isDisabled) {
elem.addEventListener('wheel', onScroll, capture);
}
return () => {
if (!isDisabled) {
elem.removeEventListener('wheel', onScroll, capture);
}
};
}, [onScroll, ref, capture, isDisabled]);
}
//# sourceMappingURL=main.js.map

@@ -1,7 +0,7 @@

import { useTextField } from "@react-aria/textfield";
import { useSpinButton } from "@react-aria/spinbutton";
import { useMessageFormatter, useNumberFormatter } from "@react-aria/i18n";
import { useFocus, useFocusWithin } from "@react-aria/interactions";
import { useFormattedTextField } from "@react-aria/textfield";
import { useFocus, useFocusWithin, useScrollWheel } from "@react-aria/interactions";
import { isAndroid, isIOS, isIPhone, mergeProps, useId } from "@react-aria/utils";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useCallback, useMemo, useState } from "react";
import _babelRuntimeHelpersEsmInteropRequireDefault from "@babel/runtime/helpers/esm/interopRequireDefault";

@@ -149,6 +149,2 @@ import _babelRuntimeHelpersEsmExtends from "@babel/runtime/helpers/esm/extends";

function $b40e566e8b7705a138eb78aae622eee$var$supportsNativeBeforeInputEvent() {
return typeof window !== 'undefined' && window.InputEvent && // @ts-ignore
typeof InputEvent.prototype.getTargetRanges === 'function';
}
/**

@@ -158,4 +154,2 @@ * Provides the behavior and accessibility implementation for a number field component.

*/
export function useNumberField(props, state, inputRef) {

@@ -219,10 +213,2 @@ let {

let onWheel = useCallback(e => {
// If the ctrlKey is pressed, this is a zoom event, do nothing.
if (e.ctrlKey) {
return;
} // stop scrolling the page
e.preventDefault();
if (e.deltaY > 0) {

@@ -236,5 +222,4 @@ increment();

let scrollingDisabled = isDisabled || isReadOnly || !focusWithin;
$b40e566e8b7705a138eb78aae622eee$var$useScrollWheel({
useScrollWheel({
onScroll: onWheel,
capture: false,
isDisabled: scrollingDisabled

@@ -271,77 +256,2 @@ }, inputRef); // The inputMode attribute influences the software keyboard that is shown on touch devices.

let stateRef = useRef(state);
stateRef.current = state; // All browsers implement the 'beforeinput' event natively except Firefox
// (currently behind a flag as of Firefox 84). React's polyfill does not
// run in all cases that the native event fires, e.g. when deleting text.
// Use the native event if available so that we can prevent invalid deletions.
// We do not attempt to polyfill this in Firefox since it would be very complicated,
// the benefit of doing so is fairly minor, and it's going to be natively supported soon.
useEffect(() => {
if (!$b40e566e8b7705a138eb78aae622eee$var$supportsNativeBeforeInputEvent()) {
return;
}
let input = inputRef.current;
let onBeforeInput = e => {
let state = stateRef.current; // Compute the next value of the input if the event is allowed to proceed.
// See https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes for a full list of input types.
let nextValue;
switch (e.inputType) {
case 'historyUndo':
case 'historyRedo':
// Explicitly allow undo/redo. e.data is null in this case, but there's no need to validate,
// because presumably the input would have already been validated previously.
return;
case 'deleteContent':
case 'deleteByCut':
case 'deleteByDrag':
nextValue = input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
case 'deleteContentForward':
// This is potentially incorrect, since the browser may actually delete more than a single UTF-16
// character. In reality, a full Unicode grapheme cluster consisting of multiple UTF-16 characters
// or code points may be deleted. However, in our currently supported locales, there are no such cases.
// If we support additional locales in the future, this may need to change.
nextValue = input.selectionEnd === input.selectionStart ? input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd + 1) : input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
case 'deleteContentBackward':
nextValue = input.selectionEnd === input.selectionStart ? input.value.slice(0, input.selectionStart - 1) + input.value.slice(input.selectionStart) : input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
default:
if (e.data != null) {
nextValue = input.value.slice(0, input.selectionStart) + e.data + input.value.slice(input.selectionEnd);
}
break;
} // If we did not compute a value, or the new value is invalid, prevent the event
// so that the browser does not update the input text, move the selection, or add to
// the undo/redo stack.
if (nextValue == null || !state.validate(nextValue)) {
e.preventDefault();
}
};
input.addEventListener('beforeinput', onBeforeInput, false);
return () => {
input.removeEventListener('beforeinput', onBeforeInput, false);
};
}, [inputRef, stateRef]);
let onBeforeInput = !$b40e566e8b7705a138eb78aae622eee$var$supportsNativeBeforeInputEvent() ? e => {
let nextValue = e.target.value.slice(0, e.target.selectionStart) + e.data + e.target.value.slice(e.target.selectionEnd);
if (!state.validate(nextValue)) {
e.preventDefault();
}
} : null;
let onChange = value => {

@@ -351,7 +261,6 @@ state.setInputValue(value);

let compositionStartState = useRef(null);
let {
labelProps,
inputProps: textFieldProps
} = useTextField({
} = useFormattedTextField({
label,

@@ -371,46 +280,4 @@ autoFocus,

inputMode,
onChange,
onBeforeInput,
onCompositionStart() {
// Chrome does not implement Input Events Level 2, which specifies the insertFromComposition
// and deleteByComposition inputType values for the beforeinput event. These are meant to occur
// at the end of a composition (e.g. Pinyin IME, Android auto correct, etc.), and crucially, are
// cancelable. The insertCompositionText and deleteCompositionText input types are not cancelable,
// nor would we want to cancel them because the input from the user is incomplete at that point.
// In Safari, insertFromComposition/deleteFromComposition will fire, however, allowing us to cancel
// the final composition result if it is invalid. As a fallback for Chrome and Firefox, which either
// don't support Input Events Level 2, or beforeinput at all, we store the state of the input when
// the compositionstart event fires, and undo the changes in compositionend (below) if it is invalid.
// Unfortunately, this messes up the undo/redo stack, but until insertFromComposition/deleteByComposition
// are implemented, there is no other way to prevent composed input.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1022204
let {
value,
selectionStart,
selectionEnd
} = inputRef.current;
compositionStartState.current = {
value,
selectionStart,
selectionEnd
};
},
onCompositionEnd() {
if (!state.validate(inputRef.current.value)) {
// Restore the input value in the DOM immediately so we can synchronously update the selection position.
// But also update the value in React state as well so it is correct for future updates.
let {
value,
selectionStart,
selectionEnd
} = compositionStartState.current;
inputRef.current.value = value;
inputRef.current.setSelectionRange(selectionStart, selectionEnd);
state.setInputValue(value);
}
}
}, inputRef);
onChange
}, state, inputRef);
let inputProps = mergeProps(spinButtonProps, textFieldProps, focusProps, {

@@ -500,24 +367,3 @@ // override the spinbutton role, we can't focus a spin button with VO

};
} // scroll wheel needs to be added not passively so it's cancelable, small helper hook to remember that
function $b40e566e8b7705a138eb78aae622eee$var$useScrollWheel(_ref, ref) {
let {
onScroll,
capture,
isDisabled
} = _ref;
useEffect(() => {
let elem = ref.current;
if (!isDisabled) {
elem.addEventListener('wheel', onScroll, capture);
}
return () => {
if (!isDisabled) {
elem.removeEventListener('wheel', onScroll, capture);
}
};
}, [onScroll, ref, capture, isDisabled]);
}
//# sourceMappingURL=module.js.map

26

package.json
{
"name": "@react-aria/numberfield",
"version": "3.0.0-nightly.992+d1844573",
"version": "3.0.0-nightly.994+faa93480",
"description": "Spectrum UI components in React",

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

"@babel/runtime": "^7.6.2",
"@react-aria/i18n": "3.0.0-nightly.992+d1844573",
"@react-aria/interactions": "3.0.0-nightly.992+d1844573",
"@react-aria/live-announcer": "3.0.0-nightly.992+d1844573",
"@react-aria/spinbutton": "3.0.0-nightly.992+d1844573",
"@react-aria/textfield": "3.0.0-nightly.992+d1844573",
"@react-aria/utils": "3.0.0-nightly.992+d1844573",
"@react-stately/numberfield": "3.0.0-nightly.992+d1844573",
"@react-types/button": "3.3.2-nightly.2672+d1844573",
"@react-types/numberfield": "3.0.0-nightly.2672+d1844573",
"@react-types/shared": "3.0.0-nightly.992+d1844573",
"@react-types/textfield": "3.0.0-nightly.992+d1844573"
"@react-aria/i18n": "3.0.0-nightly.994+faa93480",
"@react-aria/interactions": "3.0.0-nightly.994+faa93480",
"@react-aria/live-announcer": "3.0.0-nightly.994+faa93480",
"@react-aria/spinbutton": "3.0.0-nightly.994+faa93480",
"@react-aria/textfield": "3.0.0-nightly.994+faa93480",
"@react-aria/utils": "3.0.0-nightly.994+faa93480",
"@react-stately/numberfield": "3.0.0-nightly.994+faa93480",
"@react-types/button": "3.3.2-nightly.2674+faa93480",
"@react-types/numberfield": "3.0.0-nightly.2674+faa93480",
"@react-types/shared": "3.0.0-nightly.994+faa93480",
"@react-types/textfield": "3.0.0-nightly.994+faa93480"
},

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

},
"gitHead": "d1844573fa992f7a34285ebafdc08cb407829095"
"gitHead": "faa9348097bf62403e37e32daf897cdad5512e09"
}

@@ -21,5 +21,3 @@ /*

useCallback,
useEffect,
useMemo,
useRef,
useState

@@ -33,2 +31,3 @@ } from 'react';

import {useFocus, useFocusWithin} from '@react-aria/interactions';
import {useFormattedTextField} from '@react-aria/textfield';
import {

@@ -38,4 +37,4 @@ useMessageFormatter,

} from '@react-aria/i18n';
import {useScrollWheel} from '@react-aria/interactions';
import {useSpinButton} from '@react-aria/spinbutton';
import {useTextField} from '@react-aria/textfield';

@@ -55,9 +54,2 @@ interface NumberFieldAria {

function supportsNativeBeforeInputEvent() {
return typeof window !== 'undefined' &&
window.InputEvent &&
// @ts-ignore
typeof InputEvent.prototype.getTargetRanges === 'function';
}
/**

@@ -127,10 +119,2 @@ * Provides the behavior and accessibility implementation for a number field component.

let onWheel = useCallback((e) => {
// If the ctrlKey is pressed, this is a zoom event, do nothing.
if (e.ctrlKey) {
return;
}
// stop scrolling the page
e.preventDefault();
if (e.deltaY > 0) {

@@ -144,3 +128,3 @@ increment();

let scrollingDisabled = isDisabled || isReadOnly || !focusWithin;
useScrollWheel({onScroll: onWheel, capture: false, isDisabled: scrollingDisabled}, inputRef);
useScrollWheel({onScroll: onWheel, isDisabled: scrollingDisabled}, inputRef);

@@ -175,86 +159,2 @@ // The inputMode attribute influences the software keyboard that is shown on touch devices.

let stateRef = useRef(state);
stateRef.current = state;
// All browsers implement the 'beforeinput' event natively except Firefox
// (currently behind a flag as of Firefox 84). React's polyfill does not
// run in all cases that the native event fires, e.g. when deleting text.
// Use the native event if available so that we can prevent invalid deletions.
// We do not attempt to polyfill this in Firefox since it would be very complicated,
// the benefit of doing so is fairly minor, and it's going to be natively supported soon.
useEffect(() => {
if (!supportsNativeBeforeInputEvent()) {
return;
}
let input = inputRef.current;
let onBeforeInput = (e: InputEvent) => {
let state = stateRef.current;
// Compute the next value of the input if the event is allowed to proceed.
// See https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes for a full list of input types.
let nextValue: string;
switch (e.inputType) {
case 'historyUndo':
case 'historyRedo':
// Explicitly allow undo/redo. e.data is null in this case, but there's no need to validate,
// because presumably the input would have already been validated previously.
return;
case 'deleteContent':
case 'deleteByCut':
case 'deleteByDrag':
nextValue = input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
case 'deleteContentForward':
// This is potentially incorrect, since the browser may actually delete more than a single UTF-16
// character. In reality, a full Unicode grapheme cluster consisting of multiple UTF-16 characters
// or code points may be deleted. However, in our currently supported locales, there are no such cases.
// If we support additional locales in the future, this may need to change.
nextValue = input.selectionEnd === input.selectionStart
? input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd + 1)
: input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
case 'deleteContentBackward':
nextValue = input.selectionEnd === input.selectionStart
? input.value.slice(0, input.selectionStart - 1) + input.value.slice(input.selectionStart)
: input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
break;
default:
if (e.data != null) {
nextValue =
input.value.slice(0, input.selectionStart) +
e.data +
input.value.slice(input.selectionEnd);
}
break;
}
// If we did not compute a value, or the new value is invalid, prevent the event
// so that the browser does not update the input text, move the selection, or add to
// the undo/redo stack.
if (nextValue == null || !state.validate(nextValue)) {
e.preventDefault();
}
};
input.addEventListener('beforeinput', onBeforeInput, false);
return () => {
input.removeEventListener('beforeinput', onBeforeInput, false);
};
}, [inputRef, stateRef]);
let onBeforeInput = !supportsNativeBeforeInputEvent()
? e => {
let nextValue =
e.target.value.slice(0, e.target.selectionStart) +
e.data +
e.target.value.slice(e.target.selectionEnd);
if (!state.validate(nextValue)) {
e.preventDefault();
}
}
: null;
let onChange = value => {

@@ -264,4 +164,3 @@ state.setInputValue(value);

let compositionStartState = useRef(null);
let {labelProps, inputProps: textFieldProps} = useTextField({
let {labelProps, inputProps: textFieldProps} = useFormattedTextField({
label,

@@ -280,31 +179,4 @@ autoFocus,

inputMode,
onChange,
onBeforeInput,
onCompositionStart() {
// Chrome does not implement Input Events Level 2, which specifies the insertFromComposition
// and deleteByComposition inputType values for the beforeinput event. These are meant to occur
// at the end of a composition (e.g. Pinyin IME, Android auto correct, etc.), and crucially, are
// cancelable. The insertCompositionText and deleteCompositionText input types are not cancelable,
// nor would we want to cancel them because the input from the user is incomplete at that point.
// In Safari, insertFromComposition/deleteFromComposition will fire, however, allowing us to cancel
// the final composition result if it is invalid. As a fallback for Chrome and Firefox, which either
// don't support Input Events Level 2, or beforeinput at all, we store the state of the input when
// the compositionstart event fires, and undo the changes in compositionend (below) if it is invalid.
// Unfortunately, this messes up the undo/redo stack, but until insertFromComposition/deleteByComposition
// are implemented, there is no other way to prevent composed input.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1022204
let {value, selectionStart, selectionEnd} = inputRef.current;
compositionStartState.current = {value, selectionStart, selectionEnd};
},
onCompositionEnd() {
if (!state.validate(inputRef.current.value)) {
// Restore the input value in the DOM immediately so we can synchronously update the selection position.
// But also update the value in React state as well so it is correct for future updates.
let {value, selectionStart, selectionEnd} = compositionStartState.current;
inputRef.current.value = value;
inputRef.current.setSelectionRange(selectionStart, selectionEnd);
state.setInputValue(value);
}
}
}, inputRef);
onChange
}, state, inputRef);

@@ -400,18 +272,1 @@ let inputProps = mergeProps(

}
// scroll wheel needs to be added not passively so it's cancelable, small helper hook to remember that
function useScrollWheel({onScroll, capture, isDisabled}: {onScroll: (e) => void, capture: boolean, isDisabled: boolean}, ref: RefObject<HTMLElement>) {
useEffect(() => {
let elem = ref.current;
if (!isDisabled) {
elem.addEventListener('wheel', onScroll, capture);
}
return () => {
if (!isDisabled) {
elem.removeEventListener('wheel', onScroll, capture);
}
};
}, [onScroll, ref, capture, isDisabled]);
}

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
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc