Create Editable chip to edit cells containing chips (#102)

* Create Editable chip to edit cells containing chips

* Fix icons vertical alignment

* Fix linter

* Fix coverage
This commit is contained in:
Charles Bochet
2023-05-05 12:15:41 +02:00
committed by GitHub
parent 9cd57083f1
commit 55eff2b7a2
9 changed files with 168 additions and 30 deletions

View File

@ -0,0 +1,69 @@
import styled from '@emotion/styled';
import { ChangeEvent, ComponentType, useRef, useState } from 'react';
import EditableCellWrapper from './EditableCellWrapper';
export type EditableChipProps = {
placeholder?: string;
value: string;
picture: string;
changeHandler: (updated: string) => void;
shouldAlignRight?: boolean;
ChipComponent: ComponentType<{ name: string; picture: string }>;
};
type StyledEditModeProps = {
isEditMode: boolean;
};
const StyledInplaceInput = styled.input<StyledEditModeProps>`
width: 100%;
border: none;
outline: none;
&::placeholder {
font-weight: ${(props) => (props.isEditMode ? 'bold' : 'normal')};
color: ${(props) =>
props.isEditMode ? props.theme.text20 : 'transparent'};
}
`;
function EditableChip({
value,
placeholder,
changeHandler,
picture,
shouldAlignRight,
ChipComponent,
}: EditableChipProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value);
const [isEditMode, setIsEditMode] = useState(false);
const onEditModeChange = (isEditMode: boolean) => {
setIsEditMode(isEditMode);
};
return (
<EditableCellWrapper
onEditModeChange={onEditModeChange}
shouldAlignRight={shouldAlignRight}
>
{isEditMode ? (
<StyledInplaceInput
isEditMode={isEditMode}
placeholder={placeholder || ''}
autoFocus
ref={inputRef}
value={inputValue}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
changeHandler(event.target.value);
}}
/>
) : (
<ChipComponent name={value} picture={picture} />
)}
</EditableCellWrapper>
);
}
export default EditableChip;

View File

@ -29,7 +29,7 @@ const StyledNoEditText = styled.div`
max-width: 200px;
`;
function EditableCell({
function EditableText({
content,
placeholder,
changeHandler,
@ -67,4 +67,4 @@ function EditableCell({
);
}
export default EditableCell;
export default EditableText;

View File

@ -0,0 +1,33 @@
import EditableChip, { EditableChipProps } from '../EditableChip';
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../../layout/styles/themes';
import { StoryFn } from '@storybook/react';
import CompanyChip from '../../../chips/CompanyChip';
const component = {
title: 'EditableChip',
component: EditableChip,
};
export default component;
const Template: StoryFn<typeof EditableChip> = (args: EditableChipProps) => {
return (
<ThemeProvider theme={lightTheme}>
<div data-testid="content-editable-parent">
<EditableChip {...args} />
</div>
</ThemeProvider>
);
};
export const EditableChipStory = Template.bind({});
EditableChipStory.args = {
ChipComponent: CompanyChip,
placeholder: 'Test',
value: 'Test',
picture: 'https://picsum.photos/200',
changeHandler: () => {
console.log('changed');
},
};

View File

@ -0,0 +1,34 @@
import { fireEvent, render } from '@testing-library/react';
import { EditableChipStory } from '../__stories__/EditableChip.stories';
import CompanyChip from '../../../chips/CompanyChip';
it('Checks the EditableChip editing event bubbles up', async () => {
const func = jest.fn(() => null);
const { getByTestId } = render(
<EditableChipStory
value="test"
picture="http://"
changeHandler={func}
ChipComponent={CompanyChip}
/>,
);
const parent = getByTestId('content-editable-parent');
const wrapper = parent.querySelector('div');
if (!wrapper) {
throw new Error('Editable input not found');
}
fireEvent.click(wrapper);
const editableInput = parent.querySelector('input');
if (!editableInput) {
throw new Error('Editable input not found');
}
fireEvent.change(editableInput, { target: { value: 'Test' } });
expect(func).toBeCalledWith('Test');
});

View File

@ -23,11 +23,15 @@ const StyledChip = styled.div`
`;
const StyledIcon = styled.div`
margin-right: ${(props) => props.theme.spacing(1)};
display: flex;
align-items: center;
`;
const StyledDelete = styled.div`
margin-left: ${(props) => props.theme.spacing(2)};
cursor: pointer;
display: flex;
align-items: center;
`;
const StyledLabelKey = styled.div`