From f290cda333aecab104d7cd195bcc7fab2059134d Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Wed, 7 Dec 2022 12:40:19 -0500 Subject: [PATCH] fix: escapes react-select events when drawer is open --- .../components/elements/Drawer/index.tsx | 1 + .../elements/ReactSelect/Control/index.tsx | 40 +++++++++++++++++++ .../elements/ReactSelect/MultiValue/index.tsx | 23 +++++++---- .../ReactSelect/MultiValueLabel/index.tsx | 15 +++++-- .../ReactSelect/SingleValue/index.tsx | 13 +++++- .../components/elements/ReactSelect/index.tsx | 8 ++++ .../components/elements/ReactSelect/types.ts | 3 ++ 7 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 src/admin/components/elements/ReactSelect/Control/index.tsx diff --git a/src/admin/components/elements/Drawer/index.tsx b/src/admin/components/elements/Drawer/index.tsx index 0b62cccf9f..1c09bf20d0 100644 --- a/src/admin/components/elements/Drawer/index.tsx +++ b/src/admin/components/elements/Drawer/index.tsx @@ -62,6 +62,7 @@ export const Drawer: React.FC = ({ return ( > = (props) => { + const { + children, + innerProps, + selectProps: { + selectProps: { + drawerIsOpen, + }, + }, + } = props; + + return ( + { + // prevent react-select from hijacking the onMouseDown event while the drawer is open + if (!drawerIsOpen) { + innerProps.onMouseDown(e); + } + }, + // react-select has this typed incorrectly + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + onKeyDown: (e) => { + if (drawerIsOpen) { + e.stopPropagation(); + } + }, + }} + > + {children} + + ); +}; diff --git a/src/admin/components/elements/ReactSelect/MultiValue/index.tsx b/src/admin/components/elements/ReactSelect/MultiValue/index.tsx index 2b1ca08671..d09b8a7d6e 100644 --- a/src/admin/components/elements/ReactSelect/MultiValue/index.tsx +++ b/src/admin/components/elements/ReactSelect/MultiValue/index.tsx @@ -1,4 +1,4 @@ -import React, { MouseEventHandler } from 'react'; +import React from 'react'; import { MultiValueProps, components as SelectComponents, @@ -18,18 +18,18 @@ export const MultiValue: React.FC> = (props) => { data: { value, }, + selectProps: { + selectProps, + selectProps: { + drawerIsOpen, + }, + }, } = props; const { attributes, listeners, setNodeRef, transform } = useSortable({ id: value as string, }); - const onMouseDown: MouseEventHandler = (e) => { - // prevent the dropdown from opening when clicking on the drag handle - e.preventDefault(); - e.stopPropagation(); - }; - const classes = [ baseClass, className, @@ -43,7 +43,13 @@ export const MultiValue: React.FC> = (props) => { innerProps={{ ...innerProps, ref: setNodeRef, - onMouseDown, + onMouseDown: (e) => { + if (!drawerIsOpen) { + // prevent the dropdown from opening when clicking on the drag handle but not when the drawer is open + e.preventDefault(); + e.stopPropagation(); + } + }, style: { ...transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, @@ -51,6 +57,7 @@ export const MultiValue: React.FC> = (props) => { }, }} selectProps={{ + ...selectProps, // NOTE: pass the draggable props to the label to act as the draggable handle draggableProps: { ...attributes, diff --git a/src/admin/components/elements/ReactSelect/MultiValueLabel/index.tsx b/src/admin/components/elements/ReactSelect/MultiValueLabel/index.tsx index 9535cc87ca..c61e91b5c3 100644 --- a/src/admin/components/elements/ReactSelect/MultiValueLabel/index.tsx +++ b/src/admin/components/elements/ReactSelect/MultiValueLabel/index.tsx @@ -1,4 +1,4 @@ -import React, { Fragment } from 'react'; +import React, { Fragment, useEffect } from 'react'; import { components, MultiValueProps } from 'react-select'; import { useDocumentDrawer } from '../../DocumentDrawer'; import Edit from '../../../icons/Edit'; @@ -14,21 +14,28 @@ export const MultiValueLabel: React.FC> = (props) => { relationTo, label, }, - selectProps, + selectProps: { + setDrawerIsOpen, + draggableProps, + }, } = props; - const [DocumentDrawer, DocumentDrawerToggler] = useDocumentDrawer({ + const [DocumentDrawer, DocumentDrawerToggler, { isDrawerOpen }] = useDocumentDrawer({ id: value?.toString(), collectionSlug: relationTo, }); + useEffect(() => { + if (typeof setDrawerIsOpen === 'function') setDrawerIsOpen(isDrawerOpen); + }, [isDrawerOpen, setDrawerIsOpen]); + return (
diff --git a/src/admin/components/elements/ReactSelect/SingleValue/index.tsx b/src/admin/components/elements/ReactSelect/SingleValue/index.tsx index aa0f531cdb..e5797b0d3a 100644 --- a/src/admin/components/elements/ReactSelect/SingleValue/index.tsx +++ b/src/admin/components/elements/ReactSelect/SingleValue/index.tsx @@ -1,4 +1,4 @@ -import React, { Fragment } from 'react'; +import React, { Fragment, useEffect } from 'react'; import { components, SingleValueProps } from 'react-select'; import { useDocumentDrawer } from '../../DocumentDrawer'; import Edit from '../../../icons/Edit'; @@ -15,13 +15,22 @@ export const SingleValue: React.FC> = (props) => { label, }, children, + selectProps: { + selectProps: { + setDrawerIsOpen, + }, + }, } = props; - const [DocumentDrawer, DocumentDrawerToggler] = useDocumentDrawer({ + const [DocumentDrawer, DocumentDrawerToggler, { isDrawerOpen }] = useDocumentDrawer({ id: value.toString(), collectionSlug: relationTo, }); + useEffect(() => { + if (typeof setDrawerIsOpen === 'function') setDrawerIsOpen(isDrawerOpen); + }, [isDrawerOpen, setDrawerIsOpen]); + return (
diff --git a/src/admin/components/elements/ReactSelect/index.tsx b/src/admin/components/elements/ReactSelect/index.tsx index 6c5844ba27..b7958db4a5 100644 --- a/src/admin/components/elements/ReactSelect/index.tsx +++ b/src/admin/components/elements/ReactSelect/index.tsx @@ -24,6 +24,7 @@ import { MultiValue } from './MultiValue'; import { SingleValue } from './SingleValue'; import { ValueContainer } from './ValueContainer'; import { ClearIndicator } from './ClearIndicator'; +import { Control } from './Control'; import './index.scss'; const SelectAdapter: React.FC = (props) => { @@ -44,8 +45,11 @@ const SelectAdapter: React.FC = (props) => { onMenuOpen, components, droppableRef, + selectProps, } = props; + const [drawerIsOpen, setDrawerIsOpen] = React.useState(false); + const classes = [ className, 'react-select', @@ -69,6 +73,9 @@ const SelectAdapter: React.FC = (props) => { filterOption={filterOption} onMenuOpen={onMenuOpen} selectProps={{ + ...selectProps, + drawerIsOpen, + setDrawerIsOpen, droppableRef, }} components={{ @@ -78,6 +85,7 @@ const SelectAdapter: React.FC = (props) => { MultiValueLabel, DropdownIndicator: Chevron, ClearIndicator, + Control, ...components, }} /> diff --git a/src/admin/components/elements/ReactSelect/types.ts b/src/admin/components/elements/ReactSelect/types.ts index 4d26900b5d..11508d14c0 100644 --- a/src/admin/components/elements/ReactSelect/types.ts +++ b/src/admin/components/elements/ReactSelect/types.ts @@ -36,4 +36,7 @@ export type Props = { components?: { [key: string]: React.FC } + selectProps?: { + [key: string]: unknown + } }