react-typical icon indicating copy to clipboard operation
react-typical copied to clipboard

feat: include props and style

Open mikemajara opened this issue 4 years ago • 1 comments

Add props and style to forward styling and enable the use of custom components as a wrapper.

Example: Use with Chakra-UI

import { Heading } from '@chakra/react'
...
const [primary, secondary] = useToken("colors", ["gray.500", "blue.500"]);
  ...
<Typical
  steps={["Hello", 1000, "Hello world!", 500]}
  loop={Infinity}
  wrapper={Heading}
  props={{
    bgGradient:`linear(to-t, ${primary}, ${secondary})`,
    bgClip:"text"
  }}
  style={{
    fontSize: "5rem"
  }}
/>

example

Closes https://github.com/catalinmiron/react-typical/issues/18

mikemajara avatar Jun 25 '21 15:06 mikemajara

I ended up rewriting it to the following code for TypeScript support:

import React, { useRef, useEffect, memo } from 'react'
import { type } from '@camwiegert/typical'

// const memo: <T>(component: T) => T = baseMemo

export interface Props<
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  T extends React.ComponentType<any> | keyof JSX.IntrinsicElements,
> {
  steps: Parameters<typeof type>[1]
  loop?: number
  className?: string
  wrapper?: T
}

const Typical = <
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  T extends React.ComponentType<any> | keyof JSX.IntrinsicElements,
>({
  steps,
  loop,
  className,
  wrapper = 'p',
  ...props
}: Props<T> & React.ComponentProps<T>) => {
  const typicalRef = useRef<HTMLElement>(null)
  const Component = wrapper

  useEffect(() => {
    if (loop === Infinity) {
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      type(typicalRef.current!, ...steps, type)
    } else if (typeof loop === 'number') {
      const timesStep = Array(loop).fill(steps).flat()
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      type(typicalRef.current!, ...timesStep)
    } else {
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      type(typicalRef.current!, ...steps)
    }

    return () => {
      // alive.current = false
    }
  }, [typicalRef, loop, steps])

  return <Component ref={typicalRef} className={className} {...props} />
}

export default memo(Typical) as typeof Typical

and using it as follows:

      <Typical<'span'>
        steps={['Example', 800, 'Another', 800, 'Third', 800])}
        loop={Infinity}
        wrapper="span"
      />

Not only can you add props to the component without weird props prop, but it also dynamically checks all supported props of the wrapper!

leon0399 avatar Mar 23 '23 21:03 leon0399