Reafactor/UI input and displays (#1544)

* WIP

* Text field

* URL

* Finished PhoneInput

* Refactored input sub-folders

* Boolean

* Fix lint

* Fix lint

* Fix useOutsideClick

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2023-09-12 02:11:20 +02:00
committed by GitHub
parent 509ffddc57
commit a766c60aa5
90 changed files with 618 additions and 461 deletions

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { useSetRecoilState } from 'recoil';
import { actionBarOpenState } from '@/ui/action-bar/states/actionBarIsOpenState';
import { Checkbox } from '@/ui/input/checkbox/components/Checkbox';
import { Checkbox } from '@/ui/input/components/Checkbox';
import { useCurrentRowSelected } from '../hooks/useCurrentRowSelected';

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { Checkbox } from '@/ui/input/checkbox/components/Checkbox';
import { Checkbox } from '@/ui/input/components/Checkbox';
import { useSelectAllRows } from '../hooks/useSelectAllRows';

View File

@ -1,7 +1,7 @@
import { useEditableCell } from '../hooks/useEditableCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
import { EditableCellDisplayContainer } from './EditableCellContainer';
import { EditableCellDisplayContainer } from './EditableCellDisplayContainer';
export function EditableCellDisplayMode({
children,

View File

@ -6,7 +6,7 @@ import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritin
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
import { useEditableCell } from '../hooks/useEditableCell';
import { EditableCellDisplayContainer } from './EditableCellContainer';
import { EditableCellDisplayContainer } from './EditableCellDisplayContainer';
type OwnProps = PropsWithChildren<unknown>;

View File

@ -2,7 +2,7 @@ import { useRef } from 'react';
import styled from '@emotion/styled';
import { Key } from 'ts-key-enum';
import { DateInputEdit } from '@/ui/input/date/components/DateInputEdit';
import { DateInputEdit } from '@/ui/input/components/DateInputEdit';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';

View File

@ -6,11 +6,10 @@ import { useMoveSoftFocus } from '@/ui/table/hooks/useMoveSoftFocus';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { StyledInput } from '../../../../input/components/TextInput';
import { useEditableCell } from '../../hooks/useEditableCell';
import { useRegisterCloseCellHandlers } from '../../hooks/useRegisterCloseCellHandlers';
import { StyledInput } from './TextCellEdit';
type OwnProps = {
firstValue: string;
secondValue: string;

View File

@ -2,13 +2,13 @@ import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import type { ViewFieldBooleanMetadata } from '@/ui/editable-field/types/ViewField';
import { IconCheck, IconX } from '@/ui/icon';
import { BooleanInput } from '@/ui/input/components/BooleanInput';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { EditableCellDisplayContainer } from '../../components/EditableCellContainer';
import { EditableCellDisplayContainer } from '../../components/EditableCellDisplayContainer';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldBooleanMetadata>;
@ -26,14 +26,6 @@ const StyledCellBaseContainer = styled.div`
width: 100%;
`;
const StyledCellBooleancontainer = styled.div`
margin-left: 5px;
`;
function capitalizeFirstLetter(value: string) {
return value.charAt(0).toUpperCase() + value.slice(1);
}
export function GenericEditableBooleanCell({ columnDefinition }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
@ -48,6 +40,7 @@ export function GenericEditableBooleanCell({ columnDefinition }: OwnProps) {
function handleClick() {
const newValue = !fieldValue;
try {
setFieldValue(newValue);
@ -64,11 +57,7 @@ export function GenericEditableBooleanCell({ columnDefinition }: OwnProps) {
return (
<StyledCellBaseContainer>
<EditableCellDisplayContainer onClick={handleClick}>
{fieldValue ? <IconCheck /> : <IconX />}
<StyledCellBooleancontainer>
{fieldValue !== undefined &&
capitalizeFirstLetter(fieldValue.toString())}
</StyledCellBooleancontainer>
<BooleanInput value={fieldValue} />
</EditableCellDisplayContainer>
</StyledCellBaseContainer>
);

View File

@ -1,14 +1,15 @@
import { useRecoilState } from 'recoil';
import type { ViewFieldChipMetadata } from '@/ui/editable-field/types/ViewField';
import { useCellInputEventHandlers } from '@/ui/table/hooks/useCellInputEventHandlers';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { TextInput } from '../../../../input/components/TextInput';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldChipMetadata>;
};
@ -38,12 +39,27 @@ export function GenericEditableChipCellEditMode({
}
}
const {
handleEnter,
handleEscape,
handleTab,
handleShiftTab,
handleClickOutside,
} = useCellInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<TextCellEdit
<TextInput
placeholder={columnDefinition.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onTab={handleTab}
onShiftTab={handleShiftTab}
hotkeyScope={TableHotkeyScope.CellEditMode}
/>
);
}

View File

@ -1,7 +1,7 @@
import { useRecoilValue } from 'recoil';
import type { ViewFieldDateMetadata } from '@/ui/editable-field/types/ViewField';
import { DateInputDisplay } from '@/ui/input/date/components/DateInputDisplay';
import { DateInputDisplay } from '@/ui/input/components/DateInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';

View File

@ -1,7 +1,7 @@
import { useRecoilValue } from 'recoil';
import { TextDisplay } from '@/ui/content-display/components/TextDisplay';
import type { ViewFieldDoubleTextMetadata } from '@/ui/editable-field/types/ViewField';
import { TextInputDisplay } from '@/ui/input/text/components/TextInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
@ -40,7 +40,7 @@ export function GenericEditableDoubleTextCell({ columnDefinition }: OwnProps) {
columnDefinition={columnDefinition}
/>
}
nonEditModeContent={<TextInputDisplay>{displayName}</TextInputDisplay>}
nonEditModeContent={<TextDisplay text={displayName} />}
></EditableCell>
);
}

View File

@ -1,7 +1,7 @@
import { useRecoilValue } from 'recoil';
import type { ViewFieldEmailMetadata } from '@/ui/editable-field/types/ViewField';
import { EmailInputDisplay } from '@/ui/input/email/components/EmailInputDisplay';
import { EmailInputDisplay } from '@/ui/input/components/EmailInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';

View File

@ -1,14 +1,15 @@
import { useRecoilState } from 'recoil';
import type { ViewFieldEmailMetadata } from '@/ui/editable-field/types/ViewField';
import { useCellInputEventHandlers } from '@/ui/table/hooks/useCellInputEventHandlers';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { TextInput } from '../../../../input/components/TextInput';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldEmailMetadata>;
};
@ -38,12 +39,27 @@ export function GenericEditableEmailCellEditMode({
}
}
const {
handleEnter,
handleEscape,
handleTab,
handleShiftTab,
handleClickOutside,
} = useCellInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<TextCellEdit
<TextInput
placeholder={columnDefinition.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onTab={handleTab}
onShiftTab={handleShiftTab}
hotkeyScope={TableHotkeyScope.CellEditMode}
/>
);
}

View File

@ -1,14 +1,15 @@
import { useRecoilState } from 'recoil';
import type { ViewFieldMoneyMetadata } from '@/ui/editable-field/types/ViewField';
import { useCellInputEventHandlers } from '@/ui/table/hooks/useCellInputEventHandlers';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { TextInput } from '../../../../input/components/TextInput';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldMoneyMetadata>;
};
@ -53,7 +54,26 @@ export function GenericEditableMoneyCellEditMode({
}
}
const {
handleEnter,
handleEscape,
handleTab,
handleShiftTab,
handleClickOutside,
} = useCellInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<TextCellEdit autoFocus value={fieldValue ?? ''} onSubmit={handleSubmit} />
<TextInput
autoFocus
value={fieldValue ?? ''}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onTab={handleTab}
onShiftTab={handleShiftTab}
hotkeyScope={TableHotkeyScope.CellEditMode}
/>
);
}

