This repository has been archived on 2022-08-14. You can view files and clone it, but cannot push or open issues or pull requests.
outline/app/components/Guide.js

114 lines
2.4 KiB
JavaScript

// @flow
import { observer } from "mobx-react";
import * as React from "react";
import { Dialog, DialogBackdrop, useDialogState } from "reakit/Dialog";
import styled from "styled-components";
import Scrollable from "components/Scrollable";
import usePrevious from "hooks/usePrevious";
type Props = {|
children?: React.Node,
isOpen: boolean,
title?: string,
onRequestClose: () => void,
|};
const Guide = ({
children,
isOpen,
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}>
{(props) => (
<Backdrop {...props}>
<Dialog
{...dialog}
aria-label={title}
preventBodyScroll
hideOnEsc
hide={onRequestClose}
>
{(props) => (
<Scene {...props} {...rest}>
<Content>
{title && <Header>{title}</Header>}
{children}
</Content>
</Scene>
)}
</Dialog>
</Backdrop>
)}
</DialogBackdrop>
);
};
const Header = styled.h1`
font-size: 18px;
margin-top: 0;
margin-bottom: 1em;
`;
const Backdrop = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: ${(props) => props.theme.backdrop} !important;
z-index: ${(props) => props.theme.depths.modalOverlay};
transition: opacity 200ms ease-in-out;
opacity: 0;
&[data-enter] {
opacity: 1;
}
`;
const Scene = styled.div`
position: absolute;
top: 0;
right: 0;
bottom: 0;
margin: 12px;
z-index: ${(props) => props.theme.depths.modal};
display: flex;
justify-content: center;
align-items: flex-start;
width: 350px;
background: ${(props) => props.theme.background};
transition: ${(props) => props.theme.backgroundTransition};
border-radius: 8px;
outline: none;
opacity: 0;
transform: translateX(16px);
transition: transform 250ms ease, opacity 250ms ease;
&[data-enter] {
opacity: 1;
transform: translateX(0px);
}
`;
const Content = styled(Scrollable)`
width: 100%;
padding: 16px;
`;
export default observer(Guide);