Files
outline/app/components/Toggle.tsx
Tom Moor 66d5a567c2 feat: Optional full-width toggle for document display (#2869)
* Migration, model, presenter

* Working implementation

* fix: Account for table of contents

* Checkbox -> Toggle

* Checkbox -> Toggle
2021-12-19 13:58:16 -08:00

105 lines
2.1 KiB
TypeScript

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>
</>
);
}