Skip to content

Commit

Permalink
fix: add readOnly rte state
Browse files Browse the repository at this point in the history
  • Loading branch information
adityasabnis committed Oct 15, 2024
1 parent b8361d6 commit 4e9a0dc
Show file tree
Hide file tree
Showing 13 changed files with 54 additions and 27 deletions.
3 changes: 2 additions & 1 deletion src/components/RichTextEditor/BlockStyleButtons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -32,6 +32,7 @@ const BlockStyleButtons = (props) => {
label={type.label}
onToggle={() => onToggle(type.style)}
aria-label={type.ariaLabel}
disabled={disabled}
/>
));
};
Expand Down
5 changes: 3 additions & 2 deletions src/components/RichTextEditor/FilePreviewList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 : (
<div data-testid="file-preview-list" className="aui--file-preview-list">
{_.map(files, (file, index) => (
<FileSticker key={index} onFileRemove={onFileRemove} file={file} />
<FileSticker key={index} onFileRemove={onFileRemove} file={file} disabled={disabled} />
))}
</div>
);
Expand All @@ -17,4 +17,5 @@ export default FilePreviewList;
FilePreviewList.propTypes = {
files: PropTypes.object,
onFileRemove: PropTypes.func,
disabled: PropTypes.bool,
};
1 change: 1 addition & 0 deletions src/components/RichTextEditor/FileSticker.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface FileStickerFile {
export interface FileStickerProps {
file?: FileStickerFile;
onFileRemove?: (...args: any[]) => any;
disabled?: boolean;
}

declare const FileSticker: React.FC<FileStickerProps>;
Expand Down
6 changes: 4 additions & 2 deletions src/components/RichTextEditor/FileSticker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -27,11 +27,12 @@ const FileSticker = ({ onFileRemove, file }) => {
</div>
)}
{showClose && (
<span
<input
className="aui--file-sticker-close-button"
data-testid="file-sticker-close-button"
onClick={onStickerRemove}
role="button"
disabled={disabled}
/>
)}
{isUploading && <Spinner className="aui--file-sticker-spinner" size="small" />}
Expand All @@ -49,4 +50,5 @@ FileSticker.propTypes = {
isUploading: PropTypes.bool,
}),
onFileRemove: PropTypes.func,
disabled: PropTypes.bool,
};
1 change: 1 addition & 0 deletions src/components/RichTextEditor/FileUploadAction.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<FileUploadActionProps>;
Expand Down
19 changes: 13 additions & 6 deletions src/components/RichTextEditor/FileUploadAction.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -12,28 +12,35 @@ const FileUploadAction = ({ onFileUpload, fileFilter }) => {
return (
<>
<ToolbarButton
label={<div data-testid="file-download-button" className="file-download-button" />}
label={<div data-testid="file-upload-button" className="file-upload-button" />}
onToggle={() => {
fileInputRef.current.value = '';
fileInputRef.current.click();
}}
aria-label="Download file"
aria-label="Upload file"
disabled={disabled}
/>
<input
data-testid="file-download-input"
className="file-download-input"
data-testid="file-upload-input"
className="file-upload-input"
ref={fileInputRef}
type="file"
onChange={onFileChange}
accept={fileFilter}
disabled={disabled}
/>
</>
);
};

export default FileUploadAction;
FileUploadAction.defaultProps = {
disabled: false,
};

FileUploadAction.propTypes = {
onFileUpload: PropTypes.func,
fileFilter: PropTypes.string,
disabled: PropTypes.bool,
};

export default FileUploadAction;
2 changes: 2 additions & 0 deletions src/components/RichTextEditor/InlineStyleButtons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const INLINE_STYLES = [
];

const InlineStyleButtons = (props) => {
const { disabled } = props;
const currentStyle = props.editorState.getCurrentInlineStyle();

const onToggle = (style) => {
Expand All @@ -31,6 +32,7 @@ const InlineStyleButtons = (props) => {
label={type.label}
onToggle={() => onToggle(type.style)}
aria-label={type.ariaLabel}
disabled={disabled}
/>
));
};
Expand Down
1 change: 1 addition & 0 deletions src/components/RichTextEditor/ToolbarButton.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface ToolbarButtonProps {
onToggle: (...args: any[]) => any;
label: React.ReactNode;
active?: boolean;
disabled?: boolean;
}

