Files
mwitnessing/components/TextEditor.tsx
2024-02-22 04:19:38 +02:00

196 lines
6.5 KiB
TypeScript

import axiosInstance from '../src/axiosSecure';
import dynamic from 'next/dynamic';
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from 'react';
import 'react-quill/dist/quill.snow.css';
//!!! working
//const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
// const ImageResize = dynamic(() => import('quill-image-resize'), { ssr: false });
const ReactQuill = dynamic(
async () => {
const { default: RQ } = await import('react-quill');
// const { default: ImageUploader } = await import('./ImageUploader/ImageUploader');
const { default: ImageResize } = await import('quill-image-resize');
RQ.Quill.register('modules/imageResize', ImageResize);
return RQ;
},
{
ssr: false,
},
);
// import {
// Dispatch,
// LegacyRef,
// memo,
// SetStateAction,
// useMemo,
// } from 'react';
// interface IQuillEditor extends ReactQuillProps {
// forwardedRef: LegacyRef<ReactQuill>;
// }
// const QuillNoSSRWrapper = dynamic(
// async () => {
// const { default: RQ } = await import('react-quill');
// // eslint-disable-next-line react/display-name
// return function editor({ forwardedRef, ...props }: IQuillEditor) {
// return <RQ ref={forwardedRef} {...props} />;
// };
// },
// { ssr: false }
// );
const formats = [
'header',
'bold',
'italic',
'underline',
'strike',
'blockquote',
'list',
'bullet',
'indent',
'link',
'image',
'code',
'color',
'background',
'code-block',
'align',
];
interface OnChangeHandler {
(e: any): void;
}
type Props = {
value: string;
placeholder: string;
onChange: OnChangeHandler;
prefix: string;
};
const TextEditor: React.FC<Props> = forwardRef((props, ref) => {
const { value, placeholder, onChange, prefix } = props;
const quillRef = useRef(ref);
const handleOnChange = (e) => {
if (quillRef.current) {
const delta = quillRef.current.getEditor().getContents();
const html = quillRef.current.getEditor().getHTML();
onChange(html);
}
};
useImperativeHandle(ref, () => ({
getQuill: () => quillRef.current,
}));
const imageHandler = async () => {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async () => {
const uploadPromises = Array.from(input.files).map(async (item) => {
const formData = new FormData();
formData.append('image', item);
formData.append('prefix', prefix);
try {
const response = await axiosInstance.post('upload', formData);
const imageUrl = response.data.imageUrl;
if (quillRef.current) {
// const editor = quillRef.current.getEditor();
const editor = quillRef.current.getQuill(); // Adjust based on your useImperativeHandle setup
const range = editor.getSelection(true);
editor.insertEmbed(range.index, 'image', imageUrl);
return range.index + 1;
}
} catch (error) {
console.error('Error uploading image:', error);
}
});
const cursorPositions = await Promise.all(uploadPromises);
const lastCursorPosition = cursorPositions.pop();
if (lastCursorPosition !== undefined && quillRef.current) {
const editor = quillRef.current.getEditor();
editor.setSelection(lastCursorPosition);
}
};
};
const modules = React.useMemo(
() => ({
toolbar: {
container: [
// [{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown
[{ header: [1, 2, 3, 4, 5, 6, false] }],
['bold', 'italic', 'underline', 'strike', 'blockquote', 'code-block'],
[{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
['link', 'image'],
[{ color: [] }, { background: [] }, { align: [] }],
['clean'],
],
// container: [
// [{ 'font': [] }], // Dropdown to select font
// [{ 'size': ['small', false, 'large', 'huge'] }], // Dropdown to select font size
// [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
// ['bold', 'italic', 'underline', 'strike'], // toggled buttons
// [{ 'script': 'sub' }, { 'script': 'super' }], // superscript/subscript
// ['blockquote', 'code-block'],
// [{ 'list': 'ordered' }, { 'list': 'bullet' }],
// [{ 'indent': '-1' }, { 'indent': '+1' }], // indent/outdent
// [{ 'direction': 'rtl' }], // text direction
// [{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
// [{ 'align': [] }],
// ['link', 'image', 'video'], // link and image, video
// ['clean'] // remove formatting button
// ],
// we can't fix this so temporary disable it
// handlers: {
// image: imageHandler,
// },
},
imageResize: true
}),
[imageHandler],
);
//test if we ever get the ref!
useEffect(() => {
if (quillRef.current) {
console.log('quillRef.current: ', quillRef.current);
// You can now access the Quill instance directly via quillRef.current.getEditor()
// This is useful for any setup or instance-specific adjustments you might need
}
}, []);
return (
<>
<ReactQuill
ref={quillRef}
theme="snow"
value={value || ''}
modules={modules}
formats={formats}
onChange={onChange}
style={{ height: '500px', width: '100%' }}
placeholder={placeholder}
/>
</>
);
// return <QuillNoSSRWrapper forwardedRef={ref} {...props} />;
});
export default TextEditor;