feat: Seamless Edit (#2701)

* feat: Remove explicit edit

* Restore revision remains disabled for now

* Bump RME, better differentiation of focused state

* fix: Star not visible in edit mode

* remove stray log

* fix: Occassional user context not available in collaborative persistence
This commit is contained in:
Tom Moor 2021-11-08 20:52:17 -08:00 committed by GitHub
parent 37be7f99c4
commit c597f2d9a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 302 additions and 207 deletions

View File

@ -0,0 +1,105 @@
// @flow
import isPrintableKeyEvent from "is-printable-key-event";
import * as React from "react";
import styled from "styled-components";
type Props = {|
disabled?: boolean,
onChange?: (text: string) => void,
onBlur?: (event: SyntheticInputEvent<>) => void,
onInput?: (event: SyntheticInputEvent<>) => void,
onKeyDown?: (event: SyntheticInputEvent<>) => void,
placeholder?: string,
maxLength?: number,
autoFocus?: boolean,
className?: string,
children?: React.Node,
value: string,
|};
/**
* Defines a content editable component with the same interface as a native
* HTMLInputElement (or, as close as we can get).
*/
function ContentEditable({
disabled,
onChange,
onInput,
onBlur,
onKeyDown,
value,
children,
className,
maxLength,
autoFocus,
placeholder,
...rest
}: Props) {
const ref = React.useRef<?HTMLSpanElement>();
const [innerHTML, setInnerHTML] = React.useState<string>(value);
const lastValue = React.useRef("");
const wrappedEvent = (callback) => (
event: SyntheticInputEvent<HTMLInputElement>
) => {
const text = ref.current?.innerText || "";
if (maxLength && isPrintableKeyEvent(event) && text.length >= maxLength) {
event.preventDefault();
return false;
}
if (text !== lastValue.current) {
lastValue.current = text;
onChange && onChange(text);
}
callback && callback(event);
};
React.useLayoutEffect(() => {
if (autoFocus) {
ref.current?.focus();
}
});
React.useEffect(() => {
if (value !== ref.current?.innerText) {
setInnerHTML(value);
}
}, [value]);
return (
<div className={className}>
<Content
contentEditable={!disabled}
onInput={wrappedEvent(onInput)}
onBlur={wrappedEvent(onBlur)}
onKeyDown={wrappedEvent(onKeyDown)}
ref={ref}
data-placeholder={placeholder}
role="textbox"
dangerouslySetInnerHTML={{ __html: innerHTML }}
{...rest}
/>
{children}
</div>
);
}
const Content = styled.span`
&:empty {
display: inline-block;
}
&:empty::before {
display: inline-block;
color: ${(props) => props.theme.placeholder};
-webkit-text-fill-color: ${(props) => props.theme.placeholder};
content: attr(data-placeholder);
pointer-events: none;
height: 0;
}
`;
export default React.memo<Props>(ContentEditable);

View File

@ -325,7 +325,7 @@ function DocumentMenu({
{ {
title: t("Edit"), title: t("Edit"),
to: editDocumentUrl(document), to: editDocumentUrl(document),
visible: !!can.update, visible: !!can.update && !team.collaborativeEditing,
icon: <EditIcon />, icon: <EditIcon />,
}, },
{ {

View File

@ -88,7 +88,10 @@ class DataLoader extends React.Component<Props> {
} }
get isEditing() { get isEditing() {
return this.props.match.path === matchDocumentEdit; return (
this.props.match.path === matchDocumentEdit ||
this.props.auth?.team?.collaborativeEditing
);
} }
onSearchLink = async (term: string) => { onSearchLink = async (term: string) => {
@ -244,7 +247,9 @@ class DataLoader extends React.Component<Props> {
return ( return (
<> <>
<Loading location={location} /> <Loading location={location} />
{this.isEditing && <HideSidebar ui={ui} />} {this.isEditing && !team?.collaborativeEditing && (
<HideSidebar ui={ui} />
)}
</> </>
); );
} }
@ -261,7 +266,9 @@ class DataLoader extends React.Component<Props> {
return ( return (
<React.Fragment key={key}> <React.Fragment key={key}>
{this.isEditing && <HideSidebar ui={ui} />} {this.isEditing && !team.collaborativeEditing && (
<HideSidebar ui={ui} />
)}
{this.props.children({ {this.props.children({
document, document,
revision, revision,

View File

@ -357,8 +357,8 @@ class DocumentScene extends React.Component<Props> {
} }
}; };
onChangeTitle = (event) => { onChangeTitle = (value) => {
this.title = event.target.value; this.title = value;
this.updateIsDirtyDebounced(); this.updateIsDirtyDebounced();
this.autosave(); this.autosave();
}; };
@ -389,7 +389,8 @@ class DocumentScene extends React.Component<Props> {
const headings = this.editor.current const headings = this.editor.current
? this.editor.current.getHeadings() ? this.editor.current.getHeadings()
: []; : [];
const showContents = ui.tocVisible && readOnly; const showContents =
ui.tocVisible && (readOnly || team?.collaborativeEditing);
const collaborativeEditing = const collaborativeEditing =
team?.collaborativeEditing && team?.collaborativeEditing &&
@ -473,7 +474,7 @@ class DocumentScene extends React.Component<Props> {
shareId={shareId} shareId={shareId}
isRevision={!!revision} isRevision={!!revision}
isDraft={document.isDraft} isDraft={document.isDraft}
isEditing={!readOnly} isEditing={!readOnly && !team?.collaborativeEditing}
isSaving={this.isSaving} isSaving={this.isSaving}
isPublishing={this.isPublishing} isPublishing={this.isPublishing}
publishingIsDisabled={ publishingIsDisabled={

View File

@ -0,0 +1,151 @@
// @flow
import { observer } from "mobx-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { MAX_TITLE_LENGTH } from "shared/constants";
import { light } from "shared/theme";
import parseTitle from "shared/utils/parseTitle";
import Document from "models/Document";
import ContentEditable from "components/ContentEditable";
import Star, { AnimatedStar } from "components/Star";
import useStores from "hooks/useStores";
import { isModKey } from "utils/keyboard";
type Props = {
value: string,
document: Document,
readOnly: boolean,
onChange: (text: string) => void,
onGoToNextInput: (insertParagraph?: boolean) => void,
onSave: (options: { publish?: boolean, done?: boolean }) => void,
};
function EditableTitle({
value,
document,
readOnly,
onChange,
onSave,
onGoToNextInput,
}: Props) {
const ref = React.useRef();
const { policies } = useStores();
const { t } = useTranslation();
const can = policies.abilities(document.id);
const { emoji } = parseTitle(value);
const startsWithEmojiAndSpace = !!(emoji && value.startsWith(`${emoji} `));
const normalizedTitle =
!value && readOnly ? document.titleWithDefault : value;
const handleKeyDown = React.useCallback(
(event: SyntheticKeyboardEvent<>) => {
if (event.key === "Enter") {
event.preventDefault();
if (isModKey(event)) {
onSave({ done: true });
return;
}
onGoToNextInput(true);
return;
}
if (event.key === "Tab" || event.key === "ArrowDown") {
event.preventDefault();
onGoToNextInput();
return;
}
if (event.key === "p" && isModKey(event) && event.shiftKey) {
event.preventDefault();
onSave({ publish: true, done: true });
return;
}
if (event.key === "s" && isModKey(event)) {
event.preventDefault();
onSave({});
return;
}
},
[onGoToNextInput, onSave]
);
return (
<Title
ref={ref}
onChange={onChange}
onKeyDown={handleKeyDown}
placeholder={
document.isTemplate
? t("Start your template…")
: t("Start with a title…")
}
value={normalizedTitle}
$startsWithEmojiAndSpace={startsWithEmojiAndSpace}
$isStarred={document.isStarred}
autoFocus={!value}
maxLength={MAX_TITLE_LENGTH}
readOnly={readOnly}
dir="auto"
>
{(can.star || can.unstar) && <StarButton document={document} size={32} />}
</Title>
);
}
const StarButton = styled(Star)`
position: relative;
top: 4px;
left: 4px;
`;
const Title = styled(ContentEditable)`
line-height: 1.25;
margin-top: 1em;
margin-bottom: 0.5em;
background: ${(props) => props.theme.background};
transition: ${(props) => props.theme.backgroundTransition};
color: ${(props) => props.theme.text};
-webkit-text-fill-color: ${(props) => props.theme.text};
font-size: 2.25em;
font-weight: 500;
outline: none;
border: 0;
padding: 0;
resize: none;
> span {
outline: none;
}
&::placeholder {
color: ${(props) => props.theme.placeholder};
-webkit-text-fill-color: ${(props) => props.theme.placeholder};
}
${breakpoint("tablet")`
margin-left: ${(props) => (props.$startsWithEmojiAndSpace ? "-1.2em" : 0)};
`};
${AnimatedStar} {
opacity: ${(props) => (props.$isStarred ? "1 !important" : 0)};
}
&:hover {
${AnimatedStar} {
opacity: 0.5;
&:hover {
opacity: 1;
}
}
}
@media print {
color: ${(props) => light.text};
-webkit-text-fill-color: ${(props) => light.text};
background: none;
}
`;
export default observer(EditableTitle);

View File

@ -2,13 +2,7 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { inject, observer } from "mobx-react"; import { inject, observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import Textarea from "react-autosize-textarea";
import { type TFunction, withTranslation } from "react-i18next"; import { type TFunction, withTranslation } from "react-i18next";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { MAX_TITLE_LENGTH } from "shared/constants";
import { light } from "shared/theme";
import parseTitle from "shared/utils/parseTitle";
import PoliciesStore from "stores/PoliciesStore"; import PoliciesStore from "stores/PoliciesStore";
import Document from "models/Document"; import Document from "models/Document";
import ClickablePadding from "components/ClickablePadding"; import ClickablePadding from "components/ClickablePadding";
@ -16,14 +10,13 @@ import DocumentMetaWithViews from "components/DocumentMetaWithViews";
import Editor, { type Props as EditorProps } from "components/Editor"; import Editor, { type Props as EditorProps } from "components/Editor";
import Flex from "components/Flex"; import Flex from "components/Flex";
import HoverPreview from "components/HoverPreview"; import HoverPreview from "components/HoverPreview";
import Star, { AnimatedStar } from "components/Star"; import EditableTitle from "./EditableTitle";
import MultiplayerEditor from "./MultiplayerEditor"; import MultiplayerEditor from "./MultiplayerEditor";
import { isModKey } from "utils/keyboard";
import { documentHistoryUrl } from "utils/routeHelpers"; import { documentHistoryUrl } from "utils/routeHelpers";
type Props = {| type Props = {|
...EditorProps, ...EditorProps,
onChangeTitle: (event: SyntheticInputEvent<>) => void, onChangeTitle: (text: string) => void,
title: string, title: string,
document: Document, document: Document,
isDraft: boolean, isDraft: boolean,
@ -61,35 +54,6 @@ class DocumentEditor extends React.Component<Props> {
} }
}; };
handleTitleKeyDown = (event: SyntheticKeyboardEvent<>) => {
if (event.key === "Enter") {
event.preventDefault();
if (isModKey(event)) {
this.props.onSave({ done: true });
return;
}
this.insertParagraph();
this.focusAtStart();
return;
}
if (event.key === "Tab" || event.key === "ArrowDown") {
event.preventDefault();
this.focusAtStart();
return;
}
if (event.key === "p" && isModKey(event) && event.shiftKey) {
event.preventDefault();
this.props.onSave({ publish: true, done: true });
return;
}
if (event.key === "s" && isModKey(event)) {
event.preventDefault();
this.props.onSave({});
return;
}
};
handleLinkActive = (event: MouseEvent) => { handleLinkActive = (event: MouseEvent) => {
this.activeLinkEvent = event; this.activeLinkEvent = event;
}; };
@ -98,6 +62,13 @@ class DocumentEditor extends React.Component<Props> {
this.activeLinkEvent = null; this.activeLinkEvent = null;
}; };
handleGoToNextInput = (insertParagraph: boolean) => {
if (insertParagraph) {
this.insertParagraph();
}
this.focusAtStart();
};
render() { render() {
const { const {
document, document,
@ -115,45 +86,16 @@ class DocumentEditor extends React.Component<Props> {
} = this.props; } = this.props;
const EditorComponent = multiplayer ? MultiplayerEditor : Editor; const EditorComponent = multiplayer ? MultiplayerEditor : Editor;
const can = policies.abilities(document.id);
const { emoji } = parseTitle(title);
const startsWithEmojiAndSpace = !!(emoji && title.startsWith(`${emoji} `));
const normalizedTitle =
!title && readOnly ? document.titleWithDefault : title;
return ( return (
<Flex auto column> <Flex auto column>
{readOnly ? ( <EditableTitle
<Title value={title}
as="div" readOnly={readOnly}
ref={this.ref} document={document}
$startsWithEmojiAndSpace={startsWithEmojiAndSpace} onGoToNextInput={this.handleGoToNextInput}
$isStarred={document.isStarred} onChange={onChangeTitle}
dir="auto" />
>
<span>{normalizedTitle}</span>{" "}
{(can.star || can.unstar) && (
<StarButton document={document} size={32} />
)}
</Title>
) : (
<Title
type="text"
ref={this.ref}
onChange={onChangeTitle}
onKeyDown={this.handleTitleKeyDown}
placeholder={
document.isTemplate
? t("Start your template…")
: t("Start with a title…")
}
value={normalizedTitle}
$startsWithEmojiAndSpace={startsWithEmojiAndSpace}
autoFocus={!title}
maxLength={MAX_TITLE_LENGTH}
dir="auto"
/>
)}
{!shareId && ( {!shareId && (
<DocumentMetaWithViews <DocumentMetaWithViews
isDraft={isDraft} isDraft={isDraft}
@ -191,56 +133,6 @@ class DocumentEditor extends React.Component<Props> {
} }
} }
const StarButton = styled(Star)`
position: relative;
top: 4px;
`;
const Title = styled(Textarea)`
line-height: 1.25;
margin-top: 1em;
margin-bottom: 0.5em;
background: ${(props) => props.theme.background};
transition: ${(props) => props.theme.backgroundTransition};
color: ${(props) => props.theme.text};
-webkit-text-fill-color: ${(props) => props.theme.text};
font-size: 2.25em;
font-weight: 500;
outline: none;
border: 0;
padding: 0;
resize: none;
&::placeholder {
color: ${(props) => props.theme.placeholder};
-webkit-text-fill-color: ${(props) => props.theme.placeholder};
}
${breakpoint("tablet")`
margin-left: ${(props) => (props.$startsWithEmojiAndSpace ? "-1.2em" : 0)};
`};
${AnimatedStar} {
opacity: ${(props) => (props.$isStarred ? "1 !important" : 0)};
}
&:hover {
${AnimatedStar} {
opacity: 0.5;
&:hover {
opacity: 1;
}
}
}
@media print {
color: ${(props) => light.text};
-webkit-text-fill-color: ${(props) => light.text};
background: none;
}
`;
export default withTranslation()<DocumentEditor>( export default withTranslation()<DocumentEditor>(
inject("policies")(DocumentEditor) inject("policies")(DocumentEditor)
); );

View File

@ -230,7 +230,7 @@ function DocumentHeader({
</Action> </Action>
</> </>
)} )}
{canEdit && editAction} {canEdit && !team.collaborativeEditing && editAction}
{canEdit && can.createChildDocument && !isMobile && ( {canEdit && can.createChildDocument && !isMobile && (
<Action> <Action>
<NewChildDocumentMenu <NewChildDocumentMenu

View File

@ -1,42 +0,0 @@
// flow-typed signature: 4739272fd9d8d2ec5c9881791bce7104
// flow-typed version: <<STUB>>/react-autosize-textarea_v^6.0.0/flow_v0.104.0
/**
* This is an autogenerated libdef stub for:
*
* 'react-autosize-textarea'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'react-autosize-textarea' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'react-autosize-textarea/lib' {
declare module.exports: any;
}
declare module 'react-autosize-textarea/lib/TextareaAutosize' {
declare module.exports: any;
}
// Filename aliases
declare module 'react-autosize-textarea/lib/index' {
declare module.exports: $Exports<'react-autosize-textarea/lib'>;
}
declare module 'react-autosize-textarea/lib/index.js' {
declare module.exports: $Exports<'react-autosize-textarea/lib'>;
}
declare module 'react-autosize-textarea/lib/TextareaAutosize.js' {
declare module.exports: $Exports<'react-autosize-textarea/lib/TextareaAutosize'>;
}

View File

@ -92,6 +92,7 @@
"imports-loader": "0.6.5", "imports-loader": "0.6.5",
"invariant": "^2.2.2", "invariant": "^2.2.2",
"ioredis": "^4.24.3", "ioredis": "^4.24.3",
"is-printable-key-event": "^1.0.0",
"joplin-turndown-plugin-gfm": "^1.0.12", "joplin-turndown-plugin-gfm": "^1.0.12",
"js-search": "^1.4.2", "js-search": "^1.4.2",
"json-loader": "0.5.4", "json-loader": "0.5.4",
@ -131,7 +132,6 @@
"randomstring": "1.1.5", "randomstring": "1.1.5",
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-autosize-textarea": "^7.1.0",
"react-avatar-editor": "^11.1.0", "react-avatar-editor": "^11.1.0",
"react-color": "^2.17.3", "react-color": "^2.17.3",
"react-dnd": "^14.0.1", "react-dnd": "^14.0.1",

View File

@ -52,7 +52,7 @@ export default class Persistence {
documentName, documentName,
}: { }: {
document: Y.Doc, document: Y.Doc,
context: { user: User }, context: { user: ?User },
documentName: string, documentName: string,
}) => { }) => {
const [, documentId] = documentName.split("."); const [, documentId] = documentName.split(".");
@ -63,7 +63,7 @@ export default class Persistence {
await documentUpdater({ await documentUpdater({
documentId, documentId,
ydoc: document, ydoc: document,
userId: context.user.id, userId: context.user?.id,
}); });
} catch (err) { } catch (err) {
Logger.error("Unable to persist document", err, { Logger.error("Unable to persist document", err, {

View File

@ -13,7 +13,7 @@ export default async function documentUpdater({
}: { }: {
documentId: string, documentId: string,
ydoc: Y.Doc, ydoc: Y.Doc,
userId: string, userId?: string,
}) { }) {
const document = await Document.findByPk(documentId); const document = await Document.findByPk(documentId);
const state = Y.encodeStateAsUpdate(ydoc); const state = Y.encodeStateAsUpdate(ydoc);
@ -38,7 +38,8 @@ export default async function documentUpdater({
text, text,
state: Buffer.from(state), state: Buffer.from(state),
updatedAt: isUnchanged ? document.updatedAt : new Date(), updatedAt: isUnchanged ? document.updatedAt : new Date(),
lastModifiedById: isUnchanged ? document.lastModifiedById : userId, lastModifiedById:
isUnchanged || !userId ? document.lastModifiedById : userId,
collaboratorIds, collaboratorIds,
}, },
{ {

View File

@ -449,6 +449,7 @@
"Send Invites": "Send Invites", "Send Invites": "Send Invites",
"Edit current document": "Edit current document", "Edit current document": "Edit current document",
"Move current document": "Move current document", "Move current document": "Move current document",
"Open document history": "Open document history",
"Jump to search": "Jump to search", "Jump to search": "Jump to search",
"Jump to home": "Jump to home", "Jump to home": "Jump to home",
"Toggle navigation": "Toggle navigation", "Toggle navigation": "Toggle navigation",

View File

@ -3530,11 +3530,6 @@ auto-bind@^1.1.0:
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-1.2.1.tgz#807f7910b0210db9eefe133f3492c28e89698b96" resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-1.2.1.tgz#807f7910b0210db9eefe133f3492c28e89698b96"
integrity sha512-/W9yj1yKmBLwpexwAujeD9YHwYmRuWFGV8HWE7smQab797VeHa4/cnE2NFeDhA+E+5e/OGBI8763EhLjfZ/MXA== integrity sha512-/W9yj1yKmBLwpexwAujeD9YHwYmRuWFGV8HWE7smQab797VeHa4/cnE2NFeDhA+E+5e/OGBI8763EhLjfZ/MXA==
autosize@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.2.tgz#073cfd07c8bf45da4b9fd153437f5bafbba1e4c9"
integrity sha512-jnSyH2d+qdfPGpWlcuhGiHmqBJ6g3X+8T+iRwFrHPLVcdoGJE/x6Qicm6aDHfTsbgZKxyV8UU/YB2p4cjKDRRA==
autotrack@^2.4.1: autotrack@^2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/autotrack/-/autotrack-2.4.1.tgz#ccbf010e3d95ef23c8dd6db4e8df025135c82ee6" resolved "https://registry.yarnpkg.com/autotrack/-/autotrack-2.4.1.tgz#ccbf010e3d95ef23c8dd6db4e8df025135c82ee6"
@ -4897,11 +4892,6 @@ compute-scroll-into-view@^1.0.16:
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088" resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088"
integrity sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ== integrity sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ==
computed-style@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/computed-style/-/computed-style-0.1.4.tgz#7f344fd8584b2e425bedca4a1afc0e300bb05d74"
integrity sha1-fzRP2FhLLkJb7cpKGvwOMAuwXXQ=
concat-map@0.0.1: concat-map@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -8353,6 +8343,11 @@ is-potential-custom-element-name@^1.0.0:
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
is-printable-key-event@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-printable-key-event/-/is-printable-key-event-1.0.0.tgz#1ea47b8abe1a2e53a1f5ea6aecbd6d24da707c66"
integrity sha512-C/GJ8ApSdY6/RGQrSSkBzuWDtYI9/mOTRLCOu/5iYH46pI7Ki6y6B71kPL7OWRzqv9KkWSEmskKdq5IvgAGPHA==
is-promise@^2.1: is-promise@^2.1:
version "2.2.2" version "2.2.2"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
@ -9568,13 +9563,6 @@ limiter@^1.1.4:
resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2" resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2"
integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA== integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==
line-height@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/line-height/-/line-height-0.3.1.tgz#4b1205edde182872a5efa3c8f620b3187a9c54c9"
integrity sha1-SxIF7d4YKHKl76PI9iCzGHqcVMk=
dependencies:
computed-style "~0.1.3"
lines-and-columns@^1.1.6: lines-and-columns@^1.1.6:
version "1.1.6" version "1.1.6"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
@ -11688,7 +11676,7 @@ prop-types-exact@^1.2.0:
object.assign "^4.1.0" object.assign "^4.1.0"
reflect.ownkeys "^0.2.0" reflect.ownkeys "^0.2.0"
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -12044,15 +12032,6 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.8:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
react-autosize-textarea@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/react-autosize-textarea/-/react-autosize-textarea-7.1.0.tgz#902c84fc395a689ca3a484dfb6bc2be9ba3694d1"
integrity sha512-BHpjCDkuOlllZn3nLazY2F8oYO1tS2jHnWhcjTWQdcKiiMU6gHLNt/fzmqMSyerR0eTdKtfSIqtSeTtghNwS+g==
dependencies:
autosize "^4.0.2"
line-height "^0.3.1"
prop-types "^15.5.6"
react-avatar-editor@^11.1.0: react-avatar-editor@^11.1.0:
version "11.1.0" version "11.1.0"
resolved "https://registry.yarnpkg.com/react-avatar-editor/-/react-avatar-editor-11.1.0.tgz#0eaec7970b1fbbd90d42a1955be440ea27f598ea" resolved "https://registry.yarnpkg.com/react-avatar-editor/-/react-avatar-editor-11.1.0.tgz#0eaec7970b1fbbd90d42a1955be440ea27f598ea"