fix: Implement custom Select Input (#2571)

This commit is contained in:
Saumya Pandey 2021-10-07 10:18:43 +05:30 committed by GitHub
parent 99381d10ff
commit 40e09dd829
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 636 additions and 264 deletions

View File

@ -2,7 +2,7 @@
import { CheckmarkIcon } from "outline-icons";
import * as React from "react";
import { MenuItem as BaseMenuItem } from "reakit/Menu";
import styled from "styled-components";
import styled, { css } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import MenuIconWrapper from "../MenuIconWrapper";
@ -88,12 +88,12 @@ const Spacer = styled.svg`
flex-shrink: 0;
`;
export const MenuAnchor = styled.a`
export const MenuAnchorCSS = css`
display: flex;
margin: 0;
border: 0;
padding: 12px;
padding-left: ${(props) => 12 + props.level * 10}px;
padding-left: ${(props) => 12 + (props.level || 0) * 10}px;
width: 100%;
min-height: 32px;
background: none;
@ -138,5 +138,8 @@ export const MenuAnchor = styled.a`
font-size: 14px;
`};
`;
export const MenuAnchor = styled.a`
${MenuAnchorCSS}
`;
export default MenuItem;

View File

@ -4,9 +4,8 @@ import { Portal } from "react-portal";
import { Menu } from "reakit/Menu";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import useMobile from "hooks/useMobile";
import useMenuHeight from "hooks/useMenuHeight";
import usePrevious from "hooks/usePrevious";
import useWindowSize from "hooks/useWindowSize";
import {
fadeIn,
fadeAndSlideUp,
@ -35,9 +34,7 @@ export default function ContextMenu({
...rest
}: Props) {
const previousVisible = usePrevious(rest.visible);
const [maxHeight, setMaxHeight] = React.useState(undefined);
const isMobile = useMobile();
const { height: windowHeight } = useWindowSize();
const maxHeight = useMenuHeight(rest.visible, rest.unstable_disclosureRef);
const backgroundRef = React.useRef();
React.useEffect(() => {
@ -55,21 +52,6 @@ export default function ContextMenu({
// sets the menu height based on the available space between the disclosure/
// trigger and the bottom of the window
React.useLayoutEffect(() => {
const padding = 8;
if (rest.visible && !isMobile) {
setMaxHeight(
rest.unstable_disclosureRef?.current
? windowHeight -
rest.unstable_disclosureRef.current.getBoundingClientRect()
.bottom -
padding
: undefined
);
}
}, [rest.visible, rest.unstable_disclosureRef, windowHeight, isMobile]);
return (
<>
<Menu hideOnClickOutside preventBodyScroll {...rest}>
@ -104,7 +86,7 @@ export default function ContextMenu({
);
}
const Backdrop = styled.div`
export const Backdrop = styled.div`
animation: ${fadeIn} 200ms ease-in-out;
position: fixed;
top: 0;
@ -119,7 +101,7 @@ const Backdrop = styled.div`
`};
`;
const Position = styled.div`
export const Position = styled.div`
position: absolute;
z-index: ${(props) => props.theme.depths.menu};
@ -133,7 +115,7 @@ const Position = styled.div`
`};
`;
const Background = styled.div`
export const Background = styled.div`
animation: ${mobileContextMenu} 200ms ease;
transform-origin: 50% 100%;
max-width: 100%;
@ -154,8 +136,7 @@ const Background = styled.div`
${breakpoint("tablet")`
animation: ${(props) =>
props.topAnchor ? fadeAndSlideDown : fadeAndSlideUp} 200ms ease;
transform-origin: ${(props) =>
props.rightAnchor === "bottom-end" ? "75%" : "25%"} 0;
transform-origin: ${(props) => (props.rightAnchor ? "75%" : "25%")} 0;
max-width: 276px;
background: ${(props) => props.theme.menuBackground};
box-shadow: ${(props) => props.theme.menuShadow};

View File

@ -1,80 +1,91 @@
// @flow
import { observable } from "mobx";
import { observer } from "mobx-react";
import {
Select,
SelectOption,
useSelectState,
useSelectPopover,
SelectPopover,
} from "@renderlesskit/react";
import { CheckmarkIcon } from "outline-icons";
import * as React from "react";
import { VisuallyHidden } from "reakit/VisuallyHidden";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { Outline, LabelText } from "./Input";
const Select = styled.select`
border: 0;
flex: 1;
padding: 4px 0;
margin: 0 12px;
outline: none;
background: none;
color: ${(props) => props.theme.text};
height: 30px;
font-size: 14px;
option {
background: ${(props) => props.theme.buttonNeutralBackground};
}
&:disabled,
&::placeholder {
color: ${(props) => props.theme.placeholder};
}
${breakpoint("mobile", "tablet")`
font-size: 16px;
`};
`;
const Wrapper = styled.label`
display: block;
max-width: ${(props) => (props.short ? "350px" : "100%")};
`;
import styled, { css } from "styled-components";
import Button, { Inner } from "components/Button";
import { Position, Background, Backdrop } from "./ContextMenu";
import { MenuAnchorCSS } from "./ContextMenu/MenuItem";
import { LabelText } from "./Input";
import useMenuHeight from "hooks/useMenuHeight";
export type Option = { label: string, value: string };
export type Props = {
value?: string,
label?: string,
nude?: boolean,
ariaLabel: string,
short?: boolean,
className?: string,
labelHidden?: boolean,
options: Option[],
onBlur?: () => void,
onFocus?: () => void,
onChange: (string) => Promise<void> | void,
};
@observer
class InputSelect extends React.Component<Props> {
@observable focused: boolean = false;
const getOptionFromValue = (options: Option[], value) => {
return options.find((option) => option.value === value) || {};
};
handleBlur = () => {
this.focused = false;
};
const InputSelect = (props: Props) => {
const {
value,
label,
className,
labelHidden,
options,
short,
ariaLabel,
onChange,
nude,
} = props;
handleFocus = () => {
this.focused = true;
};
const select = useSelectState({
gutter: 0,
modal: true,
selectedValue: value,
});
render() {
const {
label,
className,
labelHidden,
options,
short,
...rest
} = this.props;
const popOver = useSelectPopover({
...select,
hideOnClickOutside: true,
preventBodyScroll: true,
});
const wrappedLabel = <LabelText>{label}</LabelText>;
const previousValue = React.useRef(value);
const buttonRef = React.useRef();
const minWidth = buttonRef.current?.offsetWidth || 0;
return (
const maxHeight = useMenuHeight(
select.visible,
select.unstable_disclosureRef
);
React.useEffect(() => {
if (previousValue.current === select.selectedValue) return;
previousValue.current = select.selectedValue;
async function load() {
await onChange(select.selectedValue);
}
load();
}, [onChange, select.selectedValue]);
const wrappedLabel = <LabelText>{label}</LabelText>;
const selectedValueIndex = options.findIndex(
(option) => option.value === select.selectedValue
);
return (
<>
<Wrapper short={short}>
{label &&
(labelHidden ? (
@ -82,18 +93,126 @@ class InputSelect extends React.Component<Props> {
) : (
wrappedLabel
))}
<Outline focused={this.focused} className={className}>
<Select onBlur={this.handleBlur} onFocus={this.handleFocus} {...rest}>
{options.map((option) => (
<option value={option.value} key={option.value}>
{option.label}
</option>
))}
</Select>
</Outline>
<Select {...select} aria-label={ariaLabel} ref={buttonRef}>
{(props) => (
<StyledButton
neutral
disclosure
className={className}
nude={nude}
{...props}
>
{getOptionFromValue(options, select.selectedValue).label ||
`Select a ${ariaLabel}`}
</StyledButton>
)}
</Select>
<SelectPopover {...select} {...popOver}>
{(props) => {
const topAnchor = props.style.top === "0";
const rightAnchor = props.placement === "bottom-end";
// offset top of select to place selected item under the cursor
if (selectedValueIndex !== -1) {
props.style.top = `-${(selectedValueIndex + 1) * 32}px`;
}
return (
<Positioner {...props}>
<Background
dir="auto"
topAnchor={topAnchor}
rightAnchor={rightAnchor}
style={
maxHeight && topAnchor
? { maxHeight, minWidth }
: { minWidth }
}
>
{select.visible || select.animating
? options.map((option) => (
<StyledSelectOption
{...select}
value={option.value}
key={option.value}
>
{select.selectedValue !== undefined && (
<>
{select.selectedValue === option.value ? (
<CheckmarkIcon color="currentColor" />
) : (
<Spacer />
)}
&nbsp;
</>
)}
{option.label}
</StyledSelectOption>
))
: null}
</Background>
</Positioner>
);
}}
</SelectPopover>
</Wrapper>
);
{(select.visible || select.animating) && <Backdrop />}
</>
);
};
const Spacer = styled.svg`
width: 24px;
height: 24px;
flex-shrink: 0;
`;
const StyledButton = styled(Button)`
font-weight: normal;
text-transform: none;
margin-bottom: 16px;
display: block;
width: 100%;
${(props) =>
props.nude &&
css`
border-color: transparent;
box-shadow: none;
`}
${Inner} {
line-height: 28px;
padding-left: 16px;
padding-right: 8px;
justify-content: space-between;
}
}
`;
export const StyledSelectOption = styled(SelectOption)`
${MenuAnchorCSS}
`;
const Wrapper = styled.label`
display: block;
max-width: ${(props) => (props.short ? "350px" : "100%")};
`;
const Positioner = styled(Position)`
&.focus-visible {
${StyledSelectOption} {
&[aria-selected="true"] {
color: ${(props) => props.theme.white};
background: ${(props) => props.theme.primary};
box-shadow: none;
cursor: pointer;
svg {
fill: ${(props) => props.theme.white};
}
}
}
}
`;
export default InputSelect;

View File

@ -4,19 +4,33 @@ import { useTranslation } from "react-i18next";
import InputSelect, { type Props, type Option } from "./InputSelect";
export default function InputSelectPermission(
props: $Rest<Props, { options: Array<Option> }>
props: $Rest<$Exact<Props>, {| options: Array<Option>, ariaLabel: string |}>
) {
const { value, onChange, ...rest } = props;
const { t } = useTranslation();
const handleChange = React.useCallback(
(value) => {
if (value === "no_access") {
value = "";
}
onChange(value);
},
[onChange]
);
return (
<InputSelect
label={t("Default access")}
options={[
{ label: t("View and edit"), value: "read_write" },
{ label: t("View only"), value: "read" },
{ label: t("No access"), value: "" },
{ label: t("No access"), value: "no_access" },
]}
{...props}
ariaLabel={t("Default access")}
value={value || "no_access"}
onChange={handleChange}
{...rest}
/>
);
}

View File

@ -3,7 +3,9 @@ import * as React from "react";
import { useTranslation } from "react-i18next";
import InputSelect, { type Props, type Option } from "components/InputSelect";
const InputSelectRole = (props: $Rest<Props, { options: Array<Option> }>) => {
const InputSelectRole = (
props: $Rest<$Exact<Props>, {| options: Array<Option>, ariaLabel: string |}>
) => {
const { t } = useTranslation();
return (
@ -14,6 +16,7 @@ const InputSelectRole = (props: $Rest<Props, { options: Array<Option> }>) => {
{ label: t("Viewer"), value: "viewer" },
{ label: t("Admin"), value: "admin" },
]}
ariaLabel={t("Role")}
{...props}
/>
);

View File

@ -36,7 +36,11 @@ const ListItem = (
</Subtitle>
)}
</Content>
{actions && <Actions $selected={selected}>{actions}</Actions>}
{actions && (
<Actions $selected={selected} gap={4}>
{actions}
</Actions>
)}
</>
);
@ -104,7 +108,6 @@ const Subtitle = styled.p`
export const Actions = styled(Flex)`
align-self: center;
justify-content: center;
margin-right: 4px;
color: ${(props) =>
props.$selected ? props.theme.white : props.theme.textSecondary};
`;

