Lucas/t 352 i dont want another input cell to open when i click outside (#163)
* Added logic to handle global edit mode * Added recoil global edit mode state into generic editable components * Fix lint * Added tests
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { ReactElement, useRef } from 'react';
|
||||
import { useOutsideAlerter } from '../../hooks/useOutsideAlerter';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { ReactElement } from 'react';
|
||||
import { CellBaseContainer } from './CellBaseContainer';
|
||||
import { CellEditModeContainer } from './CellEditModeContainer';
|
||||
import { CellNormalModeContainer } from './CellNormalModeContainer';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
|
||||
import { EditableCellEditMode } from './EditableCellEditMode';
|
||||
|
||||
type OwnProps = {
|
||||
editModeContent: ReactElement;
|
||||
@@ -25,58 +25,27 @@ export function EditableCell({
|
||||
onOutsideClick,
|
||||
onInsideClick,
|
||||
}: OwnProps) {
|
||||
const wrapperRef = useRef(null);
|
||||
const editableContainerRef = useRef(null);
|
||||
|
||||
useOutsideAlerter(wrapperRef, () => {
|
||||
onOutsideClick?.();
|
||||
});
|
||||
|
||||
useHotkeys(
|
||||
'esc',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick],
|
||||
const [isSomeInputInEditMode, setIsSomeInputInEditMode] = useRecoilState(
|
||||
isSomeInputInEditModeState,
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'enter',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick],
|
||||
);
|
||||
function handleOnClick() {
|
||||
if (!isSomeInputInEditMode) {
|
||||
onInsideClick?.();
|
||||
setIsSomeInputInEditMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<CellBaseContainer
|
||||
ref={wrapperRef}
|
||||
onClick={() => {
|
||||
onInsideClick && onInsideClick();
|
||||
}}
|
||||
>
|
||||
<CellBaseContainer onClick={handleOnClick}>
|
||||
{isEditMode ? (
|
||||
<CellEditModeContainer
|
||||
ref={editableContainerRef}
|
||||
<EditableCellEditMode
|
||||
editModeContent={editModeContent}
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
>
|
||||
{editModeContent}
|
||||
</CellEditModeContainer>
|
||||
isEditMode={isEditMode}
|
||||
onOutsideClick={onOutsideClick}
|
||||
/>
|
||||
) : (
|
||||
<CellNormalModeContainer>{nonEditModeContent}</CellNormalModeContainer>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import { ReactElement, useMemo, useRef } from 'react';
|
||||
import { CellEditModeContainer } from './CellEditModeContainer';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
|
||||
import { useListenClickOutsideArrayOfRef } from '../../modules/ui/common/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { debounce } from '../../modules/utils/debounce';
|
||||
|
||||
type OwnProps = {
|
||||
editModeContent: ReactElement;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
editModeVerticalPosition?: 'over' | 'below';
|
||||
isEditMode?: boolean;
|
||||
onOutsideClick?: () => void;
|
||||
onInsideClick?: () => void;
|
||||
};
|
||||
|
||||
export function EditableCellEditMode({
|
||||
editModeHorizontalAlign,
|
||||
editModeVerticalPosition,
|
||||
editModeContent,
|
||||
isEditMode,
|
||||
onOutsideClick,
|
||||
}: OwnProps) {
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const [, setIsSomeInputInEditMode] = useRecoilState(
|
||||
isSomeInputInEditModeState,
|
||||
);
|
||||
|
||||
const debouncedSetIsSomeInputInEditMode = useMemo(() => {
|
||||
return debounce(setIsSomeInputInEditMode, 20);
|
||||
}, [setIsSomeInputInEditMode]);
|
||||
|
||||
useListenClickOutsideArrayOfRef([wrapperRef], () => {
|
||||
if (isEditMode) {
|
||||
debouncedSetIsSomeInputInEditMode(false);
|
||||
onOutsideClick?.();
|
||||
}
|
||||
});
|
||||
|
||||
useHotkeys(
|
||||
'esc',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
|
||||
debouncedSetIsSomeInputInEditMode(false);
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick, debouncedSetIsSomeInputInEditMode],
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'enter',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
|
||||
debouncedSetIsSomeInputInEditMode(false);
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick, debouncedSetIsSomeInputInEditMode],
|
||||
);
|
||||
|
||||
return (
|
||||
<CellEditModeContainer
|
||||
data-testid="editable-cell-edit-mode-container"
|
||||
ref={wrapperRef}
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
>
|
||||
{editModeContent}
|
||||
</CellEditModeContainer>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ReactElement, useRef } from 'react';
|
||||
import { useOutsideAlerter } from '../../hooks/useOutsideAlerter';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { ReactElement } from 'react';
|
||||
import { CellBaseContainer } from './CellBaseContainer';
|
||||
import styled from '@emotion/styled';
|
||||
import { EditableCellMenuEditModeContainer } from './EditableCellMenuEditModeContainer';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
|
||||
import { EditableCellMenuEditMode } from './EditableCellMenuEditMode';
|
||||
|
||||
const EditableCellMenuNormalModeContainer = styled.div`
|
||||
display: flex;
|
||||
@@ -34,61 +34,31 @@ export function EditableCellMenu({
|
||||
onOutsideClick,
|
||||
onInsideClick,
|
||||
}: OwnProps) {
|
||||
const wrapperRef = useRef(null);
|
||||
const editableContainerRef = useRef(null);
|
||||
|
||||
useOutsideAlerter(wrapperRef, () => {
|
||||
onOutsideClick?.();
|
||||
});
|
||||
|
||||
useHotkeys(
|
||||
'esc',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick],
|
||||
const [isSomeInputInEditMode, setIsSomeInputInEditMode] = useRecoilState(
|
||||
isSomeInputInEditModeState,
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'enter',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick],
|
||||
);
|
||||
function handleOnClick() {
|
||||
if (!isSomeInputInEditMode) {
|
||||
onInsideClick?.();
|
||||
setIsSomeInputInEditMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<CellBaseContainer
|
||||
ref={wrapperRef}
|
||||
onClick={() => {
|
||||
onInsideClick && onInsideClick();
|
||||
}}
|
||||
>
|
||||
<CellBaseContainer onClick={handleOnClick}>
|
||||
<EditableCellMenuNormalModeContainer>
|
||||
{nonEditModeContent}
|
||||
</EditableCellMenuNormalModeContainer>
|
||||
{isEditMode && (
|
||||
<EditableCellMenuEditModeContainer
|
||||
ref={editableContainerRef}
|
||||
<EditableCellMenuEditMode
|
||||
editModeContent={editModeContent}
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
>
|
||||
{editModeContent}
|
||||
</EditableCellMenuEditModeContainer>
|
||||
isEditMode={isEditMode}
|
||||
onOutsideClick={onOutsideClick}
|
||||
onInsideClick={onInsideClick}
|
||||
/>
|
||||
)}
|
||||
</CellBaseContainer>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { ReactElement, useMemo, useRef } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
|
||||
import { useListenClickOutsideArrayOfRef } from '../../modules/ui/common/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { debounce } from '../../modules/utils/debounce';
|
||||
import { EditableCellMenuEditModeContainer } from './EditableCellMenuEditModeContainer';
|
||||
|
||||
type OwnProps = {
|
||||
editModeContent: ReactElement;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
editModeVerticalPosition?: 'over' | 'below';
|
||||
isEditMode?: boolean;
|
||||
onOutsideClick?: () => void;
|
||||
onInsideClick?: () => void;
|
||||
};
|
||||
|
||||
export function EditableCellMenuEditMode({
|
||||
editModeHorizontalAlign,
|
||||
editModeVerticalPosition,
|
||||
editModeContent,
|
||||
isEditMode,
|
||||
onOutsideClick,
|
||||
}: OwnProps) {
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const [, setIsSomeInputInEditMode] = useRecoilState(
|
||||
isSomeInputInEditModeState,
|
||||
);
|
||||
|
||||
const debouncedSetIsSomeInputInEditMode = useMemo(() => {
|
||||
return debounce(setIsSomeInputInEditMode, 20);
|
||||
}, [setIsSomeInputInEditMode]);
|
||||
|
||||
useListenClickOutsideArrayOfRef([wrapperRef], () => {
|
||||
if (isEditMode) {
|
||||
debouncedSetIsSomeInputInEditMode(false);
|
||||
onOutsideClick?.();
|
||||
}
|
||||
});
|
||||
|
||||
useHotkeys(
|
||||
'esc',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
|
||||
debouncedSetIsSomeInputInEditMode(false);
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick, debouncedSetIsSomeInputInEditMode],
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'enter',
|
||||
() => {
|
||||
if (isEditMode) {
|
||||
onOutsideClick?.();
|
||||
|
||||
debouncedSetIsSomeInputInEditMode(false);
|
||||
}
|
||||
},
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
[isEditMode, onOutsideClick, debouncedSetIsSomeInputInEditMode],
|
||||
);
|
||||
|
||||
return (
|
||||
<EditableCellMenuEditModeContainer
|
||||
ref={wrapperRef}
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
>
|
||||
{editModeContent}
|
||||
</EditableCellMenuEditModeContainer>
|
||||
);
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import { FaPlus } from 'react-icons/fa';
|
||||
import { HoverableMenuItem } from './HoverableMenuItem';
|
||||
import { EditableCellMenu } from './EditableCellMenu';
|
||||
import { CellNormalModeContainer } from './CellNormalModeContainer';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
|
||||
|
||||
const StyledEditModeContainer = styled.div`
|
||||
width: 200px;
|
||||
@@ -112,6 +114,9 @@ function EditableRelation<
|
||||
onCreate,
|
||||
}: EditableRelationProps<RelationType, ChipComponentPropsType>) {
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
const [, setIsSomeInputInEditMode] = useRecoilState(
|
||||
isSomeInputInEditModeState,
|
||||
);
|
||||
|
||||
// TODO: Tie this to a react context
|
||||
const [filterSearchResults, setSearchInput, setFilterSearch, searchInput] =
|
||||
@@ -130,7 +135,12 @@ function EditableRelation<
|
||||
|
||||
function handleCreateNewRelationButtonClick() {
|
||||
onCreate?.(searchInput);
|
||||
closeEditMode();
|
||||
}
|
||||
|
||||
function closeEditMode() {
|
||||
setIsEditMode(false);
|
||||
setIsSomeInputInEditMode(false);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -155,6 +165,7 @@ function EditableRelation<
|
||||
</StyledEditModeSelectedContainer>
|
||||
<StyledEditModeSearchContainer>
|
||||
<StyledEditModeSearchInput
|
||||
autoFocus
|
||||
placeholder={searchPlaceholder}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setFilterSearch(searchConfig);
|
||||
@@ -183,7 +194,7 @@ function EditableRelation<
|
||||
key={index}
|
||||
onClick={() => {
|
||||
onChange(result.value);
|
||||
setIsEditMode(false);
|
||||
closeEditMode();
|
||||
}}
|
||||
>
|
||||
<HoverableMenuItem>
|
||||
|
||||
Reference in New Issue
Block a user