diff --git a/GUI/package.json b/GUI/package.json index d2fddb6f6..c0be68760 100644 --- a/GUI/package.json +++ b/GUI/package.json @@ -59,12 +59,13 @@ "react-textarea-autosize": "^8.4.0", "reactflow": "^11.4.0", "regexify-string": "^1.0.19", + "rich-textarea": "^0.26.4", "rxjs": "^7.8.1", "timeago.js": "^4.0.2", + "use-debounce": "^10.0.1", "usehooks-ts": "^2.9.1", "uuid": "^9.0.0", - "zustand": "^4.4.4", - "use-debounce": "^10.0.1" + "zustand": "^4.4.4" }, "devDependencies": { "@types/howler": "^2.2.11", diff --git a/GUI/src/components/FormElements/FormTextarea/index.tsx b/GUI/src/components/FormElements/FormTextarea/index.tsx index 4190c782e..bb16cae2f 100644 --- a/GUI/src/components/FormElements/FormTextarea/index.tsx +++ b/GUI/src/components/FormElements/FormTextarea/index.tsx @@ -1,72 +1,133 @@ import { ChangeEvent, forwardRef, useId, useState } from 'react'; -import TextareaAutosize, { TextareaAutosizeProps } from 'react-textarea-autosize'; +import TextareaAutosize, { + TextareaAutosizeProps, +} from 'react-textarea-autosize'; +import { + createRegexRenderer, + RichTextarea, + RichTextareaProps, +} from 'rich-textarea'; import clsx from 'clsx'; import './FormTextarea.scss'; -type TextareaProps = TextareaAutosizeProps & { - label: string; - name: string; - hideLabel?: boolean; - showMaxLength?: boolean; - maxLengthBottom?: boolean; -}; +type TextareaProps = TextareaAutosizeProps & + RichTextareaProps & { + label: string; + name: string; + hideLabel?: boolean; + showMaxLength?: boolean; + maxLengthBottom?: boolean; + useRichText?: boolean; + }; -const FormTextarea = forwardRef(( - { - label, - name, - maxLength = 2000, - minRows = 3, - maxRows = 3, - disabled, - hideLabel, - showMaxLength, - maxLengthBottom, - defaultValue, - onChange, - ...rest - }, - ref, -) => { - const id = useId(); - const [currentLength, setCurrentLength] = useState((typeof defaultValue === 'string' && defaultValue.length) || 0); - const textareaClasses = clsx( - 'textarea', - disabled && 'textarea--disabled', - showMaxLength && 'textarea--maxlength-shown', - ); +const FormTextarea = forwardRef( + ( + { + label, + name, + maxLength = 2000, + minRows = 3, + maxRows = 3, + disabled, + hideLabel, + showMaxLength, + maxLengthBottom, + defaultValue, + useRichText, + onChange, + ...rest + }, + ref + ) => { + const id = useId(); + const [currentLength, setCurrentLength] = useState( + (typeof defaultValue === 'string' && defaultValue.length) || 0 + ); + const textareaClasses = clsx( + 'textarea', + disabled && 'textarea--disabled', + showMaxLength && 'textarea--maxlength-shown' + ); - const handleOnChange = (e: ChangeEvent) => { - if (showMaxLength) { - setCurrentLength(e.target.value.length); - } - }; + const handleOnChange = (e: ChangeEvent) => { + if (showMaxLength) { + setCurrentLength(e.target.value.length); + } + }; - return ( -
- {label && !hideLabel && } -
- { - if (onChange) onChange(e); - handleOnChange(e); - }} - {...rest} - /> - {showMaxLength && ( -
{currentLength}/{maxLength}
+ return ( +
+ {label && !hideLabel && ( + )} +
+ {useRichText ? ( + { + if (onChange) onChange(e); + handleOnChange(e); + }} + > + {createRegexRenderer([ + [ + /https?:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+/g, + ({ children, key, value }) => ( + + {children} + + ), + ], + ])} + + ) : ( + { + if (onChange) onChange(e); + handleOnChange(e); + }} + {...rest} + /> + )} + {showMaxLength && ( +
+ {currentLength}/{maxLength} +
+ )} +
-
- ); -}); + ); + } +); export default FormTextarea; diff --git a/GUI/src/pages/Settings/SettingsWorkingTime/index.tsx b/GUI/src/pages/Settings/SettingsWorkingTime/index.tsx index 84b611e17..411a705de 100644 --- a/GUI/src/pages/Settings/SettingsWorkingTime/index.tsx +++ b/GUI/src/pages/Settings/SettingsWorkingTime/index.tsx @@ -458,13 +458,13 @@ const SettingsWorkingTime: FC = () => { render={({ field }) => ( )} /> @@ -507,13 +507,13 @@ const SettingsWorkingTime: FC = () => { render={({ field }) => ( )} />