declare const ToolbarButton: React.FC<ToolbarButtonProps>;
Expand Down
10 changes: 8 additions & 2 deletions src/components/RichTextEditor/ToolbarButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
Expand All @@ -18,16 +18,22 @@ const ToolbarButton = ({ onToggle, label, active, ...rest }) => {
);

return (
<Button className={className} onMouseDown={mouseDownHandler} {...rest}>
<Button className={className} onMouseDown={mouseDownHandler} disabled={disabled} {...rest}>
{label}
</Button>
);
};

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;
1 change: 1 addition & 0 deletions src/components/RichTextEditor/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface RichTextEditorProps {
onFileSelect?: (...args: any[]) => any;
onFileRemove?: (...args: any[]) => any;
fileFilter?: string;
disabled?: boolean;
}

declare const RichTextEditor: React.FC<RichTextEditorProps> & {
Expand Down
14 changes: 9 additions & 5 deletions src/components/RichTextEditor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const RichTextEditor = ({
onFileSelect,
onFileRemove,
fileFilter,
disabled,
}) => {
const editor = React.createRef(null);
const focusEditor = () => editor.current.focus();
Expand Down Expand Up @@ -163,6 +164,7 @@ const RichTextEditor = ({
plugins={editorPlugins}
ref={editor}
spellCheck
readOnly={disabled}
/>
{!_.isEmpty(mentions) && (
<MentionList
Expand All @@ -186,11 +188,11 @@ const RichTextEditor = ({
/>
)}
</div>
<FilePreviewList files={files} onFileRemove={handleFileRemove} />
<FilePreviewList files={files} onFileRemove={handleFileRemove} disabled={disabled} />
<div className="aui--editor-toolbar">
<div className="aui--editor-style-buttons">
<InlineStyleButtons editorState={editorState} onToggle={handleOnChange} />
<BlockStyleButtons editorState={editorState} onToggle={handleOnChange} />
<InlineStyleButtons editorState={editorState} onToggle={handleOnChange} disabled={disabled} />
<BlockStyleButtons editorState={editorState} onToggle={handleOnChange} disabled={disabled} />
</div>
<div data-testid="rich-text-editor-advanced-buttons" className="aui--editor-advanced-buttons">
{!_.isEmpty(mentions) && (
Expand All @@ -202,7 +204,7 @@ const RichTextEditor = ({
/>
)}
{_.isFunction(onFileSelect) && _.isFunction(onFileRemove) && (
<FileUploadAction fileFilter={fileFilter} onFileUpload={handleFileUpload} />
<FileUploadAction fileFilter={fileFilter} onFileUpload={handleFileUpload} disabled={disabled} />
)}
</div>
</div>
Expand All @@ -226,19 +228,21 @@ 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;
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'],
Expand Down
14 changes: 7 additions & 7 deletions src/components/RichTextEditor/index.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ describe('<RichTextEditor />', () => {
render(<RichTextEditor onFileSelect={onFileSelect} onFileRemove={onFileRemove} onChange={onChange} />);

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 () => {
Expand All @@ -251,9 +251,9 @@ describe('<RichTextEditor />', () => {
render(<RichTextEditor onFileSelect={onFileSelect} onFileRemove={onFileRemove} onChange={onChange} />);

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);
});

Expand All @@ -264,7 +264,7 @@ describe('<RichTextEditor />', () => {

render(<RichTextEditor onFileSelect={onFileSelect} onFileRemove={onFileRemove} onChange={onChange} />);

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(() => {
Expand All @@ -285,7 +285,7 @@ describe('<RichTextEditor />', () => {

render(<RichTextEditor onFileSelect={onFileSelect} onFileRemove={onFileRemove} onChange={onChange} />);

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(() => {
Expand All @@ -304,7 +304,7 @@ describe('<RichTextEditor />', () => {
const onChange = jest.fn();
render(<RichTextEditor onFileSelect={onFileSelect} onFileRemove={onFileRemove} onChange={onChange} />);

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();
});

Expand All @@ -314,7 +314,7 @@ describe('<RichTextEditor />', () => {
const onChange = jest.fn();
render(<RichTextEditor onFileSelect={onFileSelect} onFileRemove={onFileRemove} onChange={onChange} />);

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(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/RichTextEditor/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
z-index: 10;
}

.aui--editor-root .file-download-input {
.aui--editor-root .file-upload-input {
display: none;
}

Expand All @@ -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;
Expand Down

0 comments on commit 4e9a0dc

Please sign in to comment.