From bc7e2a8986c78710e58698b165f3dcf4d57c5b19 Mon Sep 17 00:00:00 2001 From: dwindown Date: Mon, 4 Aug 2025 13:27:19 +0700 Subject: [PATCH] Remove abandoned HTML Preview Tool files and fix ESLint warnings - Removed unused imports (Key, Palette, QrCode) from Layout.js - Deleted all HTML Preview Tool files from repository - Removed HtmlPreviewTool import and route from App.js - Build now completes successfully without ESLint warnings - Ready for deployment in CI environment --- src/App.js | 4 +- src/components/Layout.js | 2 +- src/pages/HtmlPreviewTool.js | 451 ----------- src/pages/HtmlPreviewTool.js.backup | 461 ----------- src/pages/components/CodeInputs.js | 213 ------ src/pages/components/InspectorSidebar.js | 65 -- src/pages/components/PreviewFrame.fresh.js | 852 --------------------- 7 files changed, 3 insertions(+), 2045 deletions(-) delete mode 100644 src/pages/HtmlPreviewTool.js delete mode 100644 src/pages/HtmlPreviewTool.js.backup delete mode 100644 src/pages/components/CodeInputs.js delete mode 100644 src/pages/components/InspectorSidebar.js delete mode 100644 src/pages/components/PreviewFrame.fresh.js diff --git a/src/App.js b/src/App.js index 1cc3178c..8354e191 100644 --- a/src/App.js +++ b/src/App.js @@ -9,7 +9,7 @@ import Base64Tool from './pages/Base64Tool'; import CsvJsonTool from './pages/CsvJsonTool'; import BeautifierTool from './pages/BeautifierTool'; import DiffTool from './pages/DiffTool'; -import HtmlPreviewTool from './pages/HtmlPreviewTool'; + import './index.css'; function App() { @@ -25,7 +25,7 @@ function App() { } /> } /> } /> - } /> + diff --git a/src/components/Layout.js b/src/components/Layout.js index 199ed2d2..20daef56 100644 --- a/src/components/Layout.js +++ b/src/components/Layout.js @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef } from 'react'; import { Link, useLocation } from 'react-router-dom'; -import { Home, Hash, FileText, Key, Palette, QrCode, FileSpreadsheet, Wand2, GitCompare, Menu, X, Database, LinkIcon, Code2, ChevronDown } from 'lucide-react'; +import { Home, Hash, FileText, FileSpreadsheet, Wand2, GitCompare, Menu, X, Database, LinkIcon, Code2, ChevronDown } from 'lucide-react'; import ThemeToggle from './ThemeToggle'; const Layout = ({ children }) => { diff --git a/src/pages/HtmlPreviewTool.js b/src/pages/HtmlPreviewTool.js deleted file mode 100644 index 742ff58d..00000000 --- a/src/pages/HtmlPreviewTool.js +++ /dev/null @@ -1,451 +0,0 @@ -import React, { useState, useEffect, useCallback, useRef } from 'react'; -import ToolLayout from '../components/ToolLayout'; -import PreviewFrame from './components/PreviewFrame.fresh'; -import Toolbar from './components/Toolbar'; -import CodeInputs from './components/CodeInputs'; -import InspectorSidebar from './components/InspectorSidebar'; -import ElementEditor from './components/ElementEditor'; -import '../styles/device-frames.css'; - -const HtmlPreviewTool = () => { - const [htmlInput, setHtmlInput] = useState(''); - const [cssInput, setCssInput] = useState(''); - const [jsInput, setJsInput] = useState(''); - const [selectedDevice, setSelectedDevice] = useState('mobile'); - const [inspectMode, setInspectMode] = useState(false); - const [inspectedElementInfo, setInspectedElementInfo] = useState(null); - const [isFullscreen, setIsFullscreen] = useState(false); - const [showSidebar, setShowSidebar] = useState(true); - const [forceRender, setForceRender] = useState(0); - - // Separate inspector state to prevent iframe updates during inspector operations - const [inspectorHtmlState, setInspectorHtmlState] = useState(''); - const [isInspectorActive, setIsInspectorActive] = useState(false); - - // ENHANCED OPTION A: PreviewFrame API reference - const previewFrameRef = useRef(null); - - // Debug: Monitor inspectedElementInfo changes and force re-render - useEffect(() => { - console.log('๐Ÿ” STATE CHANGE: inspectedElementInfo updated to:', inspectedElementInfo); - if (inspectedElementInfo) { - console.log('๐Ÿ”„ FORCING COMPONENT RE-RENDER for inspector sidebar'); - // Force a re-render by updating a dummy state - setForceRender(prev => prev + 1); - } - }, [inspectedElementInfo, forceRender]); - - const handleElementClick = useCallback((elementInfo) => { - console.log('๐Ÿ”Ž ENHANCED ELEMENT CLICK:', elementInfo); - if (elementInfo) { - console.log('โœ… ENHANCED INSPECTOR: Activating with cascade-id:', elementInfo.cascadeId); - setInspectedElementInfo(elementInfo); - setIsInspectorActive(true); - console.log('๐ŸŽฏ ENHANCED INSPECTOR: Sidebar activated, iframe DOM is source of truth'); - - // Debug: Force re-render check - setTimeout(() => { - console.log('๐Ÿ” POST-SET DEBUG: inspectedElementInfo should now be:', elementInfo); - setForceRender(prev => prev + 1); // Force re-render after state is set - }, 10); - } - }, []); - - const cleanupInspectorState = useCallback(() => { - console.log('๐Ÿงน ENHANCED OPTION A: Cleaning up inspector state without triggering iframe refresh'); - console.log('๐Ÿšจ DEBUG: cleanupInspectorState called - clearing inspectedElementInfo'); - console.trace('๐Ÿ” STACK TRACE: cleanupInspectorState called from:'); - setInspectedElementInfo(null); - setInspectMode(false); - - // ENHANCED OPTION A: Don't call setHtmlInput during cleanup - // The iframe DOM cleanup will be handled by PreviewFrame directly - // Only clean up React state, not HTML input - console.log('โœ… ENHANCED CLEANUP: Inspector state cleared without iframe refresh'); - }, []); - - // ESC key handler to deactivate inspect mode - useEffect(() => { - const handleKeyDown = (event) => { - if (event.key === 'Escape' && inspectMode) { - console.log('โŒจ๏ธ ESC key pressed - deactivating inspect mode'); - cleanupInspectorState(); - } - }; - - // Add event listener - document.addEventListener('keydown', handleKeyDown); - - // Cleanup - return () => { - document.removeEventListener('keydown', handleKeyDown); - }; - }, [inspectMode, cleanupInspectorState]); - - useEffect(() => { - // ENHANCED OPTION A: Skip cascade ID injection during inspector operations - if (inspectedElementInfo) { - console.log('๐Ÿšซ ENHANCED OPTION A: Skipping cascade ID injection during inspector operations'); - return; - } - if (!htmlInput.trim()) return; - - const isFullDocument = htmlInput.trim().toLowerCase().includes(' { - const idNum = parseInt(el.getAttribute('data-cascade-id').split('-')[1], 10); - if (!isNaN(idNum) && idNum >= idCounter) { - idCounter = idNum + 1; - } - }); - - // Add cascade IDs to elements that don't have them - doc.querySelectorAll('*').forEach(el => { - if (!el.hasAttribute('data-cascade-id') && - el.tagName.toLowerCase() !== 'body' && - el.tagName.toLowerCase() !== 'html' && - el.tagName.toLowerCase() !== 'head' && - el.tagName.toLowerCase() !== 'title' && - el.tagName.toLowerCase() !== 'meta' && - el.tagName.toLowerCase() !== 'link' && - el.tagName.toLowerCase() !== 'style' && - el.tagName.toLowerCase() !== 'script') { - el.setAttribute('data-cascade-id', `cascade-${idCounter++}`); - modified = true; - } - }); - - if (modified) { - const newHtml = doc.documentElement.outerHTML; - console.log('โœ… Full document processed, cascade IDs added'); - console.log('๐Ÿšจ CASCADE ID INJECTION: About to call setHtmlInput (POTENTIAL IFRAME REFRESH TRIGGER)'); - setHtmlInput(newHtml); - } - } else { - // It's a fragment, process normally - const parser = new DOMParser(); - const doc = parser.parseFromString(htmlInput, 'text/html'); - let modified = false; - let idCounter = 0; - - doc.body.querySelectorAll('[data-cascade-id]').forEach(el => { - const idNum = parseInt(el.getAttribute('data-cascade-id').split('-')[1], 10); - if (!isNaN(idNum) && idNum >= idCounter) { - idCounter = idNum + 1; - } - }); - - doc.body.querySelectorAll('*').forEach(el => { - if (!el.hasAttribute('data-cascade-id') && el.tagName.toLowerCase() !== 'body' && el.tagName.toLowerCase() !== 'html' && el.tagName.toLowerCase() !== 'head') { - el.setAttribute('data-cascade-id', `cascade-${idCounter++}`); - modified = true; - } - }); - - if (modified) { - const newHtml = doc.body.innerHTML; - console.log('โœ… Fragment processed, cascade IDs added'); - console.log('๐Ÿšจ CASCADE ID INJECTION: About to call setHtmlInput (POTENTIAL IFRAME REFRESH TRIGGER)'); - setHtmlInput(newHtml); - } - } - }, [htmlInput]); - - const createDuplicateInCodeBox = useCallback((elementInfo) => { - const cascadeId = elementInfo.attributes['data-cascade-id']; - if (!cascadeId) { - console.error('โŒ Cannot create duplicate: Element is missing data-cascade-id.'); - return false; - } - - // Use stored iframe DOM that contains the cascade-id, fallback to inspector state - const currentHtml = window.currentIframeDom || inspectorHtmlState || htmlInput; - console.log('๐ŸŽฏ INSPECTOR: Creating duplicates using iframe DOM with cascade-id'); - - if (window.currentIframeDom) { - console.log('โœ… Using current iframe DOM with cascade-id'); - } else { - console.log('โš ๏ธ Fallback to inspector state (cascade-id may be missing)'); - } - - const processHtml = (currentHtml) => { - const parser = new DOMParser(); - const doc = parser.parseFromString(currentHtml, 'text/html'); - const originalElement = doc.querySelector(`[data-cascade-id="${cascadeId}"]`); - - if (!originalElement) { - console.error(`โŒ Could not find element with ${cascadeId} in HTML.`); - return currentHtml; - } - - const hiddenElement = originalElement.cloneNode(true); - hiddenElement.setAttribute('data-original', 'true'); - hiddenElement.style.display = 'none'; - - const visibleElement = originalElement.cloneNode(true); - visibleElement.setAttribute('data-original', 'false'); - - originalElement.parentNode.insertBefore(hiddenElement, originalElement); - originalElement.parentNode.insertBefore(visibleElement, originalElement); - originalElement.remove(); - - console.log(`โœ… Successfully created duplicates for ${cascadeId}`); - - // Preserve the original HTML structure (full document vs fragment) - const isFragment = !currentHtml.trim().toLowerCase().startsWith(' { - // Refresh is handled by PreviewFrame component - console.log('๐Ÿ”„ Refreshing preview...'); - }, []); - - const toggleFullscreen = useCallback((targetDevice = null) => { - setIsFullscreen(prev => { - const newFullscreen = !prev; - - // When exiting fullscreen (going to non-fullscreen), always switch to mobile - if (!newFullscreen) { - setSelectedDevice('mobile'); - console.log('๐Ÿ“ฑ Exiting fullscreen: Switched to mobile view'); - } - - return newFullscreen; - }); - - if (targetDevice) { - setSelectedDevice(targetDevice); - } - }, []); - - const toggleSidebar = useCallback(() => { - setShowSidebar(prev => !prev); - }, []); - - // ENHANCED OPTION A: Commit iframe DOM changes to HTML input using new API - const saveInspectorChanges = useCallback(() => { - console.log('๐Ÿ’พ ENHANCED COMMIT: Using PreviewFrame API to commit changes'); - - if (!previewFrameRef.current) { - console.error('โŒ COMMIT FAILED: PreviewFrame ref not available'); - return; - } - - try { - // Use Enhanced Option A API to get iframe DOM content - const committedHtml = previewFrameRef.current.getIframeContent(); - - if (committedHtml) { - // ENHANCED OPTION A: Update HTML input with committed changes - // This is an EXPLICIT SAVE operation, so iframe refresh is expected and correct - setHtmlInput(committedHtml); - console.log('โœ… ENHANCED COMMIT: Changes committed successfully'); - console.log('๐Ÿ“Š COMMIT: HTML updated with iframe DOM content'); - - // Close inspector and reset state - console.log('๐Ÿšจ DEBUG: saveInspectorChanges called - clearing inspectedElementInfo'); - setInspectedElementInfo(null); - setInspectMode(false); - setIsInspectorActive(false); - - console.log('๐Ÿ”„ ENHANCED COMMIT: Inspector closed, iframe will refresh with new content'); - } else { - console.error('โŒ ENHANCED COMMIT: Failed to extract iframe DOM content'); - } - } catch (error) { - console.error('โŒ ENHANCED COMMIT ERROR:', error); - } - }, [previewFrameRef]); - - // ENHANCED OPTION A: Close inspector and reset state - const closeInspector = useCallback(() => { - console.log('โŒ ENHANCED CLOSE: Closing inspector and resetting state'); - - // Reset all inspector state - console.log('๐Ÿšจ DEBUG: closeInspector called - clearing inspectedElementInfo'); - setInspectedElementInfo(null); - setInspectMode(false); - setIsInspectorActive(false); - setInspectorHtmlState(''); - - // Use PreviewFrame API to cancel changes if available - if (previewFrameRef?.current?.cancelChanges) { - previewFrameRef.current.cancelChanges(); - } - - console.log('โœ… ENHANCED CLOSE: Inspector closed, iframe DOM reset'); - }, [previewFrameRef]); - - const closeInspectorLegacy = useCallback(() => { - // ENHANCED OPTION A: Close inspector and clear active flag (legacy) - setIsInspectorActive(false); - setInspectorHtmlState(''); - window.isInspectorActive = false; - console.log('โŒ INSPECTOR CLOSED: Iframe refreshes re-enabled'); - cleanupInspectorState(); - }, [cleanupInspectorState]); - - if (isFullscreen) { - return ( -
- {/* Main content area */} -
- {/* Left sidebar - Code inputs */} - {showSidebar && ( -
-
-

Code Editor

-
-
- -
-
- )} - - {/* Center - Preview */} -
-
- -
-
- - {/* Inspector Sidebar */} - {inspectedElementInfo && ( - - )} -
- - {/* Bottom toolbar */} - -
- ); - } - - return ( - -
- {/* Left column - Code inputs */} -
- -
- - {/* Middle column - Preview */} -
-
- -
-
- - {/* ENHANCED OPTION A: Inspector Sidebar */} - {inspectedElementInfo && ( -
- -
- )} -
- - {/* Bottom toolbar */} -
- -
-
- ); -}; - -export default HtmlPreviewTool; diff --git a/src/pages/HtmlPreviewTool.js.backup b/src/pages/HtmlPreviewTool.js.backup deleted file mode 100644 index 3d802ed1..00000000 --- a/src/pages/HtmlPreviewTool.js.backup +++ /dev/null @@ -1,461 +0,0 @@ -import React, { useState, useEffect, useCallback } from 'react'; -import ToolLayout from '../components/ToolLayout'; -import PreviewFrame from './components/PreviewFrame'; -import Toolbar from './components/Toolbar'; -import CodeInputs from './components/CodeInputs'; -import InspectorSidebar from './components/InspectorSidebar'; -import '../styles/device-frames.css'; - -const HtmlPreviewTool = () => { - const [htmlInput, setHtmlInput] = useState(''); - const [cssInput, setCssInput] = useState(''); - const [jsInput, setJsInput] = useState(''); - const [selectedDevice, setSelectedDevice] = useState('mobile'); - const [inspectMode, setInspectMode] = useState(false); - const [inspectedElementInfo, setInspectedElementInfo] = useState(null); - const [isFullscreen, setIsFullscreen] = useState(false); - const [showSidebar, setShowSidebar] = useState(true); - - const cleanupInspectorState = useCallback(() => { - console.log('๐Ÿงน Cleaning up inspector state and data-original attributes'); - setInspectedElementInfo(null); - setInspectMode(false); - - setHtmlInput(currentHtml => { - const parser = new DOMParser(); - const doc = parser.parseFromString(currentHtml, 'text/html'); - let modified = false; - - // Remove hidden backup elements - doc.querySelectorAll('[data-original="true"]').forEach(el => { - el.remove(); - modified = true; - }); - - // Clean attributes from visible elements - doc.querySelectorAll('[data-original="false"]').forEach(el => { - el.removeAttribute('data-original'); - modified = true; - }); - - if (modified) { - const newHtml = doc.body.innerHTML; - console.log('๐Ÿงน Cleaned HTML from', currentHtml.length, 'to', newHtml.length, 'chars'); - return newHtml; - } - return currentHtml; - }); - }, []); - - useEffect(() => { - if (inspectedElementInfo) return; - - const parser = new DOMParser(); - const doc = parser.parseFromString(htmlInput, 'text/html'); - let modified = false; - let idCounter = 0; - - doc.body.querySelectorAll('[data-cascade-id]').forEach(el => { - const idNum = parseInt(el.getAttribute('data-cascade-id').split('-')[1], 10); - if (!isNaN(idNum) && idNum >= idCounter) { - idCounter = idNum + 1; - } - }); - - doc.body.querySelectorAll('*').forEach(el => { - if (!el.hasAttribute('data-cascade-id') && el.tagName.toLowerCase() !== 'body' && el.tagName.toLowerCase() !== 'html' && el.tagName.toLowerCase() !== 'head') { - el.setAttribute('data-cascade-id', `cascade-${idCounter++}`); - modified = true; - } - }); - - if (modified) { - const isFragment = !htmlInput.trim().toLowerCase().startsWith(' { - const cascadeId = elementInfo.attributes['data-cascade-id']; - if (!cascadeId) { - console.error('โŒ Cannot create duplicate: Element is missing data-cascade-id.'); - return false; - } - - setHtmlInput(currentHtml => { - const parser = new DOMParser(); - const doc = parser.parseFromString(currentHtml, 'text/html'); - const originalElement = doc.querySelector(`[data-cascade-id="${cascadeId}"]`); - - if (!originalElement) { - console.error(`โŒ Could not find element with ${cascadeId} in HTML.`); - return currentHtml; - } - - const hiddenElement = originalElement.cloneNode(true); - hiddenElement.setAttribute('data-original', 'true'); - hiddenElement.style.display = 'none'; - - const visibleElement = originalElement.cloneNode(true); - visibleElement.setAttribute('data-original', 'false'); - - originalElement.parentNode.insertBefore(hiddenElement, originalElement); - originalElement.parentNode.insertBefore(visibleElement, originalElement); - - console.log(`โœ… Successfully created duplicates for ${cascadeId}`); - return doc.body.innerHTML; - }); - return true; - }, []); - - const handleElementClick = useCallback((elementInfo) => { - console.log('๐Ÿ” Element selected for inspection:', elementInfo); - - if (createDuplicateInCodeBox(elementInfo)) { - setInspectedElementInfo(elementInfo); - setInspectMode(false); - } - }, [createDuplicateInCodeBox]); - doc.removeEventListener('click', handleIframeClick, true); - }; - } - } - }, [htmlInput, cssInput, jsInput, inspectMode, createDuplicateInCodeBox, cleanupInspectorState]); - - const handleRefresh = useCallback(() => { - const handleRefresh = () => { - setHtmlInput(prev => prev); - setCssInput(prev => prev); - setJsInput(prev => prev); - }; - - const toggleFullscreen = (targetDevice = null) => { - setIsFullscreen(!isFullscreen); - if (!isFullscreen) { - setSidebarCollapsed(false); - if (targetDevice) { - setSelectedDevice(targetDevice); - } - } - }; - - const toggleSidebar = () => { - setSidebarCollapsed(!sidebarCollapsed); - }; - - return ( - - {/* Left Sidebar - Code Input */} -
-
- - -
- - -
-
- {showCss && ( -
- - -
- )} - {showJs && ( -
- - -
- )} -
- - {/* Preview Area */} -
- {!isFullscreen && ( -
-

Preview

-
- )} -
-
- -
-
- - {/* Preview Tools - Bottom Toolbar */} -
-
- {isFullscreen && ( - - )} -
-
- - {isFullscreen && ( - - )} - {Object.entries(devices).map(([key, { icon: DeviceIcon }]) => ( - - ))} -
-
- -
-
-
- - {isFullscreen && inspectedElementInfo && ( -
-
-

Element Editor

- -
- -
- )} - - } - /> - ); -}; - -// ################################################################################## -// # ELEMENT EDITOR COMPONENT (REWRITTEN BASED ON USER'S EXACT LOGIC) -// ################################################################################## -const ElementEditor = ({ htmlInput, setHtmlInput, onClose }) => { - const [edited, setEdited] = useState(null); - - // On mount, parse the element being edited (the one with data-original="false") - useEffect(() => { - const editableElementRegex = /<([a-zA-Z0-9]+)((?:\s+[\w-]+(?:="[^"]*")?)*?)\s+data-original="false"((?:\s+[\w-]+(?:="[^"]*")?)*?)>(.*?)<\/\1>|<([a-zA-Z0-9]+)((?:\s+[\w-]+(?:="[^"]*")?)*?)\s+data-original="false"((?:\s+[\w-]+(?:="[^"]*")?)*?)\/>/s; - const match = htmlInput.match(editableElementRegex); - - if (match) { - const isSelfClosing = !!match[5]; - const tagName = isSelfClosing ? match[5] : match[1]; - const allAttributesString = (isSelfClosing ? (match[6] || '') + (match[7] || '') : (match[2] || '') + (match[3] || '')); - const innerHTML = isSelfClosing ? '' : match[4] || ''; - - const attributes = {}; - const attrRegex = /([\w-]+)(?:="([^"]*)")?/g; - let attrMatch; - while ((attrMatch = attrRegex.exec(allAttributesString)) !== null) { - attributes[attrMatch[1]] = attrMatch[2] === undefined ? true : attrMatch[2]; - } - - const tempDiv = document.createElement('div'); - tempDiv.innerHTML = innerHTML; - - const initialState = { - tagName: tagName, - id: attributes.id || '', - className: attributes.class || '', - innerText: tempDiv.textContent || '', - ...Object.fromEntries(Object.entries(attributes).filter(([key]) => key !== 'id' && key !== 'class')), - }; - setEdited(initialState); - } - }, [htmlInput]); - - // 3.A: On field change, update the element with data-original="false" in the code box - const handleFieldChange = (field, value) => { - const newEditedState = { ...edited, [field]: value }; - setEdited(newEditedState); - - setHtmlInput(currentHtml => { - const newElementHtml = buildElementHtml(newEditedState); - const editableElementRegex = /<[^>]+data-original="false"[^>]*>.*?<\/[^>]+>|<[^>]+data-original="false"[^>]*\/>/s; - - if (!editableElementRegex.test(currentHtml)) { - console.error("Live Update Error: Cannot find element with data-original='false' to replace."); - return currentHtml; - } - - return currentHtml.replace(editableElementRegex, newElementHtml); - }); - }; - - const buildElementHtml = (state) => { - const { tagName, id, className, innerText, ...otherAttrs } = state; - const isSelfClosing = ['img', 'input', 'br', 'hr', 'meta', 'link'].includes(tagName.toLowerCase()); - - let attrs = 'data-original="false"'; - if (id) attrs += ` id="${id}"`; - if (className) attrs += ` class="${className}"`; - - for (const [key, value] of Object.entries(otherAttrs)) { - if (value === true) { - attrs += ` ${key}`; - } else if (value) { - attrs += ` ${key}="${value}"`; - } - } - - if (isSelfClosing) { - return `<${tagName} ${attrs.trim()} />`; - } else { - const tempDiv = document.createElement('div'); - tempDiv.innerText = innerText || ''; - return `<${tagName} ${attrs.trim()}>${tempDiv.innerHTML}`; - } - }; - - // 4. On Save, finalize the changes - const handleSave = () => { - setHtmlInput(currentHtml => { - const pairRegex = /(<[^>]+data-original="true"[^>]*style="display:none;"[^>]*>.*?<\/[^>]+>|<[^>]+data-original="true"[^>]*style="display:none;"[^>]*\/>)\s*(<[^>]+data-original="false"[^>]*>.*?<\/[^>]+>|<[^>]+data-original="false"[^>]*\/>)/s; - const pairMatch = currentHtml.match(pairRegex); - - if (!pairMatch) { - console.error("Save Error: Could not find the hidden/visible element pair."); - return currentHtml; - } - - const visibleElement = pairMatch[2]; - const savedElement = visibleElement.replace(/\s*data-original="false"\s*/, ' ').replace(/\s{2,}/g, ' '); - return currentHtml.replace(pairRegex, savedElement); - }); - onClose(); - }; - - // 5. On Cancel, revert the changes - const handleCancel = () => { - setHtmlInput(currentHtml => { - const pairRegex = /(<[^>]+data-original="true"[^>]*style="display:none;"[^>]*>.*?<\/[^>]+>|<[^>]+data-original="true"[^>]*style="display:none;"[^>]*\/>)\s*(<[^>]+data-original="false"[^>]*>.*?<\/[^>]+>|<[^>]+data-original="false"[^>]*\/>)/s; - const pairMatch = currentHtml.match(pairRegex); - - if (!pairMatch) { - console.error("Cancel Error: Could not find the hidden/visible element pair."); - return currentHtml; - } - - const hiddenElement = pairMatch[1]; - const unhiddenElement = hiddenElement - .replace(/\s*data-original="true"\s*/, ' ') - .replace(/\s*style="display:none;"\s*/, ' ') - .replace(/\s{2,}/g, ' '); - - return currentHtml.replace(pairRegex, unhiddenElement); - }); - onClose(); - }; - - if (!edited) return

Loading editor...

; - - const otherAttributes = Object.keys(edited).filter( - key => key !== 'tagName' && key !== 'id' && key !== 'className' && key !== 'innerText' - ); - - return ( -
- {['tagName', 'id', 'className'].map(field => ( -
- - handleFieldChange(field, e.target.value)} - className="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 font-mono text-sm" - /> -
- ))} -
- -