196 lines
6.5 KiB
TypeScript
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; |