From f609ec3f4ccc53969763231827a90ca816496241 Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 17 Sep 2023 14:25:32 -0400 Subject: [PATCH] Implement new modal designs They aren't yet used anywhere, but this will let us move on to implementing specific modal interactions from the new designs. I made the design decision of making this new Modal component always be controlled by an explicit open state, which was inspired by some work I did with Jetpack Compose recently, where I saw that this makes state management and the behavior of components so much more obvious. --- package.json | 6 +- src/Glass.module.css | 31 ++++++ src/Glass.tsx | 52 ++++++++++ src/NewModal.module.css | 217 ++++++++++++++++++++++++++++++++++++++++ src/NewModal.tsx | 141 ++++++++++++++++++++++++++ src/index.css | 4 +- yarn.lock | 119 ++++++++++++++++++++-- 7 files changed, 561 insertions(+), 9 deletions(-) create mode 100644 src/Glass.module.css create mode 100644 src/Glass.tsx create mode 100644 src/NewModal.module.css create mode 100644 src/NewModal.tsx diff --git a/package.json b/package.json index acc6068d..77c8cf2a 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "@opentelemetry/instrumentation-document-load": "^0.33.0", "@opentelemetry/instrumentation-user-interaction": "^0.33.0", "@opentelemetry/sdk-trace-web": "^1.9.1", + "@radix-ui/react-dialog": "^1.0.4", + "@radix-ui/react-visually-hidden": "^1.0.3", "@react-aria/button": "^3.3.4", "@react-aria/dialog": "^3.1.4", "@react-aria/focus": "^3.5.0", @@ -52,7 +54,6 @@ "@vitejs/plugin-basic-ssl": "^1.0.1", "@vitejs/plugin-react": "^4.0.1", "classnames": "^2.3.1", - "color-hash": "^2.0.1", "events": "^3.3.0", "i18next": "^21.10.0", "i18next-browser-languagedetector": "^6.1.8", @@ -77,7 +78,8 @@ "sdp-transform": "^2.14.1", "tinyqueue": "^2.0.3", "unique-names-generator": "^4.6.0", - "uuid": "9" + "uuid": "9", + "vaul": "^0.6.1" }, "devDependencies": { "@babel/core": "^7.16.5", diff --git a/src/Glass.module.css b/src/Glass.module.css new file mode 100644 index 00000000..cdb9621a --- /dev/null +++ b/src/Glass.module.css @@ -0,0 +1,31 @@ +/* +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. +*/ + +.glass { + border-radius: 36px; + padding: 11px; + border: 1px solid var(--cpd-color-alpha-gray-400); + background: var(--cpd-color-alpha-gray-400); + backdrop-filter: blur(10px); +} + +.glass > * { + border-radius: 24px; +} + +.glass.frosted { + backdrop-filter: blur(20px); +} diff --git a/src/Glass.tsx b/src/Glass.tsx new file mode 100644 index 00000000..5f01d47a --- /dev/null +++ b/src/Glass.tsx @@ -0,0 +1,52 @@ +/* +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 { + ComponentPropsWithoutRef, + ReactNode, + forwardRef, + Children, +} from "react"; +import classNames from "classnames"; + +import styles from "./Glass.module.css"; + +interface Props extends ComponentPropsWithoutRef<"div"> { + children: ReactNode; + className?: string; + /** + * Increases the blur effect. + * @default false + */ + frosted?: boolean; +} + +/** + * Adds a border of glass around a child component. + */ +export const Glass = forwardRef( + ({ frosted = false, children, className, ...rest }, ref) => ( +
+ {Children.only(children)} +
+ ) +); diff --git a/src/NewModal.module.css b/src/NewModal.module.css new file mode 100644 index 00000000..12d8853c --- /dev/null +++ b/src/NewModal.module.css @@ -0,0 +1,217 @@ +/* +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. +*/ + +.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; + overflow: hidden; +} + +.dialog .content { + flex-grow: 1; + background: var(--cpd-color-bg-canvas-default); +} + +.drawer .content { + overflow: auto; +} + +.drawer { + background: var(--cpd-color-bg-canvas-default); + inset-block-end: 0; + inset-inline: max(0px, calc((100% - 520px) / 2)); + max-block-size: 90%; + border-start-start-radius: 20px; + border-start-end-radius: 20px; + /* Drawer handle comes in the Android style by default */ + --handle-block-size: 4px; + --handle-inline-size: 32px; + --handle-inset-block-start: var(--cpd-space-4x); + --handle-inset-block-end: var(--cpd-space-4x); +} + +body[data-platform="ios"] .drawer { + --handle-block-size: 5px; + --handle-inline-size: 36px; + --handle-inset-block-start: var(--cpd-space-1-5x); + --handle-inset-block-end: calc(var(--cpd-space-1x) / 4); +} + +.close { + cursor: pointer; + color: var(--cpd-color-icon-secondary); + border-radius: var(--cpd-radius-pill-effect); + padding: var(--cpd-space-1x); + background: var(--cpd-color-bg-subtle-secondary); + border: none; +} + +.close svg { + display: block; +} + +@media (hover: hover) { + .close:hover { + background: var(--cpd-color-bg-subtle-primary); + color: var(--cpd-color-icon-primary); + } +} + +.close:active { + background: var(--cpd-color-bg-subtle-primary); + color: var(--cpd-color-icon-primary); +} + +.header { + background: var(--cpd-color-bg-subtle-secondary); + display: grid; +} + +.dialog .header { + padding-block-start: var(--cpd-space-4x); + grid-template-columns: + var(--cpd-space-10x) 1fr minmax(var(--cpd-space-6x), auto) + var(--cpd-space-4x); + grid-template-rows: auto minmax(var(--cpd-space-4x), auto); + /* TODO: Support tabs */ + grid-template-areas: ". title close ." "tabs tabs tabs tabs"; + align-items: center; +} + +.dialog .header h2 { + grid-area: title; + margin: 0; +} + +.drawer .header { + grid-template-areas: "tabs"; + position: relative; +} + +.close { + grid-area: close; +} + +.dialog .body { + padding-inline: var(--cpd-space-10x); + padding-block: var(--cpd-space-10x) var(--cpd-space-12x); + overflow: auto; +} + +.drawer .body { + padding-inline: var(--cpd-space-4x); + padding-block: var(--cpd-space-9x) var(--cpd-space-10x); +} + +.handle { + content: ""; + position: absolute; + block-size: var(--handle-block-size); + inset-inline: calc((100% - var(--handle-inline-size)) / 2); + inset-block-start: var(--handle-inset-block-start); + background: var(--cpd-color-icon-secondary); + border-radius: var(--cpd-radius-pill-effect); +} diff --git a/src/NewModal.tsx b/src/NewModal.tsx new file mode 100644 index 00000000..02e77b47 --- /dev/null +++ b/src/NewModal.tsx @@ -0,0 +1,141 @@ +/* +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 { ReactNode, useCallback } from "react"; +import { AriaDialogProps } from "@react-types/dialog"; +import { useTranslation } from "react-i18next"; +import { + Root as DialogRoot, + Portal as DialogPortal, + Overlay as DialogOverlay, + Content as DialogContent, + Title as DialogTitle, + Close as DialogClose, +} from "@radix-ui/react-dialog"; +import { Drawer } from "vaul"; +import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; +import { ReactComponent as CloseIcon } from "@vector-im/compound-design-tokens/icons/close.svg"; +import classNames from "classnames"; +import { Heading } from "@vector-im/compound-web"; + +import styles from "./NewModal.module.css"; +import { useMediaQuery } from "./useMediaQuery"; +import { Glass } from "./Glass"; + +// TODO: Support tabs +export interface ModalProps extends AriaDialogProps { + title: string; + children: ReactNode; + className?: string; + /** + * The controlled open state of the modal. + */ + // An option to leave the open state uncontrolled is intentionally not + // provided, since modals are always opened due to external triggers, and it + // is the author's belief that controlled components lead to more obvious code + open: boolean; + /** + * Callback for when the user dismisses the modal. If undefined, the modal + * will be non-dismissable. + */ + onDismiss?: () => void; +} + +/** + * A modal, taking the form of a drawer / bottom sheet on touchscreen devices, + * and a dialog box on desktop. + */ +export function Modal({ + title, + children, + className, + open, + onDismiss, + ...rest +}: ModalProps) { + const { t } = useTranslation(); + const touchscreen = useMediaQuery("(hover: none)"); + const onOpenChange = useCallback( + (open: boolean) => { + if (!open) onDismiss?.(); + }, + [onDismiss] + ); + + if (touchscreen) { + return ( + + + + +
+
+
+ + {title} + +
+
{children}
+
+ + + + ); + } else { + return ( + + + + + +
+
+ + + {title} + + + {onDismiss !== undefined && ( + + + + )} +
+
{children}
+
+
+
+
+
+ ); + } +} diff --git a/src/index.css b/src/index.css index 025e93db..889106e9 100644 --- a/src/index.css +++ b/src/index.css @@ -150,7 +150,9 @@ body { html, body, #root { - height: 100%; + /* We use !important here to override vaul drawers, which have a side effect + of setting height: auto; on the body element and messing up our layouts */ + height: 100% !important; } #root { diff --git a/yarn.lock b/yarn.lock index 4299ae8a..a29ec57e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2601,6 +2601,27 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-dialog@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.4.tgz#06bce6c16bb93eb36d7a8589e665a20f4c1c52c1" + integrity sha512-hJtRy/jPULGQZceSAP2Re6/4NpKo8im6V8P2hUqZsdFiSL8l35kYsw3qbRI6Ay5mQd2+wlLqje770eq+RJ3yZg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.4" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.3" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-portal" "1.0.3" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + "@radix-ui/react-dismissable-layer@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz#883a48f5f938fa679427aa17fcba70c5494c6978" @@ -2613,6 +2634,23 @@ "@radix-ui/react-use-callback-ref" "1.0.1" "@radix-ui/react-use-escape-keydown" "1.0.3" +"@radix-ui/react-focus-guards@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad" + integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-focus-scope@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.3.tgz#9c2e8d4ed1189a1d419ee61edd5c1828726472f9" + integrity sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-form@^0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-form/-/react-form-0.0.3.tgz#328e7163e723ccc748459d66a2d685d7b4f85d5a" @@ -2757,7 +2795,7 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-layout-effect" "1.0.1" -"@radix-ui/react-visually-hidden@1.0.3": +"@radix-ui/react-visually-hidden@1.0.3", "@radix-ui/react-visually-hidden@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz#51aed9dd0fe5abcad7dee2a234ad36106a6984ac" integrity sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA== @@ -5608,6 +5646,13 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +aria-hidden@^1.1.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" + integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== + dependencies: + tslib "^2.0.0" + aria-query@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" @@ -6832,11 +6877,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-hash@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/color-hash/-/color-hash-2.0.2.tgz#abf735705da71874ddec7dcef50cd7479e7d64e9" - integrity sha512-6exeENAqBTuIR1wIo36mR8xVVBv6l1hSLd7Qmvf6158Ld1L15/dbahR9VUOiX7GmGJBCnQyS0EY+I8x+wa7egg== - color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" @@ -7794,6 +7834,11 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + detect-package-manager@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/detect-package-manager/-/detect-package-manager-2.0.1.tgz#6b182e3ae5e1826752bfef1de9a7b828cffa50d8" @@ -9352,6 +9397,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@ has-proto "^1.0.1" has-symbols "^1.0.3" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -10128,6 +10178,13 @@ intl-messageformat@^9.12.0: "@formatjs/icu-messageformat-parser" "2.1.0" tslib "^2.1.0" +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + ip@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" @@ -13601,6 +13658,25 @@ react-refresh@^0.14.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== +react-remove-scroll-bar@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" + integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A== + dependencies: + react-style-singleton "^2.2.1" + tslib "^2.0.0" + +react-remove-scroll@2.5.5: + version "2.5.5" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" + integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw== + dependencies: + react-remove-scroll-bar "^2.3.3" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + react-router-dom@^5.2.0: version "5.3.4" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6" @@ -13629,6 +13705,15 @@ react-router@5.3.4: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" +react-style-singleton@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" + integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^2.0.0" + react-textarea-autosize@^8.3.2: version "8.3.4" resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz#270a343de7ad350534141b02c9cb78903e553524" @@ -15708,6 +15793,13 @@ url@^0.11.0: punycode "^1.4.1" qs "^6.11.0" +use-callback-ref@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" + integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w== + dependencies: + tslib "^2.0.0" + use-composed-ref@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.3.0.tgz#3d8104db34b7b264030a9d916c5e94fbe280dbda" @@ -15725,6 +15817,14 @@ use-latest@^1.2.1: dependencies: use-isomorphic-layout-effect "^1.1.1" +use-sidecar@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -15833,6 +15933,13 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +vaul@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/vaul/-/vaul-0.6.1.tgz#78909e171458631ab7a76b3f20d3b987a4a68c9c" + integrity sha512-/AMuTlLefi3U9CQJqHbNQeIMrNq5FxYLCXcbuRIf1wiP3fpfvoP0GzgsnREMtGuvhtkwv0BdEC1CvTfU0+W9OQ== + dependencies: + "@radix-ui/react-dialog" "^1.0.4" + vfile-location@^3.0.0, vfile-location@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c"