View File

@ -1,18 +1,19 @@
import { useRecoilState } from 'recoil';
import type { ViewFieldNumberMetadata } from '@/ui/editable-field/types/ViewField';
import { useCellInputEventHandlers } from '@/ui/table/hooks/useCellInputEventHandlers';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import {
canBeCastAsPositiveIntegerOrNull,
castAsPositiveIntegerOrNull,
} from '~/utils/cast-as-positive-integer-or-null';
import { TextInput } from '../../../../input/components/TextInput';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldNumberMetadata>;
};
@ -74,7 +75,26 @@ export function GenericEditableNumberCellEditMode({
}
}
const {
handleEnter,
handleEscape,
handleTab,
handleShiftTab,
handleClickOutside,
} = useCellInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<TextCellEdit autoFocus value={fieldValue ?? ''} onSubmit={handleSubmit} />
<TextInput
autoFocus
value={fieldValue ?? ''}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onTab={handleTab}
onShiftTab={handleShiftTab}
hotkeyScope={TableHotkeyScope.CellEditMode}
/>
);
}

View File

@ -1,7 +1,7 @@
import { useRecoilValue } from 'recoil';
import type { ViewFieldPhoneMetadata } from '@/ui/editable-field/types/ViewField';
import { PhoneInputDisplay } from '@/ui/input/phone/components/PhoneInputDisplay';
import { PhoneDisplay } from '@/ui/content-display/components/PhoneDisplay';
import { ViewFieldPhoneMetadata } from '@/ui/editable-field/types/ViewField';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
@ -35,7 +35,7 @@ export function GenericEditablePhoneCell({
editModeContent={
<GenericEditablePhoneCellEditMode columnDefinition={columnDefinition} />
}
nonEditModeContent={<PhoneInputDisplay value={fieldValue} />}
nonEditModeContent={<PhoneDisplay value={fieldValue} />}
></EditableCell>
);
}

