UNPKG

@spark-web/utils

Version:

--- title: Utilities isExperimentalPackage: true ---

156 lines (145 loc) 5.21 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var react = require('react'); var typeCheck = require('./type-check-042a577c.cjs.dev.js'); var _slicedToArray = require('@babel/runtime/helpers/slicedToArray'); /** * Sometimes we need both a local ref _and_ a forwarded ref for the same element. * This utility merges them for us (as React doesn't offer this natively). * * @see https://github.com/gregberge/react-merge-refs/blob/main/src/index.tsx */ function mergeRefs(refs) { return function (value) { refs.forEach(function (ref) { if (typeof ref === 'function') { ref(value); } else if (ref != null) { ref.current = value; } }); }; } /** * Passes or assigns an arbitrary value to a ref function or object. * * @param ref * @param value */ function assignRef(ref, value) { if (ref == null) return; if (typeCheck.isFunction(ref)) { ref(value); } else { try { ref.current = value; } catch (error) { throw new Error("Cannot assign value \"".concat(value, "\" to ref \"").concat(ref, "\"")); } } } /** * Passes or assigns a value to multiple refs (typically a DOM node). Useful for * dealing with components that need an explicit ref for DOM calculations but * also forwards refs assigned by an app. * * @param refs Refs to fork * * @example * const internalRef = useRef<HTMLSpanElement>(null); * const composedRef = useComposedRefs(internalRef, forwardedRef); */ function useComposedRefs() { for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) { refs[_key] = arguments[_key]; } return react.useCallback(function (node) { for (var _i = 0, _refs = refs; _i < _refs.length; _i++) { var ref = _refs[_i]; assignRef(ref, node); } // `refs` is already an array. If we do what ESLint wants us to do // and wrap `refs` in square brackets, then the useCallback will fire // on every render (not just when the dependencies change). // eslint-disable-next-line react-hooks/exhaustive-deps }, refs); } /** * `useDisclosure` is a custom hook used to help handle common open, close, or toggle scenarios. */ function useDisclosure() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, defaultIsOpen = _ref.defaultIsOpen; var _useState = react.useState(defaultIsOpen !== null && defaultIsOpen !== void 0 ? defaultIsOpen : false), _useState2 = _slicedToArray(_useState, 2), isOpen = _useState2[0], setIsOpen = _useState2[1]; var onClose = function onClose() { return setIsOpen(false); }; var onOpen = function onOpen() { return setIsOpen(true); }; var onToggle = function onToggle() { return setIsOpen(function (prevState) { return !prevState; }); }; return { isOpen: isOpen, onOpen: onOpen, onClose: onClose, onToggle: onToggle }; } /** * On the server, React emits a warning when calling `useLayoutEffect`. * This is because neither `useLayoutEffect` nor `useEffect` run on the server. * We use this safe version which suppresses the warning by replacing it with a noop on the server. * * @see https://reactjs.org/docs/hooks-reference.html#uselayouteffect */ var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? react.useLayoutEffect : function () {}; var stashedTime; /** * Keeps all instances of the same animation in sync. * Taken from Sam Selikoff's example post: * @see https://github.com/samselikoff/2022-02-24-use-synchronized-animation */ function useSynchronizedAnimation(animationName) { var ref = react.useRef(null); useIsomorphicLayoutEffect(function () { var _document$getAnimatio, _document; var animations = ((_document$getAnimatio = (_document = document).getAnimations) === null || _document$getAnimatio === void 0 ? void 0 : _document$getAnimatio.call(_document) // @ts-expect-error: Property 'animationName' does not exist on type 'Animation'. .filter(function (animation) { return animation.animationName === animationName; })) || []; var animationTarget = animations.find( // @ts-expect-error: Property 'target' does not exist on type 'AnimationEffect'. function (animation) { var _animation$effect; return ((_animation$effect = animation.effect) === null || _animation$effect === void 0 ? void 0 : _animation$effect.target) === ref.current; }); if (animationTarget) { if (animationTarget === animations[0] && stashedTime) { animationTarget.currentTime = stashedTime; } if (animationTarget && animationTarget !== animations[0]) { animationTarget.currentTime = animations[0].currentTime; } return function () { if (animationTarget === animations[0]) { stashedTime = animationTarget.currentTime; } }; } }, [animationName]); return ref; } exports.assignRef = assignRef; exports.mergeRefs = mergeRefs; exports.useComposedRefs = useComposedRefs; exports.useDisclosure = useDisclosure; exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect; exports.useSynchronizedAnimation = useSynchronizedAnimation;