From 29b3ced87501adffd4a8776430855dc694a250fb Mon Sep 17 00:00:00 2001 From: YoonHaeMin Date: Sat, 24 Aug 2024 00:05:33 +0900 Subject: [PATCH] =?UTF-8?q?feat:=200823=20QA=EB=8C=80=EC=9D=91=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 웹캠 클릭 후 다른 슬로프 선택시 닫히도록 수정 - 비디오 열림과 선택된 웹캠을 전역상태로 분리 * feat: 윌리휠리 webcam 데이터 추가 * fix: stroke path 색상 버그해결 * fix: 주석 제거 * feat: hls 라이브러리 교체 * feat: iOS 대응 추가 * feat: 비디오 clean up 추가 --- package.json | 2 +- .../image/elysian-gangchon/deer-slop-path.tsx | 4 +- .../elysian-gangchon/horse-slop-path.tsx | 4 +- .../image/elysian-gangchon/puma-slop-path.tsx | 4 +- .../slop/image/high1/hera1-slop-path.tsx | 4 +- src/entities/slop/image/muju/allegro-path.tsx | 4 +- .../slop/image/muju/cadenza-slope-path.tsx | 4 +- .../slop/image/muju/flamingo-path.tsx | 4 +- .../slop/image/muju/freeway2-path.tsx | 4 +- .../slop/image/muju/moderato-path.tsx | 4 +- src/entities/slop/image/muju/mozart-path.tsx | 4 +- .../slop/image/muju/panorama-path.tsx | 4 +- .../slop/image/muju/polka-slope-path.tsx | 4 +- .../slop/image/muju/r-gardner-slope-path.tsx | 4 +- .../slop/image/muju/raiders-lowest-path.tsx | 4 +- .../slop/image/muju/rookiehill-slope-path.tsx | 4 +- .../slop/image/muju/rusutsu-slope-path.tsx | 4 +- .../slop/image/muju/shortcut-slope-path.tsx | 4 +- .../slop/image/muju/soyokgihang-path.tsx | 4 +- .../slop/image/muju/spitch-slope-path.tsx | 4 +- .../slop/image/muju/western-slope-path.tsx | 4 +- .../wellihilli/challenge-slope1-path.tsx | 4 +- .../image/wellihilli/echo-slope1-path.tsx | 4 +- .../image/wellihilli/echo-slope2-path.tsx | 4 +- .../image/wellihilli/echo-slope3-path.tsx | 4 +- .../slop/image/yongpyong/blue-slope-path.tsx | 4 +- .../image/yongpyong/gold-paradise-path.tsx | 4 +- .../image/yongpyong/new-red-slope-path.tsx | 4 +- .../slop/image/yongpyong/rainbow1-path.tsx | 4 +- .../slop/image/yongpyong/rainbow2-path.tsx | 4 +- .../slop/image/yongpyong/rainbow3-path.tsx | 4 +- .../slop/image/yongpyong/rainbow4-path.tsx | 4 +- .../yongpyong/summit-land-the-green-path.tsx | 4 +- src/entities/slop/model/wellihilli.tsx | 5 ++ src/features/slop/hooks/useSlopStore.ts | 19 +++++- src/features/slop/hooks/useTimer.ts | 4 +- src/features/slop/ui/slop-camera.tsx | 40 +++++++------ src/features/slop/ui/slop-video.tsx | 58 +++++++++++++------ src/widgets/webcam/ui/webcam-map.tsx | 1 + src/widgets/webcam/ui/webcam-slop-list.tsx | 5 +- yarn.lock | 28 ++------- 41 files changed, 161 insertions(+), 129 deletions(-) diff --git a/package.json b/package.json index 944c7d3..36731f5 100644 --- a/package.json +++ b/package.json @@ -20,12 +20,12 @@ "@use-gesture/react": "^10.3.1", "autoprefixer": "^10.4.19", "class-variance-authority": "^0.7.0", + "hls.js": "^1.5.15", "next": "14.2.5", "next-themes": "^0.3.0", "nextjs-google-analytics": "^2.3.7", "react": "^18", "react-dom": "^18", - "react-hls-player": "^3.0.7", "sonner": "^1.5.0", "tailwind-scrollbar-hide": "^1.1.7", "tailwindcss-animate": "^1.0.7", diff --git a/src/entities/slop/image/elysian-gangchon/deer-slop-path.tsx b/src/entities/slop/image/elysian-gangchon/deer-slop-path.tsx index 2ec671d..60c1b70 100644 --- a/src/entities/slop/image/elysian-gangchon/deer-slop-path.tsx +++ b/src/entities/slop/image/elysian-gangchon/deer-slop-path.tsx @@ -2,8 +2,8 @@ import React from 'react'; import { cn } from '@/shared/lib'; const DeerSlopPath = ({ color }: { color?: string }) => { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#FF9928]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#FF9928]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#FF9928]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#FF9928]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#171D23]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#171D23]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#303A45]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#303A45]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#447EFF]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#447EFF]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#303A45]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#303A45]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#303A45]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#303A45]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#303A45]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#303A45]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#303A45]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#303A45]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#303A45]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#303A45]'; + const strokeColorClass = color ? color.replace('fill-', 'texts-') : defaultStrokeColor; return ( { - const defaultStrokeColor = 'stroke-[#303A45]'; - const strokeColorClass = color ? color.replace('fill-', 'stroke-') : defaultStrokeColor; + const defaultStrokeColor = 'text-[#303A45]'; + const strokeColorClass = color ? color.replace('fill-', 'text-') : defaultStrokeColor; return ( void; + setSelectedCamera: (cameraId: CameraId) => void; + setOpenCamera: () => void; + setCloseCamera: () => void; } -const useSlopStore = create((set) => ({ +const useSlopStore = create((set) => ({ selectedSlop: null, + selectedCamera: { + id: null, + isOpen: false, + }, setSelectedSlop: (slopId: SlopId) => set(() => ({ selectedSlop: slopId })), + setSelectedCamera: (cameraId: CameraId) => + set((state) => ({ selectedCamera: { ...state.selectedCamera, id: cameraId } })), + setOpenCamera: () => + set((state) => ({ selectedCamera: { ...state.selectedCamera, isOpen: true } })), + setCloseCamera: () => + set((state) => ({ selectedCamera: { ...state.selectedCamera, isOpen: false } })), })); export default useSlopStore; diff --git a/src/features/slop/hooks/useTimer.ts b/src/features/slop/hooks/useTimer.ts index ca30496..25fce37 100644 --- a/src/features/slop/hooks/useTimer.ts +++ b/src/features/slop/hooks/useTimer.ts @@ -33,12 +33,12 @@ const useTimer = (initialTime: number, onComplete?: () => void): UseTimerReturn }; }, [isRunning, timeLeft, onComplete]); - const startTimer = (newTime?: number) => { + const startTimer = useCallback((newTime?: number) => { if (newTime !== undefined) { setTimeLeft(newTime); } setIsRunning(true); - }; + },[]); const pauseTimer = useCallback(() => setIsRunning(false), []); diff --git a/src/features/slop/ui/slop-camera.tsx b/src/features/slop/ui/slop-camera.tsx index 51c8da3..be3c204 100644 --- a/src/features/slop/ui/slop-camera.tsx +++ b/src/features/slop/ui/slop-camera.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; import { toast } from 'sonner'; import type { Position, Webcam } from '@/entities/slop/model/model'; @@ -25,7 +25,8 @@ const SlopCamera = ({ onCameraClick, updateCameraPosition, }: SlopWebcamProps) => { - const [isVideoOpen, setIsVideoOpen] = useState(false); + const { setSelectedSlop, selectedCamera, setSelectedCamera, setOpenCamera, setCloseCamera } = + useSlopStore(); const cameraRef = useRef(null); @@ -37,8 +38,8 @@ const SlopCamera = ({ }); }, [id, updateCameraPosition, cameraRef]); - const toggleVideo = () => { - setIsVideoOpen((pre) => !pre); + const openVideo = () => { + setOpenCamera(); if (!src) { toast( @@ -49,22 +50,24 @@ const SlopCamera = ({ } }; - const { setSelectedSlop } = useSlopStore(); - return ( <> -
{ - setSelectedSlop(null); - onCameraClick({ scale, id: id }); - }} - > +
- } isOpen={isOpen}> + { + setSelectedSlop(null); + setSelectedCamera(id); + onCameraClick({ scale, id: id }); + }} + /> + } + isOpen={isOpen} + >
-