View File

@ -0,0 +1,32 @@
// @flow
import * as React from "react";
import { type ElementRef } from "reakit";
import useMobile from "hooks/useMobile";
import useWindowSize from "hooks/useWindowSize";
const useMenuHeight = (
visible: void | boolean,
unstable_disclosureRef: void | { current: null | ElementRef<"button"> }
) => {
const [maxHeight, setMaxHeight] = React.useState(undefined);
const isMobile = useMobile();
const { height: windowHeight } = useWindowSize();
React.useLayoutEffect(() => {
const padding = 8;
if (visible && !isMobile) {
setMaxHeight(
unstable_disclosureRef?.current
? windowHeight -
unstable_disclosureRef.current.getBoundingClientRect().bottom -
padding
: undefined
);
}
}, [visible, unstable_disclosureRef, windowHeight, isMobile]);
return maxHeight;
};
export default useMenuHeight;

View File

@ -54,8 +54,8 @@ const CollectionEdit = ({ collection, onSubmit }: Props) => {
[collection, color, icon, name, onSubmit, showToast, sort, t]
);
const handleSortChange = (ev: SyntheticInputEvent<HTMLSelectElement>) => {
const [field, direction] = ev.target.value.split(".");
const handleSortChange = (value: string) => {
const [field, direction] = value.split(".");
if (direction === "asc" || direction === "desc") {
setSort({ field, direction });
@ -101,6 +101,7 @@ const CollectionEdit = ({ collection, onSubmit }: Props) => {
]}
value={`${sort.field}.${sort.direction}`}
onChange={handleSortChange}
ariaLabel={t("Sort")}
/>
<Button type="submit" disabled={isSaving || !collection.name}>
{isSaving ? `${t("Saving")}` : t("Save")}

View File

@ -88,8 +88,8 @@ class CollectionNew extends React.Component<Props> {
this.hasOpenedIconPicker = true;
};
handlePermissionChange = (ev: SyntheticInputEvent<HTMLInputElement>) => {
this.permission = ev.target.value;
handlePermissionChange = (newPermission: string) => {
this.permission = newPermission;
};
handleSharingChange = (ev: SyntheticInputEvent<HTMLInputElement>) => {

View File

@ -5,7 +5,7 @@ import styled from "styled-components";
import CollectionGroupMembership from "models/CollectionGroupMembership";
import Group from "models/Group";
import GroupListItem from "components/GroupListItem";
import InputSelect from "components/InputSelect";
import InputSelect, { type Props as SelectProps } from "components/InputSelect";
import CollectionGroupMemberMenu from "menus/CollectionGroupMemberMenu";
type Props = {|
@ -47,8 +47,10 @@ const CollectionGroupMemberListItem = ({
? collectionGroupMembership.permission
: undefined
}
onChange={(ev) => onUpdate(ev.target.value)}
onChange={onUpdate}
ariaLabel={t("Permissions")}
labelHidden
nude
/>
<Spacer />
<CollectionGroupMemberMenu
@ -65,7 +67,7 @@ const Spacer = styled.div`
width: 8px;
`;
const Select = styled(InputSelect)`
const Select = (styled(InputSelect)`
margin: 0;
font-size: 14px;
border-color: transparent;
@ -73,6 +75,6 @@ const Select = styled(InputSelect)`
select {
margin: 0;
}
`;
`: React.ComponentType<SelectProps>);
export default CollectionGroupMemberListItem;

View File

@ -8,7 +8,7 @@ import Avatar from "components/Avatar";
import Badge from "components/Badge";
import Button from "components/Button";
import Flex from "components/Flex";
import InputSelect from "components/InputSelect";
import InputSelect, { type Props as SelectProps } from "components/InputSelect";
import ListItem from "components/List/Item";
import Time from "components/Time";
import MemberMenu from "menus/MemberMenu";
@ -64,9 +64,11 @@ const MemberListItem = ({
label={t("Permissions")}
options={PERMISSIONS}
value={membership ? membership.permission : undefined}
onChange={(ev) => onUpdate(ev.target.value)}
onChange={onUpdate}
disabled={!canEdit}
ariaLabel={t("Permissions")}
labelHidden
nude
/>
)}
{canEdit && (
@ -90,7 +92,7 @@ const Spacer = styled.div`
width: 8px;
`;
const Select = styled(InputSelect)`
const Select = (styled(InputSelect)`
margin: 0;
font-size: 14px;
border-color: transparent;
@ -98,6 +100,6 @@ const Select = styled(InputSelect)`
select {
margin: 0;
}
`;
`: React.ComponentType<SelectProps>);
export default MemberListItem;

View File

@ -138,9 +138,9 @@ function CollectionPermissions({ collection }: Props) {
);
const handleChangePermission = React.useCallback(
async (ev) => {
async (permission: string) => {
try {
await collection.save({ permission: ev.target.value });
await collection.save({ permission });
showToast(t("Default access permissions were updated"), {
type: "success",
});

View File

@ -112,10 +112,10 @@ function Invite({ onSubmit }: Props) {
});
}, [showToast, t]);
const handleRoleChange = React.useCallback((ev, index) => {
const handleRoleChange = React.useCallback((role: Role, index: number) => {
setInvites((prevInvites) => {
const newInvites = [...prevInvites];
newInvites[index]["role"] = ev.target.value;
newInvites[index]["role"] = role;
return newInvites;
});
}, []);
@ -194,7 +194,7 @@ function Invite({ onSubmit }: Props) {
required={!!invite.email}
/>
<InputSelectRole
onChange={(ev) => handleRoleChange(ev, index)}
onChange={(role: any) => handleRoleChange((role: Role), index)}
value={invite.role}
labelHidden={index !== 0}
short

View File

@ -1,13 +1,10 @@
// @flow
import { observable } from "mobx";
import { observer, inject } from "mobx-react";
import { observer } from "mobx-react";
import { ProfileIcon } from "outline-icons";
import * as React from "react";
import { Trans, withTranslation, type TFunction } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
import styled from "styled-components";
import { languageOptions } from "shared/i18n";
import AuthStore from "stores/AuthStore";
import ToastsStore from "stores/ToastsStore";
import UserDelete from "scenes/UserDelete";
import Button from "components/Button";
import Flex from "components/Flex";
@ -17,162 +14,137 @@ import Input, { LabelText } from "components/Input";
import InputSelect from "components/InputSelect";
import Scene from "components/Scene";
import ImageUpload from "./components/ImageUpload";
import useStores from "hooks/useStores";
import useToasts from "hooks/useToasts";
type Props = {
auth: AuthStore,
toasts: ToastsStore,
t: TFunction,
};
const Profile = () => {
const { auth } = useStores();
const form = React.useRef<?HTMLFormElement>();
const [name, setName] = React.useState<string>(auth.user?.name || "");
const [avatarUrl, setAvatarUrl] = React.useState<?string>();
const [showDeleteModal, setShowDeleteModal] = React.useState(false);
const [language, setLanguage] = React.useState(auth.user?.language);
@observer
class Profile extends React.Component<Props> {
timeout: TimeoutID;
form: ?HTMLFormElement;
const { showToast } = useToasts();
const { t } = useTranslation();
@observable name: string;
@observable avatarUrl: ?string;
@observable showDeleteModal: boolean = false;
@observable language: string;
componentDidMount() {
if (this.props.auth.user) {
this.name = this.props.auth.user.name;
this.language = this.props.auth.user.language;
}
}
componentWillUnmount() {
clearTimeout(this.timeout);
}
handleSubmit = async (ev: SyntheticEvent<>) => {
const { t } = this.props;
const handleSubmit = async (ev: SyntheticEvent<>) => {
ev.preventDefault();
await this.props.auth.updateUser({
name: this.name,
avatarUrl: this.avatarUrl,
language: this.language,
await auth.updateUser({
name,
avatarUrl,
language,
});
this.props.toasts.showToast(t("Profile saved"), { type: "success" });
showToast(t("Profile saved"), { type: "success" });
};
handleNameChange = (ev: SyntheticInputEvent<*>) => {
this.name = ev.target.value;
const handleNameChange = (ev: SyntheticInputEvent<*>) => {
setName(ev.target.value);
};
handleAvatarUpload = async (avatarUrl: string) => {
const { t } = this.props;
this.avatarUrl = avatarUrl;
const handleAvatarUpload = async (avatarUrl: string) => {
setAvatarUrl(avatarUrl);
await this.props.auth.updateUser({
avatarUrl: this.avatarUrl,
await auth.updateUser({
avatarUrl,
});
this.props.toasts.showToast(t("Profile picture updated"), {
showToast(t("Profile picture updated"), {
type: "success",
});
};
handleAvatarError = (error: ?string) => {
const { t } = this.props;
this.props.toasts.showToast(
error || t("Unable to upload new profile picture"),
{ type: "error" }
);
const handleAvatarError = (error: ?string) => {
showToast(error || t("Unable to upload new profile picture"), {
type: "error",
});
};
handleLanguageChange = (ev: SyntheticInputEvent<*>) => {
this.language = ev.target.value;
const handleLanguageChange = (value: string) => {
setLanguage(value);
};
toggleDeleteAccount = () => {
this.showDeleteModal = !this.showDeleteModal;
const toggleDeleteAccount = () => {
setShowDeleteModal((prev) => !prev);
};
get isValid() {
return this.form && this.form.checkValidity();
}
const isValid = form.current && form.current.checkValidity();
render() {
const { t } = this.props;
const { user, isSaving } = this.props.auth;
if (!user) return null;
const avatarUrl = this.avatarUrl || user.avatarUrl;
const { user, isSaving } = auth;
if (!user) return null;
return (
<Scene title={t("Profile")} icon={<ProfileIcon color="currentColor" />}>
<Heading>{t("Profile")}</Heading>
<ProfilePicture column>
<LabelText>{t("Photo")}</LabelText>
<AvatarContainer>
<ImageUpload
onSuccess={this.handleAvatarUpload}
onError={this.handleAvatarError}
return (
<Scene title={t("Profile")} icon={<ProfileIcon color="currentColor" />}>
<Heading>{t("Profile")}</Heading>
<ProfilePicture column>
<LabelText>{t("Photo")}</LabelText>
<AvatarContainer>
<ImageUpload
onSuccess={handleAvatarUpload}
onError={handleAvatarError}
>
<Avatar src={avatarUrl || user?.avatarUrl} />
<Flex auto align="center" justify="center">
{t("Upload")}
</Flex>
</ImageUpload>
</AvatarContainer>
</ProfilePicture>
<form onSubmit={handleSubmit} ref={form}>
<Input
label={t("Full name")}
autoComplete="name"
value={name}
onChange={handleNameChange}
required
short
/>
<br />
<InputSelect
label={t("Language")}
options={languageOptions}
value={language}
onChange={handleLanguageChange}
ariaLabel={t("Language")}
short
/>
<HelpText small>
<Trans>
Please note that translations are currently in early access.
<br />
Community contributions are accepted though our{" "}
<a
href="https://translate.getoutline.com"
target="_blank"
rel="noreferrer"
>
<Avatar src={avatarUrl} />
<Flex auto align="center" justify="center">
{t("Upload")}
</Flex>
</ImageUpload>
</AvatarContainer>
</ProfilePicture>
<form onSubmit={this.handleSubmit} ref={(ref) => (this.form = ref)}>
<Input
label={t("Full name")}
autoComplete="name"
value={this.name}
onChange={this.handleNameChange}
required
short
/>
<br />
<InputSelect
label={t("Language")}
options={languageOptions}
value={this.language}
onChange={this.handleLanguageChange}
short
/>
<HelpText small>
<Trans>
Please note that translations are currently in early access.
<br />
Community contributions are accepted though our{" "}
<a
href="https://translate.getoutline.com"
target="_blank"
rel="noreferrer"
>
translation portal
</a>
</Trans>
.
</HelpText>
<Button type="submit" disabled={isSaving || !this.isValid}>
{isSaving ? `${t("Saving")}` : t("Save")}
</Button>
</form>
translation portal
</a>
</Trans>
.
</HelpText>
<Button type="submit" disabled={isSaving || !isValid}>
{isSaving ? `${t("Saving")}` : t("Save")}
</Button>
</form>
<DangerZone>
<h2>{t("Delete Account")}</h2>
<HelpText small>
<Trans>
You may delete your account at any time, note that this is
unrecoverable
</Trans>
</HelpText>
<Button onClick={this.toggleDeleteAccount} neutral>
{t("Delete account")}
</Button>
</DangerZone>
{this.showDeleteModal && (
<UserDelete onRequestClose={this.toggleDeleteAccount} />
)}
</Scene>
);
}
}
<DangerZone>
<h2>{t("Delete Account")}</h2>
<HelpText small>
<Trans>
You may delete your account at any time, note that this is
unrecoverable
</Trans>
</HelpText>
<Button onClick={toggleDeleteAccount} neutral>
{t("Delete account")}
</Button>
</DangerZone>
{showDeleteModal && <UserDelete onRequestClose={toggleDeleteAccount} />}
</Scene>
);
};
const DangerZone = styled.div`
margin-top: 60px;
@ -215,4 +187,4 @@ const Avatar = styled.img`
${avatarStyles};
`;
export default withTranslation()<Profile>(inject("auth", "toasts")(Profile));
export default observer(Profile);

View File

@ -52,6 +52,7 @@
"@hocuspocus/server": "^1.0.0-alpha.73",
"@outlinewiki/koa-passport": "^4.1.4",
"@outlinewiki/passport-azure-ad-oauth2": "^0.1.0",
"@renderlesskit/react": "^0.6.0",
"@sentry/node": "^6.3.1",
"@sentry/react": "^6.3.1",
"@sentry/tracing": "^6.3.1",
@ -224,4 +225,4 @@
"js-yaml": "^3.13.1"
},
"version": "0.59.0"
}
}

257
yarn.lock
View File

@ -978,10 +978,10 @@
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.3.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.15.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.3.1", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.15.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a"
integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
dependencies:
regenerator-runtime "^0.13.4"
@ -1062,6 +1062,41 @@
serialize-query-params "^1.3.3"
superstruct "^0.8.3"
"@chakra-ui/counter@^1.1.9":
version "1.1.9"
resolved "https://registry.yarnpkg.com/@chakra-ui/counter/-/counter-1.1.9.tgz#954794624806ea6a00f0ebdd3d50c6838d0b41fc"
integrity sha512-WHkYSHJynkFwVFD6wg6afDteBeAmDHV35/tPMwpyTcgagpF99xY/8mULnBoLkkCc/PMe+meHuZJEXuCaxy4ecg==
dependencies:
"@chakra-ui/hooks" "1.6.0"
"@chakra-ui/utils" "1.8.2"
"@chakra-ui/hooks@1.6.0", "@chakra-ui/hooks@^1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-1.6.0.tgz#94f54540298b6a5a7ef68b15e451e76b0ee1fed4"
integrity sha512-5QFICaE1omNCJyVQQX62sZvRvIpI4VansN2AvZpSdrMjRiWvmBNLZN2Khr7+8j6F7uDh5LSgTxiP02vWLp12hA==
dependencies:
"@chakra-ui/react-utils" "1.1.2"
"@chakra-ui/utils" "1.8.2"
compute-scroll-into-view "1.0.14"
copy-to-clipboard "3.3.1"
"@chakra-ui/react-utils@1.1.2", "@chakra-ui/react-utils@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@chakra-ui/react-utils/-/react-utils-1.1.2.tgz#7ea80b6ae25bd7b182095cc9ffaad23c464408b5"
integrity sha512-S8jPVKGZH2qF7ZGxl/0DF/dXXI2AxDNGf4Ahi2LGHqajMvqBB7vtYIRRmIA7+jAnErhzO8WUi3i4Z7oScp6xSA==
dependencies:
"@chakra-ui/utils" "^1.7.0"
"@chakra-ui/utils@1.8.2", "@chakra-ui/utils@^1.7.0", "@chakra-ui/utils@^1.8.2":
version "1.8.2"
resolved "https://registry.yarnpkg.com/@chakra-ui/utils/-/utils-1.8.2.tgz#5a9f1f67c5f2232769fe7d009fcf96eebf3c2b4e"
integrity sha512-MnE4czCQCE87Ch1DfAdmZvObgRviw9wQ9Zti372P8VD1ILEdff/C5WBWHW6mgG3YcorPAxgnrNF3MmNE95jRkA==
dependencies:
"@types/lodash.mergewith" "4.6.6"
css-box-model "1.2.1"
framesync "5.3.0"
lodash.mergewith "4.6.2"
"@cnakazawa/watch@^1.0.3":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
@ -1117,6 +1152,45 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
"@formatjs/ecma402-abstract@1.9.8":
version "1.9.8"
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.9.8.tgz#f3dad447fbc7f063f88e2a148b7a353161740e74"
integrity sha512-2U4n11bLmTij/k4ePCEFKJILPYwdMcJTdnKVBi+JMWBgu5O1N+XhCazlE6QXqVO1Agh2Doh0b/9Jf1mSmSVfhA==
dependencies:
"@formatjs/intl-localematcher" "0.2.20"
tslib "^2.1.0"
"@formatjs/fast-memoize@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.0.tgz#1123bfcc5d21d761f15d8b1c32d10e1b6530355d"
integrity sha512-fObitP9Tlc31SKrPHgkPgQpGo4+4yXfQQITTCNH8AZdEqB7Mq4nPrjpUL/tNGN3lEeJcFxDbi0haX8HM7QvQ8w==
dependencies:
tslib "^2.1.0"
"@formatjs/icu-messageformat-parser@2.0.11":
version "2.0.11"
resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.11.tgz#e4ba40b9a8aefc8bccfc96be5906d3bca305b4b3"
integrity sha512-5mWb8U8aulYGwnDZWrr+vdgn5PilvtrqQYQ1pvpgzQes/osi85TwmL2GqTGLlKIvBKD2XNA61kAqXYY95w4LWg==
dependencies:
"@formatjs/ecma402-abstract" "1.9.8"
"@formatjs/icu-skeleton-parser" "1.2.12"
tslib "^2.1.0"
"@formatjs/icu-skeleton-parser@1.2.12":
version "1.2.12"
resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.2.12.tgz#45426eb1448c0c08c931eb9f0672283c0e4d0062"
integrity sha512-DTFxWmEA02ZNW6fsYjGYSADvtrqqjCYF7DSgCmMfaaE0gLP4pCdAgOPE+lkXXU+jP8iCw/YhMT2Seyk/C5lBWg==
dependencies:
"@formatjs/ecma402-abstract" "1.9.8"
tslib "^2.1.0"
"@formatjs/intl-localematcher@0.2.20":
version "0.2.20"
resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.20.tgz#782aef53d1c1b6112ee67468dc59f9b8d1ba7b17"
integrity sha512-/Ro85goRZnCojzxOegANFYL0LaDIpdPjAukR7xMTjOtRx+3yyjR0ifGTOW3/Kjhmab3t6GnyHBYWZSudxEOxPA==
dependencies:
tslib "^2.1.0"
"@hapi/address@^2.1.2":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
@ -1184,6 +1258,21 @@
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
"@internationalized/message@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.0.2.tgz#c3db2b6b7f75af815819f77da11f8424381416e3"
integrity sha512-ZZ8FQDCsri3vUB2mfDD76Vbf97DH361AiZUXKHV4BqwCtYyaNYiZqIr8KXrcMCxJvrIYVQLSn8+jeIQRO3bvtw==
dependencies:
"@babel/runtime" "^7.6.2"
intl-messageformat "^9.6.12"
"@internationalized/number@^3.0.2":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.0.3.tgz#d29003dffdff54ca6f2287ec0cb77ff3d045478f"
integrity sha512-ewFoVvsxSyd9QZnknvOWPjirYqdMQhXTeDhJg3hM6C/FeZt0banpGH1nZ0SGMZXHz8NK9uAa2KVIq+jqAIOg4w==
dependencies:
"@babel/runtime" "^7.6.2"
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@ -2168,6 +2257,76 @@
dependencies:
"@babel/runtime" "^7.13.10"
"@react-aria/i18n@^3.3.2":
version "3.3.2"
resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.3.2.tgz#891902938333c6ab5491b7acb7581f8567045dbc"
integrity sha512-a4AptbWLPVMJfjPdyW60TFtT4gvKAputx9YaUrIywoV/5p900AcOOc3uuL43+vuCKBzMkGUeTa1a4eL1HstDUA==
dependencies:
"@babel/runtime" "^7.6.2"
"@internationalized/message" "^3.0.2"
"@internationalized/number" "^3.0.2"
"@react-aria/ssr" "^3.0.3"
"@react-aria/utils" "^3.8.2"
"@react-types/shared" "^3.8.0"
"@react-aria/interactions@^3.5.1", "@react-aria/interactions@^3.6.0":
version "3.6.0"
resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.6.0.tgz#63c16e6179e8ae38221e26256d9a7639d7f9b24e"
integrity sha512-dMEGYIIhJ3uxDd19Z/rxuqQp9Rx9c46AInrfzAiOijQj/fTmb4ubCsuFOAQrc0sy1HCY1/ntnRZQuRgT/iS74w==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/utils" "^3.9.0"
"@react-types/shared" "^3.9.0"
"@react-aria/live-announcer@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.0.1.tgz#772888326808d180adc5bc9fa0b4b1416ec08811"
integrity sha512-c63UZ4JhXxy29F6FO1LUkQLDRzv17W4g3QQ+sy6tmFw7R5I5r8uh8jR7RCbBX7bdGCLnQDwOQ055KsM/a9MT3A==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/utils" "^3.8.2"
"@react-aria/visually-hidden" "^3.2.3"
"@react-aria/spinbutton@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.0.1.tgz#e0d5595e1c74518ca46acdeebf7bd19022ee5d50"
integrity sha512-V2wUhSgJDxSqzo5HPbx7OgGpFeuvxq8/7nNO8mT3cEZfZASUGvjIdCRmAf243qyfo9Yby4zdx9E/BxNOGCZ9cQ==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/i18n" "^3.3.2"
"@react-aria/live-announcer" "^3.0.1"
"@react-aria/utils" "^3.8.2"
"@react-types/button" "^3.4.1"
"@react-types/shared" "^3.8.0"
"@react-aria/ssr@^3.0.3", "@react-aria/ssr@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.1.0.tgz#b7163e6224725c30121932a8d1422ef91d1fab22"
integrity sha512-RxqQKmE8sO7TGdrcSlHTcVzMP450hqowtBSd2bBS9oPlcokVkaGq28c3Rwa8ty5ctw4EBCjXqjP7xdcKMGDzug==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/utils@^3.8.2", "@react-aria/utils@^3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.9.0.tgz#c5446f807091a744311d4d559fa8a42e7448824d"
integrity sha512-P0dEOMHGHHJ5KC8iCpaMxAtgdUdeISAm4FZnmoD5fK3JxlKEC046hUxlad83RkNOBZkT2dDvF4HeDCUqdMWHKQ==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/ssr" "^3.1.0"
"@react-stately/utils" "^3.2.2"
"@react-types/shared" "^3.9.0"
clsx "^1.1.1"
"@react-aria/visually-hidden@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.2.3.tgz#4779df0a468873550afb42a7f5fcb2411d82db8d"
integrity sha512-iAe5EFI7obEOwTnIdAwWrKq+CrIJFGTw85v8fXnQ7CIVGRDblX85GOUww9bzQNPDLLRYWS4VF702ii8kV4+JCw==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/interactions" "^3.5.1"
"@react-aria/utils" "^3.8.2"
clsx "^1.1.1"
"@react-dnd/asap@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.0.tgz#b300eeed83e9801f51bd66b0337c9a6f04548651"
@ -2183,6 +2342,25 @@
resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a"
integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==
"@react-stately/utils@^3.2.2":
version "3.2.2"
resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.2.2.tgz#468eafa60740c6b0b847a368215dfaa55e87f505"
integrity sha512-7NCpRMAexDdgVqbrB9uDrkDpM4Tdw5BU6Gu6IKUXmKsoDYziE6mAjaGkCZBitsrln1Cezc6euI5YPa1JqxgpJg==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-types/button@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.4.1.tgz#715ac9d4997c79233be4d9020b58f85936b8252b"
integrity sha512-B54M84LxdEppwjXNlkBEJyMfe9fd+bvFV7R6+NJvupGrZm/LuFNYjFcHk7yjMKWTdWm6DbpIuQz54n5qTW7Vlg==
dependencies:
"@react-types/shared" "^3.8.0"
"@react-types/shared@^3.8.0", "@react-types/shared@^3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.9.0.tgz#d834f3e6e2c992089192f3c83fb7963e3a6f5207"
integrity sha512-YYksINfR6q92P10AhPEGo47Hd7oz1hrnZ6Vx8Gsrq62IbqDdv1XOTzPBaj17Z1ymNY2pitLUSEXsLmozt4wxxQ==
"@relative-ci/agent@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@relative-ci/agent/-/agent-2.0.0.tgz#21f73fec146a0f7c94684ead0f6ecbf05ea5c4ee"
@ -2206,6 +2384,24 @@
execa "^4.0.0"
java-properties "^1.0.0"
"@renderlesskit/react@^0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@renderlesskit/react/-/react-0.6.0.tgz#93ced709412f6e50538c132812e40ae6fe1f96ef"
integrity sha512-v1FChZQj8te+XK9MhGT5XVxgynAMriY6CKcY4pCa7+YljM2vLuRgo7yaOhh5saHrd/t5dbtcdS4s/xo9lZFYEQ==
dependencies:
"@chakra-ui/counter" "^1.1.9"
"@chakra-ui/hooks" "^1.6.0"
"@chakra-ui/react-utils" "^1.1.2"
"@chakra-ui/utils" "^1.8.2"
"@react-aria/i18n" "^3.3.2"
"@react-aria/interactions" "^3.6.0"
"@react-aria/spinbutton" "^3.0.1"
"@react-aria/utils" "^3.9.0"
date-fns "^2.23.0"
reakit-system "^0.15.2"
reakit-utils "^0.15.2"
reakit-warning "^0.6.2"
"@rollup/plugin-babel@^5.2.0":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.2.3.tgz#ee8fffbaa62a6c9ccd41b1bfca32e81f847700ee"
@ -2593,6 +2789,18 @@
"@types/koa-compose" "*"
"@types/node" "*"
"@types/lodash.mergewith@4.6.6":
version "4.6.6"
resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz#c4698f5b214a433ff35cb2c75ee6ec7f99d79f10"
integrity sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg==
dependencies:
"@types/lodash" "*"
"@types/lodash@*":
version "4.14.172"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.172.tgz#aad774c28e7bfd7a67de25408e03ee5a8c3d028a"
integrity sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==
"@types/long@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
@ -4475,6 +4683,11 @@ cloneable-readable@^1.0.0:
process-nextick-args "^2.0.0"
readable-stream "^2.3.5"
clsx@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
cluster-key-slot@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
@ -4653,6 +4866,11 @@ compressorjs@^1.0.7:
blueimp-canvas-to-blob "^3.28.0"
is-blob "^2.1.0"
compute-scroll-into-view@1.0.14:
version "1.0.14"
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz#80e3ebb25d6aa89f42e533956cb4b16a04cfe759"
integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==
compute-scroll-into-view@^1.0.16:
version "1.0.16"
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088"
@ -4826,7 +5044,7 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
copy-to-clipboard@^3.0.8, copy-to-clipboard@^3.3.1:
copy-to-clipboard@3.3.1, copy-to-clipboard@^3.0.8, copy-to-clipboard@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae"
integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==
@ -4986,6 +5204,13 @@ crypto-random-string@^2.0.0:
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
css-box-model@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1"
integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==
dependencies:
tiny-invariant "^1.0.6"
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
@ -5110,7 +5335,7 @@ date-fns@2.22.1:
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.22.1.tgz#1e5af959831ebb1d82992bf67b765052d8f0efc4"
integrity sha512-yUFPQjrxEmIsMqlHhAhmxkuH769baF21Kk+nZwZGyrMoyLA+LugaQtC0+Tqf9CBUUULWwUJt6Q5ySI3LJDDCGg==
date-fns@^2.16.1:
date-fns@^2.16.1, date-fns@^2.23.0:
version "2.23.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.23.0.tgz#4e886c941659af0cf7b30fafdd1eaa37e88788a9"
integrity sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==
@ -7758,6 +7983,15 @@ interpret@^1.0.0, interpret@^1.4.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
intl-messageformat@^9.6.12:
version "9.9.1"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.9.1.tgz#255d453b0656b4f7e741f31d2b4a95bf2adfe064"
integrity sha512-cuzS/XKHn//hvKka77JKU2dseiVY2dofQjIOZv6ZFxFt4Z9sPXnZ7KQ9Ak2r+4XBCjI04MqJ1PhKs/3X22AkfA==
dependencies:
"@formatjs/fast-memoize" "1.2.0"
"@formatjs/icu-messageformat-parser" "2.0.11"
tslib "^2.1.0"
invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@ -9617,6 +9851,11 @@ lodash.keys@2.3.x, lodash.keys@~2.3.0:
lodash._shimkeys "~2.3.0"
lodash.isobject "~2.3.0"
lodash.mergewith@4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
lodash.noop@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c"
@ -12092,19 +12331,19 @@ readdirp@~3.5.0:
dependencies:
picomatch "^2.2.1"
reakit-system@^0.15.2:
reakit-system@^0.15.1, reakit-system@^0.15.2:
version "0.15.2"
resolved "https://registry.yarnpkg.com/reakit-system/-/reakit-system-0.15.2.tgz#a485fab84b3942acbed6212c3b56a6ef8611c457"
integrity sha512-TvRthEz0DmD0rcJkGamMYx+bATwnGNWJpe/lc8UV2Js8nnPvkaxrHk5fX9cVASFrWbaIyegZHCWUBfxr30bmmA==
dependencies:
reakit-utils "^0.15.2"
reakit-utils@^0.15.2:
reakit-utils@^0.15.1, reakit-utils@^0.15.2:
version "0.15.2"
resolved "https://registry.yarnpkg.com/reakit-utils/-/reakit-utils-0.15.2.tgz#b4d5836e534576bfd175171541d43182ad97f2d2"
integrity sha512-i/RYkq+W6hvfFmXw5QW7zvfJJT/K8a4qZ0hjA79T61JAFPGt23DsfxwyBbyK91GZrJ9HMrXFVXWMovsKBc1qEQ==
reakit-warning@^0.6.2:
reakit-warning@^0.6.1, reakit-warning@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/reakit-warning/-/reakit-warning-0.6.2.tgz#9c346ae483eb1f284f2088653f90cabd26dbee56"
integrity sha512-z/3fvuc46DJyD3nJAUOto6inz2EbSQTjvI/KBQDqxwB0y02HDyeP8IWOJxvkuAUGkWpeSx+H3QWQFSNiPcHtmw==