mirror of
https://github.com/plankanban/planka.git
synced 2025-08-03 20:45:27 +02:00
parent
ad7fb51cfa
commit
2ee1166747
1557 changed files with 76832 additions and 47042 deletions
105
client/src/components/cards/CardModal/NameField.jsx
Executable file
105
client/src/components/cards/CardModal/NameField.jsx
Executable file
|
@ -0,0 +1,105 @@
|
|||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import TextareaAutosize from 'react-textarea-autosize';
|
||||
import { TextArea } from 'semantic-ui-react';
|
||||
import { useDidUpdate, usePrevious, useToggle } from '../../../lib/hooks';
|
||||
|
||||
import { useEscapeInterceptor, useField, useNestedRef } from '../../../hooks';
|
||||
|
||||
import styles from './NameField.module.scss';
|
||||
|
||||
const Sizes = {
|
||||
MEDIUM: 'medium',
|
||||
LARGE: 'large',
|
||||
};
|
||||
|
||||
const NameField = React.memo(({ defaultValue, size, onUpdate }) => {
|
||||
const prevDefaultValue = usePrevious(defaultValue);
|
||||
const [value, handleChange, setValue] = useField(defaultValue);
|
||||
const [blurFieldState, blurField] = useToggle();
|
||||
|
||||
const [fiedRef, handleFieldRef] = useNestedRef();
|
||||
const isFocusedRef = useRef(false);
|
||||
|
||||
const handleEscape = useCallback(() => {
|
||||
setValue(defaultValue);
|
||||
blurField();
|
||||
}, [defaultValue, setValue, blurField]);
|
||||
|
||||
const [activateEscapeInterceptor, deactivateEscapeInterceptor] =
|
||||
useEscapeInterceptor(handleEscape);
|
||||
|
||||
const handleFocus = useCallback(() => {
|
||||
activateEscapeInterceptor();
|
||||
isFocusedRef.current = true;
|
||||
}, [activateEscapeInterceptor]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
fiedRef.current.blur();
|
||||
}
|
||||
},
|
||||
[fiedRef],
|
||||
);
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
deactivateEscapeInterceptor();
|
||||
isFocusedRef.current = false;
|
||||
|
||||
const cleanValue = value.trim();
|
||||
|
||||
if (cleanValue) {
|
||||
if (cleanValue !== defaultValue) {
|
||||
onUpdate(cleanValue);
|
||||
}
|
||||
} else {
|
||||
setValue(defaultValue);
|
||||
}
|
||||
}, [defaultValue, onUpdate, value, setValue, deactivateEscapeInterceptor]);
|
||||
|
||||
useDidUpdate(() => {
|
||||
if (!isFocusedRef.current && defaultValue !== prevDefaultValue) {
|
||||
setValue(defaultValue);
|
||||
}
|
||||
}, [defaultValue, prevDefaultValue]);
|
||||
|
||||
useDidUpdate(() => {
|
||||
fiedRef.current.blur();
|
||||
}, [blurFieldState]);
|
||||
|
||||
return (
|
||||
<TextArea
|
||||
ref={handleFieldRef}
|
||||
as={TextareaAutosize}
|
||||
value={value}
|
||||
maxLength={1024}
|
||||
spellCheck={false}
|
||||
className={classNames(styles.field, styles[`field${upperFirst(size)}`])}
|
||||
onFocus={handleFocus}
|
||||
onKeyDown={handleKeyDown}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
NameField.propTypes = {
|
||||
defaultValue: PropTypes.string.isRequired,
|
||||
size: PropTypes.oneOf(Object.values(Sizes)),
|
||||
onUpdate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
NameField.defaultProps = {
|
||||
size: Sizes.MEDIUM,
|
||||
};
|
||||
|
||||
export default NameField;
|
Loading…
Add table
Add a link
Reference in a new issue