UNPKG

funuicss

Version:

React and Next.js component UI Library for creating Easy and good looking websites with fewer lines of code. Elevate your web development experience with our cutting-edge React/Next.js component UI Library. Craft stunning websites effortlessly, boasting b

791 lines (790 loc) โ€ข 34 kB
// 'use client'; // import React, { useEffect, useRef, useCallback, useState, useMemo } from 'react'; // import { useQuill } from 'react-quilljs'; // import { MdOutlineEmojiEmotions } from 'react-icons/md'; // import { AllEmojis } from '../../utils/Emojis'; // import Dropdown from '../drop/Dropdown'; // import RowFlex from '../specials/RowFlex'; // import ToolTip from '../tooltip/ToolTip'; // import Circle from '../specials/Circle'; // import Tip from '../tooltip/Tip'; // import Flex from '../flex/Flex'; // type RangeStatic = { // index: number; // length: number; // }; // interface RichTextProps { // value: string; // onChange: (content: string) => void; // showEmojis?: boolean; // placeholder?: string; // afterEmoji?: React.ReactNode; // funcss?: string; // modules?: any; // theme?: 'bubble' | 'snow'; // fontFamily?: string; // maxValue?: number; // } // const RichText: React.FC<RichTextProps> = ({ // value, // onChange, // showEmojis = false, // placeholder = 'Write something...', // afterEmoji, // funcss = '', // modules, // theme = 'bubble', // fontFamily, // maxValue, // }) => { // const savedRange = useRef<RangeStatic | null>(null); // const onChangeRef = useRef(onChange); // const maxValueRef = useRef(maxValue); // const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null); // const isInitialMount = useRef(true); // const isTypingRef = useRef(false); // const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null); // const isUserChangeRef = useRef(false); // const [isFocused, setIsFocused] = useState(false); // const lastKnownValueRef = useRef(value); // const isEditorInitializedRef = useRef(false); // const isUpdatingFromPropsRef = useRef(false); // const forceUpdateRef = useRef(0); // // Store the value prop in a ref to compare with internal state // const valuePropRef = useRef(value); // // Update refs when props change // useEffect(() => { // onChangeRef.current = onChange; // maxValueRef.current = maxValue; // }, [onChange, maxValue]); // const defaultModules = useMemo(() => ({ // toolbar: [['bold', 'italic', 'underline'], [{ list: 'bullet' }]], // }), []); // const { quill, quillRef } = useQuill({ // theme, // placeholder, // modules: modules || defaultModules, // }); // // Clean HTML helper function // const cleanHTML = useCallback((html: string): string => { // if (!html) return ''; // return html // .replace(/<p><br><\/p>/g, '') // .replace(/\s+/g, ' ') // .trim(); // }, []); // // Debounced onChange handler // const debouncedOnChange = useCallback((content: string) => { // if (debounceTimeoutRef.current) { // clearTimeout(debounceTimeoutRef.current); // } // debounceTimeoutRef.current = setTimeout(() => { // onChangeRef.current(content); // }, 300); // 300ms debounce delay // }, []); // // Handle text change with debouncing // const handleTextChange = useCallback((delta: any, oldDelta: any, source: string) => { // if (!quill || source !== 'user') return; // // Skip if we're updating from props // if (isUpdatingFromPropsRef.current) { // isUpdatingFromPropsRef.current = false; // return; // } // isUserChangeRef.current = true; // isTypingRef.current = true; // // Reset typing flag after 500ms of inactivity // if (typingTimeoutRef.current) { // clearTimeout(typingTimeoutRef.current); // } // typingTimeoutRef.current = setTimeout(() => { // isTypingRef.current = false; // }, 500); // const plainText = quill.getText().trim(); // const currentHTML = quill.root.innerHTML; // // --- Enforce maxValue if needed --- // if (maxValueRef.current && plainText.length > maxValueRef.current) { // // Store current selection // const selection = quill.getSelection(); // // Remove the extra content // quill.deleteText(maxValueRef.current, plainText.length - maxValueRef.current); // // Restore selection if it was at the end // if (selection && selection.index > maxValueRef.current) { // quill.setSelection(maxValueRef.current); // } // return; // Don't trigger onChange for truncated text // } // // --- Clean the HTML output --- // const cleanedHTML = cleanHTML(currentHTML); // lastKnownValueRef.current = cleanedHTML; // // Update value prop ref // valuePropRef.current = cleanedHTML; // debouncedOnChange(cleanedHTML); // }, [quill, debouncedOnChange, cleanHTML]); // // Handle selection change // const handleSelectionChange = useCallback((range: RangeStatic | null) => { // if (range) savedRange.current = range; // }, []); // // Handle focus // const handleFocus = useCallback(() => { // setIsFocused(true); // isUserChangeRef.current = false; // }, []); // // Handle blur // const handleBlur = useCallback(() => { // setIsFocused(false); // isTypingRef.current = false; // isUserChangeRef.current = false; // }, []); // // Initialize editor with value // const initializeEditorWithValue = useCallback(() => { // if (!quill) return; // const cleanedValue = cleanHTML(value); // if (cleanedValue && cleanedValue !== '<p><br></p>' && cleanedValue !== '<p></p>') { // quill.clipboard.dangerouslyPasteHTML(0, cleanedValue); // } // lastKnownValueRef.current = cleanedValue; // valuePropRef.current = cleanedValue; // }, [quill, value, cleanHTML]); // // Update editor content from props // const updateEditorFromProps = useCallback(() => { // if (!quill || !isEditorInitializedRef.current) return; // // Clean the incoming value // const cleanedValue = cleanHTML(value); // // Get current editor content // const currentHTML = quill.root.innerHTML; // const currentCleaned = cleanHTML(currentHTML); // // Only update if values are different and not empty paragraphs // if (cleanedValue !== currentCleaned && cleanedValue !== '<p><br></p>' && cleanedValue !== '<p></p>') { // // Mark that we're updating from props // isUpdatingFromPropsRef.current = true; // // Store selection // const selection = quill.getSelection(); // // Calculate position to set cursor // const cursorPosition = Math.min( // selection?.index || 0, // cleanedValue.replace(/<[^>]*>/g, '').length // ); // // Replace content // quill.setText(''); // if (cleanedValue) { // quill.clipboard.dangerouslyPasteHTML(0, cleanedValue); // } // // Update refs // lastKnownValueRef.current = cleanedValue; // valuePropRef.current = cleanedValue; // // Restore cursor position // if (quill.hasFocus()) { // setTimeout(() => { // quill.setSelection(cursorPosition); // }, 0); // } // } // }, [quill, value, cleanHTML]); // // Set up event listeners // useEffect(() => { // if (!quill) return; // const editor = quill.root; // quill.on('selection-change', handleSelectionChange); // quill.on('text-change', handleTextChange); // // Add focus/blur event listeners // editor.addEventListener('focus', handleFocus); // editor.addEventListener('blur', handleBlur); // // Initialize editor with initial value on first mount // if (isInitialMount.current) { // initializeEditorWithValue(); // isInitialMount.current = false; // } // isEditorInitializedRef.current = true; // return () => { // quill.off('selection-change', handleSelectionChange); // quill.off('text-change', handleTextChange); // // Remove focus/blur event listeners // editor.removeEventListener('focus', handleFocus); // editor.removeEventListener('blur', handleBlur); // // Clean up timeouts // if (debounceTimeoutRef.current) { // clearTimeout(debounceTimeoutRef.current); // } // if (typingTimeoutRef.current) { // clearTimeout(typingTimeoutRef.current); // } // }; // }, [quill, handleSelectionChange, handleTextChange, handleFocus, handleBlur, initializeEditorWithValue]); // // Update editor when value prop changes (for external updates) // useEffect(() => { // if (!quill || !isEditorInitializedRef.current) return; // // Skip if value hasn't changed // if (value === valuePropRef.current) return; // // Don't update while user is typing // if (isTypingRef.current) { // // If user is typing but value changed significantly (like from template selection), // // we should still update // const currentPlain = quill.getText(); // const newPlain = value.replace(/<[^>]*>/g, ''); // // If the plain text is significantly different, update anyway // if (Math.abs(currentPlain.length - newPlain.length) > 10 || // !currentPlain.includes(newPlain.substring(0, 20)) && // !newPlain.includes(currentPlain.substring(0, 20))) { // updateEditorFromProps(); // } // return; // } // // Don't update if editor is focused and user recently made changes // if (isFocused && isUserChangeRef.current) { // return; // } // updateEditorFromProps(); // }, [quill, value, isFocused, updateEditorFromProps]); // // Force update when forceUpdateRef changes (for external reset) // useEffect(() => { // if (quill && isEditorInitializedRef.current) { // updateEditorFromProps(); // } // }, [forceUpdateRef.current, quill, updateEditorFromProps]); // const insertEmoji = useCallback((emoji: string) => { // if (quill) { // // Use current selection if available, otherwise use saved range or end of text // const selection = quill.getSelection(); // const plainText = quill.getText().trim(); // if (!maxValueRef.current || plainText.length + emoji.length <= maxValueRef.current) { // let insertIndex; // if (selection) { // insertIndex = selection.index; // } else if (savedRange.current) { // insertIndex = savedRange.current.index; // } else { // insertIndex = quill.getLength(); // } // // Mark as user change // isUserChangeRef.current = true; // quill.insertText(insertIndex, emoji); // quill.setSelection(insertIndex + emoji.length); // // Update saved range // savedRange.current = { // index: insertIndex + emoji.length, // length: 0 // }; // // Focus the editor // quill.focus(); // // Update refs // const currentHTML = quill.root.innerHTML; // const cleanedHTML = cleanHTML(currentHTML); // lastKnownValueRef.current = cleanedHTML; // valuePropRef.current = cleanedHTML; // debouncedOnChange(cleanedHTML); // } // } // }, [quill, cleanHTML, debouncedOnChange]); // const renderEmojiSection = useCallback((title: string, emojis: string[]) => ( // <> // <div className="mb-2 mt-2 text-sm">{title}</div> // <RowFlex gap={0.3}> // {emojis.map((emoji, i) => ( // <span // key={i} // className="h6 pointer" // onClick={() => insertEmoji(emoji)} // > // {emoji} // </span> // ))} // </RowFlex> // </> // ), [insertEmoji]); // return ( // <div // className={`fit round-edge ${funcss}`} // style={{ position: 'relative', overflow: 'visible' }} // > // <div id="editor-container" className="bubble-editor-container p-0"> // <div // ref={quillRef} // className={theme === 'bubble' ? 'bubble-editor' : 'snow-editor'} // style={{ // fontFamily: fontFamily || 'inherit', // }} // /> // </div> // {(showEmojis || maxValue) && ( // <div // className="p-1" // style={{ height: 'fit-content', top: `calc(100%)`, width: '100%' }} // > // <Flex justify="space-between" gap={1} alignItems="center" width="100%"> // {(showEmojis || afterEmoji) ? ( // <div> // <Flex width="100%" gap={0.5} alignItems="center"> // {showEmojis && ( // <Dropdown // closableOnlyOutside // button={ // <ToolTip> // <Circle size={2} funcss="bg border"> // <MdOutlineEmojiEmotions /> // </Circle> // <Tip // tip="top" // animation="ScaleUp" // duration={0.5} // content="Emojis" // /> // </ToolTip> // } // items={[ // { // label: ( // <div // className="w-200 h-200" // style={{ overflowY: 'auto' }} // > // {renderEmojiSection('โค๏ธ Smileys & People', AllEmojis.Smiley)} // {renderEmojiSection('๐Ÿ‘ Gestures & Body Parts', AllEmojis.Gesture)} // {renderEmojiSection('๐Ÿ”ฅ Symbols & Expressions', AllEmojis.Symbols)} // {renderEmojiSection('๐Ÿš€ Travel, Objects & Activities', AllEmojis.Travel)} // {renderEmojiSection('๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ People & Professions', AllEmojis.People)} // {renderEmojiSection('๐Ÿถ Animals & Nature', AllEmojis.Animals)} // </div> // ), // }, // ]} // /> // )} // {afterEmoji} // </Flex> // </div> // ) : ( // <div /> // )} // {maxValue && quill ? ( // <div className="text-xs text-right"> // <span className="text-primary"> // {quill.getText().trim().length} // </span> // /{maxValue} // </div> // ) : ( // <div /> // )} // </Flex> // </div> // )} // </div> // ); // }; // export default RichText; // 'use client'; // import React, { useEffect, useRef, useCallback, useState } from 'react'; // import { useQuill } from 'react-quilljs'; // import { MdOutlineEmojiEmotions } from 'react-icons/md'; // import { AllEmojis } from '../../utils/Emojis'; // import Dropdown from '../drop/Dropdown'; // import RowFlex from '../specials/RowFlex'; // import ToolTip from '../tooltip/ToolTip'; // import Circle from '../specials/Circle'; // import Tip from '../tooltip/Tip'; // import Flex from '../flex/Flex'; // type RangeStatic = { // index: number; // length: number; // }; // interface RichTextProps { // value: string; // onChange: (content: string) => void; // showEmojis?: boolean; // placeholder?: string; // afterEmoji?: React.ReactNode; // funcss?: string; // modules?: any; // theme?: 'bubble' | 'snow'; // fontFamily?: string; // maxValue?: number; // } // const RichText: React.FC<RichTextProps> = ({ // value, // onChange, // showEmojis = false, // placeholder = 'Write something...', // afterEmoji, // funcss = '', // modules, // theme = 'bubble', // fontFamily, // maxValue, // }) => { // const savedRange = useRef<RangeStatic | null>(null); // const onChangeRef = useRef(onChange); // const maxValueRef = useRef(maxValue); // const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null); // const isInitialMount = useRef(true); // const isTypingRef = useRef(false); // const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null); // const [isFocused, setIsFocused] = useState(false); // const lastKnownValueRef = useRef(value); // // Update refs when props change // useEffect(() => { // onChangeRef.current = onChange; // maxValueRef.current = maxValue; // }, [onChange, maxValue]); // const defaultModules = { // toolbar: [['bold', 'italic', 'underline'], [{ list: 'bullet' }]], // }; // const { quill, quillRef } = useQuill({ // theme, // placeholder, // modules: modules || defaultModules, // }); // // Debounced onChange handler // const debouncedOnChange = useCallback((content: string) => { // if (debounceTimeoutRef.current) { // clearTimeout(debounceTimeoutRef.current); // } // debounceTimeoutRef.current = setTimeout(() => { // onChangeRef.current(content); // }, 300); // 300ms debounce delay // }, []); // // Handle text change with debouncing // const handleTextChange = useCallback(() => { // if (!quill) return; // isTypingRef.current = true; // // Reset typing flag after 500ms of inactivity // if (typingTimeoutRef.current) { // clearTimeout(typingTimeoutRef.current); // } // typingTimeoutRef.current = setTimeout(() => { // isTypingRef.current = false; // }, 500); // const plainText = quill.getText().trim(); // // --- Enforce maxValue if needed --- // if (maxValueRef.current && plainText.length > maxValueRef.current) { // const truncated = plainText.slice(0, maxValueRef.current); // quill.setText(truncated); // quill.setSelection(truncated.length); // return; // Don't trigger onChange for truncated text // } // // --- Clean the HTML output --- // const cleanedHTML = quill.root.innerHTML // ?.replace(/<p><br><\/p>/g, '') // remove empty paragraphs // ?.replace(/\s+/g, ' ') // collapse multiple spaces // ?.trim(); // remove leading/trailing spaces // lastKnownValueRef.current = cleanedHTML || ''; // debouncedOnChange(lastKnownValueRef.current); // }, [quill, debouncedOnChange]); // // Handle selection change // const handleSelectionChange = useCallback((range: RangeStatic | null) => { // if (range) savedRange.current = range; // }, []); // // Handle focus // const handleFocus = useCallback(() => { // setIsFocused(true); // }, []); // // Handle blur // const handleBlur = useCallback(() => { // setIsFocused(false); // isTypingRef.current = false; // }, []); // // Set up event listeners // useEffect(() => { // if (!quill) return; // const editor = quill.root; // quill.on('selection-change', handleSelectionChange); // quill.on('text-change', handleTextChange); // // Add focus/blur event listeners // editor.addEventListener('focus', handleFocus); // editor.addEventListener('blur', handleBlur); // return () => { // quill.off('selection-change', handleSelectionChange); // quill.off('text-change', handleTextChange); // // Remove focus/blur event listeners // editor.removeEventListener('focus', handleFocus); // editor.removeEventListener('blur', handleBlur); // // Clean up timeouts // if (debounceTimeoutRef.current) { // clearTimeout(debounceTimeoutRef.current); // } // if (typingTimeoutRef.current) { // clearTimeout(typingTimeoutRef.current); // } // }; // }, [quill, handleSelectionChange, handleTextChange, handleFocus, handleBlur]); // // Initialize editor with initial value // useEffect(() => { // if (!quill) return; // // Only set initial value on first mount // if (isInitialMount.current && value) { // // clean before setting editor value // const cleanedValue = value // ?.replace(/<p><br><\/p>/g, '') // ?.replace(/\s+/g, ' ') // ?.trim(); // quill.root.innerHTML = cleanedValue || ''; // lastKnownValueRef.current = cleanedValue || ''; // isInitialMount.current = false; // } // }, [quill, value]); // // Update editor when value prop changes (for external updates) // useEffect(() => { // if (!quill || isInitialMount.current) return; // // Skip if value is the same as current editor content // if (value === lastKnownValueRef.current) return; // // Don't update while user is typing or editor is focused // if (isTypingRef.current || isFocused) { // return; // } // // clean before setting editor value // const cleanedValue = value // ?.replace(/<p><br><\/p>/g, '') // ?.replace(/\s+/g, ' ') // ?.trim(); // if (quill.root.innerHTML !== cleanedValue) { // quill.root.innerHTML = cleanedValue || ''; // lastKnownValueRef.current = cleanedValue || ''; // } // }, [quill, value, isFocused]); // const insertEmoji = useCallback((emoji: string) => { // if (quill && savedRange.current) { // const plainText = quill.getText().trim(); // if (!maxValueRef.current || plainText.length + emoji.length <= maxValueRef.current) { // const selection = quill.getSelection(); // quill.insertText(savedRange.current.index, emoji); // quill.setSelection(savedRange.current.index + emoji.length); // } // } // }, [quill]); // const renderEmojiSection = useCallback((title: string, emojis: string[]) => ( // <> // <div className="mb-2 mt-2 text-sm">{title}</div> // <RowFlex gap={0.3}> // {emojis.map((emoji, i) => ( // <span // key={i} // className="h6 pointer" // onClick={() => insertEmoji(emoji)} // > // {emoji} // </span> // ))} // </RowFlex> // </> // ), [insertEmoji]); // return ( // <div // className={`fit round-edge ${funcss}`} // style={{ position: 'relative', overflow: 'visible' }} // > // <div id="editor-container" className="bubble-editor-container p-0"> // <div // ref={quillRef} // className={theme === 'bubble' ? 'bubble-editor' : 'snow-editor'} // style={{ // fontFamily: fontFamily || 'inherit', // }} // /> // </div> // {(showEmojis || maxValue) && ( // <div // className="p-1" // style={{ height: 'fit-content', top: `calc(100%)`, width: '100%' }} // > // <Flex justify="space-between" gap={1} alignItems="center" width="100%"> // {(showEmojis || afterEmoji) ? ( // <div> // <Flex width="100%" gap={0.5} alignItems="center"> // {showEmojis && ( // <Dropdown // closableOnlyOutside // button={ // <ToolTip> // <Circle size={2} funcss="bg border"> // <MdOutlineEmojiEmotions /> // </Circle> // <Tip // tip="top" // animation="ScaleUp" // duration={0.5} // content="Emojis" // /> // </ToolTip> // } // items={[ // { // label: ( // <div // className="w-200 h-200" // style={{ overflowY: 'auto' }} // > // {renderEmojiSection('โค๏ธ Smileys & People', AllEmojis.Smiley)} // {renderEmojiSection('๐Ÿ‘ Gestures & Body Parts', AllEmojis.Gesture)} // {renderEmojiSection('๐Ÿ”ฅ Symbols & Expressions', AllEmojis.Symbols)} // {renderEmojiSection('๐Ÿš€ Travel, Objects & Activities', AllEmojis.Travel)} // {renderEmojiSection('๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ People & Professions', AllEmojis.People)} // {renderEmojiSection('๐Ÿถ Animals & Nature', AllEmojis.Animals)} // </div> // ), // }, // ]} // /> // )} // {afterEmoji} // </Flex> // </div> // ) : ( // <div /> // )} // {maxValue && quill ? ( // <div className="text-xs text-right"> // <span className="text-primary"> // {quill.getText().trim().length} // </span> // /{maxValue} // </div> // ) : ( // <div /> // )} // </Flex> // </div> // )} // </div> // ); // }; // export default RichText; 'use client'; "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var react_1 = __importStar(require("react")); var react_quilljs_1 = require("react-quilljs"); var md_1 = require("react-icons/md"); var Emojis_1 = require("../../utils/Emojis"); var Dropdown_1 = __importDefault(require("../drop/Dropdown")); var RowFlex_1 = __importDefault(require("../specials/RowFlex")); var ToolTip_1 = __importDefault(require("../tooltip/ToolTip")); var Circle_1 = __importDefault(require("../specials/Circle")); var Tip_1 = __importDefault(require("../tooltip/Tip")); var Flex_1 = __importDefault(require("../flex/Flex")); var RichText = function (_a) { var value = _a.value, onChange = _a.onChange, _b = _a.showEmojis, showEmojis = _b === void 0 ? false : _b, _c = _a.placeholder, placeholder = _c === void 0 ? 'Write something...' : _c, afterEmoji = _a.afterEmoji, _d = _a.funcss, funcss = _d === void 0 ? '' : _d, modules = _a.modules, _e = _a.theme, theme = _e === void 0 ? 'bubble' : _e, fontFamily = _a.fontFamily, maxValue = _a.maxValue; var savedRange = (0, react_1.useRef)(null); var defaultModules = { toolbar: [['bold', 'italic', 'underline'], [{ list: 'bullet' }]], }; var _f = (0, react_quilljs_1.useQuill)({ theme: theme, placeholder: placeholder, modules: modules || defaultModules, }), quill = _f.quill, quillRef = _f.quillRef; (0, react_1.useEffect)(function () { if (!quill) return; var handleSelectionChange = function (range) { if (range) savedRange.current = range; }; var handleTextChange = function () { var _a, _b, _c; if (!quill) return; var plainText = quill.getText().trim(); // --- Enforce maxValue if needed --- if (maxValue && plainText.length > maxValue) { var truncated = plainText.slice(0, maxValue); quill.setText(truncated); quill.setSelection(truncated.length); } // --- Clean the HTML output --- var cleanedHTML = (_c = (_b = (_a = quill.root.innerHTML) === null || _a === void 0 ? void 0 : _a.replace(/<p><br><\/p>/g, '') // remove empty paragraphs ) === null || _b === void 0 ? void 0 : _b.replace(/\s+/g, ' ') // collapse multiple spaces ) === null || _c === void 0 ? void 0 : _c.trim(); // remove leading/trailing spaces onChange(cleanedHTML || ''); }; quill.on('selection-change', handleSelectionChange); quill.on('text-change', handleTextChange); return function () { quill.off('selection-change', handleSelectionChange); quill.off('text-change', handleTextChange); }; }, [quill, onChange, maxValue]); (0, react_1.useEffect)(function () { var _a, _b; if (quill && value !== quill.root.innerHTML) { // clean before setting editor value var cleanedValue = (_b = (_a = value === null || value === void 0 ? void 0 : value.replace(/<p><br><\/p>/g, '')) === null || _a === void 0 ? void 0 : _a.replace(/\s+/g, ' ')) === null || _b === void 0 ? void 0 : _b.trim(); quill.root.innerHTML = cleanedValue || ''; } }, [quill, value]); var insertEmoji = function (emoji) { if (quill && savedRange.current) { var plainText = quill.getText().trim(); if (!maxValue || plainText.length + emoji.length <= maxValue) { quill.insertText(savedRange.current.index, emoji); quill.setSelection(savedRange.current.index + emoji.length); } } }; var renderEmojiSection = function (title, emojis) { return (react_1.default.createElement(react_1.default.Fragment, null, react_1.default.createElement("div", { className: "mb-2 mt-2 text-sm" }, title), react_1.default.createElement(RowFlex_1.default, { gap: 0.3 }, emojis.map(function (emoji, i) { return (react_1.default.createElement("span", { key: i, className: "h6 pointer", onClick: function () { return insertEmoji(emoji); } }, emoji)); })))); }; return (react_1.default.createElement("div", { className: "fit round-edge ".concat(funcss), style: { position: 'relative', overflow: 'visible' } }, react_1.default.createElement("div", { id: "editor-container", className: "bubble-editor-container p-0" }, react_1.default.createElement("div", { ref: quillRef, className: theme === 'bubble' ? 'bubble-editor' : 'snow-editor', style: { fontFamily: fontFamily || 'inherit', } })), (showEmojis || maxValue) && (react_1.default.createElement("div", { className: "p-1", style: { height: 'fit-content', top: "calc(100%)", width: '100%' } }, react_1.default.createElement(Flex_1.default, { justify: "space-between", gap: 1, alignItems: "center", width: "100%" }, (showEmojis || afterEmoji) ? (react_1.default.createElement("div", null, react_1.default.createElement(Flex_1.default, { width: "100%", gap: 0.5, alignItems: "center" }, showEmojis && (react_1.default.createElement(Dropdown_1.default, { closableOnlyOutside: true, button: react_1.default.createElement(ToolTip_1.default, null, react_1.default.createElement(Circle_1.default, { size: 2, funcss: "bg border" }, react_1.default.createElement(md_1.MdOutlineEmojiEmotions, null)), react_1.default.createElement(Tip_1.default, { tip: "top", animation: "ScaleUp", duration: 0.5, content: "Emojis" })), items: [ { label: (react_1.default.createElement("div", { className: "w-200 h-200", style: { overflowY: 'auto' } }, renderEmojiSection('โค๏ธ Smileys & People', Emojis_1.AllEmojis.Smiley), renderEmojiSection('๐Ÿ‘ Gestures & Body Parts', Emojis_1.AllEmojis.Gesture), renderEmojiSection('๐Ÿ”ฅ Symbols & Expressions', Emojis_1.AllEmojis.Symbols), renderEmojiSection('๐Ÿš€ Travel, Objects & Activities', Emojis_1.AllEmojis.Travel), renderEmojiSection('๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ People & Professions', Emojis_1.AllEmojis.People), renderEmojiSection('๐Ÿถ Animals & Nature', Emojis_1.AllEmojis.Animals))), }, ] })), afterEmoji))) : (react_1.default.createElement("div", null)), maxValue && quill ? (react_1.default.createElement("div", { className: "text-xs text-right" }, react_1.default.createElement("span", { className: "text-primary" }, quill.getText().trim().length), "/", maxValue)) : (react_1.default.createElement("div", null))))))); }; exports.default = RichText;