Refacto/remaining inplace input cells (#531)

* Add inplace date input component

* Add inplace phone input component

* Add inplace double text input component

* Add inplace chip input component

* Remove useless styled component

* Reduce code through props destructuring
This commit is contained in:
Emilien Chauvet
2023-07-07 15:00:01 -07:00
committed by GitHub
parent f62fdc1219
commit 6446692f25
16 changed files with 168 additions and 88 deletions

View File

@ -12,20 +12,12 @@ type OwnProps = {
editModeVerticalPosition?: 'over' | 'below';
};
export function EditableCell({
editModeHorizontalAlign = 'left',
editModeVerticalPosition = 'over',
editModeContent,
nonEditModeContent,
}: OwnProps) {
export function EditableCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceInput
editModeHorizontalAlign={editModeHorizontalAlign}
editModeVerticalPosition={editModeVerticalPosition}
editModeContent={editModeContent}
nonEditModeContent={nonEditModeContent}
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={!!hasSoftFocus}
/>

View File

@ -1,93 +0,0 @@
import { ChangeEvent, ComponentType, ReactNode, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/themes/effects';
import { EditableCell } from '../EditableCell';
export type EditableChipProps = {
placeholder?: string;
value: string;
picture: string;
changeHandler: (updated: string) => void;
editModeHorizontalAlign?: 'left' | 'right';
ChipComponent: ComponentType<{
name: string;
picture: string;
isOverlapped?: boolean;
}>;
commentCount?: number;
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
rightEndContents?: ReactNode[];
};
// TODO: refactor
const StyledInplaceInput = styled.input`
width: 100%;
${textInputStyle}
`;
const NoEditModeContainer = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
width: 100%;
`;
const RightContainer = styled.div`
margin-left: ${(props) => props.theme.spacing(1)};
`;
function EditableChip({
value,
placeholder,
changeHandler,
picture,
editModeHorizontalAlign,
ChipComponent,
rightEndContents,
}: EditableChipProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value);
const handleRightEndContentClick = (
event: React.MouseEvent<HTMLDivElement>,
) => {
event.stopPropagation();
};
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<StyledInplaceInput
placeholder={placeholder || ''}
autoFocus
ref={inputRef}
value={inputValue}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
changeHandler(event.target.value);
}}
/>
}
nonEditModeContent={
<NoEditModeContainer>
<ChipComponent name={inputValue} picture={picture} />
<RightContainer>
{rightEndContents &&
rightEndContents.length > 0 &&
rightEndContents.map((content, index) => (
<div key={index} onClick={handleRightEndContentClick}>
{content}
</div>
))}
</RightContainer>
</NoEditModeContainer>
}
/>
);
}
export default EditableChip;

View File

@ -0,0 +1,33 @@
import { ComponentType, ReactNode } from 'react';
import { InplaceChipInput } from '../../inplace-input/types/InplaceChipInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
export type OwnProps = {
placeholder?: string;
value: string;
picture: string;
changeHandler: (upChipd: string) => void;
editModeHorizontalAlign?: 'left' | 'right';
ChipComponent: ComponentType<{
name: string;
picture: string;
isOverlapped?: boolean;
}>;
commentCount?: number;
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
rightEndContents?: ReactNode[];
};
export function EditableChipCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceChipInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -1,81 +0,0 @@
import { forwardRef, useState } from 'react';
import styled from '@emotion/styled';
import { humanReadableDate } from '@/utils/utils';
import DatePicker from '../../form/DatePicker';
import { EditableCell } from '../EditableCell';
export type EditableDateProps = {
value: Date;
changeHandler: (date: Date) => void;
editModeHorizontalAlign?: 'left' | 'right';
};
const StyledContainer = styled.div`
align-items: center;
display: flex;
margin: 0px ${({ theme }) => theme.spacing(2)};
`;
export type StyledCalendarContainerProps = {
editModeHorizontalAlign?: 'left' | 'right';
};
const StyledCalendarContainer = styled.div<StyledCalendarContainerProps>`
background: ${({ theme }) => theme.background.secondary};
border: 1px solid ${({ theme }) => theme.border.color.light};
border-radius: 8px;
box-shadow: ${({ theme }) => theme.boxShadow.strong};
left: -10px;
position: absolute;
top: 10px;
z-index: 1;
`;
export function EditableDate({
value,
changeHandler,
editModeHorizontalAlign,
}: EditableDateProps) {
const [inputValue, setInputValue] = useState(value);
type DivProps = React.HTMLProps<HTMLDivElement>;
const DateDisplay = forwardRef<HTMLDivElement, DivProps>(
({ value, onClick }, ref) => (
<div onClick={onClick} ref={ref}>
{value && humanReadableDate(new Date(value as string))}
</div>
),
);
type DatePickerContainerProps = {
children: React.ReactNode;
};
const DatePickerContainer = ({ children }: DatePickerContainerProps) => {
return <StyledCalendarContainer>{children}</StyledCalendarContainer>;
};
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<StyledContainer>
<DatePicker
date={inputValue}
onChangeHandler={(date: Date) => {
changeHandler(date);
setInputValue(date);
}}
customInput={<DateDisplay />}
customCalendarContainer={DatePickerContainer}
/>
</StyledContainer>
}
nonEditModeContent={
<div>{inputValue && humanReadableDate(inputValue)}</div>
}
></EditableCell>
);
}

View File

@ -0,0 +1,22 @@
import { InplaceDateInput } from '../../inplace-input/types/InplaceDateInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
type OwnProps = {
placeholder?: string;
value: Date;
changeHandler: (date: Date) => void;
editModeHorizontalAlign?: 'left' | 'right';
};
export function EditableDateCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceDateInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -1,72 +0,0 @@
import { ChangeEvent, ReactElement, useRef } from 'react';
import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/themes/effects';
import { EditableCell } from '../EditableCell';
type OwnProps = {
firstValue: string;
secondValue: string;
firstValuePlaceholder: string;
secondValuePlaceholder: string;
nonEditModeContent: ReactElement;
onChange: (firstValue: string, secondValue: string) => void;
};
const StyledContainer = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
& > input:last-child {
border-left: 1px solid ${({ theme }) => theme.border.color.medium};
padding-left: ${({ theme }) => theme.spacing(2)};
}
`;
const StyledEditInplaceInput = styled.input`
height: 18px;
margin: 0;
width: 45%;
${textInputStyle}
`;
export function EditableDoubleText({
firstValue,
secondValue,
firstValuePlaceholder,
secondValuePlaceholder,
nonEditModeContent,
onChange,
}: OwnProps) {
const firstValueInputRef = useRef<HTMLInputElement>(null);
return (
<EditableCell
editModeContent={
<StyledContainer>
<StyledEditInplaceInput
autoFocus
placeholder={firstValuePlaceholder}
ref={firstValueInputRef}
value={firstValue}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
onChange(event.target.value, secondValue);
}}
/>
<StyledEditInplaceInput
placeholder={secondValuePlaceholder}
ref={firstValueInputRef}
value={secondValue}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
onChange(firstValue, event.target.value);
}}
/>
</StyledContainer>
}
nonEditModeContent={nonEditModeContent}
></EditableCell>
);
}

