diff --git a/src/components/RichTextEditor/BlockStyleButtons.jsx b/src/components/RichTextEditor/BlockStyleButtons.jsx index 050614c8f..64aa846e0 100644 --- a/src/components/RichTextEditor/BlockStyleButtons.jsx +++ b/src/components/RichTextEditor/BlockStyleButtons.jsx @@ -17,7 +17,7 @@ const BLOCK_TYPES = [ ]; const BlockStyleButtons = (props) => { - const { editorState } = props; + const { editorState, disabled } = props; const selection = editorState.getSelection(); const blockType = editorState.getCurrentContent().getBlockForKey(selection.getStartKey()).getType(); @@ -32,6 +32,7 @@ const BlockStyleButtons = (props) => { label={type.label} onToggle={() => onToggle(type.style)} aria-label={type.ariaLabel} + disabled={disabled} /> )); }; diff --git a/src/components/RichTextEditor/FilePreviewList.jsx b/src/components/RichTextEditor/FilePreviewList.jsx index 9e9557f2f..fa8b233b5 100644 --- a/src/components/RichTextEditor/FilePreviewList.jsx +++ b/src/components/RichTextEditor/FilePreviewList.jsx @@ -3,11 +3,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import FileSticker from './FileSticker'; -const FilePreviewList = ({ files, onFileRemove }) => +const FilePreviewList = ({ files, onFileRemove, disabled }) => _.isEmpty(files) ? null : (
{_.map(files, (file, index) => ( - + ))}
); @@ -17,4 +17,5 @@ export default FilePreviewList; FilePreviewList.propTypes = { files: PropTypes.object, onFileRemove: PropTypes.func, + disabled: PropTypes.bool, }; diff --git a/src/components/RichTextEditor/FileSticker.d.ts b/src/components/RichTextEditor/FileSticker.d.ts index 778c2910d..c2daa8172 100644 --- a/src/components/RichTextEditor/FileSticker.d.ts +++ b/src/components/RichTextEditor/FileSticker.d.ts @@ -10,6 +10,7 @@ export interface FileStickerFile { export interface FileStickerProps { file?: FileStickerFile; onFileRemove?: (...args: any[]) => any; + disabled?: boolean; } declare const FileSticker: React.FC; diff --git a/src/components/RichTextEditor/FileSticker.jsx b/src/components/RichTextEditor/FileSticker.jsx index fcdb660f0..341eca304 100644 --- a/src/components/RichTextEditor/FileSticker.jsx +++ b/src/components/RichTextEditor/FileSticker.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import Spinner from '../Spinner'; -const FileSticker = ({ onFileRemove, file }) => { +const FileSticker = ({ onFileRemove, file, disabled }) => { const [showClose, setShowClose] = React.useState(false); const { name, path, isUploading } = file; const isImage = /\.(jpe?g|png)$/i.test(name); @@ -27,11 +27,12 @@ const FileSticker = ({ onFileRemove, file }) => { )} {showClose && ( - )} {isUploading && } @@ -49,4 +50,5 @@ FileSticker.propTypes = { isUploading: PropTypes.bool, }), onFileRemove: PropTypes.func, + disabled: PropTypes.bool, }; diff --git a/src/components/RichTextEditor/FileUploadAction.d.ts b/src/components/RichTextEditor/FileUploadAction.d.ts index 723db4c9f..4d1b03f6b 100644 --- a/src/components/RichTextEditor/FileUploadAction.d.ts +++ b/src/components/RichTextEditor/FileUploadAction.d.ts @@ -3,6 +3,7 @@ import * as React from 'react'; export interface FileUploadActionProps { onFileUpload?: (...args: any[]) => any; fileFilter?: string; + disabled?: boolean; } declare const FileUploadAction: React.FC; diff --git a/src/components/RichTextEditor/FileUploadAction.jsx b/src/components/RichTextEditor/FileUploadAction.jsx index af58957bd..49d3b9c1b 100644 --- a/src/components/RichTextEditor/FileUploadAction.jsx +++ b/src/components/RichTextEditor/FileUploadAction.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ToolbarButton from './ToolbarButton'; -const FileUploadAction = ({ onFileUpload, fileFilter }) => { +const FileUploadAction = ({ onFileUpload, fileFilter, disabled }) => { const fileInputRef = React.useRef(); const onFileChange = (e) => { @@ -12,28 +12,35 @@ const FileUploadAction = ({ onFileUpload, fileFilter }) => { return ( <> } + label={
} onToggle={() => { fileInputRef.current.value = ''; fileInputRef.current.click(); }} - aria-label="Download file" + aria-label="Upload file" + disabled={disabled} /> ); }; -export default FileUploadAction; +FileUploadAction.defaultProps = { + disabled: false, +}; FileUploadAction.propTypes = { onFileUpload: PropTypes.func, fileFilter: PropTypes.string, + disabled: PropTypes.bool, }; + +export default FileUploadAction; diff --git a/src/components/RichTextEditor/InlineStyleButtons.jsx b/src/components/RichTextEditor/InlineStyleButtons.jsx index 4a676a96e..f0afc4405 100644 --- a/src/components/RichTextEditor/InlineStyleButtons.jsx +++ b/src/components/RichTextEditor/InlineStyleButtons.jsx @@ -18,6 +18,7 @@ const INLINE_STYLES = [ ]; const InlineStyleButtons = (props) => { + const { disabled } = props; const currentStyle = props.editorState.getCurrentInlineStyle(); const onToggle = (style) => { @@ -31,6 +32,7 @@ const InlineStyleButtons = (props) => { label={type.label} onToggle={() => onToggle(type.style)} aria-label={type.ariaLabel} + disabled={disabled} /> )); }; diff --git a/src/components/RichTextEditor/ToolbarButton.d.ts b/src/components/RichTextEditor/ToolbarButton.d.ts index 46fa96486..f51e02132 100644 --- a/src/components/RichTextEditor/ToolbarButton.d.ts +++ b/src/components/RichTextEditor/ToolbarButton.d.ts @@ -4,6 +4,7 @@ export interface ToolbarButtonProps { onToggle: (...args: any[]) => any; label: React.ReactNode; active?: boolean; + disabled?: boolean; } declare const ToolbarButton: React.FC; diff --git a/src/components/RichTextEditor/ToolbarButton.jsx b/src/components/RichTextEditor/ToolbarButton.jsx index 67031a57c..c55458165 100644 --- a/src/components/RichTextEditor/ToolbarButton.jsx +++ b/src/components/RichTextEditor/ToolbarButton.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import Button from '../Button'; -const ToolbarButton = ({ onToggle, label, active, ...rest }) => { +const ToolbarButton = ({ onToggle, label, active, disabled, ...rest }) => { const className = classnames('aui--toolbar-button', { active, }); @@ -18,16 +18,22 @@ const ToolbarButton = ({ onToggle, label, active, ...rest }) => { ); return ( - ); }; +ToolbarButton.defaultProps = { + active: false, + disabled: false, +}; + ToolbarButton.propTypes = { onToggle: PropTypes.func.isRequired, label: PropTypes.node.isRequired, active: PropTypes.bool, + disabled: PropTypes.bool, }; export default ToolbarButton; diff --git a/src/components/RichTextEditor/index.d.ts b/src/components/RichTextEditor/index.d.ts index e8499bf86..8fe0afcf1 100644 --- a/src/components/RichTextEditor/index.d.ts +++ b/src/components/RichTextEditor/index.d.ts @@ -18,6 +18,7 @@ export interface RichTextEditorProps { onFileSelect?: (...args: any[]) => any; onFileRemove?: (...args: any[]) => any; fileFilter?: string; + disabled?: boolean; } declare const RichTextEditor: React.FC & { diff --git a/src/components/RichTextEditor/index.jsx b/src/components/RichTextEditor/index.jsx index abf183730..44aed6a7d 100644 --- a/src/components/RichTextEditor/index.jsx +++ b/src/components/RichTextEditor/index.jsx @@ -44,6 +44,7 @@ const RichTextEditor = ({ onFileSelect, onFileRemove, fileFilter, + disabled, }) => { const editor = React.createRef(null); const focusEditor = () => editor.current.focus(); @@ -163,6 +164,7 @@ const RichTextEditor = ({ plugins={editorPlugins} ref={editor} spellCheck + readOnly={disabled} /> {!_.isEmpty(mentions) && ( )}
- +
- - + +
{!_.isEmpty(mentions) && ( @@ -202,7 +204,7 @@ const RichTextEditor = ({ /> )} {_.isFunction(onFileSelect) && _.isFunction(onFileRemove) && ( - + )}
@@ -226,11 +228,13 @@ RichTextEditor.propTypes = { onFileSelect: PropTypes.func, onFileRemove: PropTypes.func, fileFilter: PropTypes.string, + disabled: PropTypes.bool, }; RichTextEditor.defaultProps = { placeholder: 'Tell a story...', fileFilter: '.jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.psd,.csv,.zip,.7z', + disabled: false, }; RichTextEditor.createEmpty = EditorState.createEmpty; @@ -238,7 +242,7 @@ RichTextEditor.createWithText = createEditorStateWithText; RichTextEditor.stateToHTML = editorStateToHTML; /** * @example - * // parser exaple with dom-purify + * // parser example with dom-purify * const DOMPurifyDefaultConfig = { * USE_PROFILES: { html: true }, * FORBID_TAGS: ['style'], diff --git a/src/components/RichTextEditor/index.spec.jsx b/src/components/RichTextEditor/index.spec.jsx index 3dc1bc10e..3a9918c11 100644 --- a/src/components/RichTextEditor/index.spec.jsx +++ b/src/components/RichTextEditor/index.spec.jsx @@ -240,7 +240,7 @@ describe('', () => { render(); expect(screen.getByTestId('rich-text-editor-wrapper')).toBeInTheDocument(); - expect(screen.getByTestId('file-download-button')).toBeInTheDocument(); + expect(screen.getByTestId('file-upload-button')).toBeInTheDocument(); }); it('should be able to select a pdf file when clicking file upload button', async () => { @@ -251,9 +251,9 @@ describe('', () => { render(); expect(onFileSelect).toHaveBeenCalledTimes(0); - await user.click(screen.getByLabelText('Download file')); + await user.click(screen.getByLabelText('Upload file')); const file = new File(['test'], 'test.pdf', { type: 'application/pdf' }); - await user.upload(screen.getByTestId('file-download-input'), file); + await user.upload(screen.getByTestId('file-upload-input'), file); expect(onFileSelect).toHaveBeenCalledTimes(1); }); @@ -264,7 +264,7 @@ describe('', () => { render(); - await user.upload(screen.getByTestId('file-download-input'), new File(['test'], 'file.pdf')); + await user.upload(screen.getByTestId('file-upload-input'), new File(['test'], 'file.pdf')); const preview = await screen.findByTestId('file-preview-list'); await waitFor(() => { @@ -285,7 +285,7 @@ describe('', () => { render(); - await user.upload(screen.getByTestId('file-download-input'), new File(['test'], 'file.pdf')); + await user.upload(screen.getByTestId('file-upload-input'), new File(['test'], 'file.pdf')); const preview = await screen.findByTestId('file-preview-list'); await waitFor(() => { @@ -304,7 +304,7 @@ describe('', () => { const onChange = jest.fn(); render(); - await user.upload(screen.getByTestId('file-download-input'), new File(['test'], 'test.png')); + await user.upload(screen.getByTestId('file-upload-input'), new File(['test'], 'test.png')); expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument(); }); @@ -314,7 +314,7 @@ describe('', () => { const onChange = jest.fn(); render(); - await user.upload(screen.getByTestId('file-download-input'), new File(['test'], 'test.png')); + await user.upload(screen.getByTestId('file-upload-input'), new File(['test'], 'test.png')); const preview = await screen.findByTestId('file-preview-list'); await waitFor(() => { diff --git a/src/components/RichTextEditor/styles.css b/src/components/RichTextEditor/styles.css index cb38e3724..2eafe2578 100644 --- a/src/components/RichTextEditor/styles.css +++ b/src/components/RichTextEditor/styles.css @@ -35,7 +35,7 @@ z-index: 10; } -.aui--editor-root .file-download-input { +.aui--editor-root .file-upload-input { display: none; } @@ -61,7 +61,7 @@ margin-right: 0; } -.aui--editor-root .aui--editor-toolbar .aui--toolbar-button .file-download-button { +.aui--editor-root .aui--editor-toolbar .aui--toolbar-button .file-upload-button { background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40.2 40.2'%3E%3Cpath d='M35.6,5.6c-1.1-1.1-2.6-1.8-4.2-1.8c-1.6,0-3,0.6-4.2,1.8l-15.7,16c-1.6,1.6-1.6,4.3,0,6c1.6,1.6,4.3,1.6,5.9,0L29,15.9c0.3-0.3,0.3-0.8,0-1c-0.3-0.3-0.8-0.3-1,0L16.4,26.6c-1,1-2.8,1-3.8,0c-1.1-1.1-1.1-2.8,0-3.9l15.7-16C30,5,32.9,5,34.6,6.7c1.7,1.8,1.7,4.6,0,6.4L14.9,33c-1.2,1.2-2.7,1.8-4.3,1.8S7.4,34.2,6.3,33c-2.4-2.4-2.4-6.4,0-8.8L21.7,8.5c0.3-0.3,0.3-0.8,0-1c-0.3-0.3-0.8-0.3-1,0L5.3,23.2c-2.9,3-2.9,7.9,0,10.9c1.4,1.5,3.3,2.3,5.4,2.3c2,0,3.9-0.8,5.4-2.3l19.6-20C37.9,11.7,37.9,7.9,35.6,5.6z'%3E%3C/path%3E%3C/svg%3E"); width: 18px; height: 18px;