View File

@ -1,14 +1,16 @@
import { isPossiblePhoneNumber } from 'libphonenumber-js';
import { useRecoilState } from 'recoil';
import type { ViewFieldPhoneMetadata } from '@/ui/editable-field/types/ViewField';
import { useCellInputEventHandlers } from '@/ui/table/hooks/useCellInputEventHandlers';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { PhoneInput } from '../../../../input/components/PhoneInput';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { PhoneCellEdit } from './PhoneCellEdit';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldPhoneMetadata>;
};
@ -28,22 +30,39 @@ export function GenericEditablePhoneCellEditMode({
const updateField = useUpdateEntityField();
function handleSubmit(newText: string) {
if (newText === fieldValue) return;
function handleSubmit(newValue: string) {
if (!isPossiblePhoneNumber(newValue)) return;
setFieldValue(newText);
if (newValue === fieldValue) return;
setFieldValue(newValue);
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, columnDefinition, newText);
updateField(currentRowEntityId, columnDefinition, newValue);
}
}
const {
handleEnter,
handleEscape,
handleTab,
handleShiftTab,
handleClickOutside,
} = useCellInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<PhoneCellEdit
<PhoneInput
placeholder={columnDefinition.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onShiftTab={handleShiftTab}
onTab={handleTab}
hotkeyScope={TableHotkeyScope.CellEditMode}
/>
);
}

View File

@ -1,7 +1,7 @@
import { useRecoilValue } from 'recoil';
import { TextDisplay } from '@/ui/content-display/components/TextDisplay';
import type { ViewFieldTextMetadata } from '@/ui/editable-field/types/ViewField';
import { TextInputDisplay } from '@/ui/input/text/components/TextInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
@ -34,7 +34,7 @@ export function GenericEditableTextCell({
editModeContent={
<GenericEditableTextCellEditMode columnDefinition={columnDefinition} />
}
nonEditModeContent={<TextInputDisplay>{fieldValue}</TextInputDisplay>}
nonEditModeContent={<TextDisplay text={fieldValue} />}
></EditableCell>
);
}

View File

@ -1,14 +1,15 @@
import { useRecoilState } from 'recoil';
import type { ViewFieldTextMetadata } from '@/ui/editable-field/types/ViewField';
import { useCellInputEventHandlers } from '@/ui/table/hooks/useCellInputEventHandlers';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { TextInput } from '../../../../input/components/TextInput';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldTextMetadata>;
};
@ -38,12 +39,27 @@ export function GenericEditableTextCellEditMode({
}
}
const {
handleEnter,
handleEscape,
handleTab,
handleShiftTab,
handleClickOutside,
} = useCellInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<TextCellEdit
<TextInput
placeholder={columnDefinition.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onTab={handleTab}
onShiftTab={handleShiftTab}
hotkeyScope={TableHotkeyScope.CellEditMode}
/>
);
}