View File

@ -0,0 +1,26 @@
import { ReactElement } from 'react';
import { InplaceDoubleTextInput } from '../../inplace-input/types/InplaceDoubleTextInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
type OwnProps = {
firstValue: string;
secondValue: string;
firstValuePlaceholder: string;
secondValuePlaceholder: string;
nonEditModeContent: ReactElement;
onChange: (firstValue: string, secondValue: string) => void;
};
export function EditableDoubleTextCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceDoubleTextInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -1,70 +0,0 @@
import { ChangeEvent, MouseEvent, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js';
import { textInputStyle } from '@/ui/themes/effects';
import { RawLink } from '../../links/RawLink';
import { EditableCell } from '../EditableCell';
type OwnProps = {
placeholder?: string;
value: string;
changeHandler: (updated: string) => void;
};
const StyledRawLink = styled(RawLink)`
overflow: hidden;
a {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`;
// TODO: refactor
const StyledEditInplaceInput = styled.input`
margin: 0;
width: 100%;
${textInputStyle}
`;
export function EditablePhone({ value, placeholder, changeHandler }: OwnProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value);
return (
<EditableCell
editModeContent={
<StyledEditInplaceInput
autoFocus
placeholder={placeholder || ''}
ref={inputRef}
value={inputValue}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
changeHandler(event.target.value);
}}
/>
}
nonEditModeContent={
<>
{isValidPhoneNumber(inputValue) ? (
<StyledRawLink
href={parsePhoneNumber(inputValue, 'FR')?.getURI()}
onClick={(event: MouseEvent<HTMLElement>) => {
event.stopPropagation();
}}
>
{parsePhoneNumber(inputValue, 'FR')?.formatInternational() ||
inputValue}
</StyledRawLink>
) : (
<StyledRawLink href="#">{inputValue}</StyledRawLink>
)}
</>
}
/>
);
}

View File

@ -0,0 +1,21 @@
import { InplacePhoneInput } from '../../inplace-input/types/InplacePhoneInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
type OwnProps = {
placeholder?: string;
value: string;
changeHandler: (Phone: string) => void;
};
export function EditablePhoneCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplacePhoneInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -1,19 +0,0 @@
import styled from '@emotion/styled';
export const EditableRelationCreateButton = styled.button`
align-items: center;
background: none;
border: none;
border-radius: 4px;
cursor: pointer;
display: flex;
font-family: 'Inter';
font-size: ${({ theme }) => theme.font.size.md};
gap: ${({ theme }) => theme.spacing(2)};
height: 31px;
padding-bottom: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(1)};
padding-top: ${({ theme }) => theme.spacing(1)};
user-select: none;
width: 100%;
`;

View File

@ -9,20 +9,12 @@ type OwnProps = {
editModeHorizontalAlign?: 'left' | 'right';
};
export function EditableTextCell({
editModeHorizontalAlign = 'left',
content,
changeHandler,
placeholder,
}: OwnProps) {
export function EditableTextCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceTextInput
editModeHorizontalAlign={editModeHorizontalAlign}
content={content}
changeHandler={changeHandler}
placeholder={placeholder}
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>