/** * Style Customizer v2 — panel app. Renders the sub-tabs (Design / Templates / Custom CSS) * and portals the live preview into the builder's content area. */ import React from 'react'; import { createPortal } from 'react-dom'; import { AiAssistant } from './AiAssistant'; import { ColorsPane, CustomCssPane, DesignList, ElementSlate, TemplatesPane } from './panes'; import { ConfirmModal, ConfirmState } from './Popover'; import { PreviewPane } from './PreviewPane'; import { getActiveBridge, SelectionInfo } from './PreviewBridge'; import { DEVICE_LABELS, STATE_FORCE } from './constants'; import { useStore } from './store'; import { Section } from './types'; const __ = ( window as any ).wp?.i18n?.__ || ( ( s: string ) => s ); const apiFetch = ( window as any ).wp?.apiFetch; // Temporarily disabled for this release — the AI form-building chat's own styling side effect // is disabled the same way, server-side, via EVF_AI_API::client_supports_style(). Re-enable by // flipping this back to true. const STYLE_AI_ENABLED = false; /** Single-list navigation: 'list' is the home screen (PRE-DEFINED + Elements + Advanced); * the rest are drill-downs reached from it, each with its own "← Back" header. */ type View = 'list' | 'element' | 'templates' | 'colors' | 'css'; interface Toast { msg: string; actLabel?: string; onAct?: () => void; kind?: 'success' | 'info'; } export function App() { const store = useStore(); const [ view, setView ] = React.useState< View >( 'list' ); const [ curSection, setCurSection ] = React.useState< string | null >( null ); const [ activeState, setActiveState ] = React.useState< Record< string, string > >( {} ); const [ confirm, setConfirm ] = React.useState< ConfirmState | null >( null ); const [ toast, setToast ] = React.useState< Toast | null >( null ); const [ saving, setSaving ] = React.useState( false ); const [ saveError, setSaveError ] = React.useState( '' ); const [ saveErrorConflict, setSaveErrorConflict ] = React.useState( false ); const [ selectPulse, setSelectPulse ] = React.useState( 0 ); const toastTimer = React.useRef< ReturnType< typeof setTimeout > | null >( null ); const sections: Section[] = React.useMemo( () => Object.keys( store.sections ).map( ( key ) => ( { key, ...store.sections[ key ] } ) ), [ store.sections ] ); const dirty = store.isDirty(); // Lets the AI assistant panel dismiss itself — a click here may be about to open a native //