feat: Optional full-width toggle for document display (#2869)

* Migration, model, presenter

* Working implementation

* fix: Account for table of contents

* Checkbox -> Toggle

* Checkbox -> Toggle
This commit is contained in:
Tom Moor
2021-12-19 13:58:16 -08:00
committed by GitHub
parent 73bc7d9f2a
commit 66d5a567c2
18 changed files with 239 additions and 146 deletions

View File

@@ -1,62 +0,0 @@
import * as React from "react";
import { VisuallyHidden } from "reakit/VisuallyHidden";
import styled from "styled-components";
import HelpText from "~/components/HelpText";
export type Props = {
checked?: boolean;
label?: React.ReactNode;
labelHidden?: boolean;
className?: string;
name?: string;
disabled?: boolean;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => unknown;
note?: React.ReactNode;
small?: boolean;
};
const LabelText = styled.span<{ small?: boolean }>`
font-weight: 500;
margin-left: ${(props) => (props.small ? "6px" : "10px")};
${(props) => (props.small ? `color: ${props.theme.textSecondary}` : "")};
`;
const Wrapper = styled.div<{ small?: boolean }>`
padding-bottom: 8px;
${(props) => (props.small ? "font-size: 14px" : "")};
width: 100%;
`;
const Label = styled.label`
display: flex;
align-items: center;
user-select: none;
`;
export default function Checkbox({
label,
labelHidden,
note,
className,
small,
...rest
}: Props) {
const wrappedLabel = <LabelText small={small}>{label}</LabelText>;
return (
<>
<Wrapper small={small} className={className}>
<Label>
<input type="checkbox" {...rest} />
{label &&
(labelHidden ? (
<VisuallyHidden>{wrappedLabel}</VisuallyHidden>
) : (
wrappedLabel
))}
</Label>
{note && <HelpText small>{note}</HelpText>}
</Wrapper>
</>
);
}

View File

@@ -7,7 +7,7 @@ import Arrow from "~/components/Arrow";
type Props = {
direction: "left" | "right";
style?: React.CSSProperties;
onClick?: () => any;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
};
const Toggle = React.forwardRef<HTMLButtonElement, Props>(

104
app/components/Toggle.tsx Normal file
View File

@@ -0,0 +1,104 @@
import * as React from "react";
import { VisuallyHidden } from "reakit/VisuallyHidden";
import styled from "styled-components";
import HelpText from "~/components/HelpText";
export type Props = {
checked?: boolean;
label?: React.ReactNode;
labelHidden?: boolean;
className?: string;
name?: string;
disabled?: boolean;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => unknown;
note?: React.ReactNode;
};
const LabelText = styled.span`
font-weight: 500;
margin-left: 10px;
`;
const Wrapper = styled.div`
padding-bottom: 8px;
width: 100%;
`;
const Label = styled.label`
display: flex;
align-items: center;
user-select: none;
`;
const SlideToggle = styled.label`
cursor: pointer;
text-indent: -9999px;
width: 26px;
height: 14px;
background: ${(props) => props.theme.slate};
display: block;
border-radius: 10px;
position: relative;
&:after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 10px;
height: 10px;
background: ${(props) => props.theme.white};
border-radius: 5px;
transition: width 100ms ease-in-out;
}
&:active:after {
width: 12px;
}
`;
const HiddenInput = styled.input`
height: 0;
width: 0;
visibility: hidden;
&:checked + ${SlideToggle} {
background: ${(props) => props.theme.primary};
}
&:checked + ${SlideToggle}:after {
left: calc(100% - 2px);
transform: translateX(-100%);
}
`;
let inputId = 0;
export default function Toggle({
label,
labelHidden,
note,
className,
...rest
}: Props) {
const wrappedLabel = <LabelText>{label}</LabelText>;
const [id] = React.useState(`checkbox-input-${inputId++}`);
return (
<>
<Wrapper className={className}>
<Label>
<HiddenInput type="checkbox" id={id} {...rest} />
<SlideToggle htmlFor={id} />
{label &&
(labelHidden ? (
<VisuallyHidden>{wrappedLabel}</VisuallyHidden>
) : (
wrappedLabel
))}
</Label>
{note && <HelpText small>{note}</HelpText>}
</Wrapper>
</>
);
}