View File

@ -1,7 +1,7 @@
import { useRecoilValue } from 'recoil';
import { URLDisplay } from '@/ui/content-display/components/URLDisplay';
import type { ViewFieldURLMetadata } from '@/ui/editable-field/types/ViewField';
import { InplaceInputURLDisplayMode } from '@/ui/input/url/components/URLTextInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
@ -36,9 +36,7 @@ export function GenericEditableURLCell({
editModeContent={
<GenericEditableURLCellEditMode columnDefinition={columnDefinition} />
}
nonEditModeContent={
<InplaceInputURLDisplayMode value={sanitizeURL(fieldValue)} />
}
nonEditModeContent={<URLDisplay value={sanitizeURL(fieldValue)} />}
></EditableCell>
);
}

View File

@ -1,15 +1,16 @@
import { useRecoilState } from 'recoil';
import type { ViewFieldURLMetadata } from '@/ui/editable-field/types/ViewField';
import { useCellInputEventHandlers } from '@/ui/table/hooks/useCellInputEventHandlers';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/selectors/tableEntityFieldFamilySelector';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { isURL } from '~/utils/is-url';
import { TextInput } from '../../../../input/components/TextInput';
import type { ColumnDefinition } from '../../../types/ColumnDefinition';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
columnDefinition: ColumnDefinition<ViewFieldURLMetadata>;
};
@ -39,12 +40,27 @@ export function GenericEditableURLCellEditMode({ columnDefinition }: OwnProps) {
}
}
const {
handleEnter,
handleEscape,
handleTab,
handleShiftTab,
handleClickOutside,
} = useCellInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<TextCellEdit
<TextInput
placeholder={columnDefinition.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onTab={handleTab}
onShiftTab={handleShiftTab}
hotkeyScope={TableHotkeyScope.CellEditMode}
/>
);
}

View File

@ -1,108 +0,0 @@
import { useRef, useState } from 'react';
import PhoneInput, { isPossiblePhoneNumber } from 'react-phone-number-input';
import styled from '@emotion/styled';
import { useRegisterCloseCellHandlers } from '../../hooks/useRegisterCloseCellHandlers';
import 'react-phone-number-input/style.css';
const StyledContainer = styled.div`
align-items: center;
border: none;
border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex;
justify-content: center;
`;
export type PhoneCellEditProps = {
placeholder?: string;
autoFocus?: boolean;
value: string;
onSubmit: (newText: string) => void;
};
const StyledCustomPhoneInput = styled(PhoneInput)`
--PhoneInput-color--focus: transparent;
--PhoneInputCountryFlag-borderColor--focus: transparent;
--PhoneInputCountrySelect-marginRight: ${({ theme }) => theme.spacing(2)};
--PhoneInputCountrySelectArrow-color: ${({ theme }) =>
theme.font.color.tertiary};
--PhoneInputCountrySelectArrow-opacity: 1;
font-family: ${({ theme }) => theme.font.family};
height: 32px;
.PhoneInputCountry {
--PhoneInputCountryFlag-height: 12px;
--PhoneInputCountryFlag-width: 16px;
border-right: 1px solid ${({ theme }) => theme.border.color.light};
display: flex;
justify-content: center;
margin-left: ${({ theme }) => theme.spacing(2)};
}
.PhoneInputCountryIcon {
background: none;
border-radius: ${({ theme }) => theme.border.radius.xs};
box-shadow: none;
margin-right: 1px;
overflow: hidden;
&:focus {
box-shadow: none !important;
}
}
.PhoneInputCountrySelectArrow {
margin-right: ${({ theme }) => theme.spacing(2)};
}
.PhoneInputInput {
background: ${({ theme }) => theme.background.transparent.secondary};
border: none;
color: ${({ theme }) => theme.font.color.primary};
&::placeholder,
&::-webkit-input-placeholder {
color: ${({ theme }) => theme.font.color.light};
font-family: ${({ theme }) => theme.font.family};
font-weight: ${({ theme }) => theme.font.weight.medium};
}
:focus {
outline: none;
}
}
`;
export function PhoneCellEdit({
autoFocus,
value,
onSubmit,
}: PhoneCellEditProps) {
const [internalValue, setInternalValue] = useState<string | undefined>(value);
const wrapperRef = useRef<HTMLDivElement | null>(null);
function handleSubmit() {
if (
internalValue === undefined ||
isPossiblePhoneNumber(internalValue ?? '')
) {
onSubmit(internalValue ?? '');
}
}
useRegisterCloseCellHandlers(wrapperRef, handleSubmit);
return (
<StyledContainer ref={wrapperRef}>
<StyledCustomPhoneInput
autoFocus={autoFocus}
placeholder="Phone number"
value={value}
onChange={setInternalValue}
/>
</StyledContainer>
);
}

