mirror of
https://github.com/plankanban/planka.git
synced 2025-07-19 13:19:44 +02:00
fix: Add mentions support when editing comments
This commit is contained in:
parent
6c2999044b
commit
fc7863aaaf
3 changed files with 84 additions and 32 deletions
|
@ -20,7 +20,6 @@
|
|||
margin-bottom: 8px !important;
|
||||
|
||||
textarea {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(9, 30, 66, 0.13);
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
*/
|
||||
|
||||
import { dequal } from 'dequal';
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import TextareaAutosize from 'react-textarea-autosize';
|
||||
import { Button, Form, TextArea } from 'semantic-ui-react';
|
||||
import { Mention, MentionsInput } from 'react-mentions';
|
||||
import { Button, Form } from 'semantic-ui-react';
|
||||
import { useClickAwayListener } from '../../../lib/hooks';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
|
@ -17,6 +17,7 @@ import entryActions from '../../../entry-actions';
|
|||
import { useForm, useNestedRef } from '../../../hooks';
|
||||
import { focusEnd } from '../../../utils/element-helpers';
|
||||
import { isModifierKeyPressed } from '../../../utils/event-helpers';
|
||||
import UserAvatar from '../../users/UserAvatar';
|
||||
|
||||
import styles from './Edit.module.scss';
|
||||
|
||||
|
@ -24,6 +25,7 @@ const Edit = React.memo(({ commentId, onClose }) => {
|
|||
const selectCommentById = useMemo(() => selectors.makeSelectCommentById(), []);
|
||||
|
||||
const comment = useSelector((state) => selectCommentById(state, commentId));
|
||||
const boardMemberships = useSelector(selectors.selectMembershipsForCurrentBoard);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
@ -35,12 +37,13 @@ const Edit = React.memo(({ commentId, onClose }) => {
|
|||
[comment.text],
|
||||
);
|
||||
|
||||
const [data, handleFieldChange] = useForm(() => ({
|
||||
const [data, , setData] = useForm(() => ({
|
||||
text: '',
|
||||
...defaultData,
|
||||
}));
|
||||
|
||||
const [textFieldRef, handleTextFieldRef] = useNestedRef();
|
||||
const mentionsInputRef = useRef(null);
|
||||
const textFieldRef = useRef(null);
|
||||
const [buttonRef, handleButtonRef] = useNestedRef();
|
||||
|
||||
const submit = useCallback(() => {
|
||||
|
@ -60,6 +63,15 @@ const Edit = React.memo(({ commentId, onClose }) => {
|
|||
submit();
|
||||
}, [submit]);
|
||||
|
||||
const handleFieldChange = useCallback(
|
||||
(_, text) => {
|
||||
setData({
|
||||
text,
|
||||
});
|
||||
},
|
||||
[setData],
|
||||
);
|
||||
|
||||
const handleFieldKeyDown = useCallback(
|
||||
(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
|
@ -83,25 +95,53 @@ const Edit = React.memo(({ commentId, onClose }) => {
|
|||
handleClickAwayCancel,
|
||||
);
|
||||
|
||||
const suggestionRenderer = useCallback(
|
||||
(entry, _, highlightedDisplay) => (
|
||||
<div className={styles.suggestion}>
|
||||
<UserAvatar id={entry.id} size="tiny" />
|
||||
{highlightedDisplay}
|
||||
</div>
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
focusEnd(textFieldRef.current);
|
||||
}, [textFieldRef]);
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<TextArea
|
||||
{...clickAwayProps} // eslint-disable-line react/jsx-props-no-spreading
|
||||
ref={handleTextFieldRef}
|
||||
as={TextareaAutosize}
|
||||
name="text"
|
||||
value={data.text}
|
||||
maxLength={1048576}
|
||||
minRows={3}
|
||||
spellCheck={false}
|
||||
className={styles.field}
|
||||
onKeyDown={handleFieldKeyDown}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<div className={styles.field}>
|
||||
<MentionsInput
|
||||
{...clickAwayProps} // eslint-disable-line react/jsx-props-no-spreading
|
||||
allowSpaceInQuery
|
||||
allowSuggestionsAboveCursor
|
||||
ref={mentionsInputRef}
|
||||
inputRef={textFieldRef}
|
||||
value={data.text}
|
||||
maxLength={1048576}
|
||||
rows={3}
|
||||
className="mentions-input"
|
||||
style={{
|
||||
control: {
|
||||
minHeight: '79px',
|
||||
},
|
||||
}}
|
||||
onChange={handleFieldChange}
|
||||
onKeyDown={handleFieldKeyDown}
|
||||
>
|
||||
<Mention
|
||||
appendSpaceOnAdd
|
||||
data={boardMemberships.map(({ user }) => ({
|
||||
id: user.id,
|
||||
display: user.username || user.name,
|
||||
}))}
|
||||
displayTransform={(_, display) => `@${display}`}
|
||||
renderSuggestion={suggestionRenderer}
|
||||
className={styles.mention}
|
||||
/>
|
||||
</MentionsInput>
|
||||
</div>
|
||||
<div className={styles.controls}>
|
||||
<Button
|
||||
{...clickAwayProps} // eslint-disable-line react/jsx-props-no-spreading
|
||||
|
|
|
@ -11,20 +11,33 @@
|
|||
|
||||
.field {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(9, 30, 66, 0.13);
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
color: #333;
|
||||
display: block;
|
||||
line-height: 1.4;
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
padding: 8px 12px;
|
||||
resize: none;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
textarea {
|
||||
border: 1px solid rgba(9, 30, 66, 0.13);
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
color: #333;
|
||||
display: block;
|
||||
line-height: 1.4;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
padding: 8px 12px;
|
||||
resize: none;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mention {
|
||||
background-color: #f1f8ff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.suggestion {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue