framer-motion#useMotionValue TypeScript Examples

The following examples show how to use framer-motion#useMotionValue. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useWrapperScroll.ts    From tesla-homepage-ui-clone with MIT License 6 votes vote down vote up
useWrapperScroll = (): {
  scrollY: MotionValue<number>;
  scrollYProgress: MotionValue<number>;
} => {
  const { wrapperRef } = useContext(ModelsContext);

  const scrollY = useMotionValue(0);
  const scrollYProgress = useMotionValue(0);

  useEffect(() => {
    if (wrapperRef.current) {
      const updateScrollValue = () => {
        if (wrapperRef.current) {
          const { scrollTop, scrollHeight, offsetHeight } = wrapperRef.current;

          const fullScroll = scrollHeight - offsetHeight;

          scrollY.set(scrollTop);
          scrollYProgress.set(scrollTop / fullScroll);
        }
      };
      wrapperRef.current.addEventListener('scroll', updateScrollValue);

      return () => wrapperRef?.current?.removeEventListener('scroll', updateScrollValue);
    }
  }, [wrapperRef, scrollY, scrollYProgress]);

  return { scrollY, scrollYProgress };
}
Example #2
Source File: useInViewScroll.ts    From framer-motion-hooks with MIT License 6 votes vote down vote up
useInViewScroll = (
  el: RefObject<HTMLElement>,
  options: IOptions = {}
): MotionValue<number> => {
  const progress = useMotionValue(0)
  const { scrollY } = useViewportScroll()

  useEffect(() => {
    const handleScrollProgress = () => {
      const node = el.current
      if (!node) return

      const threshold = options.threshold || 0

      const elPosY = node.getBoundingClientRect().top + scrollY.get()
      const elHeight = node.scrollHeight

      const viewIntersect = Math.max(elPosY - window.innerHeight, 0)
      const current = scrollY.get() - viewIntersect - threshold
      const total = Math.min(window.innerHeight, elPosY) + elHeight - threshold

      const quotient = current / total

      if (quotient > 0 && quotient < 1) {
        progress.set(quotient)
      }
    }

    handleScrollProgress()
    const unsubscribeFromScroll = scrollY.onChange(handleScrollProgress)

    return () => unsubscribeFromScroll()
  }, [el, options])

  return progress
}
Example #3
Source File: useStateAsMotion.tsx    From framer-motion-hooks with MIT License 6 votes vote down vote up
useStateAsMotion = (state: any) => {
  const motionValue = useMotionValue(state)

  useEffect(() => {
    motionValue.set(state)
  }, [state])

  return motionValue
}
Example #4
Source File: ActionCard.tsx    From nosgestesclimat-site with MIT License 4 votes vote down vote up
Card = ({ children, style, onVote, id, ...props }) => {
	// motion stuff
	const cardElem = useRef(null)

	const x = useMotionValue(0)
	const controls = useAnimation()

	const [constrained, setConstrained] = useState(true)

	const [direction, setDirection] = useState()

	const [velocity, setVelocity] = useState()

	const getVote = (childNode, parentNode) => {
		const childRect = childNode.getBoundingClientRect()
		const parentRect = parentNode.getBoundingClientRect()
		let result =
			parentRect.left >= childRect.right
				? false
				: parentRect.right <= childRect.left
				? true
				: undefined
		return result
	}

	// determine direction of swipe based on velocity
	const getDirection = () => {
		return velocity >= 1 ? 'right' : velocity <= -1 ? 'left' : undefined
	}

	const getTrajectory = () => {
		setVelocity(x.getVelocity())
		setDirection(getDirection())
	}

	const flyAway = (min) => {
		const flyAwayDistance = (direction) => {
			const parentWidth = cardElem.current.parentNode.getBoundingClientRect()
				.width
			const childWidth = cardElem.current.getBoundingClientRect().width
			return direction === 'left'
				? -parentWidth / 2 - childWidth / 2
				: parentWidth / 2 + childWidth / 2
		}

		if (direction && Math.abs(velocity) > min) {
			setConstrained(false)
			controls.start({
				x: flyAwayDistance(direction),
			})
		}
	}

	useEffect(() => {
		const unsubscribeX = x.onChange(() => {
			const childNode = cardElem.current
			const parentNode = cardElem.current.parentNode
			const result = getVote(childNode, parentNode)
			result !== undefined && onVote(result)
		})

		return () => unsubscribeX()
	})

	const xInput = [-100, 0, 100]
	const background = useTransform(x, xInput, [
		'linear-gradient(180deg, #f2a4f4 0%, #f49494 100%)',
		'linear-gradient(180deg, #fff 0%, #fff 100%)',
		'linear-gradient(180deg, rgb(230, 255, 0) 0%, rgb(3, 209, 0) 100%)',
	])
	return (
		<StyledCard
			animate={controls}
			dragConstraints={constrained && { left: 0, right: 0, top: 0, bottom: 0 }}
			dragElastic={1}
			ref={cardElem}
			style={{ x }}
			onDrag={getTrajectory}
			myBackground={background}
			onDragEnd={() => flyAway(500)}
			whileTap={{ scale: 1.1 }}
			{...props}
		>
			{children}
		</StyledCard>
	)
}
Example #5
Source File: Checkbox.tsx    From chroma-react with MIT License 4 votes vote down vote up
Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
  (
    {
      ['aria-label']: ariaLabel,
      checked,
      className,
      classes: additionalClasses,
      color = 'default',
      disabled = false,
      errorMessage,
      hasError,
      helpMessage,
      indeterminate = false,
      id,
      label,
      name,
      ...rootProps
    },
    ref
  ) => {
    const classes = useStyles({ classes: additionalClasses });

    const [uniqueId] = React.useState<string>(
      () => id || name || generateUniqueId('checkbox-')
    );

    const pathLength = useMotionValue(0);
    const opacity = useTransform(pathLength, [0.05, 0.15], [0, 1]);

    if (!label && !ariaLabel && process.env.NODE_ENV === 'development') {
      throw new Error(
        'If a "label" is not provided to Checkbox, please provide "aria-label".'
      );
    }

    const variant = [
      checked ? 'checked' : 'unchecked',
      disabled ? 'disabled' : 'enabled',
    ];

    return (
      <motion.div
        className={clsx(classes.root, className)}
        animate={variant}
        initial={false}
        whileHover="hover"
        whileTap="pressed"
      >
        <input
          aria-describedby={buildDescribedBy({
            hasError,
            hasHelpMessage: !!helpMessage,
            uniqueId,
          })}
          aria-checked={
            checked && !indeterminate
              ? 'true'
              : !checked && !indeterminate
              ? 'false'
              : !checked && indeterminate
              ? 'mixed'
              : 'false'
          }
          className={clsx(classes.input, {
            [classes.inputInverse]: color === 'inverse',
          })}
          ref={ref}
          type="checkbox"
          id={uniqueId}
          name={name}
          checked={checked}
          disabled={disabled}
          tabIndex={0}
          {...rootProps}
        />
        <div className={classes.labelContainer}>
          <motion.label
            className={classes.label}
            htmlFor={uniqueId}
            animate={variant}
            whileHover="hover"
            whileTap="pressed"
          >
            <motion.svg
              className={classes.svg}
              width="21"
              height="21"
              viewBox="0 0 21 21"
            >
              <motion.path
                className={classes.box}
                d="M1,5.524A4.523,4.523,0,0,1,5.524,1h9.952A4.523,4.523,0,0,1,20,5.524v9.952A4.523,4.523,0,0,1,15.476,20H5.524A4.523,4.523,0,0,1,1,15.476Z"
                fill="transparent"
                stroke="var(--checkbox-secondary-emphasis)"
                strokeOpacity="0"
                strokeMiterlimit="10"
                strokeWidth="2"
                variants={getBoxVariants({
                  disabled,
                  hasError,
                  color,
                })}
              />
              {indeterminate && disabled ? (
                <motion.path
                  d="M6.5,10.458h8"
                  fill="transparent"
                  strokeWidth="2.25"
                  stroke="#FFFFFF"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  style={{ pathLength, opacity }}
                  custom={checked}
                  variants={getTickVariants({
                    disabled,
                    indeterminate,
                    color,
                  })}
                />
              ) : indeterminate ? (
                <>
                  <motion.path
                    d="M10.5,10.458h-4"
                    fill="transparent"
                    strokeWidth="2.25"
                    stroke="#FFFFFF"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    style={{ pathLength, opacity }}
                    custom={checked}
                    variants={getTickVariants({
                      disabled,
                      indeterminate,
                      color,
                    })}
                  />
                  <motion.path
                    d="M10.5,10.458h4"
                    fill="transparent"
                    strokeWidth="2.25"
                    stroke="#FFFFFF"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    style={{ pathLength, opacity }}
                    custom={checked}
                    variants={getTickVariants({
                      disabled,
                      indeterminate,
                      color,
                    })}
                  />
                </>
              ) : (
                <motion.path
                  d="M5.761,11.962l2.187,2.187,7.291-7.3"
                  fill="transparent"
                  strokeWidth="2.25"
                  stroke="#FFFFFF"
                  strokeOpacity="1"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  style={{ pathLength, opacity }}
                  custom={checked}
                  variants={getTickVariants({ disabled, indeterminate, color })}
                />
              )}
            </motion.svg>
            <Text
              size="subbody"
              className={clsx(
                color === 'inverse' ? classes.labelInverse : undefined,
                !label && ariaLabel && classes.srOnly
              )}
            >
              {label || ariaLabel}
            </Text>
          </motion.label>
        </div>
        {helpMessage && (
          <FormHelpMessage
            color={color}
            rootElementId={uniqueId}
            describedById={helpFor(uniqueId)}
          >
            {helpMessage}
          </FormHelpMessage>
        )}
        {hasError && (
          <FormErrorMessage
            color={color}
            rootElementId={uniqueId}
            describedById={errorFor(uniqueId)}
          >
            {errorMessage}
          </FormErrorMessage>
        )}
      </motion.div>
    );
  }
)