Files
cartlog-admin/node_modules/jodit-react/src/JoditEditor.tsx
2026-01-01 15:25:19 +05:30

166 lines
3.5 KiB
TypeScript

import React, { useEffect, useRef, forwardRef } from 'react';
import type { IJodit } from 'jodit/esm/types/jodit';
import type { Jodit as JoditBaseConstructor } from 'jodit/esm/index';
import type { Config } from 'jodit/esm/config';
import { Jodit } from './include.jodit';
import type { DeepPartial } from 'jodit/esm/types';
function usePrevious(value: string): string {
const ref = useRef<string>('');
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
interface Props<T extends typeof JoditBaseConstructor = typeof Jodit> {
JoditConstructor?: T;
config?: DeepPartial<Config>;
className?: string;
id?: string;
name?: string;
onBlur?: (value: string, event: MouseEvent) => void;
onChange?: (value: string) => void;
tabIndex?: number;
value?: string;
editorRef?: (editor: IJodit) => void;
}
const JoditEditor = forwardRef<IJodit, Props>(
(
{
JoditConstructor = Jodit,
className,
config,
id,
name,
onBlur,
onChange,
tabIndex,
value,
editorRef
},
ref
) => {
const textAreaRef = useRef<HTMLTextAreaElement | null>(null);
const joditRef = useRef<IJodit | null>(null);
useEffect(() => {
const element = textAreaRef.current!;
const jodit = JoditConstructor.make(element, config);
joditRef.current = jodit;
if (typeof editorRef === 'function') {
editorRef(jodit);
}
return () => {
if (jodit.isReady) {
jodit.destruct();
} else {
jodit
.waitForReady()
.then(joditInstance => joditInstance.destruct());
}
};
}, [JoditConstructor, config, editorRef]);
useEffect(() => {
if (ref) {
if (typeof ref === 'function') {
ref(joditRef.current);
} else {
ref.current = joditRef.current;
}
}
}, [textAreaRef, ref, joditRef]);
const preClassName = usePrevious(className ?? '');
useEffect(() => {
const classList = joditRef.current?.container?.classList;
if (
preClassName !== className &&
typeof preClassName === 'string'
) {
preClassName
.split(/\s+/)
.filter(Boolean)
.forEach(cl => classList?.remove(cl));
}
if (className && typeof className === 'string') {
className
.split(/\s+/)
.filter(Boolean)
.forEach(cl => classList?.add(cl));
}
}, [className, preClassName]);
useEffect(() => {
if (joditRef.current?.workplace) {
joditRef.current.workplace.tabIndex = tabIndex || -1;
}
}, [tabIndex]);
useEffect(() => {
const jodit = joditRef.current;
if (!jodit?.events || !(onBlur || onChange)) {
return;
}
const onBlurHandler = (event: MouseEvent) =>
onBlur && onBlur(joditRef?.current?.value ?? '', event);
const onChangeHandler = (value: string) =>
onChange && onChange(value);
// adding event handlers
jodit.events
.on('blur', onBlurHandler)
.on('change', onChangeHandler);
return () => {
// Remove event handlers
jodit.events
?.off('blur', onBlurHandler)
.off('change', onChangeHandler);
};
}, [onBlur, onChange]);
useEffect(() => {
const jodit = joditRef.current;
const updateValue = () => {
if (jodit && value !== undefined && jodit.value !== value) {
jodit.value = value;
}
};
if (jodit) {
if (jodit.isReady) {
updateValue();
} else {
jodit.waitForReady().then(updateValue);
}
}
}, [value]);
return (
<div className={'jodit-react-container'}>
<textarea
defaultValue={value}
name={name}
id={id}
ref={textAreaRef}
/>
</div>
);
}
);
JoditEditor.displayName = 'JoditEditor';
export default JoditEditor;