From 2d5cd8ee09b08e2307736a09955dae8a0c272d0a Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Sat, 3 Sep 2022 00:47:16 +0900 Subject: [PATCH] =?UTF-8?q?fix(emoji):=20useLayoutWidth=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=B4=20=EB=AA=A9=ED=91=9C=EB=90=9C=20?= =?UTF-8?q?=EC=97=98=EB=A6=AC=EB=A8=BC=ED=8A=B8=EC=9D=98=20width=EB=A5=BC?= =?UTF-8?q?=20=ED=99=9C=EC=9A=A9=ED=95=9C=20=EC=9D=B4=EB=AA=A8=EC=A7=80=20?= =?UTF-8?q?=EB=9E=9C=EB=8D=A4=20x=EC=B6=95=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20PC=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=AA=A8=EC=A7=80=20=EC=95=88=EB=82=98=EC=98=AC=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=87=EB=8A=94=20=EA=B0=80=EB=8A=A5=EC=84=B1=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/domains/Emoji/Emojis.tsx | 15 +++-- components/uis/Layout/index.tsx | 81 ++++++++++++++----------- hooks/commons/index.ts | 2 + hooks/commons/useElementSize/index.ts | 36 +++++++++++ hooks/commons/useEventListener/index.ts | 64 +++++++++++++++++++ 5 files changed, 158 insertions(+), 40 deletions(-) create mode 100644 hooks/commons/useElementSize/index.ts create mode 100644 hooks/commons/useEventListener/index.ts diff --git a/components/domains/Emoji/Emojis.tsx b/components/domains/Emoji/Emojis.tsx index 608785c..d9042fc 100644 --- a/components/domains/Emoji/Emojis.tsx +++ b/components/domains/Emoji/Emojis.tsx @@ -1,6 +1,7 @@ import { motion } from "framer-motion"; import { useRecoilValue } from "recoil"; import { Book, Heart, MirrorBall, Note } from "~/assets/svgs"; +import { useLayoutWidth } from "~/components/uis/Layout"; import { emojiAtomState } from "~/store/emoji"; const Emojis = ({ stage }: { stage: 1 | 2 | 3 }) => { @@ -19,9 +20,11 @@ export default Emojis; export const EmojiScaled = ({ stage }: { stage: 1 | 2 | 3 }) => { const emoji = useRecoilValue(emojiAtomState); - const getRandomHalfToFull = () => Math.random() / 4 + 3 / 4; + const getRandom3QuarterToFull = () => Math.random() / 4 + 3 / 4; const randomMinus = Math.random() > 0.5 ? 1 : -1; + const { width } = useLayoutWidth(); + const EmojiSVG = emoji ? emoji.emojiType === "HEART" ? Heart @@ -40,16 +43,16 @@ export const EmojiScaled = ({ stage }: { stage: 1 | 2 | 3 }) => { marginBottom: stage === 3 ? 140 : 1, }} initial={{ - x: (randomMinus * window.innerWidth * Math.random()) / 2, - y: 400 * getRandomHalfToFull(), + x: (randomMinus * width * Math.random()) / 2, + y: 400 * getRandom3QuarterToFull(), }} animate={{ - x: (randomMinus * window.innerWidth * Math.random()) / 2, - y: -2000 * getRandomHalfToFull(), + x: (randomMinus * width * Math.random()) / 2, + y: -2000 * getRandom3QuarterToFull(), opacity: Math.random() * 0.9 + 0.1, }} - transition={{ duration: 3 * getRandomHalfToFull() }} + transition={{ duration: 3 * getRandom3QuarterToFull() }} > diff --git a/components/uis/Layout/index.tsx b/components/uis/Layout/index.tsx index ca706ea..724f466 100644 --- a/components/uis/Layout/index.tsx +++ b/components/uis/Layout/index.tsx @@ -1,45 +1,58 @@ -import React from "react"; -import styled from "@emotion/styled"; +import React, { createContext, useContext } from "react"; +import { css } from "@emotion/react"; +import { useElementSize } from "~/hooks/commons"; + +const Context = createContext({ width: 450 }); +export const useLayoutWidth = () => useContext(Context); interface Props { children: React.ReactNode; screenColor?: string; } -function Layout({ children, screenColor = "#000000" }: Props) { - return ( - - {children} - - ); -} +const Layout = ({ children, screenColor = "#000000" }: Props) => { + const [ref, size] = useElementSize(); -const S = { - Container: styled.div` - height: 100%; - width: 100%; - max-height: 100%; - z-index: 100; - display: flex; - justify-content: center; - `, - - Screen: styled.div<{ screenColor?: string }>` - max-width: 450px; - width: 100%; - height: 100%; - overflow-y: auto; - overflow-x: hidden; - background: ${(p) => p.screenColor}; - color: #fff; - position: relative; - backdrop-filter: blur(10px); + return ( + +
+
+ {children} +
+
+
+ ); }; export default Layout; diff --git a/hooks/commons/index.ts b/hooks/commons/index.ts index d195135..f41d473 100644 --- a/hooks/commons/index.ts +++ b/hooks/commons/index.ts @@ -8,3 +8,5 @@ export { default as useLongPress } from "./useLongPress"; export { default as useDisclosure } from "./useDisclosure"; export { default as useThrottle } from "./useThrottle"; export { default as useIsMobile } from "./useIsMobile"; +export { default as useElementSize } from "./useElementSize"; +export { default as useEventListener } from "./useEventListener"; diff --git a/hooks/commons/useElementSize/index.ts b/hooks/commons/useElementSize/index.ts new file mode 100644 index 0000000..f4acf07 --- /dev/null +++ b/hooks/commons/useElementSize/index.ts @@ -0,0 +1,36 @@ +import { useCallback, useState } from "react"; +import useEventListener from "../useEventListener"; +import useIsomorphicLayoutEffect from "../useIsomorphicLayoutEffect"; + +interface Size { + width: number; + height: number; +} + +function useElementSize(): [ + (node: T | null) => void, + Size +] { + const [ref, setRef] = useState(null); + const [size, setSize] = useState({ + width: 0, + height: 0, + }); + + const handleSize = useCallback(() => { + setSize({ + width: ref?.offsetWidth || 0, + height: ref?.offsetHeight || 0, + }); + }, [ref?.offsetHeight, ref?.offsetWidth]); + + useEventListener("resize", handleSize); + + useIsomorphicLayoutEffect(() => { + handleSize(); + }, [ref?.offsetHeight, ref?.offsetWidth]); + + return [setRef, size]; +} + +export default useElementSize; diff --git a/hooks/commons/useEventListener/index.ts b/hooks/commons/useEventListener/index.ts new file mode 100644 index 0000000..7c590ae --- /dev/null +++ b/hooks/commons/useEventListener/index.ts @@ -0,0 +1,64 @@ +import type { RefObject } from "react"; +import { useEffect, useRef } from "react"; +import useIsomorphicLayoutEffect from "../useIsomorphicLayoutEffect"; + +function useEventListener( + eventName: K, + handler: (event: WindowEventMap[K]) => void, + element?: undefined, + options?: boolean | AddEventListenerOptions +): void; + +function useEventListener< + K extends keyof HTMLElementEventMap, + T extends HTMLElement = HTMLDivElement +>( + eventName: K, + handler: (event: HTMLElementEventMap[K]) => void, + element: RefObject, + options?: boolean | AddEventListenerOptions +): void; + +function useEventListener( + eventName: K, + handler: (event: DocumentEventMap[K]) => void, + element: RefObject, + options?: boolean | AddEventListenerOptions +): void; + +function useEventListener< + KW extends keyof WindowEventMap, + KH extends keyof HTMLElementEventMap, + T extends HTMLElement | void = void +>( + eventName: KW | KH, + handler: ( + event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event + ) => void, + element?: RefObject, + options?: boolean | AddEventListenerOptions +) { + const savedHandler = useRef(handler); + + useIsomorphicLayoutEffect(() => { + savedHandler.current = handler; + }, [handler]); + + useEffect(() => { + const targetElement: T | Window = element?.current || window; + if (!(targetElement && targetElement.addEventListener)) { + return; + } + + const eventListener: typeof handler = (event) => + savedHandler.current(event); + + targetElement.addEventListener(eventName, eventListener, options); + + return () => { + targetElement.removeEventListener(eventName, eventListener); + }; + }, [eventName, element, options]); +} + +export default useEventListener;