diff --git a/package.json b/package.json index 1471acd6..5bf96ac8 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "@storybook/react": "^6.5.0-alpha.5", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.5.1", "@types/content-type": "^1.1.5", "@types/d3": "^7.4.0", "@types/dom-screen-wake-lock": "^1.0.1", diff --git a/public/locales/en-GB/app.json b/public/locales/en-GB/app.json index 14ee2185..789552e5 100644 --- a/public/locales/en-GB/app.json +++ b/public/locales/en-GB/app.json @@ -29,7 +29,7 @@ "Continue in browser": "Continue in browser", "Copied!": "Copied!", "Copy": "Copy", - "Copy and share this call link": "Copy and share this call link", + "Copy link": "Copy link", "Create account": "Create account", "Debug log": "Debug log", "Debug log request": "Debug log request", @@ -54,9 +54,12 @@ "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.", "Include debug logs": "Include debug logs", "Inspector": "Inspector", + "Invite": "Invite", + "Invite to this call": "Invite to this call", "Join call": "Join call", "Join call now": "Join call now", "Join existing call?": "Join existing call?", + "Link copied to clipboard": "Link copied to clipboard", "Loading…": "Loading…", "Local volume": "Local volume", "Logging in…": "Logging in…", @@ -92,9 +95,7 @@ "Sending debug logs…": "Sending debug logs…", "Sending…": "Sending…", "Settings": "Settings", - "Share": "Share", "Share screen": "Share screen", - "Share this call": "Share this call", "Sharing screen": "Sharing screen", "Show call inspector": "Show call inspector", "Show connection stats": "Show connection stats", diff --git a/src/Modal.module.css b/src/Modal.module.css index e72f6496..d6af51df 100644 --- a/src/Modal.module.css +++ b/src/Modal.module.css @@ -14,96 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -.overlay { - position: fixed; - z-index: 100; - inset: 0; - background: rgba(3, 12, 27, 0.528); -} - -@keyframes fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.dialogOverlay[data-state="open"] { - animation: fade-in 200ms; -} - -@keyframes fade-out { - from { - opacity: 1; - } - to { - opacity: 0; - } -} - -.dialogOverlay[data-state="closed"] { - animation: fade-out 130ms; -} - .modal { - position: fixed; - z-index: 101; display: flex; flex-direction: column; } .dialog { - left: 50%; - top: 50%; - transform: translate(-50%, -50%); box-sizing: border-box; inline-size: 520px; max-inline-size: 90%; max-block-size: 600px; } -@keyframes zoom-in { - from { - opacity: 0; - transform: translate(-50%, -50%) scale(80%); - } - to { - opacity: 1; - transform: translate(-50%, -50%) scale(100%); - } -} - -@keyframes zoom-out { - from { - opacity: 1; - transform: translate(-50%, -50%) scale(100%); - } - to { - opacity: 0; - transform: translate(-50%, -50%) scale(80%); - } -} - -.dialog[data-state="open"] { - animation: zoom-in 200ms; -} - -.dialog[data-state="closed"] { - animation: zoom-out 130ms; -} - -@media (prefers-reduced-motion) { - .dialog[data-state="open"] { - animation-name: fade-in; - } - - .dialog[data-state="closed"] { - animation-name: fade-out; - } -} - .content { display: flex; flex-direction: column; diff --git a/src/Modal.tsx b/src/Modal.tsx index ac701402..83e43eb2 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -32,6 +32,7 @@ import classNames from "classnames"; import { Heading } from "@vector-im/compound-web"; import styles from "./Modal.module.css"; +import overlayStyles from "./Overlay.module.css"; import { useMediaQuery } from "./useMediaQuery"; import { Glass } from "./Glass"; @@ -85,9 +86,14 @@ export function Modal({ dismissible={onDismiss !== undefined} > - +
@@ -108,12 +114,18 @@ export function Modal({
diff --git a/src/Overlay.module.css b/src/Overlay.module.css new file mode 100644 index 00000000..37bcf95d --- /dev/null +++ b/src/Overlay.module.css @@ -0,0 +1,99 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.bg { + position: fixed; + z-index: 100; + inset: 0; + background: rgba(3, 12, 27, 0.528); +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.bg.animate[data-state="open"] { + animation: fade-in 200ms; +} + +@keyframes fade-out { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +.bg.animate[data-state="closed"] { + animation: fade-out 130ms; +} + +.overlay { + position: fixed; + z-index: 101; +} + +.overlay.animate { + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} + +@keyframes zoom-in { + from { + opacity: 0; + transform: translate(-50%, -50%) scale(80%); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(100%); + } +} + +@keyframes zoom-out { + from { + opacity: 1; + transform: translate(-50%, -50%) scale(100%); + } + to { + opacity: 0; + transform: translate(-50%, -50%) scale(80%); + } +} + +.overlay.animate[data-state="open"] { + animation: zoom-in 200ms; +} + +.overlay.animate[data-state="closed"] { + animation: zoom-out 130ms; +} + +@media (prefers-reduced-motion) { + .overlay.animate[data-state="open"] { + animation-name: fade-in; + } + + .overlay.animate[data-state="closed"] { + animation-name: fade-out; + } +} diff --git a/src/Toast.module.css b/src/Toast.module.css new file mode 100644 index 00000000..5f19b3b2 --- /dev/null +++ b/src/Toast.module.css @@ -0,0 +1,38 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.toast { + color: var(--cpd-color-text-on-solid-primary); + background: var(--cpd-color-alpha-gray-1200); + padding-inline: var(--cpd-space-3x); + padding-block: var(--cpd-space-1x); + border: none; + border-radius: var(--cpd-radius-pill-effect); + box-shadow: var(--small-drop-shadow); + display: flex; + align-items: center; + gap: var(--cpd-space-1x); +} + +.toast > h3 { + margin: 0; +} + +.toast > svg { + color: var(--cpd-color-icon-on-solid-primary); + flex-shrink: 0; + margin-inline-end: calc(-1 * var(--cpd-space-1x)); +} diff --git a/src/Toast.tsx b/src/Toast.tsx new file mode 100644 index 00000000..de532cde --- /dev/null +++ b/src/Toast.tsx @@ -0,0 +1,108 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { + ComponentType, + FC, + SVGAttributes, + useCallback, + useEffect, +} from "react"; +import { + Root as DialogRoot, + Portal as DialogPortal, + Overlay as DialogOverlay, + Content as DialogContent, + Close as DialogClose, + Title as DialogTitle, +} from "@radix-ui/react-dialog"; +import classNames from "classnames"; +import { Text } from "@vector-im/compound-web"; + +import styles from "./Toast.module.css"; +import overlayStyles from "./Overlay.module.css"; + +interface Props { + /** + * The controlled open state of the toast. + */ + open: boolean; + /** + * Callback for when the user dismisses the toast. + */ + onDismiss: () => void; + /** + * A number of milliseconds after which the toast should be automatically + * dismissed. + */ + autoDismiss?: number; + children: string; + /** + * A supporting icon to display within the toast. + */ + Icon?: ComponentType>; +} + +/** + * A temporary message shown in an overlay in the center of the screen. + */ +export const Toast: FC = ({ + open, + onDismiss, + autoDismiss, + children, + Icon, +}) => { + const onOpenChange = useCallback( + (open: boolean) => { + if (!open) onDismiss(); + }, + [onDismiss] + ); + + useEffect(() => { + if (open && autoDismiss !== undefined) { + const timeout = setTimeout(onDismiss, autoDismiss); + return () => clearTimeout(timeout); + } + }, [open, autoDismiss, onDismiss]); + + return ( + + + + + + + + {children} + + + {Icon && } + + + + + ); +}; diff --git a/src/button/ShareButton.tsx b/src/button/InviteButton.tsx similarity index 95% rename from src/button/ShareButton.tsx rename to src/button/InviteButton.tsx index 02c0fc9c..45fb9776 100644 --- a/src/button/ShareButton.tsx +++ b/src/button/InviteButton.tsx @@ -19,13 +19,13 @@ import { Button } from "@vector-im/compound-web"; import { useTranslation } from "react-i18next"; import UserAddSolidIcon from "@vector-im/compound-design-tokens/icons/user-add-solid.svg?react"; -export const ShareButton: FC< +export const InviteButton: FC< Omit, "children"> > = (props) => { const { t } = useTranslation(); return ( ); }; diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index eade3f52..bc513c18 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -47,7 +47,7 @@ import { useEnableE2EE } from "../settings/useSetting"; import { useRoomAvatar } from "./useRoomAvatar"; import { useRoomName } from "./useRoomName"; import { useJoinRule } from "./useJoinRule"; -import { ShareModal } from "./ShareModal"; +import { InviteModal } from "./InviteModal"; declare global { interface Window { @@ -267,15 +267,15 @@ export function GroupCallView({ const joinRule = useJoinRule(rtcSession.room); - const [shareModalOpen, setShareModalOpen] = useState(false); - const onDismissShareModal = useCallback( - () => setShareModalOpen(false), - [setShareModalOpen] + const [shareModalOpen, setInviteModalOpen] = useState(false); + const onDismissInviteModal = useCallback( + () => setInviteModalOpen(false), + [setInviteModalOpen] ); const onShareClickFn = useCallback( - () => setShareModalOpen(true), - [setShareModalOpen] + () => setInviteModalOpen(true), + [setInviteModalOpen] ); const onShareClick = joinRule === JoinRule.Public ? onShareClickFn : null; @@ -318,10 +318,10 @@ export function GroupCallView({ } const shareModal = ( - ); diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 9c96cc76..a9a6b0b1 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -69,7 +69,7 @@ import { useWakeLock } from "../useWakeLock"; import { useMergedRefs } from "../useMergedRefs"; import { MuteStates } from "./MuteStates"; import { MatrixInfo } from "./VideoPreview"; -import { ShareButton } from "../button/ShareButton"; +import { InviteButton } from "../button/InviteButton"; import { LayoutToggle } from "./LayoutToggle"; import { ECAddonConnectionState, @@ -416,7 +416,7 @@ export function InCallView({ {!reducedControls && onShareClick !== null && ( - + )} diff --git a/src/room/ShareModal.module.css b/src/room/InviteModal.module.css similarity index 82% rename from src/room/ShareModal.module.css rename to src/room/InviteModal.module.css index dec0c304..dd7aa755 100644 --- a/src/room/ShareModal.module.css +++ b/src/room/InviteModal.module.css @@ -14,6 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -.copyButton { +.url { + text-align: center; + color: var(--cpd-color-text-secondary); + margin-block-end: var(--cpd-space-8x); +} + +.button { width: 100%; } diff --git a/src/room/InviteModal.tsx b/src/room/InviteModal.tsx new file mode 100644 index 00000000..33d6ef97 --- /dev/null +++ b/src/room/InviteModal.tsx @@ -0,0 +1,84 @@ +/* +Copyright 2022 - 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { FC, MouseEvent, useCallback, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Room } from "matrix-js-sdk"; +import { Button, Text } from "@vector-im/compound-web"; +import LinkIcon from "@vector-im/compound-design-tokens/icons/link.svg?react"; +import CheckIcon from "@vector-im/compound-design-tokens/icons/check.svg?react"; +import useClipboard from "react-use-clipboard"; + +import { Modal } from "../Modal"; +import { getAbsoluteRoomUrl } from "../matrix-utils"; +import styles from "./InviteModal.module.css"; +import { useRoomSharedKey } from "../e2ee/sharedKeyManagement"; +import { Toast } from "../Toast"; + +interface Props { + room: Room; + open: boolean; + onDismiss: () => void; +} + +export const InviteModal: FC = ({ room, open, onDismiss }) => { + const { t } = useTranslation(); + const roomSharedKey = useRoomSharedKey(room.roomId); + const url = useMemo( + () => + getAbsoluteRoomUrl(room.roomId, room.name, roomSharedKey ?? undefined), + [room, roomSharedKey] + ); + const [, setCopied] = useClipboard(url); + const [toastOpen, setToastOpen] = useState(false); + const onToastDismiss = useCallback(() => setToastOpen(false), [setToastOpen]); + + const onButtonClick = useCallback( + (e: MouseEvent) => { + e.stopPropagation(); + setCopied(); + onDismiss(); + setToastOpen(true); + }, + [setCopied, onDismiss] + ); + + return ( + <> + + + {url} + + + + + {t("Link copied to clipboard")} + + + ); +}; diff --git a/src/room/LobbyView.tsx b/src/room/LobbyView.tsx index 7703206b..e49b70cf 100644 --- a/src/room/LobbyView.tsx +++ b/src/room/LobbyView.tsx @@ -27,7 +27,7 @@ import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header"; import { useLocationNavigation } from "../useLocationNavigation"; import { MatrixInfo, VideoPreview } from "./VideoPreview"; import { MuteStates } from "./MuteStates"; -import { ShareButton } from "../button/ShareButton"; +import { InviteButton } from "../button/InviteButton"; import { HangupButton, MicButton, @@ -108,7 +108,7 @@ export const LobbyView: FC = ({ /> - {onShareClick !== null && } + {onShareClick !== null && } )} diff --git a/src/room/ShareModal.tsx b/src/room/ShareModal.tsx deleted file mode 100644 index 0439f10a..00000000 --- a/src/room/ShareModal.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2022 - 2023 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { FC } from "react"; -import { useTranslation } from "react-i18next"; -import { Room } from "matrix-js-sdk"; - -import { Modal } from "../Modal"; -import { CopyButton } from "../button"; -import { getAbsoluteRoomUrl } from "../matrix-utils"; -import styles from "./ShareModal.module.css"; -import { useRoomSharedKey } from "../e2ee/sharedKeyManagement"; - -interface Props { - room: Room; - open: boolean; - onDismiss: () => void; -} - -export const ShareModal: FC = ({ room, open, onDismiss }) => { - const { t } = useTranslation(); - const roomSharedKey = useRoomSharedKey(room.roomId); - - return ( - -

{t("Copy and share this call link")}

- -
- ); -}; diff --git a/test/Toast-test.tsx b/test/Toast-test.tsx new file mode 100644 index 00000000..605feaea --- /dev/null +++ b/test/Toast-test.tsx @@ -0,0 +1,59 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { screen, render } from "@testing-library/react"; +import { Toast } from "../src/Toast"; +import userEvent from "@testing-library/user-event"; +import { withFakeTimers } from "./utils"; + +test("Toast renders", () => { + render( + {}}> + Hello world! + + ); + expect(screen.queryByRole("dialog")).toBe(null); + render( + {}}> + Hello world! + + ); + expect(screen.getByRole("dialog")).toMatchSnapshot(); +}); + +test("Toast dismisses when clicked", async () => { + const onDismiss = jest.fn(); + render( + + Hello world! + + ); + await userEvent.click(screen.getByRole("dialog")); + expect(onDismiss).toHaveBeenCalled(); +}); + +test("Toast dismisses itself after the specified timeout", async () => { + withFakeTimers(() => { + const onDismiss = jest.fn(); + render( + + Hello world! + + ); + jest.advanceTimersByTime(2000); + expect(onDismiss).toHaveBeenCalled(); + }); +}); diff --git a/test/__snapshots__/Toast-test.tsx.snap b/test/__snapshots__/Toast-test.tsx.snap new file mode 100644 index 00000000..3391de02 --- /dev/null +++ b/test/__snapshots__/Toast-test.tsx.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Toast renders 1`] = ` + +`; diff --git a/test/room/checkForParallelCalls-test.ts b/test/room/checkForParallelCalls-test.ts index 6b5f0166..0a1344df 100644 --- a/test/room/checkForParallelCalls-test.ts +++ b/test/room/checkForParallelCalls-test.ts @@ -18,15 +18,7 @@ import { Mocked, mocked } from "jest-mock"; import { RoomState } from "matrix-js-sdk/src/models/room-state"; import { PosthogAnalytics } from "../../src/analytics/PosthogAnalytics"; import { checkForParallelCalls } from "../../src/room/checkForParallelCalls"; - -const withFakeTimers = (continuation: () => void) => { - jest.useFakeTimers(); - try { - continuation(); - } finally { - jest.useRealTimers(); - } -}; +import { withFakeTimers } from "../utils"; const withMockedPosthog = ( continuation: (posthog: Mocked) => void diff --git a/test/utils.ts b/test/utils.ts new file mode 100644 index 00000000..9fb282ef --- /dev/null +++ b/test/utils.ts @@ -0,0 +1,24 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export function withFakeTimers(continuation: () => void): void { + jest.useFakeTimers(); + try { + continuation(); + } finally { + jest.useRealTimers(); + } +} diff --git a/yarn.lock b/yarn.lock index 87d36fc5..b871710a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -65,7 +65,28 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.16.5", "@babel/core@^7.17.10", "@babel/core@^7.21.3", "@babel/core@^7.22.20", "@babel/core@^7.7.5": +"@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.16.5", "@babel/core@^7.17.10", "@babel/core@^7.7.5": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.20.tgz#e3d0eed84c049e2a2ae0a64d27b6a37edec385b7" + integrity sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.22.20" + "@babel/helpers" "^7.22.15" + "@babel/parser" "^7.22.16" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.22.20" + "@babel/types" "^7.22.19" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/core@^7.21.3", "@babel/core@^7.22.20": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== @@ -96,6 +117,16 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.22.15", "@babel/generator@^7.7.2": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" + integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== + dependencies: + "@babel/types" "^7.22.15" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/generator@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" @@ -106,16 +137,6 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/generator@^7.7.2": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" - integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== - dependencies: - "@babel/types" "^7.22.15" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - "@babel/helper-annotate-as-pure@^7.18.6", "@babel/helper-annotate-as-pure@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" @@ -253,6 +274,17 @@ "@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-validator-identifier" "^7.22.5" +"@babel/helper-module-transforms@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz#da9edc14794babbe7386df438f3768067132f59e" + integrity sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" @@ -353,6 +385,15 @@ "@babel/traverse" "^7.22.11" "@babel/types" "^7.22.11" +"@babel/helpers@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" + integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.22.15" + "@babel/types" "^7.22.15" + "@babel/helpers@^7.23.0": version "7.23.1" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" @@ -381,7 +422,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.14.tgz#c7de58e8de106e88efca42ce17f0033209dfd245" integrity sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ== -"@babel/parser@^7.14.7": +"@babel/parser@^7.14.7", "@babel/parser@^7.22.16": version "7.22.16" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== @@ -1362,6 +1403,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.20.tgz#db572d9cb5c79e02d83e5618b82f6991c07584c9" + integrity sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.16" + "@babel/types" "^7.22.19" + debug "^4.1.0" + globals "^11.1.0" + "@babel/traverse@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" @@ -1396,7 +1453,7 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" -"@babel/types@^7.3.3": +"@babel/types@^7.22.19", "@babel/types@^7.3.3": version "7.22.19" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== @@ -4333,6 +4390,11 @@ "@testing-library/dom" "^9.0.0" "@types/react-dom" "^18.0.0" +"@testing-library/user-event@^14.5.1": + version "14.5.1" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.1.tgz#27337d72046d5236b32fd977edee3f74c71d332f" + integrity sha512-UCcUKrUYGj7ClomOo2SpNVvx4/fkd/2BbIHDCle8A0ax+P3bU7yJwDBDrS6ZwdTMARWTGODX1hEsCcO+7beJjg== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"