fix: Drag and drop images in editor, conflict with sidebar react-dnd (#1918)

* fix: Drag and drop images in editor, conflict with sidebar react-dnd
see: https://github.com/react-dnd/react-dnd/pull/3052

* Bump to non-canary

* Upgrade react-dnd

* react-dnd api changes

* lint

* fix: dnd doesn't work on first render

* remove unneccessary async

* chore: Update react-dnd (API changed again)

* restore fade
This commit is contained in:
Tom Moor 2021-03-09 18:41:30 -08:00 committed by GitHub
parent ed2a42ac27
commit bac7a364d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 321 additions and 323 deletions

View File

@ -16,7 +16,7 @@ type AlignValues =
| "flex-start" | "flex-start"
| "flex-end"; | "flex-end";
type Props = { type Props = {|
column?: ?boolean, column?: ?boolean,
shrink?: ?boolean, shrink?: ?boolean,
align?: AlignValues, align?: AlignValues,
@ -24,12 +24,18 @@ type Props = {
auto?: ?boolean, auto?: ?boolean,
className?: string, className?: string,
children?: React.Node, children?: React.Node,
}; role?: string,
|};
const Flex = (props: Props) => { const Flex = React.forwardRef<Props, HTMLDivElement>((props: Props, ref) => {
const { children, ...restProps } = props; const { children, ...restProps } = props;
return <Container {...restProps}>{children}</Container>;
}; return (
<Container ref={ref} {...restProps}>
{children}
</Container>
);
});
const Container = styled.div` const Container = styled.div`
display: flex; display: flex;

View File

@ -12,6 +12,8 @@ import {
SettingsIcon, SettingsIcon,
} from "outline-icons"; } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styled from "styled-components"; import styled from "styled-components";
import CollectionNew from "scenes/CollectionNew"; import CollectionNew from "scenes/CollectionNew";
@ -63,126 +65,142 @@ function MainSidebar() {
setInviteModalOpen(false); setInviteModalOpen(false);
}, []); }, []);
const [dndArea, setDndArea] = React.useState();
const handleSidebarRef = React.useCallback((node) => setDndArea(node), []);
const html5Options = React.useMemo(() => ({ rootElement: dndArea }), [
dndArea,
]);
const { user, team } = auth; const { user, team } = auth;
if (!user || !team) return null; if (!user || !team) return null;
const can = policies.abilities(team.id); const can = policies.abilities(team.id);
return ( return (
<Sidebar> <Sidebar ref={handleSidebarRef}>
<AccountMenu> {dndArea && (
{(props) => ( <DndProvider backend={HTML5Backend} options={html5Options}>
<TeamButton <AccountMenu>
{...props} {(props) => (
subheading={user.name} <TeamButton
teamName={team.name} {...props}
logoUrl={team.avatarUrl} subheading={user.name}
showDisclosure teamName={team.name}
/> logoUrl={team.avatarUrl}
)} showDisclosure
</AccountMenu> />
<Scrollable flex topShadow> )}
<Section> </AccountMenu>
<SidebarLink <Scrollable flex topShadow>
to="/home" <Section>
icon={<HomeIcon color="currentColor" />} <SidebarLink
exact={false} to="/home"
label={t("Home")} icon={<HomeIcon color="currentColor" />}
/> exact={false}
<SidebarLink label={t("Home")}
to={{ />
pathname: "/search", <SidebarLink
state: { fromMenu: true }, to={{
}} pathname: "/search",
icon={<SearchIcon color="currentColor" />} state: { fromMenu: true },
label={t("Search")} }}
exact={false} icon={<SearchIcon color="currentColor" />}
/> label={t("Search")}
<SidebarLink exact={false}
to="/starred" />
icon={<StarredIcon color="currentColor" />} <SidebarLink
exact={false} to="/starred"
label={t("Starred")} icon={<StarredIcon color="currentColor" />}
/> exact={false}
<SidebarLink label={t("Starred")}
to="/templates" />
icon={<ShapesIcon color="currentColor" />} <SidebarLink
exact={false} to="/templates"
label={t("Templates")} icon={<ShapesIcon color="currentColor" />}
active={documents.active ? documents.active.template : undefined} exact={false}
/> label={t("Templates")}
<SidebarLink active={
to="/drafts" documents.active ? documents.active.template : undefined
icon={<EditIcon color="currentColor" />} }
label={ />
<Drafts align="center"> <SidebarLink
{t("Drafts")} to="/drafts"
<Bubble count={documents.totalDrafts} /> icon={<EditIcon color="currentColor" />}
</Drafts> label={
} <Drafts align="center">
active={ {t("Drafts")}
documents.active <Bubble count={documents.totalDrafts} />
? !documents.active.publishedAt && </Drafts>
!documents.active.isDeleted && }
!documents.active.isTemplate active={
: undefined documents.active
} ? !documents.active.publishedAt &&
/> !documents.active.isDeleted &&
</Section> !documents.active.isTemplate
<Section auto> : undefined
<Collections onCreateCollection={handleCreateCollectionModalOpen} /> }
</Section> />
<Section> </Section>
<SidebarLink <Section auto>
to="/archive" <Collections
icon={<ArchiveIcon color="currentColor" />} onCreateCollection={handleCreateCollectionModalOpen}
exact={false} />
label={t("Archive")} </Section>
active={ <Section>
documents.active <SidebarLink
? documents.active.isArchived && !documents.active.isDeleted to="/archive"
: undefined icon={<ArchiveIcon color="currentColor" />}
} exact={false}
/> label={t("Archive")}
<SidebarLink active={
to="/trash" documents.active
icon={<TrashIcon color="currentColor" />} ? documents.active.isArchived && !documents.active.isDeleted
exact={false} : undefined
label={t("Trash")} }
active={documents.active ? documents.active.isDeleted : undefined} />
/> <SidebarLink
<SidebarLink to="/trash"
to="/settings" icon={<TrashIcon color="currentColor" />}
icon={<SettingsIcon color="currentColor" />} exact={false}
exact={false} label={t("Trash")}
label={t("Settings")} active={
/> documents.active ? documents.active.isDeleted : undefined
}
/>
<SidebarLink
to="/settings"
icon={<SettingsIcon color="currentColor" />}
exact={false}
label={t("Settings")}
/>
{can.invite && (
<SidebarLink
to="/settings/people"
onClick={handleInviteModalOpen}
icon={<PlusIcon color="currentColor" />}
label={`${t("Invite people")}`}
/>
)}
</Section>
</Scrollable>
{can.invite && ( {can.invite && (
<SidebarLink <Modal
to="/settings/people" title={t("Invite people")}
onClick={handleInviteModalOpen} onRequestClose={handleInviteModalClose}
icon={<PlusIcon color="currentColor" />} isOpen={inviteModalOpen}
label={`${t("Invite people")}`} >
/> <Invite onSubmit={handleInviteModalClose} />
</Modal>
)} )}
</Section> <Modal
</Scrollable> title={t("Create a collection")}
{can.invite && ( onRequestClose={handleCreateCollectionModalClose}
<Modal isOpen={createCollectionModalOpen}
title={t("Invite people")} >
onRequestClose={handleInviteModalClose} <CollectionNew onSubmit={handleCreateCollectionModalClose} />
isOpen={inviteModalOpen} </Modal>
> </DndProvider>
<Invite onSubmit={handleInviteModalClose} />
</Modal>
)} )}
<Modal
title={t("Create a collection")}
onRequestClose={handleCreateCollectionModalClose}
isOpen={createCollectionModalOpen}
>
<CollectionNew onSubmit={handleCreateCollectionModalClose} />
</Modal>
</Sidebar> </Sidebar>
); );
} }

