Make compatible with TypeScript
acferM opened this issue ยท 2 comments
I was recently making a site using TSX an i wanted to use react-typical but when tried to install @types/react-typical it was not finding that module, so i guess they didn't made it yet.
The source code of the project is quite small, and it doesn't "hurt" that much to do // @ts-ignore
before importing the module.
And first it'd be needed to type https://github.com/camwiegert/typical, the library this component uses.
@acferM I just used this project locally as a TS module. Here's what I did ๐
As @davidomarf rightfully said, https://github.com/camwiegert/typical isn't typed.
So I made a declaration.d.ts
at the root of the project.
I am using Next.js with src/
folder as my root so I created src/declaration.d.ts
. I wrote types of @camwiegert/typical
in this file.
src/declaration.d.ts
declare module '@camwiegert/typical' {
export function type(node: HTMLElement, ...args: any[]): Promise<void>
declare function edit(node: HTMLElement, text: string): Promise<void>
declare function wait(ms: number): Promise<void>
declare function perform(node: HTMLElement, edits: any, speed?: number): Promise<void>
export function editor(edits: any): Generator<(node: any) => number, void, unknown>
export function writer(
[...text]: Iterable<any>,
startIndex?: number,
endIndex?: number
): Generator<string, void, unknown>
export function deleter(
[...text]: Iterable<any>,
startIndex?: number,
endIndex?: number
): Generator<string, void, unknown>
export function getOverlap(start: any, [...end]: Iterable<any>): number
}
Then I created a lib/react-typical
folder. In that folder, I created 2 files: index.ts
& styles.module.css
. I needed to create styles.module.css
because I couldn't import .css
files like import styles from "./styles.css
because in Next.js or rather in React, we do it like import "./styles.css"
.
Not sure, how this module does it. It might be some rollup magic Idk.
But in Next.js, we can import styles from "./styles.module.css"
if & only if you have the file extension .module.css
.
It was also giving TS error if I did import styles from "./styles.css"
so I used .module.css
.
I also merged PR #8 into my code & exported the function as a named export rather than default export. I faced a weird error while using <Wrapper />
so I had to use React.createElement
instead. You can learn more about the errors here. But it's all solved so you can copy-paste this thing into your project & it should work :)
index.ts
import React from 'react'
import { type, type as loopedType } from '@camwiegert/typical'
import styles from './styles.module.css'
type Props = {
steps: Array<any>
loop: number
className?: string
wrapper?: keyof JSX.IntrinsicElements
} & React.HTMLAttributes<HTMLOrSVGElement>
const Typical = ({ steps, loop, className, wrapper: Wrapper = 'p' }: Props) => {
const typicalRef: React.RefObject<HTMLElement> = React.useRef<HTMLElement>(null)
const classNames: string[] = [styles.typicalWrapper]
if (className) {
classNames.unshift(className)
}
const typicalStyles: string = classNames.join(' ')
React.useEffect(() => {
if (loop === Infinity) {
type(typicalRef.current as HTMLElement, ...steps, loopedType)
} else if (typeof loop === 'number') {
type(typicalRef.current as HTMLElement, ...Array(loop).fill(steps).flat())
} else {
type(typicalRef.current as HTMLElement, ...steps)
}
}, [typicalRef])
return React.createElement(Wrapper, {
ref: typicalRef,
className: typicalStyles,
})
}
export const ReactTypical = React.memo(Typical)
styles.module.css
.typicalWrapper::after {
content: '|';
animation: blink 1s infinite step-start;
}
@keyframes blink {
50% {
opacity: 0;
}
}
That's it. The usage is like:
class Index extends React.Component {
state = {
hypeText: ['Creator', 'Entrepreneur', 'Doer', 'Lone Wolf'],
}
render() {
return <ReactTypical steps={hypeText.flatMap((hype) => [hype, 5000])} loop={Infinity} />
}
}