start-ui-web
start-ui-web copied to clipboard
Code to implement : Editable component
trafficstars
I suggest you my whole component : Editable I think we will need to make some adjustments like using Typescript. Here is the entire code :
Editable.js
import React, { Fragment, useState } from 'react';
import {
ButtonGroup,
Flex,
IconButton,
Text,
Textarea,
} from '@chakra-ui/react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { HiCheck, HiPencilAlt, HiX } from 'react-icons/hi';
import TextareaAutosize from 'react-textarea-autosize';
export const Editable = ({
value,
onSubmit,
onChange,
onCancel,
isSubmitDisabled,
...rest
}) => {
const { t } = useTranslation();
const [isEditing, setIsEditing] = useState(false);
const [content, setContent] = useState(value);
const handleEdit = () => {
if (isEditing) {
setIsEditing(false);
onSubmit(content.trim());
return;
}
setIsEditing(true);
setContent(value);
};
const handleCancel = () => {
setContent(value);
setIsEditing((x) => !x);
onCancel(value);
};
const handleChange = (e) => {
setContent(e.target?.value);
onChange(e);
};
return (
<Flex alignItems="flex-start" {...rest}>
{isEditing ? (
<Textarea
as={TextareaAutosize}
value={content}
transition="none"
ml="-0.5rem"
mr={3}
px={2}
py={1}
minH={4}
autoFocus
maxRows="10"
onChange={handleChange}
/>
) : (
<Text
flexGrow={1}
color="gray.500"
lineHeight="1.375" // set this lineHeight to be the same as textarea default lineHeight
py={1}
mr={2}
>
{(value || '').split('\n').map((item, key) => (
<Fragment key={key}>
{item}
<br />
</Fragment>
))}
</Text>
)}
<ButtonGroup size="sm">
{isEditing && (
<IconButton
aria-label={t('components.editable.cancel')}
onClick={handleCancel}
icon={<HiX />}
/>
)}
<IconButton
aria-label={
isEditing
? t('components.editable.submit')
: t('components.editable.edit')
}
isDisabled={isSubmitDisabled}
onClick={handleEdit}
icon={isEditing ? <HiCheck /> : <HiPencilAlt />}
/>
</ButtonGroup>
</Flex>
);
};
Editable.propTypes = {
value: PropTypes.string,
onSubmit: PropTypes.func,
onChange: PropTypes.func,
onCancel: PropTypes.func,
isSubmitDisabled: PropTypes.bool,
};
Editable.defaultProps = {
value: '',
onSubmit: () => {},
onChange: () => {},
onCancel: () => {},
isSubmitDisabled: false,
};
Editable.stories.mdx
import { Editable } from './Editable';
export default {
title: 'components/Editable',
component: Editable,
};
export const Default = () => <Editable />;
export const UsageWithValue = () => <Editable value="One Prepaid" />;
export const UsageWithTriggeredEvents = () => {
const handleCancel = (value) => {
console.log('Cancel', { value });
};
const handleSubmit = (value) => {
console.log('Submit', { value });
};
const handleChange = (e) => {
console.log('Change', { value: e.target.value });
};
return (
<Editable
onCancel={handleCancel}
onSubmit={handleSubmit}
onChange={handleChange}
/>
);
};
Result example :
https://user-images.githubusercontent.com/50022361/106932147-aaa85780-6717-11eb-8efc-52e68361588f.mp4
A good example using zagjs https://zagjs.com/components/react/editable