framer-motion#useTransform TypeScript Examples

The following examples show how to use framer-motion#useTransform. 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: index.tsx    From tesla-homepage-ui-clone with MIT License 6 votes vote down vote up
ModelOverlay: React.FC<Props> = ({ model, children }) => {
  const { scrollY } = useWrapperScroll();

  const getSectionDimensions = useCallback(() => {
    return {
      offsetTop: model.sectionRef.current?.offsetTop ?? 0,
      offsetHeight: model.sectionRef.current?.offsetHeight ?? 0,
    } as SectionDimensions;
  }, [model.sectionRef]);

  const [dimensions, setDimensions] = useState<SectionDimensions>(getSectionDimensions());

  useLayoutEffect(() => {
    function onResize() {
      window.requestAnimationFrame(() => setDimensions(getSectionDimensions()));
    }

    window.addEventListener('resize', onResize);

    return () => window.removeEventListener('resize', onResize);
  }, [getSectionDimensions, model.sectionRef]);

  const sectionScrollProgress = useTransform(scrollY, y => (y - dimensions.offsetTop) / dimensions.offsetHeight);
  const opacity = useTransform(sectionScrollProgress, [-0.65, -0.05, 0.05, 0.65], [0, 1, 1, 0]);
  const pointerEvents = useTransform(opacity, value => (value > 0 ? 'auto' : 'none'));

  return <Container style={{ opacity, pointerEvents }}>{children}</Container>;
}
Example #2
Source File: index.tsx    From tesla-homepage-ui-clone with MIT License 6 votes vote down vote up
UniqueOverlay: React.FC = () => {
  const { scrollYProgress } = useWrapperScroll();

  const opacity = useTransform(scrollYProgress, [0.9, 1], [0, 1]);

  return (
    <Container id="top-page">
      <Header />
      <Footer opacity={opacity} />
    </Container>
  );
}
Example #3
Source File: parallax.tsx    From samuelkraft-next with MIT License 6 votes vote down vote up
Parallax = ({ children, offset = 50, clampInitial, clampFinal }: ParallaxProps): JSX.Element => {
  const prefersReducedMotion = useReducedMotion()
  const [elementTop, setElementTop] = useState(0)
  const [clientHeight, setClientHeight] = useState(0)
  const ref = useRef(null)

  const { scrollY } = useViewportScroll()

  const initial = elementTop - clientHeight
  const final = elementTop + offset

  const yRange = useTransform(scrollY, [initial, final], [clampInitial ? 0 : offset, clampFinal ? 0 : -offset])
  const y = useSpring(yRange, { stiffness: 400, damping: 90 })

  useLayoutEffect(() => {
    const element = ref.current
    const onResize = () => {
      setElementTop(element.getBoundingClientRect().top + window.scrollY || window.pageYOffset)
      setClientHeight(window.innerHeight)
    }
    onResize()
    window.addEventListener('resize', onResize)
    return () => window.removeEventListener('resize', onResize)
  }, [ref])

  // Don't parallax if the user has "reduced motion" enabled
  if (prefersReducedMotion) {
    return <>{children}</>
  }

  return (
    <motion.div ref={ref} style={{ y }}>
      {children}
    </motion.div>
  )
}
Example #4
Source File: Parallax.tsx    From vignette-web with MIT License 5 votes vote down vote up
Parallax = ({
  children,
  id,
  offset = 30,
  className,
  fadeIn,
}: ParallaxProps): JSX.Element => {
  const prefersReducedMotion = useReducedMotion()
  const [elementTop, setElementTop] = useState(0)
  const [clientHeight, setClientHeight] = useState(0)
  const ref = useRef<HTMLDivElement>(null)

  const { scrollY } = useViewportScroll()

  const initial = elementTop - clientHeight
  const final = elementTop + offset

  const router = useRouter()

  const yRange = useTransform(scrollY, [initial, final], [offset, -offset], {
    clamp: true,
  })
  const y = useSpring(yRange, { stiffness: 400, damping: 90 })

  useEffect(() => {
    const element = ref.current
    const onResize = () => {
      if (element) {
        setElementTop(
          element.getBoundingClientRect().top + window.scrollY ||
            window.pageYOffset,
        )
      }

      setClientHeight(window.innerHeight)
    }
    onResize()
    window.addEventListener(`resize`, onResize)
    return () => window.removeEventListener(`resize`, onResize)
  }, [ref, router.pathname])

  // Don't parallax if the user has "reduced motion" enabled
  if (prefersReducedMotion) {
    return <>{children}</>
  }

  return (
    <motion.div
      id={id}
      className={className}
      ref={ref}
      style={{ y }}
      transition={fadeIn ? { delay: 0.15, duration: 0.3 } : {}}
      initial={fadeIn && { opacity: 0 }}
      whileInView={fadeIn ? { opacity: 1 } : {}}
      viewport={{ once: true }}
    >
      {children}
    </motion.div>
  )
}
Example #5
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 #6
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>
    );
  }
)