View File

@ -13,153 +13,145 @@ import Toggle, { ToggleButton, Positioner } from "./components/Toggle";
import usePrevious from "hooks/usePrevious"; import usePrevious from "hooks/usePrevious";
import useStores from "hooks/useStores"; import useStores from "hooks/useStores";
let firstRender = true;
let ANIMATION_MS = 250; let ANIMATION_MS = 250;
let isFirstRender = true;
type Props = { type Props = {|
children: React.Node, children: React.Node,
}; |};
function Sidebar({ children }: Props) { const Sidebar = React.forwardRef<Props, HTMLButtonElement>(
const [isCollapsing, setCollapsing] = React.useState(false); ({ children }: Props, ref) => {
const theme = useTheme(); const [isCollapsing, setCollapsing] = React.useState(false);
const { t } = useTranslation(); const theme = useTheme();
const { ui } = useStores(); const { t } = useTranslation();
const location = useLocation(); const { ui } = useStores();
const previousLocation = usePrevious(location); const location = useLocation();
const previousLocation = usePrevious(location);
const width = ui.sidebarWidth; const width = ui.sidebarWidth;
const collapsed = ui.isEditing || ui.sidebarCollapsed; const collapsed = ui.isEditing || ui.sidebarCollapsed;
const maxWidth = theme.sidebarMaxWidth; const maxWidth = theme.sidebarMaxWidth;
const minWidth = theme.sidebarMinWidth + 16; // padding const minWidth = theme.sidebarMinWidth + 16; // padding
const setWidth = ui.setSidebarWidth; const setWidth = ui.setSidebarWidth;
const [offset, setOffset] = React.useState(0); const [offset, setOffset] = React.useState(0);
const [isAnimating, setAnimating] = React.useState(false); const [isAnimating, setAnimating] = React.useState(false);
const [isResizing, setResizing] = React.useState(false); const [isResizing, setResizing] = React.useState(false);
const isSmallerThanMinimum = width < minWidth; const isSmallerThanMinimum = width < minWidth;
const handleDrag = React.useCallback( const handleDrag = React.useCallback(
(event: MouseEvent) => { (event: MouseEvent) => {
// suppresses text selection // suppresses text selection
event.preventDefault(); event.preventDefault();
// this is simple because the sidebar is always against the left edge // this is simple because the sidebar is always against the left edge
const width = Math.min(event.pageX - offset, maxWidth); const width = Math.min(event.pageX - offset, maxWidth);
const isSmallerThanCollapsePoint = width < minWidth / 2;
if (isSmallerThanCollapsePoint) {
setWidth(theme.sidebarCollapsedWidth);
} else {
setWidth(width);
}
},
[theme, offset, minWidth, maxWidth, setWidth]
);
const handleStopDrag = React.useCallback(
(event: MouseEvent) => {
setResizing(false);
if (document.activeElement) {
document.activeElement.blur();
}
if (isSmallerThanMinimum) {
const isSmallerThanCollapsePoint = width < minWidth / 2; const isSmallerThanCollapsePoint = width < minWidth / 2;
if (isSmallerThanCollapsePoint) { if (isSmallerThanCollapsePoint) {
setAnimating(false); setWidth(theme.sidebarCollapsedWidth);
setCollapsing(true);
ui.collapseSidebar();
} else { } else {
setWidth(minWidth); setWidth(width);
setAnimating(true);
} }
} else { },
setWidth(width); [theme, offset, minWidth, maxWidth, setWidth]
);
const handleStopDrag = React.useCallback(
(event: MouseEvent) => {
setResizing(false);
if (document.activeElement) {
document.activeElement.blur();
}
if (isSmallerThanMinimum) {
const isSmallerThanCollapsePoint = width < minWidth / 2;
if (isSmallerThanCollapsePoint) {
setAnimating(false);
setCollapsing(true);
ui.collapseSidebar();
} else {
setWidth(minWidth);
setAnimating(true);
}
} else {
setWidth(width);
}
},
[ui, isSmallerThanMinimum, minWidth, width, setWidth]
);
const handleMouseDown = React.useCallback(
(event: MouseEvent) => {
setOffset(event.pageX - width);
setResizing(true);
setAnimating(false);
},
[width]
);
React.useEffect(() => {
if (isAnimating) {
setTimeout(() => setAnimating(false), ANIMATION_MS);
} }
}, }, [isAnimating]);
[ui, isSmallerThanMinimum, minWidth, width, setWidth]
);
const handleMouseDown = React.useCallback( React.useEffect(() => {
(event: MouseEvent) => { if (isCollapsing) {
setOffset(event.pageX - width); setTimeout(() => {
setResizing(true); setWidth(minWidth);
setAnimating(false); setCollapsing(false);
}, }, ANIMATION_MS);
[width] }
); }, [setWidth, minWidth, isCollapsing]);
React.useEffect(() => { React.useEffect(() => {
if (isAnimating) { if (isResizing) {
setTimeout(() => setAnimating(false), ANIMATION_MS); document.addEventListener("mousemove", handleDrag);
} document.addEventListener("mouseup", handleStopDrag);
}, [isAnimating]); }
React.useEffect(() => { return () => {
if (isCollapsing) { document.removeEventListener("mousemove", handleDrag);
setTimeout(() => { document.removeEventListener("mouseup", handleStopDrag);
setWidth(minWidth); };
setCollapsing(false); }, [isResizing, handleDrag, handleStopDrag]);
}, ANIMATION_MS);
}
}, [setWidth, minWidth, isCollapsing]);
React.useEffect(() => { const handleReset = React.useCallback(() => {
if (isResizing) { ui.setSidebarWidth(theme.sidebarWidth);
document.addEventListener("mousemove", handleDrag); }, [ui, theme.sidebarWidth]);
document.addEventListener("mouseup", handleStopDrag);
}
return () => { React.useEffect(() => {
document.removeEventListener("mousemove", handleDrag); ui.setSidebarResizing(isResizing);
document.removeEventListener("mouseup", handleStopDrag); }, [ui, isResizing]);
};
}, [isResizing, handleDrag, handleStopDrag]);
const handleReset = React.useCallback(() => { React.useEffect(() => {
ui.setSidebarWidth(theme.sidebarWidth); if (location !== previousLocation) {
}, [ui, theme.sidebarWidth]); isFirstRender = false;
ui.hideMobileSidebar();
}
}, [ui, location, previousLocation]);
React.useEffect(() => { const style = React.useMemo(
ui.setSidebarResizing(isResizing); () => ({
}, [ui, isResizing]); width: `${width}px`,
}),
[width]
);
React.useEffect(() => { const toggleStyle = React.useMemo(
if (location !== previousLocation) { () => ({
ui.hideMobileSidebar(); right: "auto",
} marginLeft: `${collapsed ? theme.sidebarCollapsedWidth : width}px`,
}, [ui, location, previousLocation]); }),
[width, theme.sidebarCollapsedWidth, collapsed]
);
const style = React.useMemo( const content = (
() => ({ <>
width: `${width}px`,
}),
[width]
);
const toggleStyle = React.useMemo(
() => ({
right: "auto",
marginLeft: `${collapsed ? theme.sidebarCollapsedWidth : width}px`,
}),
[width, theme.sidebarCollapsedWidth, collapsed]
);
const content = (
<>
<Container
style={style}
$sidebarWidth={ui.sidebarWidth}
$isCollapsing={isCollapsing}
$isAnimating={isAnimating}
$isSmallerThanMinimum={isSmallerThanMinimum}
$mobileSidebarVisible={ui.mobileSidebarVisible}
$collapsed={collapsed}
column
>
{ui.mobileSidebarVisible && ( {ui.mobileSidebarVisible && (
<Portal> <Portal>
<Fade> <Fade>
@ -180,26 +172,36 @@ function Sidebar({ children }: Props) {
aria-label={t("Expand")} aria-label={t("Expand")}
/> />
)} )}
</Container> </>
{!ui.isEditing && ( );
<Toggle
style={toggleStyle}
onClick={ui.toggleCollapsedSidebar}
direction={ui.sidebarCollapsed ? "right" : "left"}
aria-label={ui.sidebarCollapsed ? t("Expand") : t("Collapse")}
/>
)}
</>
);
// Fade in the sidebar on first render after page load return (
if (firstRender) { <>
firstRender = false; <Container
return <Fade>{content}</Fade>; ref={ref}
style={style}
$sidebarWidth={ui.sidebarWidth}
$isCollapsing={isCollapsing}
$isAnimating={isAnimating}
$isSmallerThanMinimum={isSmallerThanMinimum}
$mobileSidebarVisible={ui.mobileSidebarVisible}
$collapsed={collapsed}
column
>
{isFirstRender ? <Fade>{content}</Fade> : content}
</Container>
{!ui.isEditing && (
<Toggle
style={toggleStyle}
onClick={ui.toggleCollapsedSidebar}
direction={ui.sidebarCollapsed ? "right" : "left"}
aria-label={ui.sidebarCollapsed ? t("Expand") : t("Collapse")}
/>
)}
</>
);
} }
);
return content;
}
const Background = styled.a` const Background = styled.a`
position: fixed; position: fixed;

