UNPKG

@barguide/react-hooks

Version:
202 lines (188 loc) 6.42 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var react = require('react'); var events = require('events'); var throttle = require('lodash/throttle'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var throttle__default = /*#__PURE__*/_interopDefaultLegacy(throttle); /** * @external https://nodejs.org/api/events.html * @description Much of the Node.js core API is built around an idiomatic * asynchronous event-driven architecture in which certain kinds of objects * (called "emitters") emit named events that cause Function objects * ("listeners") to be called. */ const emitter = new events.EventEmitter(); /** * @name useCheckoutLoader * @description We use the "effect" hook to add/remove an "emitter" instance * to our Modal component. By passing the "setter" from our React State we * can get a live subscription to the state state */ const useEmitter = (event, callback, initialValue = false) => { const [state, setState] = react.useState(initialValue); const onEventCallback = (value = !state) => { setState(value); if (typeof callback === 'function') callback(value); }; react.useEffect(() => { emitter.addListener(event, onEventCallback); return () => { emitter.removeListener(event, onEventCallback); }; }); return [state, setState]; }; /** * @name useFormCheckbox * @description A convenience hook for working with text inputs of type checkbox */ const useFormCheckbox = (initialValue = false) => { // Hooks const [value, setValue] = react.useState(initialValue); // Handlers const onChange = (event) => { setValue(event.target.checked); }; return { onChange, setValue, value }; }; /** * @name useFormInput * @description A convenience hook for working with text inputs */ const useFormInput = (initialValue = '') => { // Hooks const [value, setValue] = react.useState(initialValue); // Handlers const onChange = (event) => { setValue(event.target.value); }; return { onChange, setValue, value }; }; /** * @name useFormSelect * @description A convenience hook for working with text inputs of type checkbox */ const useFormSelect = (values) => { // Setup const initialValue = values[0]; // Hooks const [value, setValue] = react.useState(initialValue); // Handlers const onChange = (event) => { setValue(event.target.value); }; return { onChange, setValue, value }; }; /** * @name useFormValidation * @description Simple hook that takes a form element as a ref and returns * the validity using HTML validation and the rules on the form inputs */ const useFormValidation = (formRef, dependencies) => { // Hooks const [valid, setValid] = react.useState(false); // Setup const { current } = formRef; // Life Cycle react.useEffect(() => { if (!current) return; setValid(current.checkValidity()); }, dependencies); return valid; }; /** * @name useScroll * @description Pass this hook a callback to be fired in a * throttled callback/handler */ const useScroll = (callback) => { // Setup const throttledCallback = throttle__default["default"](callback, 100, { leading: true, trailing: true }); // Life Cycle react.useEffect(() => { window.addEventListener('scroll', throttledCallback); callback(); return () => { window.removeEventListener('scroll', throttledCallback); }; }, []); }; /** * @name useCheckoutLoader * @description We use the "effect" hook to add/remove an "emitter" instance * to our Modal component. By passing the "setter" from our React State we * can get a live subscription to the state */ const useScrollDirection = () => { const threshhold = 30; const triggerBottom = 100; const triggerTop = 100; const triggerDistance = 150; const [bottom, setBottom] = react.useState(false); const [direction, setDirection] = react.useState(false); const [position, setPosition] = react.useState(0); const [top, setTop] = react.useState(false); const onScroll = (_event) => { const root = document.documentElement; const { clientHeight, scrollTop, scrollHeight } = root; const remainder = scrollHeight - clientHeight - scrollTop; const isBottom = remainder <= triggerBottom; const isTop = scrollTop <= threshhold; const isSignificant = Math.abs(scrollTop - position) > triggerDistance; const nearBottom = remainder <= triggerBottom; const nearTop = scrollTop <= triggerTop; const isException = nearBottom || nearTop; if (isException) { if (nearTop && !top) { setBottom(false); setTop(true); } else if (nearBottom && !bottom) { setBottom(true); setTop(false); } return; } // Required travel distance if (isSignificant) { const isDownward = scrollTop > position; // Edge-cases if (top !== isTop) setTop(isTop); else if (bottom !== isBottom) setBottom(isBottom); // Account for negative scrolling (mobile) setPosition(scrollTop <= 0 ? 0 : scrollTop); setDirection(isDownward); } }; const throttledResize = throttle__default["default"](onScroll, 100, { leading: true, trailing: true }); react.useEffect(() => { window.addEventListener('scroll', throttledResize); return () => { window.removeEventListener('scroll', throttledResize); }; }); return { bottom, direction, position, top }; }; exports.useEmitter = useEmitter; exports.useFormCheckbox = useFormCheckbox; exports.useFormInput = useFormInput; exports.useFormSelect = useFormSelect; exports.useFormValidation = useFormValidation; exports.useScroll = useScroll; exports.useScrollDirection = useScrollDirection;