View File

@ -1,59 +0,0 @@
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/theme/constants/effects';
import { useRegisterCloseCellHandlers } from '../../hooks/useRegisterCloseCellHandlers';
export const StyledInput = styled.input`
margin: 0;
width: 100%;
${textInputStyle}
`;
type OwnProps = {
placeholder?: string;
autoFocus?: boolean;
value: string;
onSubmit: (newText: string) => void;
};
export function TextCellEdit({
placeholder,
autoFocus,
value,
onSubmit,
}: OwnProps) {
const [internalText, setInternalText] = useState(value);
const wrapperRef = useRef(null);
function handleSubmit() {
onSubmit(internalText);
}
function handleCancel() {
setInternalText(value);
}
function handleChange(event: ChangeEvent<HTMLInputElement>) {
setInternalText(event.target.value);
}
useEffect(() => {
setInternalText(value);
}, [value]);
useRegisterCloseCellHandlers(wrapperRef, handleSubmit, handleCancel);
return (
<StyledInput
autoComplete="off"
ref={wrapperRef}
placeholder={placeholder}
onChange={handleChange}
autoFocus={autoFocus}
value={internalText}
/>
);
}

View File

@ -1,12 +1,12 @@
import type { Meta, StoryObj } from '@storybook/react';
import { PhoneCellEdit } from '@/ui/table/editable-cell/type/components/PhoneCellEdit';
import { PhoneInput } from '@/ui/input/components/PhoneInput';
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
const meta: Meta<typeof PhoneCellEdit> = {
const meta: Meta<typeof PhoneInput> = {
title: 'UI/Table/EditableCell/PhoneCellEdit',
component: PhoneCellEdit,
component: PhoneInput,
decorators: [ComponentWithRecoilScopeDecorator],
args: {
value: '+33714446494',
@ -18,6 +18,6 @@ const meta: Meta<typeof PhoneCellEdit> = {
};
export default meta;
type Story = StoryObj<typeof PhoneCellEdit>;
type Story = StoryObj<typeof PhoneInput>;
export const Default: Story = {};

View File

@ -0,0 +1,47 @@
import { useCurrentCellEditMode } from '../editable-cell/hooks/useCurrentCellEditMode';
import { useEditableCell } from '../editable-cell/hooks/useEditableCell';
import { useMoveSoftFocus } from './useMoveSoftFocus';
export function useCellInputEventHandlers<T>({
onSubmit,
onCancel,
}: {
onSubmit?: (newValue: T) => void;
onCancel?: () => void;
}) {
const { closeEditableCell } = useEditableCell();
const { isCurrentCellInEditMode } = useCurrentCellEditMode();
const { moveRight, moveLeft, moveDown } = useMoveSoftFocus();
return {
handleClickOutside: (event: MouseEvent | TouchEvent, newValue: T) => {
if (isCurrentCellInEditMode) {
event.stopImmediatePropagation();
onSubmit?.(newValue);
closeEditableCell();
}
},
handleEscape: () => {
closeEditableCell();
onCancel?.();
},
handleEnter: (newValue: T) => {
onSubmit?.(newValue);
closeEditableCell();
moveDown();
},
handleTab: (newValue: T) => {
onSubmit?.(newValue);
closeEditableCell();
moveRight();
},
handleShiftTab: (newValue: T) => {
onSubmit?.(newValue);
closeEditableCell();
moveLeft();
},
};
}