View File

@ -35,7 +35,7 @@ class Collections extends React.Component<Props> {
componentDidMount() { componentDidMount() {
const { collections } = this.props; const { collections } = this.props;
if (!collections.isFetching && !collections.isLoaded) { if (!collections.isLoaded) {
collections.fetchPage({ limit: 100 }); collections.fetchPage({ limit: 100 });
} }
} }

View File

@ -123,7 +123,8 @@ function DocumentLink({
// Draggable // Draggable
const [{ isDragging }, drag] = useDrag({ const [{ isDragging }, drag] = useDrag({
item: { type: "document", ...node, depth, active: isActiveDocument }, type: "document",
item: () => ({ ...node, depth, active: isActiveDocument }),
collect: (monitor) => ({ collect: (monitor) => ({
isDragging: !!monitor.isDragging(), isDragging: !!monitor.isDragging(),
}), }),
@ -146,7 +147,7 @@ function DocumentLink({
// Drop to re-parent // Drop to re-parent
const [{ isOverReparent, canDropToReparent }, dropToReparent] = useDrop({ const [{ isOverReparent, canDropToReparent }, dropToReparent] = useDrop({
accept: "document", accept: "document",
drop: async (item, monitor) => { drop: (item, monitor) => {
if (monitor.didDrop()) return; if (monitor.didDrop()) return;
if (!collection) return; if (!collection) return;
documents.move(item.id, collection.id, node.id); documents.move(item.id, collection.id, node.id);
@ -183,7 +184,7 @@ function DocumentLink({
// Drop to reorder // Drop to reorder
const [{ isOverReorder }, dropToReorder] = useDrop({ const [{ isOverReorder }, dropToReorder] = useDrop({
accept: "document", accept: "document",
drop: async (item, monitor) => { drop: (item, monitor) => {
if (!collection) return; if (!collection) return;
if (item.id === node.id) return; if (item.id === node.id) return;

View File

@ -3,8 +3,6 @@ import "focus-visible";
import { createBrowserHistory } from "history"; import { createBrowserHistory } from "history";
import { Provider } from "mobx-react"; import { Provider } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { render } from "react-dom"; import { render } from "react-dom";
import { Router } from "react-router-dom"; import { Router } from "react-router-dom";
import { initI18n } from "shared/i18n"; import { initI18n } from "shared/i18n";
@ -47,17 +45,15 @@ if (element) {
<Provider {...stores}> <Provider {...stores}>
<Theme> <Theme>
<ErrorBoundary> <ErrorBoundary>
<DndProvider backend={HTML5Backend}> <Router history={history}>
<Router history={history}> <>
<> <PageTheme />
<PageTheme /> <ScrollToTop>
<ScrollToTop> <Routes />
<Routes /> </ScrollToTop>
</ScrollToTop> <Toasts />
<Toasts /> </>
</> </Router>
</Router>
</DndProvider>
</ErrorBoundary> </ErrorBoundary>
</Theme> </Theme>
</Provider>, </Provider>,

View File

@ -140,8 +140,8 @@
"react-autosize-textarea": "^6.0.0", "react-autosize-textarea": "^6.0.0",
"react-avatar-editor": "^10.3.0", "react-avatar-editor": "^10.3.0",
"react-color": "^2.17.3", "react-color": "^2.17.3",
"react-dnd": "^11.1.3", "react-dnd": "^14.0.1",
"react-dnd-html5-backend": "^11.1.3", "react-dnd-html5-backend": "^14.0.0",
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"react-dropzone": "^11.2.4", "react-dropzone": "^11.2.4",
"react-helmet": "^5.2.0", "react-helmet": "^5.2.0",

View File

@ -2033,14 +2033,6 @@
dependencies: dependencies:
"@types/unist" "*" "@types/unist" "*"
"@types/hoist-non-react-statics@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
@ -2105,19 +2097,6 @@
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00"
integrity sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ== integrity sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==
"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react@*":
version "17.0.0"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.0.tgz#5af3eb7fad2807092f0046a1302b7823e27919b8"
integrity sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==
dependencies:
"@types/prop-types" "*"
csstype "^3.0.2"
"@types/resolve@1.17.1": "@types/resolve@1.17.1":
version "1.17.1" version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
@ -4339,11 +4318,6 @@ cssstyle@^2.2.0:
dependencies: dependencies:
cssom "~0.3.6" cssom "~0.3.6"
csstype@^3.0.2:
version "3.0.5"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.5.tgz#7fdec6a28a67ae18647c51668a9ff95bb2fa7bb8"
integrity sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==
cyclist@^1.0.1: cyclist@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
@ -4624,14 +4598,14 @@ direction@^0.1.5:
resolved "https://registry.yarnpkg.com/direction/-/direction-0.1.5.tgz#ce5d797f97e26f8be7beff53f7dc40e1c1a9ec4c" resolved "https://registry.yarnpkg.com/direction/-/direction-0.1.5.tgz#ce5d797f97e26f8be7beff53f7dc40e1c1a9ec4c"
integrity sha1-zl15f5fib4vnvv9T99xA4cGp7Ew= integrity sha1-zl15f5fib4vnvv9T99xA4cGp7Ew=
dnd-core@^11.1.3: dnd-core@14.0.0:
version "11.1.3" version "14.0.0"
resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-11.1.3.tgz#f92099ba7245e49729d2433157031a6267afcc98" resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.0.tgz#973ab3470d0a9ac5a0fa9021c4feba93ad12347d"
integrity sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA== integrity sha512-wTDYKyjSqWuYw3ZG0GJ7k+UIfzxTNoZLjDrut37PbcPGNfwhlKYlPUqjAKUjOOv80izshUiqusaKgJPItXSevA==
dependencies: dependencies:
"@react-dnd/asap" "^4.0.0" "@react-dnd/asap" "^4.0.0"
"@react-dnd/invariant" "^2.0.0" "@react-dnd/invariant" "^2.0.0"
redux "^4.0.4" redux "^4.0.5"
doctrine@1.5.0: doctrine@1.5.0:
version "1.5.0" version "1.5.0"
@ -5526,7 +5500,7 @@ fast-deep-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=
fast-deep-equal@^3.1.1: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
@ -6453,7 +6427,7 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0" minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1" minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@ -10686,22 +10660,23 @@ react-color@^2.17.3:
reactcss "^1.2.0" reactcss "^1.2.0"
tinycolor2 "^1.4.1" tinycolor2 "^1.4.1"
react-dnd-html5-backend@^11.1.3: react-dnd-html5-backend@^14.0.0:
version "11.1.3" version "14.0.0"
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz#2749f04f416ec230ea193f5c1fbea2de7dffb8f7" resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.0.0.tgz#28d660a2ad1e07447c34a65cd25f7de8f1657194"
integrity sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw== integrity sha512-2wAQqRFC1hbRGmk6+dKhOXsyQQOn3cN8PSZyOUeOun9J8t3tjZ7PS2+aFu7CVu2ujMDwTJR3VTwZh8pj2kCv7g==
dependencies: dependencies:
dnd-core "^11.1.3" dnd-core "14.0.0"
react-dnd@^11.1.3: react-dnd@^14.0.1:
version "11.1.3" version "14.0.1"
resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-11.1.3.tgz#f9844f5699ccc55dfc81462c2c19f726e670c1af" resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.1.tgz#012a855b0fb35a27c7c84aba7ff6c495e0baddb2"
integrity sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ== integrity sha512-r57KKBfmAYTwmQ/cREQehNjEX9U9Xi4AUWykLX92fB9JkY9z90DMWZhSE1M7o6Y71Y2/a2SBvSPQ385QboNrIQ==
dependencies: dependencies:
"@react-dnd/invariant" "^2.0.0"
"@react-dnd/shallowequal" "^2.0.0" "@react-dnd/shallowequal" "^2.0.0"
"@types/hoist-non-react-statics" "^3.3.1" dnd-core "14.0.0"
dnd-core "^11.1.3" fast-deep-equal "^3.1.3"
hoist-non-react-statics "^3.3.0" hoist-non-react-statics "^3.3.2"
react-dom@^16.8.6: react-dom@^16.8.6:
version "16.14.0" version "16.14.0"
@ -11028,7 +11003,7 @@ redis@^3.0.0:
redis-errors "^1.2.0" redis-errors "^1.2.0"
redis-parser "^3.0.0" redis-parser "^3.0.0"
redux@^4.0.4: redux@^4.0.5:
version "4.0.5" version "4.0.5"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==