UNPKG

react-text-editor-kit

Version:

React Text Editor Kit is a customizable rich text editor component for React applications. It provides a flexible and easy-to-use interface for users to create and edit content with various formatting options. And also easy to integrate in react applicati

144 lines (129 loc) 4.23 kB
import React, { useEffect, useRef, useState } from "react"; import Styles from "../css/style.module.css"; import ArrowDown from "./SVGImages/ArrowDown"; function SelectFormat({ remove_from_toolbar, editorRef, isDisable }) { const [isOpen, setIsOpen] = useState(false); const [selectedOption, setSelectedOption] = useState("Paragraph"); const selectRef = useRef(null); let formats = [ { label: "Paragraph", value: "p" }, { label: "Heading 1", value: "h1" }, { label: "Heading 2", value: "h2" }, { label: "Heading 3", value: "h3" }, { label: "Heading 4", value: "h4" }, { label: "Heading 5", value: "h5" }, { label: "Heading 6", value: "h6" }, { label: "Blockquote", value: "blockquote" }, { label: "Preformatted", value: "pre" }, ]; if (remove_from_toolbar?.length > 0) { let find_remove = remove_from_toolbar.find( (toolbar) => toolbar.name === "format" ); if (find_remove?.options?.length > 0) { formats = formats.filter( (item) => !find_remove?.options.includes(item.value) ); } } const toggleSelect = (e) => { if (isDisable) { return; } e.preventDefault(); setIsOpen(!isOpen); }; const handleOptionClick = (e, option) => { e.preventDefault(); editorRef.current.focus(); document.execCommand("formatBlock", false, option.value); setSelectedOption(option.label); setIsOpen(false); }; const getClosestBlockElement = () => { const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); const commonAncestorContainer = range.commonAncestorContainer; let node = commonAncestorContainer; while (node) { if (node.nodeName.match(/^(p|div|h[1-6]|blockquote|pre)$/i)) { return node.nodeName.toLowerCase(); } node = node.parentNode; } } return null; }; const handleKeyDown = () => { const editor = editorRef.current; if (!editor) return; if (!editor.contains(window.getSelection().anchorNode)) { return; } editor.focus(); if (editor.innerText.trim() === "") { setSelectedOption("Paragraph"); } }; useEffect(() => { const handleClickOutside = (event) => { if (!selectRef.current.contains(event.target)) { setIsOpen(false); } }; const handleSelectionChange = () => { if (editorRef?.current?.contains(window.getSelection().anchorNode)) { const formatBlock = getClosestBlockElement(); if (formatBlock) { let find = formats.find((format) => format.value === formatBlock); if (find) { setSelectedOption(find.label); } else { setSelectedOption("Paragraph"); } } } }; document.addEventListener("click", handleClickOutside); document.addEventListener("selectionchange", handleSelectionChange); document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("click", handleClickOutside); document.removeEventListener("selectionchange", handleSelectionChange); document.removeEventListener("keydown", handleKeyDown); }; }, [editorRef]); return ( <button className={`${Styles.customSelectFormat} ${ isDisable ? Styles.disabledButton : "" }`} onClick={toggleSelect} ref={selectRef} disabled={isDisable} style={{ minWidth: "120px", }} > <div className={Styles.selectSelected}> {selectedOption} <ArrowDown /> </div> {isOpen && ( <div className={Styles.selectItemsFormat}> {formats.map((option, index) => ( <div key={`key${index}`} onClick={(e) => handleOptionClick(e, option)} className={Styles.selectOption} > <option.value>{option.label}</option.value> </div> ))} </div> )} </button> ); } export default SelectFormat;