-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(GamesTable): Animate row height when filtering
- Loading branch information
1 parent
94d7578
commit 8827d8a
Showing
3 changed files
with
192 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { useEffect, useRef } from "react" | ||
|
||
type ElementType = HTMLElement | Window | Document | null | ||
type EventMap<Type extends ElementType> = Type extends HTMLElement | ||
? HTMLElementEventMap | ||
: Type extends Window | ||
? WindowEventMap | ||
: DocumentEventMap | ||
|
||
interface UseEventListenerProps< | ||
Type extends ElementType, | ||
EventName extends keyof EventMap<Type> | ||
> { | ||
ref: Type | ||
event: EventName | ||
handler: (e: EventMap<Type>[EventName]) => void | ||
disabled?: boolean | ||
} | ||
|
||
export const useEventListener = < | ||
Type extends ElementType, | ||
EventName extends keyof EventMap<Type> | ||
>({ | ||
ref, | ||
event, | ||
handler, | ||
disabled, | ||
}: UseEventListenerProps<Type, EventName>) => { | ||
const clear = useRef<() => void>(() => null) | ||
const lastHandler = useRef(handler) | ||
lastHandler.current = handler | ||
|
||
useEffect(() => { | ||
clear.current() | ||
if (disabled || !ref) return | ||
|
||
const emit = (e: EventMap<Type>[EventName]) => lastHandler.current(e) | ||
|
||
ref.addEventListener( | ||
event as string, | ||
emit as EventListenerOrEventListenerObject | ||
) | ||
clear.current = () => { | ||
ref.removeEventListener( | ||
event as string, | ||
emit as EventListenerOrEventListenerObject | ||
) | ||
} | ||
return () => clear.current() | ||
}, [disabled, event, ref]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { RefObject, useEffect, useMemo, useRef, useState } from "react" | ||
|
||
import { useEventListener } from "./useEventListener" | ||
|
||
interface TransitionStyles { | ||
whileShow?: string | ||
toShow?: string | ||
toHide?: string | ||
whileHide?: string | ||
} | ||
|
||
type TransitionState = | ||
| "start-hide" | ||
| "to-hide" | ||
| "hide" | ||
| "start-show" | ||
| "to-show" | ||
| "show" | ||
|
||
const noStyles: Required<TransitionStyles> = { | ||
whileShow: "", | ||
toShow: "", | ||
toHide: "", | ||
whileHide: "", | ||
} | ||
|
||
const getStyles = (state: TransitionState, styles?: TransitionStyles) => { | ||
const { whileShow, toShow, toHide, whileHide } = { ...noStyles, ...styles } | ||
switch (state) { | ||
case "start-hide": | ||
return `${toShow}` | ||
case "to-hide": | ||
return `${toHide}` | ||
case "hide": | ||
return `${whileHide} ${toHide}` | ||
case "start-show": | ||
return `${toHide}` | ||
case "to-show": | ||
return `${toShow}` | ||
case "show": | ||
return `${whileShow} ${toShow}` | ||
} | ||
} | ||
|
||
const getState = (transition: "idle" | "start" | "running", hide: boolean) => { | ||
if (transition === "start") { | ||
return hide ? "start-hide" : "start-show" | ||
} | ||
if (transition === "running") { | ||
return hide ? "to-hide" : "to-show" | ||
} | ||
return hide ? "hide" : "show" | ||
} | ||
|
||
interface TransitionProps { | ||
ref: RefObject<HTMLElement | null> | ||
hide: boolean | ||
styles?: TransitionStyles | ||
} | ||
export const useTransition = ({ ref, hide, styles }: TransitionProps) => { | ||
const [transition, setTransition] = useState<"idle" | "start" | "running">( | ||
"idle" | ||
) | ||
const lastHide = useRef(hide) | ||
|
||
useEffect(() => { | ||
if (lastHide.current === hide) return | ||
lastHide.current = hide | ||
setTransition("start") | ||
}, [hide]) | ||
|
||
useEffect(() => { | ||
if (transition !== "start") return | ||
setTransition("running") | ||
}, [transition]) | ||
|
||
useEventListener({ | ||
ref: ref.current, | ||
event: "transitionend", | ||
handler: () => { | ||
console.log("transitionend") | ||
setTransition("idle") | ||
}, | ||
}) | ||
|
||
const state = useMemo( | ||
() => getState(transition, lastHide.current), | ||
[transition] | ||
) | ||
|
||
return { | ||
state, | ||
className: getStyles(state, styles), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters