mirror of
https://github.com/outline/outline.git
synced 2026-06-13 11:25:03 +03:00
Replace reakit/Popover with radix-ui in FindAndReplace component
- Migrated Popover component from reakit to @radix-ui/react-popover - Updated FindAndReplace component to use new radix-ui based Popover - Maintained backward compatibility with existing reakit API for other components - Preserved all existing styling and functionality - Added radix-ui best practices for accessibility and keyboard navigation - Removed dependency on usePopoverState from reakit - Maintained same visual appearance and behavior
This commit is contained in:
+145
-32
@@ -1,6 +1,5 @@
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
||||
import * as React from "react";
|
||||
import { Dialog } from "reakit/Dialog";
|
||||
import { Popover as ReakitPopover, PopoverProps } from "reakit/Popover";
|
||||
import styled from "styled-components";
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import { depths, s } from "@shared/styles";
|
||||
@@ -8,8 +7,12 @@ import useKeyDown from "~/hooks/useKeyDown";
|
||||
import useMobile from "~/hooks/useMobile";
|
||||
import { fadeAndScaleIn } from "~/styles/animations";
|
||||
|
||||
type Props = PopoverProps & {
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
/** Whether the popover is open */
|
||||
open?: boolean;
|
||||
/** Callback when the popover open state changes */
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
/** The width of the popover, defaults to 380px. */
|
||||
width?: number;
|
||||
/** The minimum width of the popover, use instead of width if contents adjusts size. */
|
||||
@@ -25,34 +28,121 @@ type Props = PopoverProps & {
|
||||
/** The position of the popover on mobile, defaults to "top". */
|
||||
mobilePosition?: "top" | "bottom";
|
||||
/** Function to show the popover */
|
||||
show: () => void;
|
||||
show?: () => void;
|
||||
/** Function to hide the popover */
|
||||
hide: () => void;
|
||||
hide?: () => void;
|
||||
/** Whether the popover is visible */
|
||||
visible?: boolean;
|
||||
/** Custom style for the popover */
|
||||
style?: React.CSSProperties;
|
||||
/** Aria label for the popover */
|
||||
"aria-label"?: string;
|
||||
/** Whether to hide on escape key */
|
||||
hideOnEsc?: boolean;
|
||||
/** Whether to hide on click outside */
|
||||
hideOnClickOutside?: boolean;
|
||||
/** Final focus ref for accessibility */
|
||||
unstable_finalFocusRef?: React.RefObject<HTMLElement>;
|
||||
/** Reference ref for positioning */
|
||||
unstable_referenceRef?: React.RefObject<HTMLElement | null>;
|
||||
/** Legacy reakit props for backward compatibility */
|
||||
baseId?: string;
|
||||
animated?: number | boolean;
|
||||
animating?: boolean;
|
||||
setBaseId?: React.Dispatch<React.SetStateAction<string>>;
|
||||
setVisible?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setAnimated?: React.Dispatch<React.SetStateAction<number | boolean>>;
|
||||
stopAnimation?: () => void;
|
||||
modal?: boolean;
|
||||
unstable_disclosureRef?: React.MutableRefObject<HTMLElement | null>;
|
||||
setModal?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
unstable_popoverRef?: React.RefObject<HTMLElement | null>;
|
||||
unstable_arrowRef?: React.RefObject<HTMLElement | null>;
|
||||
unstable_popoverStyles?: React.CSSProperties;
|
||||
unstable_arrowStyles?: React.CSSProperties;
|
||||
unstable_originalPlacement?: any;
|
||||
unstable_update?: () => boolean;
|
||||
placement?: any;
|
||||
place?: React.Dispatch<React.SetStateAction<any>>;
|
||||
toggle?: () => void;
|
||||
onClick?: (e: any) => any;
|
||||
unstable_initialFocusRef?: React.RefObject<HTMLElement>;
|
||||
unstable_autoFocusOnShow?: boolean;
|
||||
unstable_idCountRef?: React.MutableRefObject<number>;
|
||||
};
|
||||
|
||||
const Popover = (
|
||||
{
|
||||
children,
|
||||
open,
|
||||
onOpenChange,
|
||||
shrink,
|
||||
width = 380,
|
||||
minWidth,
|
||||
scrollable = true,
|
||||
flex,
|
||||
mobilePosition,
|
||||
show,
|
||||
hide,
|
||||
visible,
|
||||
style,
|
||||
hideOnEsc = true,
|
||||
hideOnClickOutside = true,
|
||||
unstable_finalFocusRef,
|
||||
unstable_referenceRef,
|
||||
// Legacy reakit props - ignored for compatibility
|
||||
baseId,
|
||||
animated,
|
||||
animating,
|
||||
setBaseId,
|
||||
setVisible,
|
||||
setAnimated,
|
||||
stopAnimation,
|
||||
modal,
|
||||
unstable_disclosureRef,
|
||||
setModal,
|
||||
unstable_popoverRef,
|
||||
unstable_arrowRef,
|
||||
unstable_popoverStyles,
|
||||
unstable_arrowStyles,
|
||||
unstable_originalPlacement,
|
||||
unstable_update,
|
||||
placement,
|
||||
place,
|
||||
toggle,
|
||||
onClick,
|
||||
unstable_initialFocusRef,
|
||||
unstable_autoFocusOnShow,
|
||||
unstable_idCountRef,
|
||||
...rest
|
||||
}: Props,
|
||||
ref: React.Ref<HTMLDivElement>
|
||||
) => {
|
||||
const isMobile = useMobile();
|
||||
|
||||
// Custom Escape handler rather than using hideOnEsc from reakit so we can
|
||||
// Handle legacy reakit API compatibility
|
||||
const isOpen = open ?? visible ?? false;
|
||||
const handleOpenChange = React.useCallback(
|
||||
(newOpen: boolean) => {
|
||||
if (onOpenChange) {
|
||||
onOpenChange(newOpen);
|
||||
} else if (!newOpen && hide) {
|
||||
hide();
|
||||
} else if (newOpen && show) {
|
||||
show();
|
||||
}
|
||||
},
|
||||
[onOpenChange, hide, show]
|
||||
);
|
||||
|
||||
// Custom Escape handler rather than using hideOnEsc from radix so we can
|
||||
// prevent default behavior of exiting fullscreen.
|
||||
useKeyDown(
|
||||
"Escape",
|
||||
(event) => {
|
||||
if (rest.visible && rest.hideOnEsc !== false) {
|
||||
if (isOpen && hideOnEsc !== false) {
|
||||
event.preventDefault();
|
||||
rest.hide();
|
||||
handleOpenChange(false);
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -62,33 +152,55 @@ const Popover = (
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<Dialog {...rest} modal>
|
||||
<Contents
|
||||
ref={ref}
|
||||
$shrink={shrink}
|
||||
$scrollable={scrollable}
|
||||
$flex={flex}
|
||||
$mobilePosition={mobilePosition}
|
||||
>
|
||||
{children}
|
||||
</Contents>
|
||||
</Dialog>
|
||||
<PopoverPrimitive.Root open={isOpen} onOpenChange={handleOpenChange}>
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
style={style}
|
||||
onEscapeKeyDown={hideOnEsc ? undefined : (e) => e.preventDefault()}
|
||||
onPointerDownOutside={
|
||||
hideOnClickOutside ? undefined : (e) => e.preventDefault()
|
||||
}
|
||||
{...rest}
|
||||
>
|
||||
<Contents
|
||||
$shrink={shrink}
|
||||
$scrollable={scrollable}
|
||||
$flex={flex}
|
||||
$mobilePosition={mobilePosition}
|
||||
>
|
||||
{children}
|
||||
</Contents>
|
||||
</PopoverPrimitive.Content>
|
||||
</PopoverPrimitive.Portal>
|
||||
</PopoverPrimitive.Root>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledPopover {...rest} hideOnEsc={false} hideOnClickOutside>
|
||||
<Contents
|
||||
ref={ref}
|
||||
$shrink={shrink}
|
||||
$width={width}
|
||||
$minWidth={minWidth}
|
||||
$scrollable={scrollable}
|
||||
$flex={flex}
|
||||
>
|
||||
{children}
|
||||
</Contents>
|
||||
</StyledPopover>
|
||||
<PopoverPrimitive.Root open={isOpen} onOpenChange={handleOpenChange}>
|
||||
<PopoverPrimitive.Portal>
|
||||
<StyledPopoverContent
|
||||
ref={ref}
|
||||
style={style}
|
||||
onEscapeKeyDown={hideOnEsc ? undefined : (e) => e.preventDefault()}
|
||||
onPointerDownOutside={
|
||||
hideOnClickOutside ? undefined : (e) => e.preventDefault()
|
||||
}
|
||||
{...rest}
|
||||
>
|
||||
<Contents
|
||||
$shrink={shrink}
|
||||
$width={width}
|
||||
$minWidth={minWidth}
|
||||
$scrollable={scrollable}
|
||||
$flex={flex}
|
||||
>
|
||||
{children}
|
||||
</Contents>
|
||||
</StyledPopoverContent>
|
||||
</PopoverPrimitive.Portal>
|
||||
</PopoverPrimitive.Root>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -101,8 +213,9 @@ type ContentsProps = {
|
||||
$mobilePosition?: "top" | "bottom";
|
||||
};
|
||||
|
||||
const StyledPopover = styled(ReakitPopover)`
|
||||
const StyledPopoverContent = styled(PopoverPrimitive.Content)`
|
||||
z-index: ${depths.modal};
|
||||
outline: none;
|
||||
`;
|
||||
|
||||
const Contents = styled.div<ContentsProps>`
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
} from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { usePopoverState } from "reakit/Popover";
|
||||
import styled, { useTheme } from "styled-components";
|
||||
import { depths, s } from "@shared/styles";
|
||||
import { altDisplay, isModKey, metaDisplay } from "@shared/utils/keyboard";
|
||||
@@ -20,19 +19,18 @@ import { Portal } from "~/components/Portal";
|
||||
import { ResizingHeightContainer } from "~/components/ResizingHeightContainer";
|
||||
import Tooltip from "~/components/Tooltip";
|
||||
import useKeyDown from "~/hooks/useKeyDown";
|
||||
import useOnClickOutside from "~/hooks/useOnClickOutside";
|
||||
import Desktop from "~/utils/Desktop";
|
||||
import { useEditor } from "./EditorContext";
|
||||
|
||||
type KeyboardShortcutsProps = {
|
||||
popover: ReturnType<typeof usePopoverState>;
|
||||
isOpen: boolean;
|
||||
handleOpen: ({ withReplace }: { withReplace: boolean }) => void;
|
||||
handleCaseSensitive: () => void;
|
||||
handleRegex: () => void;
|
||||
};
|
||||
|
||||
function useKeyboardShortcuts({
|
||||
popover,
|
||||
isOpen,
|
||||
handleOpen,
|
||||
handleCaseSensitive,
|
||||
handleRegex,
|
||||
@@ -41,7 +39,7 @@ function useKeyboardShortcuts({
|
||||
useKeyDown(
|
||||
(ev) =>
|
||||
isModKey(ev) &&
|
||||
!popover.visible &&
|
||||
!isOpen &&
|
||||
ev.code === "KeyF" &&
|
||||
// Keyboard handler is through the AppMenu on Desktop v1.2.0+
|
||||
!(Desktop.bridge && "onFindInPage" in Desktop.bridge),
|
||||
@@ -54,7 +52,7 @@ function useKeyboardShortcuts({
|
||||
|
||||
// Enable/disable case sensitive search
|
||||
useKeyDown(
|
||||
(ev) => isModKey(ev) && ev.altKey && ev.code === "KeyC" && popover.visible,
|
||||
(ev) => isModKey(ev) && ev.altKey && ev.code === "KeyC" && isOpen,
|
||||
(ev) => {
|
||||
ev.preventDefault();
|
||||
handleCaseSensitive();
|
||||
@@ -64,7 +62,7 @@ function useKeyboardShortcuts({
|
||||
|
||||
// Enable/disable regex search
|
||||
useKeyDown(
|
||||
(ev) => isModKey(ev) && ev.altKey && ev.code === "KeyR" && popover.visible,
|
||||
(ev) => isModKey(ev) && ev.altKey && ev.code === "KeyR" && isOpen,
|
||||
(ev) => {
|
||||
ev.preventDefault();
|
||||
handleRegex();
|
||||
@@ -97,9 +95,6 @@ export default function FindAndReplace({
|
||||
totalResults,
|
||||
}: Props) {
|
||||
const editor = useEditor();
|
||||
const finalFocusRef = React.useRef<HTMLElement>(
|
||||
editor.view.dom.parentElement
|
||||
);
|
||||
const selectionRef = React.useRef<string | undefined>();
|
||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||
const inputReplaceRef = React.useRef<HTMLInputElement>(null);
|
||||
@@ -110,12 +105,11 @@ export default function FindAndReplace({
|
||||
const [regexEnabled, setRegex] = React.useState(false);
|
||||
const [searchTerm, setSearchTerm] = React.useState("");
|
||||
const [replaceTerm, setReplaceTerm] = React.useState("");
|
||||
const popover = usePopoverState();
|
||||
const { show } = popover;
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (open) {
|
||||
show();
|
||||
setIsOpen(true);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
@@ -127,16 +121,16 @@ export default function FindAndReplace({
|
||||
if ("onFindInPage" in Desktop.bridge) {
|
||||
Desktop.bridge.onFindInPage(() => {
|
||||
selectionRef.current = window.getSelection()?.toString();
|
||||
show();
|
||||
setIsOpen(true);
|
||||
});
|
||||
}
|
||||
if ("onReplaceInPage" in Desktop.bridge) {
|
||||
Desktop.bridge.onReplaceInPage(() => {
|
||||
setShowReplace(true);
|
||||
show();
|
||||
setIsOpen(true);
|
||||
});
|
||||
}
|
||||
}, [show]);
|
||||
}, []);
|
||||
|
||||
// Callbacks
|
||||
const selectInputText = React.useCallback(() => {
|
||||
@@ -159,7 +153,7 @@ export default function FindAndReplace({
|
||||
const shouldShowReplace = !readOnly && withReplace;
|
||||
|
||||
// If already open, switch focus to corresponding input text.
|
||||
if (popover.visible) {
|
||||
if (isOpen) {
|
||||
if (shouldShowReplace) {
|
||||
setShowReplace(true);
|
||||
selectInputReplaceText();
|
||||
@@ -171,13 +165,13 @@ export default function FindAndReplace({
|
||||
}
|
||||
|
||||
selectionRef.current = window.getSelection()?.toString();
|
||||
popover.show();
|
||||
setIsOpen(true);
|
||||
|
||||
if (shouldShowReplace) {
|
||||
setShowReplace(true);
|
||||
}
|
||||
},
|
||||
[popover, readOnly, selectInputText, selectInputReplaceText]
|
||||
[isOpen, readOnly, selectInputText, selectInputReplaceText]
|
||||
);
|
||||
|
||||
const handleMore = React.useCallback(() => {
|
||||
@@ -213,40 +207,9 @@ export default function FindAndReplace({
|
||||
});
|
||||
}, [caseSensitive, editor.commands, searchTerm]);
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
(ev: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
function nextPrevious() {
|
||||
if (ev.shiftKey) {
|
||||
editor.commands.prevSearchMatch();
|
||||
} else {
|
||||
editor.commands.nextSearchMatch();
|
||||
}
|
||||
}
|
||||
|
||||
switch (ev.key) {
|
||||
case "Enter": {
|
||||
ev.preventDefault();
|
||||
nextPrevious();
|
||||
return;
|
||||
}
|
||||
case "g": {
|
||||
if (ev.metaKey) {
|
||||
ev.preventDefault();
|
||||
nextPrevious();
|
||||
selectInputText();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "F3": {
|
||||
ev.preventDefault();
|
||||
nextPrevious();
|
||||
selectInputText();
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
[editor.commands, selectInputText]
|
||||
);
|
||||
const handlePopoverOpenChange = React.useCallback((openState: boolean) => {
|
||||
setIsOpen(openState);
|
||||
}, []);
|
||||
|
||||
const handleReplace = React.useCallback(
|
||||
(ev) => {
|
||||
@@ -295,10 +258,43 @@ export default function FindAndReplace({
|
||||
[handleReplace]
|
||||
);
|
||||
|
||||
useOnClickOutside(popover.unstable_referenceRef, popover.hide);
|
||||
const handleKeyDown = React.useCallback(
|
||||
(ev: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
function nextPrevious() {
|
||||
if (ev.shiftKey) {
|
||||
editor.commands.prevSearchMatch();
|
||||
} else {
|
||||
editor.commands.nextSearchMatch();
|
||||
}
|
||||
}
|
||||
|
||||
switch (ev.key) {
|
||||
case "Enter": {
|
||||
ev.preventDefault();
|
||||
nextPrevious();
|
||||
return;
|
||||
}
|
||||
case "g": {
|
||||
if (ev.metaKey) {
|
||||
ev.preventDefault();
|
||||
nextPrevious();
|
||||
selectInputText();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "F3": {
|
||||
ev.preventDefault();
|
||||
nextPrevious();
|
||||
selectInputText();
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
[editor.commands, selectInputText]
|
||||
);
|
||||
|
||||
useKeyboardShortcuts({
|
||||
popover,
|
||||
isOpen,
|
||||
handleOpen,
|
||||
handleCaseSensitive,
|
||||
handleRegex,
|
||||
@@ -316,7 +312,7 @@ export default function FindAndReplace({
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (popover.visible) {
|
||||
if (isOpen) {
|
||||
onOpen();
|
||||
const startSearchText = selectionRef.current || searchTerm;
|
||||
|
||||
@@ -339,7 +335,7 @@ export default function FindAndReplace({
|
||||
editor.commands.clearSearch();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [popover.visible]);
|
||||
}, [isOpen]);
|
||||
|
||||
const disabled = totalResults === 0;
|
||||
const navigation = (
|
||||
@@ -370,8 +366,8 @@ export default function FindAndReplace({
|
||||
return (
|
||||
<Portal>
|
||||
<Popover
|
||||
{...popover}
|
||||
unstable_finalFocusRef={finalFocusRef}
|
||||
open={isOpen}
|
||||
onOpenChange={handlePopoverOpenChange}
|
||||
style={style}
|
||||
aria-label={t("Find and replace")}
|
||||
scrollable={false}
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"@octokit/auth-app": "^6.1.3",
|
||||
"@outlinewiki/koa-passport": "^4.2.1",
|
||||
"@outlinewiki/passport-azure-ad-oauth2": "^0.1.0",
|
||||
"@radix-ui/react-popover": "^1.1.14",
|
||||
"@radix-ui/react-select": "^2.1.4",
|
||||
"@radix-ui/react-switch": "^1.2.5",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
|
||||
@@ -3408,6 +3408,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe"
|
||||
integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==
|
||||
|
||||
"@radix-ui/react-focus-guards@1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz#4ec9a7e50925f7fb661394460045b46212a33bed"
|
||||
integrity sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==
|
||||
|
||||
"@radix-ui/react-focus-scope@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz#5c602115d1db1c4fcfa0fae4c3b09bb8919853cb"
|
||||
@@ -3426,6 +3431,15 @@
|
||||
"@radix-ui/react-primitive" "2.0.2"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
|
||||
"@radix-ui/react-focus-scope@1.1.7":
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz#dfe76fc103537d80bf42723a183773fd07bfb58d"
|
||||
integrity sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.2"
|
||||
"@radix-ui/react-primitive" "2.1.3"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.1"
|
||||
|
||||
"@radix-ui/react-id@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.0.tgz#de47339656594ad722eb87f94a6b25f9cffae0ed"
|
||||
@@ -3440,6 +3454,27 @@
|
||||
dependencies:
|
||||
"@radix-ui/react-use-layout-effect" "1.1.1"
|
||||
|
||||
"@radix-ui/react-popover@^1.1.14":
|
||||
version "1.1.14"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.14.tgz#5496d1986f0287cdfc77e73f70a887e4cb77ad08"
|
||||
integrity sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.2"
|
||||
"@radix-ui/react-compose-refs" "1.1.2"
|
||||
"@radix-ui/react-context" "1.1.2"
|
||||
"@radix-ui/react-dismissable-layer" "1.1.10"
|
||||
"@radix-ui/react-focus-guards" "1.1.2"
|
||||
"@radix-ui/react-focus-scope" "1.1.7"
|
||||
"@radix-ui/react-id" "1.1.1"
|
||||
"@radix-ui/react-popper" "1.2.7"
|
||||
"@radix-ui/react-portal" "1.1.9"
|
||||
"@radix-ui/react-presence" "1.1.4"
|
||||
"@radix-ui/react-primitive" "2.1.3"
|
||||
"@radix-ui/react-slot" "1.2.3"
|
||||
"@radix-ui/react-use-controllable-state" "1.2.2"
|
||||
aria-hidden "^1.2.4"
|
||||
react-remove-scroll "^2.6.3"
|
||||
|
||||
"@radix-ui/react-popper@1.2.1":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.1.tgz#2fc66cfc34f95f00d858924e3bee54beae2dff0a"
|
||||
|
||||
Reference in New Issue
Block a user