diff --git a/client/package-lock.json b/client/package-lock.json index 6f912566..b9891269 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -69,6 +69,7 @@ "react-i18next": "^15.5.1", "react-input-mask": "^2.0.4", "react-intersection-observer": "^9.16.0", + "react-mentions": "^4.4.10", "react-photoswipe-gallery": "^2.2.7", "react-redux": "^8.1.3", "react-router-dom": "^6.30.0", @@ -12296,6 +12297,31 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, + "node_modules/react-mentions": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.10.tgz", + "integrity": "sha512-JHiQlgF1oSZR7VYPjq32wy97z1w1oE4x10EuhKjPr4WUKhVzG1uFQhQjKqjQkbVqJrmahf+ldgBTv36NrkpKpA==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "7.4.5", + "invariant": "^2.2.4", + "prop-types": "^15.5.8", + "substyle": "^9.1.0" + }, + "peerDependencies": { + "react": ">=16.8.3", + "react-dom": ">=16.8.3" + } + }, + "node_modules/react-mentions/node_modules/@babel/runtime": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", + "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.13.2" + } + }, "node_modules/react-onclickoutside": { "version": "6.13.2", "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.2.tgz", @@ -12677,6 +12703,12 @@ "node": ">=4" } }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, "node_modules/regexp-match-indices": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz", @@ -14183,6 +14215,19 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==" }, + "node_modules/substyle": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz", + "integrity": "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.4", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": ">=16.8.3" + } + }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", diff --git a/client/package.json b/client/package.json index cf8921fd..c429160a 100755 --- a/client/package.json +++ b/client/package.json @@ -140,6 +140,7 @@ "react-i18next": "^15.5.1", "react-input-mask": "^2.0.4", "react-intersection-observer": "^9.16.0", + "react-mentions": "^4.4.10", "react-photoswipe-gallery": "^2.2.7", "react-redux": "^8.1.3", "react-router-dom": "^6.30.0", diff --git a/client/src/components/comments/Comments/Add.jsx b/client/src/components/comments/Comments/Add.jsx index 56e8b139..cc5f18a0 100755 --- a/client/src/components/comments/Comments/Add.jsx +++ b/client/src/components/comments/Comments/Add.jsx @@ -4,15 +4,17 @@ */ import React, { useCallback, useState } from 'react'; -import { useDispatch } from 'react-redux'; +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 { Button, Form } from 'semantic-ui-react'; +import { MentionsInput, Mention } from 'react-mentions'; import { useClickAwayListener, useDidUpdate, useToggle } from '../../../lib/hooks'; +import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; import { useEscapeInterceptor, useForm, useNestedRef } from '../../../hooks'; import { isModifierKeyPressed } from '../../../utils/event-helpers'; +import UserAvatar, { Sizes } from '../../users/UserAvatar/UserAvatar'; import styles from './Add.module.scss'; @@ -27,9 +29,25 @@ const Add = React.memo(() => { const [data, handleFieldChange, setData] = useForm(DEFAULT_DATA); const [selectTextFieldState, selectTextField] = useToggle(); - const [textFieldRef, handleTextFieldRef] = useNestedRef(); + const textFieldRef = React.createRef(); const [buttonRef, handleButtonRef] = useNestedRef(); + const mentionsInputStyle = { + control: { + minHeight: isOpened ? '60px' : '36px', + }, + }; + + const renderSuggestion = useCallback( + (suggestion, search, highlightedDisplay) => ( +