fix(Nextjs): Editable Text ClassName error

This commit is contained in:
shiva raj badu 2025-07-18 23:18:49 +05:45
parent f4d547937f
commit e57b21838a
No known key found for this signature in database
3 changed files with 57 additions and 9 deletions

View file

@ -61,10 +61,10 @@ const TiptapText: React.FC<TiptapTextProps> = ({
}
return (
<div className="relative w-full">
<div className="relative z-50 w-full">
{!disabled && (
<BubbleMenu editor={editor} tippyOptions={{ duration: 100 }}>
<div className="flex bg-white rounded-lg shadow-lg p-2 gap-1 border border-gray-200 z-50">
<div className="flex bg-white rounded-lg shadow-lg p-2 gap-1 border border-gray-200 z-50">
<button
onClick={() => editor?.chain().focus().toggleBold().run()}
className={`p-1 rounded hover:bg-gray-100 transition-colors ${editor?.isActive("bold") ? "bg-blue-100 text-blue-600" : ""

View file

@ -1,5 +1,4 @@
"use client";
import { renderToStaticMarkup } from 'react-dom/server';
import React, { useRef, useEffect, useState, ReactNode } from 'react';
import ReactDOM from 'react-dom/client';
@ -24,9 +23,6 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const [processedElements, setProcessedElements] = useState(new Set<HTMLElement>());
useEffect(() => {
if (!isEditMode || !containerRef.current) return;
@ -46,6 +42,9 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
return;
}
// Skip if element is inside an ignored element tree
if (isInIgnoredElementTree(htmlElement)) return;
// Get direct text content (not from child elements)
const directTextContent = getDirectTextContent(htmlElement);
const trimmedText = directTextContent.trim();
@ -120,6 +119,56 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
});
};
// Function to check if element is inside an ignored element tree
const isInIgnoredElementTree = (element: HTMLElement): boolean => {
// List of element types that should be ignored entirely with all their children
const ignoredElementTypes = [
'TABLE', 'TBODY', 'THEAD', 'TFOOT', 'TR', 'TD', 'TH', // Table elements
'SVG', 'G', 'PATH', 'CIRCLE', 'RECT', 'LINE', // SVG elements
'CANVAS', // Canvas element
'VIDEO', 'AUDIO', // Media elements
'IFRAME', 'EMBED', 'OBJECT', // Embedded content
'SELECT', 'OPTION', 'OPTGROUP', // Select dropdown elements
'SCRIPT', 'STYLE', 'NOSCRIPT', // Script/style elements
];
// List of class patterns that indicate ignored element trees
const ignoredClassPatterns = [
'chart', 'graph', 'visualization', // Chart/graph components
'menu', 'dropdown', 'tooltip', // UI components
'editor', 'wysiwyg', // Editor components
'calendar', 'datepicker', // Date picker components
'slider', 'carousel', // Interactive components
];
// Check if current element or any parent is in ignored list
let currentElement: HTMLElement | null = element;
while (currentElement) {
// Check element type
if (ignoredElementTypes.includes(currentElement.tagName)) {
return true;
}
// Check class patterns
const className = currentElement.className.length > 0 ? currentElement.className.toLowerCase() : '';
if (ignoredClassPatterns.some(pattern => className.includes(pattern))) {
return true;
}
// Check for specific attributes that indicate non-text content
if (currentElement.hasAttribute('contenteditable') ||
currentElement.hasAttribute('data-chart') ||
currentElement.hasAttribute('data-visualization') ||
currentElement.hasAttribute('data-interactive')) {
return true;
}
currentElement = currentElement.parentElement;
}
return false;
};
// Helper function to get only direct text content (not from children)
const getDirectTextContent = (element: HTMLElement): string => {
let text = '';
@ -155,7 +204,7 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
return true;
}
// Skip elements that contain interactive content
// Skip elements that contain interactive content (simplified since we now use isInIgnoredElementTree)
if (element.querySelector('img, svg, button, input, textarea, select, a[href]')) {
return true;
}
@ -163,7 +212,7 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
// Skip container elements (elements that primarily serve as layout containers)
const containerClasses = ['grid', 'flex', 'space-', 'gap-', 'container', 'wrapper'];
const hasContainerClass = containerClasses.some(cls =>
element.className.includes(cls)
element.className.length > 0 ? element.className.includes(cls) : false
);
if (hasContainerClass) return true;

View file

@ -43,7 +43,6 @@ export const useGroupLayouts = () => {
</div>
);
}
if (isEditMode) {
return (
<SmartEditableProvider