Persist table cell values on cell close (#655)

* Persist table cell values on cell close

* Apply to all cells
This commit is contained in:
Charles Bochet
2023-07-13 21:20:08 -07:00
committed by GitHub
parent ca1723f2e6
commit 551c3b5e60
20 changed files with 260 additions and 133 deletions

View File

@ -26,6 +26,8 @@ type OwnProps = {
editModeHorizontalAlign?: 'left' | 'right';
editModeVerticalPosition?: 'over' | 'below';
editHotkeysScope?: HotkeysScope;
onSubmit?: () => void;
onCancel?: () => void;
};
export function EditableCell({
@ -34,6 +36,8 @@ export function EditableCell({
editModeContent,
nonEditModeContent,
editHotkeysScope,
onSubmit,
onCancel,
}: OwnProps) {
const { isCurrentCellInEditMode } = useCurrentCellEditMode();
@ -45,6 +49,8 @@ export function EditableCell({
<EditableCellEditMode
editModeHorizontalAlign={editModeHorizontalAlign}
editModeVerticalPosition={editModeVerticalPosition}
onSubmit={onSubmit}
onCancel={onCancel}
>
{editModeContent}
</EditableCellEditMode>

View File

@ -1,13 +1,9 @@
import { ReactElement, useRef } from 'react';
import styled from '@emotion/styled';
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus';
import { overlayBackground } from '@/ui/themes/effects';
import { useEditableCell } from './hooks/useEditableCell';
import { useRegisterCloseCellHandlers } from './hooks/useRegisterCloseCellHandlers';
export const EditableCellEditModeContainer = styled.div<OwnProps>`
align-items: center;
@ -33,60 +29,20 @@ type OwnProps = {
editModeHorizontalAlign?: 'left' | 'right';
editModeVerticalPosition?: 'over' | 'below';
onOutsideClick?: () => void;
onCancel?: () => void;
onSubmit?: () => void;
};
export function EditableCellEditMode({
editModeHorizontalAlign,
editModeVerticalPosition,
children,
onCancel,
onSubmit,
}: OwnProps) {
const wrapperRef = useRef(null);
const { closeEditableCell } = useEditableCell();
const { moveRight, moveLeft, moveDown } = useMoveSoftFocus();
useListenClickOutsideArrayOfRef([wrapperRef], () => {
closeEditableCell();
});
useScopedHotkeys(
'enter',
() => {
closeEditableCell();
moveDown();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell],
);
useScopedHotkeys(
'esc',
() => {
closeEditableCell();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell],
);
useScopedHotkeys(
'tab',
() => {
closeEditableCell();
moveRight();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell, moveRight],
);
useScopedHotkeys(
'shift+tab',
() => {
closeEditableCell();
moveLeft();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell, moveRight],
);
useRegisterCloseCellHandlers(wrapperRef, onSubmit, onCancel);
return (
<EditableCellEditModeContainer

View File

@ -4,7 +4,6 @@ import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { useCloseCurrentCellInEditMode } from '@/ui/tables/hooks/useClearCellInEditMode';
import { isSoftFocusActiveState } from '@/ui/tables/states/isSoftFocusActiveState';
import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState';
import { useCurrentCellEditMode } from './useCurrentCellEditMode';
@ -30,7 +29,6 @@ export function useEditableCell() {
if (!isSomeInputInEditMode) {
set(isSomeInputInEditModeState, true);
set(isSoftFocusActiveState, false);
setCurrentCellInEditMode();

View File

@ -0,0 +1,66 @@
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus';
import { useCurrentCellEditMode } from './useCurrentCellEditMode';
import { useEditableCell } from './useEditableCell';
export function useRegisterCloseCellHandlers(
wrapperRef: React.RefObject<HTMLDivElement>,
onSubmit?: () => void,
onCancel?: () => void,
) {
const { closeEditableCell } = useEditableCell();
const { isCurrentCellInEditMode } = useCurrentCellEditMode();
useListenClickOutsideArrayOfRef([wrapperRef], () => {
if (isCurrentCellInEditMode) {
onSubmit?.();
closeEditableCell();
}
});
const { moveRight, moveLeft, moveDown } = useMoveSoftFocus();
useScopedHotkeys(
'enter',
() => {
onSubmit?.();
closeEditableCell();
moveDown();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell, onSubmit, moveDown],
);
useScopedHotkeys(
'esc',
() => {
closeEditableCell();
onCancel?.();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell, onCancel],
);
useScopedHotkeys(
'tab',
() => {
onSubmit?.();
closeEditableCell();
moveRight();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell, onSubmit, moveRight],
);
useScopedHotkeys(
'shift+tab',
() => {
onSubmit?.();
closeEditableCell();
moveLeft();
},
InternalHotkeysScope.CellEditMode,
[closeEditableCell, onSubmit, moveRight],
);
}

View File

@ -14,6 +14,8 @@ type OwnProps = {
secondValuePlaceholder: string;
nonEditModeContent: ReactElement;
onChange: (firstValue: string, secondValue: string) => void;
onSubmit?: () => void;
onCancel?: () => void;
loading?: boolean;
};
@ -23,6 +25,8 @@ export function EditableCellDoubleText({
firstValuePlaceholder,
secondValuePlaceholder,
onChange,
onSubmit,
onCancel,
nonEditModeContent,
loading,
}: OwnProps) {
@ -50,6 +54,8 @@ export function EditableCellDoubleText({
firstValuePlaceholder={firstValuePlaceholder}
secondValuePlaceholder={secondValuePlaceholder}
onChange={handleOnChange}
onSubmit={onSubmit}
onCancel={onCancel}
/>
}
nonEditModeContent={loading ? <CellSkeleton /> : nonEditModeContent}

View File

@ -15,8 +15,8 @@ type OwnProps = {
firstValuePlaceholder: string;
secondValuePlaceholder: string;
onChange: (firstValue: string, secondValue: string) => void;
onSubmit?: (firstValue: string, secondValue: string) => void;
onExit?: () => void;
onSubmit?: () => void;
onCancel?: () => void;
};
const StyledContainer = styled.div`
@ -37,7 +37,7 @@ export function EditableCellDoubleTextEditMode({
secondValuePlaceholder,
onChange,
onSubmit,
onExit,
onCancel,
}: OwnProps) {
const [focusPosition, setFocusPosition] = useState<'left' | 'right'>('left');
@ -57,9 +57,7 @@ export function EditableCellDoubleTextEditMode({
() => {
closeCell();
moveDown();
if (onSubmit) {
onSubmit(firstValue, secondValue);
}
onSubmit?.();
},
InternalHotkeysScope.CellDoubleTextInput,
[closeCell],
@ -68,9 +66,7 @@ export function EditableCellDoubleTextEditMode({
useScopedHotkeys(
Key.Escape,
() => {
if (onExit) {
onExit();
}
onCancel?.();
closeCell();
},
InternalHotkeysScope.CellDoubleTextInput,
@ -84,9 +80,7 @@ export function EditableCellDoubleTextEditMode({
setFocusPosition('right');
secondValueInputRef.current?.focus();
} else {
if (onExit) {
onExit();
}
onSubmit?.();
closeCell();
moveRight();
}
@ -102,6 +96,7 @@ export function EditableCellDoubleTextEditMode({
setFocusPosition('left');
firstValueInputRef.current?.focus();
} else {
onSubmit?.();
closeCell();
moveLeft();
}

View File

@ -9,9 +9,17 @@ type OwnProps = {
placeholder?: string;
value: string;
onChange: (updated: string) => void;
onSubmit?: () => void;
onCancel?: () => void;
};
export function EditableCellPhone({ value, placeholder, onChange }: OwnProps) {
export function EditableCellPhone({
value,
placeholder,
onChange,
onSubmit,
onCancel,
}: OwnProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value);
@ -34,6 +42,8 @@ export function EditableCellPhone({ value, placeholder, onChange }: OwnProps) {
/>
}
nonEditModeContent={<InplaceInputPhoneDisplayMode value={inputValue} />}
onSubmit={onSubmit}
onCancel={onCancel}
/>
);
}

View File

@ -12,6 +12,8 @@ type OwnProps = {
onChange: (newValue: string) => void;
editModeHorizontalAlign?: 'left' | 'right';
loading?: boolean;
onSubmit?: () => void;
onCancel?: () => void;
};
export function EditableCellText({
@ -20,6 +22,8 @@ export function EditableCellText({
onChange,
editModeHorizontalAlign,
loading,
onCancel,
onSubmit,
}: OwnProps) {
const [internalValue, setInternalValue] = useState(value);
@ -41,6 +45,8 @@ export function EditableCellText({
}}
/>
}
onSubmit={onSubmit}
onCancel={onCancel}
nonEditModeContent={
loading ? (
<CellSkeleton />

View File

@ -28,6 +28,8 @@ export type EditableChipProps = {
commentThreadCount?: number;
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
rightEndContents?: ReactNode[];
onSubmit?: () => void;
onCancel?: () => void;
};
// TODO: refactor
@ -58,6 +60,8 @@ export function EditableCellChip({
editModeHorizontalAlign,
ChipComponent,
rightEndContents,
onSubmit,
onCancel,
}: EditableChipProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value);
@ -87,6 +91,8 @@ export function EditableCellChip({
}}
/>
}
onSubmit={onSubmit}
onCancel={onCancel}
nonEditModeContent={
<NoEditModeContainer>
<ChipComponent id={id} name={inputValue} picture={picture} />

View File

@ -31,6 +31,10 @@ export function useLeaveTableFocus() {
.getLoadable(currentHotkeysScopeState)
.valueOrThrow();
if (isSomeInputInEditMode) {
return;
}
if (!isSoftFocusActive && !isSomeInputInEditMode) {
return;
}