Migrate Guide.tsx from Reakit to Radix Dialog (#9752)

* Migrate Guide.tsx from Reakit to Radix Dialog

- Replace Reakit Dialog imports with @radix-ui/react-dialog
- Update component structure to use Dialog.Root, Dialog.Portal, Dialog.Overlay, and Dialog.Content
- Remove useDialogState hook in favor of direct open/onOpenChange props
- Preserve identical styling and animations using data-state attributes
- Maintain slide-in animation from right side with 250ms transition
- Keep all existing props and behavior intact

* stash

* fix animations

---------

Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
This commit is contained in:
codegen-sh[bot]
2025-07-28 07:54:29 -04:00
committed by GitHub
parent 520a2e363e
commit 7e11b23f87
2 changed files with 71 additions and 59 deletions
+36 -53
View File
@@ -1,9 +1,14 @@
import * as React from "react";
import { Dialog, DialogBackdrop, useDialogState } from "reakit/Dialog";
import * as Dialog from "@radix-ui/react-dialog";
import styled from "styled-components";
import { depths, s } from "@shared/styles";
import Scrollable from "~/components/Scrollable";
import usePrevious from "~/hooks/usePrevious";
import {
fadeIn,
fadeOut,
fadeInAndSlideLeft,
fadeOutAndSlideRight,
} from "~/styles/animations";
type Props = {
children?: React.ReactNode;
@@ -18,55 +23,33 @@ const Guide: React.FC<Props> = ({
title = "Untitled",
onRequestClose,
...rest
}: Props) => {
const dialog = useDialogState({
animated: 250,
});
const wasOpen = usePrevious(isOpen);
React.useEffect(() => {
if (!wasOpen && isOpen) {
dialog.show();
}
if (wasOpen && !isOpen) {
dialog.hide();
}
}, [dialog, wasOpen, isOpen]);
return (
<DialogBackdrop {...dialog}>
{(backdropProps) => (
<Backdrop {...backdropProps}>
<Dialog
{...dialog}
aria-label={title}
preventBodyScroll
hideOnEsc
hide={onRequestClose}
}: Props) => (
<Dialog.Root open={isOpen} onOpenChange={(open) => !open && onRequestClose()}>
<Dialog.Portal>
<StyledOverlay>
<Scene
onEscapeKeyDown={onRequestClose}
onPointerDownOutside={onRequestClose}
aria-describedby={undefined}
{...rest}
>
{(dialogProps) => (
<Scene {...dialogProps} {...rest}>
<Content>
{title && <Header>{title}</Header>}
{children}
</Content>
</Scene>
)}
</Dialog>
</Backdrop>
)}
</DialogBackdrop>
);
};
</StyledOverlay>
</Dialog.Portal>
</Dialog.Root>
);
const Header = styled.h1`
const Header = styled(Dialog.Title)`
font-size: 18px;
margin-top: 0;
margin-bottom: 1em;
`;
const Backdrop = styled.div`
const StyledOverlay = styled(Dialog.Overlay)`
position: fixed;
top: 0;
left: 0;
@@ -74,37 +57,37 @@ const Backdrop = styled.div`
bottom: 0;
background-color: ${s("backdrop")} !important;
z-index: ${depths.overlay};
transition: opacity 200ms ease-in-out;
opacity: 0;
&[data-enter] {
opacity: 1;
&[data-state="open"] {
animation: ${fadeIn} 200ms ease;
}
&[data-state="closed"] {
animation: ${fadeOut} 200ms ease;
}
`;
const Scene = styled.div`
const Scene = styled(Dialog.Content)`
position: absolute;
top: 0;
right: 0;
bottom: 0;
margin: 12px;
z-index: ${depths.modal};
display: flex;
z-index: ${depths.modal};
justify-content: center;
align-items: flex-start;
width: 350px;
background: ${s("background")};
border-radius: 8px;
outline: none;
opacity: 0;
transform: translateX(16px);
transition:
transform 250ms ease,
opacity 250ms ease;
&[data-enter] {
opacity: 1;
transform: translateX(0px);
&[data-state="open"] {
animation: ${fadeInAndSlideLeft} 200ms ease;
}
&[data-state="closed"] {
animation: ${fadeOutAndSlideRight} 200ms ease;
}
`;
+29
View File
@@ -5,6 +5,11 @@ export const fadeIn = keyframes`
to { opacity: 1; }
`;
export const fadeOut = keyframes`
from { opacity: 1; }
to { opacity: 0; }
`;
export const fadeOutCursor = keyframes`
0% { opacity: 1; }
90% { opacity: 1; }
@@ -47,6 +52,30 @@ export const fadeAndSlideUp = keyframes`
}
`;
export const fadeInAndSlideLeft = keyframes`
from {
opacity: 0;
transform: translateX(10px);
}
to {
opacity: 1;
transform: translateX(0px);
}
`;
export const fadeOutAndSlideRight = keyframes`
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(10px);
}
`;
export const mobileContextMenu = keyframes`
from {
opacity: 0;