+

{name}

@@ -73,9 +76,10 @@ const SlopCamera = ({
{containerRef?.current && - isVideoOpen && + selectedCamera.isOpen && + selectedCamera.id === id && src && - createPortal(, containerRef.current)} + createPortal(, containerRef.current)} ); }; diff --git a/src/features/slop/ui/slop-video.tsx b/src/features/slop/ui/slop-video.tsx index 651c498..d226614 100644 --- a/src/features/slop/ui/slop-video.tsx +++ b/src/features/slop/ui/slop-video.tsx @@ -1,12 +1,10 @@ -import dynamic from 'next/dynamic'; -import React from 'react'; +import Hls from 'hls.js'; +import React, { useEffect, useRef } from 'react'; import { cn } from '@/shared/lib'; import CloseButton from '@/shared/ui/close-button'; import Loading from '@/shared/ui/loading'; import useTimer from '../hooks/useTimer'; -const ReactHlsPlayer = dynamic(() => import('react-hls-player'), { ssr: false }); - interface SlopVideoProps { src: string; closeVideo: () => void; @@ -14,36 +12,62 @@ interface SlopVideoProps { const SlopVideo = ({ src, closeVideo }: SlopVideoProps) => { const playerRef = React.useRef(null); + const hlsRef = useRef(null); + const { isRunning, startTimer, timeLeft } = useTimer(30, () => { handleVideoClose(); }); - function fireOnVideoStart() { - document.body.classList.add('video-active'); - playerRef?.current?.focus(); - startTimer(); - } - const handleVideoClose = () => { - document.body.classList.remove('video-active'); closeVideo(); }; + useEffect(() => { + const video = playerRef.current; + if (!video) return; + + const handleStart = () => { + startTimer(); + }; + + if (Hls.isSupported()) { + const hls = new Hls(); + hlsRef.current = hls; + + hls.loadSource(src); + hls.attachMedia(video); + + hls.on(Hls.Events.FRAG_BUFFERED, handleStart); + } else if (video.canPlayType('application/vnd.apple.mpegurl')) { + video.src = src; + video.addEventListener('canplay', handleStart); + } + + return () => { + if (hlsRef.current) { + hlsRef.current.destroy(); + hlsRef.current = null; + } + if (video) { + video.removeEventListener('canplay', handleStart); + video.pause(); + video.src = ''; + video.load(); + } + }; + }, [src, startTimer]); + return (
- { - fireOnVideoStart(); - }} /> {isRunning && (
diff --git a/src/widgets/webcam/ui/webcam-map.tsx b/src/widgets/webcam/ui/webcam-map.tsx index 292cd85..e0e74eb 100644 --- a/src/widgets/webcam/ui/webcam-map.tsx +++ b/src/widgets/webcam/ui/webcam-map.tsx @@ -29,6 +29,7 @@ const WebcamMap = forwardRef( {webcams.map((webcam) => { const slop = slops.filter((slop) => slop.webcamId === webcam.id); + // webcam을 띄워야 하는 slop를 찾음 return ( { - const { selectedSlop, setSelectedSlop } = useSlopStore(); + const { selectedSlop, setSelectedSlop, setSelectedCamera, setCloseCamera } = useSlopStore(); return (
    @@ -32,9 +32,12 @@ const WebcamSlopList = ({ className, list, webcams, onItemClick }: WebcamSlopLis onClick={() => { if (selectedSlop === item.id) { setSelectedSlop(null); + setSelectedCamera(null); } else { setSelectedSlop(item.id); + setSelectedCamera(item.webcamId); } + setCloseCamera(); if (item.webcamId) { const webcam = webcams.find((webcam) => webcam.id === item.webcamId); if (!webcam) return; diff --git a/yarn.lock b/yarn.lock index eda68e0..b49ff72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1663,11 +1663,6 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -eventemitter3@^4.0.3: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1953,13 +1948,10 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" -hls.js@^0.14.17: - version "0.14.17" - resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.17.tgz#0127cff2ec2f994a54eb955fe669ef6153a8e317" - integrity sha512-25A7+m6qqp6UVkuzUQ//VVh2EEOPYlOBg32ypr34bcPO7liBMOkKFvbjbCBfiPAOTA/7BSx1Dujft3Th57WyFg== - dependencies: - eventemitter3 "^4.0.3" - url-toolkit "^2.1.6" +hls.js@^1.5.15: + version "1.5.15" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.5.15.tgz#dbceb45492dcbdce9659e0d43cffa6c5cebaefb7" + integrity sha512-6cD7xN6bycBHaXz2WyPIaHn/iXFizE5au2yvY5q9aC4wfihxAr16C9fUy4nxh2a3wOw0fEgLRa9dN6wsYjlpNg== ignore@^5.2.0, ignore@^5.3.1: version "5.3.1" @@ -2757,13 +2749,6 @@ react-dom@^18: loose-envify "^1.1.0" scheduler "^0.23.2" -react-hls-player@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/react-hls-player/-/react-hls-player-3.0.7.tgz#1f66f55c2a5dc1fa6441ddc47b7c892079a276cf" - integrity sha512-i5QWNyLmaUhV/mgnpljRJT0CBfJnylClV/bne8aiXO3ZqU0+D3U/jtTDwdXM4i5qHhyFy9lemyZ179IgadKd0Q== - dependencies: - hls.js "^0.14.17" - react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -3333,11 +3318,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url-toolkit@^2.1.6: - version "2.2.5" - resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.2.5.tgz#58406b18e12c58803e14624df5e374f638b0f607" - integrity sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg== - use-callback-ref@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.2.tgz#6134c7f6ff76e2be0b56c809b17a650c942b1693"