Refacto/abstract inplace input (#530)
* Move code to new folder * Deduplicate code, remove dependancy on table * Remove more table dependency * Move close logic to input * Migrate editable text cell * Rename EditableTextInput * Fix component test id
This commit is contained in:
@ -4,7 +4,7 @@ import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFiltere
|
||||
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
|
||||
import { Entity } from '@/relation-picker/types/EntityTypeForSelect';
|
||||
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell';
|
||||
import { useInplaceInput } from '@/ui/components/inplace-input/hooks/useCloseInplaceInput';
|
||||
import {
|
||||
Company,
|
||||
User,
|
||||
@ -28,7 +28,7 @@ export function CompanyAccountOwnerPicker({ company }: OwnProps) {
|
||||
);
|
||||
const [updateCompany] = useUpdateCompanyMutation();
|
||||
|
||||
const { closeEditableCell } = useEditableCell();
|
||||
const { closeInplaceInput } = useInplaceInput();
|
||||
|
||||
const companies = useFilteredSearchEntityQuery({
|
||||
queryHook: useSearchUserQuery,
|
||||
@ -52,7 +52,7 @@ export function CompanyAccountOwnerPicker({ company }: OwnProps) {
|
||||
},
|
||||
});
|
||||
|
||||
closeEditableCell();
|
||||
closeInplaceInput();
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import CompanyChip from '@/companies/components/CompanyChip';
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { EditableCell } from '@/ui/components/editable-cell/EditableCell';
|
||||
import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState';
|
||||
import { isCreateModeScopedState } from '@/ui/components/inplace-input/states/isCreateModeScopedState';
|
||||
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
||||
import { Company, Person } from '~/generated/graphql';
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState';
|
||||
import { isCreateModeScopedState } from '@/ui/components/inplace-input/states/isCreateModeScopedState';
|
||||
import { DoubleTextInput } from '@/ui/components/inputs/DoubleTextInput';
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { logError } from '@/utils/logs/logError';
|
||||
|
||||
@ -2,8 +2,8 @@ import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'
|
||||
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
|
||||
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
|
||||
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell';
|
||||
import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState';
|
||||
import { useInplaceInput } from '@/ui/components/inplace-input/hooks/useCloseInplaceInput';
|
||||
import { isCreateModeScopedState } from '@/ui/components/inplace-input/states/isCreateModeScopedState';
|
||||
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
||||
import {
|
||||
CommentableType,
|
||||
@ -25,7 +25,7 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
|
||||
);
|
||||
const [updatePeople] = useUpdatePeopleMutation();
|
||||
|
||||
const { closeEditableCell } = useEditableCell();
|
||||
const { closeInplaceInput } = useInplaceInput();
|
||||
|
||||
const companies = useFilteredSearchEntityQuery({
|
||||
queryHook: useSearchCompanyQuery,
|
||||
@ -50,7 +50,7 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
|
||||
},
|
||||
});
|
||||
|
||||
closeEditableCell();
|
||||
closeInplaceInput();
|
||||
}
|
||||
|
||||
function handleCreate() {
|
||||
|
||||
@ -4,7 +4,7 @@ import { IconCurrencyDollar } from '@tabler/icons-react';
|
||||
|
||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
|
||||
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
|
||||
import { InplaceTextInput } from '@/ui/components/inplace-input/types/InplaceTextInput';
|
||||
import { CellContext } from '@/ui/tables/states/CellContext';
|
||||
import { RowContext } from '@/ui/tables/states/RowContext';
|
||||
|
||||
@ -113,7 +113,7 @@ export function CompanyBoardCard({
|
||||
<span>
|
||||
<IconCurrencyDollar size={theme.icon.size.md} />
|
||||
<HackScope>
|
||||
<EditableText
|
||||
<InplaceTextInput
|
||||
content={pipelineProgress.amount?.toString() || ''}
|
||||
placeholder="Opportunity amount"
|
||||
changeHandler={(value) =>
|
||||
|
||||
@ -1,26 +1,9 @@
|
||||
import { ReactElement } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { InplaceInput } from '../inplace-input/InplaceInput';
|
||||
|
||||
import { useEditableCell } from './hooks/useCloseEditableCell';
|
||||
import { useIsSoftFocusOnCurrentCell } from './hooks/useIsSoftFocusOnCurrentCell';
|
||||
import { useSetSoftFocusOnCurrentCell } from './hooks/useSetSoftFocusOnCurrentCell';
|
||||
import { isEditModeScopedState } from './states/isEditModeScopedState';
|
||||
import { EditableCellDisplayMode } from './EditableCellDisplayMode';
|
||||
import { EditableCellEditMode } from './EditableCellEditMode';
|
||||
import { EditableCellSoftFocusMode } from './EditableCellSoftFocusMode';
|
||||
|
||||
export const CellBaseContainer = styled.div`
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: 32px;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
editModeContent: ReactElement;
|
||||
@ -35,43 +18,16 @@ export function EditableCell({
|
||||
editModeContent,
|
||||
nonEditModeContent,
|
||||
}: OwnProps) {
|
||||
const [isEditMode] = useRecoilScopedState(isEditModeScopedState);
|
||||
|
||||
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
|
||||
|
||||
const { closeEditableCell, openEditableCell } = useEditableCell();
|
||||
|
||||
// TODO: we might have silent problematic behavior because of the setTimeout in openEditableCell, investigate
|
||||
// Maybe we could build a switchEditableCell to handle the case where we go from one cell to another.
|
||||
// See https://github.com/twentyhq/twenty/issues/446
|
||||
function handleOnClick() {
|
||||
openEditableCell();
|
||||
setSoftFocusOnCurrentCell();
|
||||
}
|
||||
|
||||
function handleOnOutsideClick() {
|
||||
closeEditableCell();
|
||||
}
|
||||
|
||||
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
|
||||
|
||||
return (
|
||||
<CellBaseContainer onClick={handleOnClick}>
|
||||
{isEditMode ? (
|
||||
<EditableCellEditMode
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
onOutsideClick={handleOnOutsideClick}
|
||||
>
|
||||
{editModeContent}
|
||||
</EditableCellEditMode>
|
||||
) : hasSoftFocus ? (
|
||||
<EditableCellSoftFocusMode>
|
||||
{nonEditModeContent}
|
||||
</EditableCellSoftFocusMode>
|
||||
) : (
|
||||
<EditableCellDisplayMode>{nonEditModeContent}</EditableCellDisplayMode>
|
||||
)}
|
||||
</CellBaseContainer>
|
||||
<InplaceInput
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
editModeContent={editModeContent}
|
||||
nonEditModeContent={nonEditModeContent}
|
||||
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
|
||||
hasSoftFocus={!!hasSoftFocus}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const HoverableMenuItem = styled.div`
|
||||
align-items: center;
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
transition: background 0.1s ease;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background: ${({ theme }) => theme.background.transparent.light};
|
||||
}
|
||||
`;
|
||||
@ -0,0 +1,30 @@
|
||||
import { InplaceTextInput } from '../../inplace-input/types/InplaceTextInput';
|
||||
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
|
||||
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
|
||||
|
||||
type OwnProps = {
|
||||
placeholder?: string;
|
||||
content: string;
|
||||
changeHandler: (updated: string) => void;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
};
|
||||
|
||||
export function EditableTextCell({
|
||||
editModeHorizontalAlign = 'left',
|
||||
content,
|
||||
changeHandler,
|
||||
placeholder,
|
||||
}: OwnProps) {
|
||||
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
|
||||
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
|
||||
return (
|
||||
<InplaceTextInput
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
content={content}
|
||||
changeHandler={changeHandler}
|
||||
placeholder={placeholder}
|
||||
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
|
||||
hasSoftFocus={hasSoftFocus}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
import { ReactElement } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { useInplaceInput } from './hooks/useCloseInplaceInput';
|
||||
import { isEditModeScopedState } from './states/isEditModeScopedState';
|
||||
import { InplaceInputDisplayMode } from './InplaceInputDisplayMode';
|
||||
import { InplaceInputEditMode } from './InplaceInputEditMode';
|
||||
import { InplaceInputSoftFocusMode } from './InplaceInputSoftFocusMode';
|
||||
|
||||
export const InplaceInputBaseContainer = styled.div`
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: 32px;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
editModeContent: ReactElement;
|
||||
nonEditModeContent: ReactElement;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
editModeVerticalPosition?: 'over' | 'below';
|
||||
setSoftFocusOnCurrentInplaceInput?: () => void;
|
||||
hasSoftFocus?: boolean;
|
||||
};
|
||||
|
||||
export function InplaceInput({
|
||||
editModeHorizontalAlign = 'left',
|
||||
editModeVerticalPosition = 'over',
|
||||
editModeContent,
|
||||
nonEditModeContent,
|
||||
setSoftFocusOnCurrentInplaceInput,
|
||||
hasSoftFocus,
|
||||
}: OwnProps) {
|
||||
const [isEditMode] = useRecoilScopedState(isEditModeScopedState);
|
||||
|
||||
const { closeInplaceInput, openInplaceInput } = useInplaceInput();
|
||||
|
||||
// TODO: we might have silent problematic behavior because of the setTimeout in openInplaceInput, investigate
|
||||
// Maybe we could build a switchInplaceInput to handle the case where we go from one InplaceInput to another.
|
||||
// See https://github.com/twentyhq/twenty/issues/446
|
||||
function handleOnClick() {
|
||||
openInplaceInput();
|
||||
setSoftFocusOnCurrentInplaceInput && setSoftFocusOnCurrentInplaceInput();
|
||||
}
|
||||
|
||||
function handleOnOutsideClick() {
|
||||
closeInplaceInput();
|
||||
}
|
||||
return (
|
||||
<InplaceInputBaseContainer onClick={handleOnClick}>
|
||||
{isEditMode ? (
|
||||
<InplaceInputEditMode
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
onOutsideClick={handleOnOutsideClick}
|
||||
>
|
||||
{editModeContent}
|
||||
</InplaceInputEditMode>
|
||||
) : hasSoftFocus ? (
|
||||
<InplaceInputSoftFocusMode>
|
||||
{nonEditModeContent}
|
||||
</InplaceInputSoftFocusMode>
|
||||
) : (
|
||||
<InplaceInputDisplayMode hasSoftFocus={!!hasSoftFocus}>
|
||||
{nonEditModeContent}
|
||||
</InplaceInputDisplayMode>
|
||||
)}
|
||||
</InplaceInputBaseContainer>
|
||||
);
|
||||
}
|
||||
@ -1,12 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useIsSoftFocusOnCurrentCell } from './hooks/useIsSoftFocusOnCurrentCell';
|
||||
|
||||
type Props = {
|
||||
softFocus: boolean;
|
||||
};
|
||||
|
||||
export const EditableCellNormalModeOuterContainer = styled.div<Props>`
|
||||
export const InplaceInputNormalModeOuterContainer = styled.div<Props>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
@ -24,7 +22,7 @@ export const EditableCellNormalModeOuterContainer = styled.div<Props>`
|
||||
: ''}
|
||||
`;
|
||||
|
||||
export const EditableCellNormalModeInnerContainer = styled.div`
|
||||
export const InplaceInputNormalModeInnerContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
@ -32,16 +30,17 @@ export const EditableCellNormalModeInnerContainer = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export function EditableCellDisplayMode({
|
||||
export function InplaceInputDisplayMode({
|
||||
children,
|
||||
}: React.PropsWithChildren<unknown>) {
|
||||
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
|
||||
|
||||
hasSoftFocus,
|
||||
}: React.PropsWithChildren & {
|
||||
hasSoftFocus: boolean;
|
||||
}) {
|
||||
return (
|
||||
<EditableCellNormalModeOuterContainer softFocus={hasSoftFocus}>
|
||||
<EditableCellNormalModeInnerContainer>
|
||||
<InplaceInputNormalModeOuterContainer softFocus={hasSoftFocus}>
|
||||
<InplaceInputNormalModeInnerContainer>
|
||||
{children}
|
||||
</EditableCellNormalModeInnerContainer>
|
||||
</EditableCellNormalModeOuterContainer>
|
||||
</InplaceInputNormalModeInnerContainer>
|
||||
</InplaceInputNormalModeOuterContainer>
|
||||
);
|
||||
}
|
||||
@ -6,9 +6,9 @@ import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsid
|
||||
import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus';
|
||||
import { overlayBackground } from '@/ui/themes/effects';
|
||||
|
||||
import { useEditableCell } from './hooks/useCloseEditableCell';
|
||||
import { useInplaceInput } from './hooks/useCloseInplaceInput';
|
||||
|
||||
export const EditableCellEditModeContainer = styled.div<OwnProps>`
|
||||
export const InplaceInputEditModeContainer = styled.div<OwnProps>`
|
||||
align-items: center;
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
@ -34,7 +34,7 @@ type OwnProps = {
|
||||
onOutsideClick?: () => void;
|
||||
};
|
||||
|
||||
export function EditableCellEditMode({
|
||||
export function InplaceInputEditMode({
|
||||
editModeHorizontalAlign,
|
||||
editModeVerticalPosition,
|
||||
children,
|
||||
@ -42,7 +42,7 @@ export function EditableCellEditMode({
|
||||
}: OwnProps) {
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const { closeEditableCell } = useEditableCell();
|
||||
const { closeInplaceInput } = useInplaceInput();
|
||||
const { moveRight, moveLeft, moveDown } = useMoveSoftFocus();
|
||||
|
||||
useListenClickOutsideArrayOfRef([wrapperRef], () => {
|
||||
@ -52,7 +52,7 @@ export function EditableCellEditMode({
|
||||
useHotkeys(
|
||||
'enter',
|
||||
() => {
|
||||
closeEditableCell();
|
||||
closeInplaceInput();
|
||||
moveDown();
|
||||
},
|
||||
{
|
||||
@ -60,26 +60,26 @@ export function EditableCellEditMode({
|
||||
enableOnFormTags: true,
|
||||
preventDefault: true,
|
||||
},
|
||||
[closeEditableCell],
|
||||
[closeInplaceInput],
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'esc',
|
||||
() => {
|
||||
closeEditableCell();
|
||||
closeInplaceInput();
|
||||
},
|
||||
{
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
preventDefault: true,
|
||||
},
|
||||
[closeEditableCell],
|
||||
[closeInplaceInput],
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'tab',
|
||||
() => {
|
||||
closeEditableCell();
|
||||
closeInplaceInput();
|
||||
moveRight();
|
||||
},
|
||||
{
|
||||
@ -87,13 +87,13 @@ export function EditableCellEditMode({
|
||||
enableOnFormTags: true,
|
||||
preventDefault: true,
|
||||
},
|
||||
[closeEditableCell, moveRight],
|
||||
[closeInplaceInput, moveRight],
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'shift+tab',
|
||||
() => {
|
||||
closeEditableCell();
|
||||
closeInplaceInput();
|
||||
moveLeft();
|
||||
},
|
||||
{
|
||||
@ -101,17 +101,17 @@ export function EditableCellEditMode({
|
||||
enableOnFormTags: true,
|
||||
preventDefault: true,
|
||||
},
|
||||
[closeEditableCell, moveRight],
|
||||
[closeInplaceInput, moveRight],
|
||||
);
|
||||
|
||||
return (
|
||||
<EditableCellEditModeContainer
|
||||
data-testid="editable-cell-edit-mode-container"
|
||||
<InplaceInputEditModeContainer
|
||||
data-testid="inplace-input-edit-mode-container"
|
||||
ref={wrapperRef}
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
>
|
||||
{children}
|
||||
</EditableCellEditModeContainer>
|
||||
</InplaceInputEditModeContainer>
|
||||
);
|
||||
}
|
||||
@ -5,13 +5,13 @@ import { useRecoilState } from 'recoil';
|
||||
import { captureHotkeyTypeInFocusState } from '@/hotkeys/states/captureHotkeyTypeInFocusState';
|
||||
import { isNonTextWritingKey } from '@/utils/hotkeys/isNonTextWritingKey';
|
||||
|
||||
import { useEditableCell } from './hooks/useCloseEditableCell';
|
||||
import { EditableCellDisplayMode } from './EditableCellDisplayMode';
|
||||
import { useInplaceInput } from './hooks/useCloseInplaceInput';
|
||||
import { InplaceInputDisplayMode } from './InplaceInputDisplayMode';
|
||||
|
||||
export function EditableCellSoftFocusMode({
|
||||
export function InplaceInputSoftFocusMode({
|
||||
children,
|
||||
}: React.PropsWithChildren<unknown>) {
|
||||
const { closeEditableCell, openEditableCell } = useEditableCell();
|
||||
const { closeInplaceInput, openInplaceInput } = useInplaceInput();
|
||||
const [captureHotkeyTypeInFocus] = useRecoilState(
|
||||
captureHotkeyTypeInFocusState,
|
||||
);
|
||||
@ -19,14 +19,14 @@ export function EditableCellSoftFocusMode({
|
||||
useHotkeys(
|
||||
'enter',
|
||||
() => {
|
||||
openEditableCell();
|
||||
openInplaceInput();
|
||||
},
|
||||
{
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
preventDefault: true,
|
||||
},
|
||||
[closeEditableCell],
|
||||
[closeInplaceInput],
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
@ -44,7 +44,7 @@ export function EditableCellSoftFocusMode({
|
||||
if (captureHotkeyTypeInFocus) {
|
||||
return;
|
||||
}
|
||||
openEditableCell();
|
||||
openInplaceInput();
|
||||
},
|
||||
{
|
||||
enableOnContentEditable: true,
|
||||
@ -53,5 +53,7 @@ export function EditableCellSoftFocusMode({
|
||||
},
|
||||
);
|
||||
|
||||
return <EditableCellDisplayMode>{children}</EditableCellDisplayMode>;
|
||||
return (
|
||||
<InplaceInputDisplayMode hasSoftFocus>{children}</InplaceInputDisplayMode>
|
||||
);
|
||||
}
|
||||
@ -1,14 +1,15 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
// TODO: Remove dependancy to table
|
||||
import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState';
|
||||
|
||||
import { isEditModeScopedState } from '../states/isEditModeScopedState';
|
||||
|
||||
export function useEditableCell() {
|
||||
export function useInplaceInput() {
|
||||
const [, setIsEditMode] = useRecoilScopedState(isEditModeScopedState);
|
||||
|
||||
const closeEditableCell = useRecoilCallback(
|
||||
const closeInplaceInput = useRecoilCallback(
|
||||
({ set }) =>
|
||||
async () => {
|
||||
setIsEditMode(false);
|
||||
@ -20,7 +21,7 @@ export function useEditableCell() {
|
||||
[setIsEditMode],
|
||||
);
|
||||
|
||||
const openEditableCell = useRecoilCallback(
|
||||
const openInplaceInput = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
const isSomeInputInEditMode = snapshot
|
||||
@ -37,7 +38,7 @@ export function useEditableCell() {
|
||||
);
|
||||
|
||||
return {
|
||||
closeEditableCell,
|
||||
openEditableCell,
|
||||
closeInplaceInput,
|
||||
openInplaceInput,
|
||||
};
|
||||
}
|
||||
@ -3,13 +3,15 @@ import styled from '@emotion/styled';
|
||||
|
||||
import { textInputStyle } from '@/ui/themes/effects';
|
||||
|
||||
import { EditableCell } from '../EditableCell';
|
||||
import { InplaceInput } from '../InplaceInput';
|
||||
|
||||
type OwnProps = {
|
||||
placeholder?: string;
|
||||
content: string;
|
||||
changeHandler: (updated: string) => void;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
setSoftFocusOnCurrentInplaceInput?: () => void;
|
||||
hasSoftFocus?: boolean;
|
||||
};
|
||||
|
||||
// TODO: refactor
|
||||
@ -26,17 +28,19 @@ const StyledNoEditText = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export function EditableText({
|
||||
export function InplaceTextInput({
|
||||
content,
|
||||
placeholder,
|
||||
changeHandler,
|
||||
editModeHorizontalAlign,
|
||||
setSoftFocusOnCurrentInplaceInput,
|
||||
hasSoftFocus,
|
||||
}: OwnProps) {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [inputValue, setInputValue] = useState(content);
|
||||
|
||||
return (
|
||||
<EditableCell
|
||||
<InplaceInput
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeContent={
|
||||
<StyledInplaceInput
|
||||
@ -50,7 +54,9 @@ export function EditableText({
|
||||
}}
|
||||
/>
|
||||
}
|
||||
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentInplaceInput}
|
||||
hasSoftFocus={hasSoftFocus}
|
||||
nonEditModeContent={<StyledNoEditText>{inputValue}</StyledNoEditText>}
|
||||
></EditableCell>
|
||||
></InplaceInput>
|
||||
);
|
||||
}
|
||||
@ -4,7 +4,7 @@ import { createColumnHelper } from '@tanstack/react-table';
|
||||
import { CompanyAccountOwnerCell } from '@/companies/components/CompanyAccountOwnerCell';
|
||||
import { CompanyEditableNameChipCell } from '@/companies/components/CompanyEditableNameCell';
|
||||
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
|
||||
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
|
||||
import { EditableTextCell } from '@/ui/components/editable-cell/types/EditableTextCell';
|
||||
import { ColumnHead } from '@/ui/components/table/ColumnHead';
|
||||
import {
|
||||
IconBuildingSkyscraper,
|
||||
@ -44,7 +44,7 @@ export const useCompaniesColumns = () => {
|
||||
<ColumnHead viewName="URL" viewIcon={<IconLink size={16} />} />
|
||||
),
|
||||
cell: (props) => (
|
||||
<EditableText
|
||||
<EditableTextCell
|
||||
content={props.row.original.domainName || ''}
|
||||
placeholder="Domain name"
|
||||
changeHandler={(value) => {
|
||||
@ -66,7 +66,7 @@ export const useCompaniesColumns = () => {
|
||||
<ColumnHead viewName="Employees" viewIcon={<IconUsers size={16} />} />
|
||||
),
|
||||
cell: (props) => (
|
||||
<EditableText
|
||||
<EditableTextCell
|
||||
content={props.row.original.employees?.toString() || ''}
|
||||
placeholder="Employees"
|
||||
changeHandler={(value) => {
|
||||
@ -89,7 +89,7 @@ export const useCompaniesColumns = () => {
|
||||
<ColumnHead viewName="Address" viewIcon={<IconMap size={16} />} />
|
||||
),
|
||||
cell: (props) => (
|
||||
<EditableText
|
||||
<EditableTextCell
|
||||
content={props.row.original.address || ''}
|
||||
placeholder="Address"
|
||||
changeHandler={(value) => {
|
||||
|
||||
@ -39,13 +39,13 @@ export const InteractWithManyRows: Story = {
|
||||
);
|
||||
|
||||
expect(
|
||||
canvas.queryByTestId('editable-cell-edit-mode-container'),
|
||||
canvas.queryByTestId('inplace-input-edit-mode-container'),
|
||||
).toBeNull();
|
||||
|
||||
await userEvent.click(firstRowEmailCell);
|
||||
|
||||
expect(
|
||||
canvas.queryByTestId('editable-cell-edit-mode-container'),
|
||||
canvas.queryByTestId('inplace-input-edit-mode-container'),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(secondRowEmailCell);
|
||||
@ -57,7 +57,7 @@ export const InteractWithManyRows: Story = {
|
||||
);
|
||||
|
||||
expect(
|
||||
canvas.queryByTestId('editable-cell-edit-mode-container'),
|
||||
canvas.queryByTestId('inplace-input-edit-mode-container'),
|
||||
).toBeNull();
|
||||
|
||||
await userEvent.click(secondRowEmailCellFocused);
|
||||
@ -65,7 +65,7 @@ export const InteractWithManyRows: Story = {
|
||||
await sleep(25);
|
||||
|
||||
expect(
|
||||
canvas.queryByTestId('editable-cell-edit-mode-container'),
|
||||
canvas.queryByTestId('inplace-input-edit-mode-container'),
|
||||
).toBeInTheDocument();
|
||||
},
|
||||
parameters: {
|
||||
|
||||
@ -5,7 +5,7 @@ import { EditablePeopleFullName } from '@/people/components/EditablePeopleFullNa
|
||||
import { PeopleCompanyCell } from '@/people/components/PeopleCompanyCell';
|
||||
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
|
||||
import { EditablePhone } from '@/ui/components/editable-cell/types/EditablePhone';
|
||||
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
|
||||
import { EditableTextCell } from '@/ui/components/editable-cell/types/EditableTextCell';
|
||||
import { ColumnHead } from '@/ui/components/table/ColumnHead';
|
||||
import {
|
||||
IconBuildingSkyscraper,
|
||||
@ -55,7 +55,7 @@ export const usePeopleColumns = () => {
|
||||
<ColumnHead viewName="Email" viewIcon={<IconMail size={16} />} />
|
||||
),
|
||||
cell: (props) => (
|
||||
<EditableText
|
||||
<EditableTextCell
|
||||
placeholder="Email"
|
||||
content={props.row.original.email || ''}
|
||||
changeHandler={async (value: string) => {
|
||||
@ -137,7 +137,7 @@ export const usePeopleColumns = () => {
|
||||
<ColumnHead viewName="City" viewIcon={<IconMap size={16} />} />
|
||||
),
|
||||
cell: (props) => (
|
||||
<EditableText
|
||||
<EditableTextCell
|
||||
editModeHorizontalAlign="right"
|
||||
placeholder="City"
|
||||
content={props.row.original.city || ''}
|
||||
|
||||
Reference in New Issue
Block a user