/**
* External dependencies
*/
import type { ReactNode } from 'react';
import clsx from 'clsx';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { createContext, useCallback, useContext, useState } from '@wordpress/element';
import { __experimentalHeading as Heading } from '@wordpress/components';
import { Card, CollapsibleCard, Stack } from '@wordpress/ui';
import { useDispatch } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
/**
* Internal dependencies
*/
import { AdminContext } from '../index';
import EditorPreview from './components/editor-preview';
import Filter, { type EditorMode } from './components/filter';
import Controls from './components/controls';
import * as EditorSettings from './editor-settings';
import * as EditorOptions from './editor-options';
import type {
EditorConfigContextType,
EditorSettings as EditorSettingsType,
EditorOptions as EditorOptionsType,
} from '../../types';
/**
* Context
*/
export const EditorConfigContext = createContext< EditorConfigContextType >(
{} as EditorConfigContextType
);
// Value for the `inert` attribute; the empty string enables it (React 18 form).
function inertValue( condition: boolean ): '' | undefined {
return condition ? '' : undefined;
}
// Whether a setting with the given title matches the current search query.
export function useSearchVisibility( title: string ): boolean {
const { searchQuery } = useContext( EditorConfigContext );
if ( ! searchQuery ) {
return true;
}
return title.toLowerCase().includes( searchQuery.toLowerCase() );
}
// Collapsible panel, forced open while a search query is active and otherwise
// toggled by the user.
function SettingsPanel( { title, children }: { title: string; children: ReactNode } ) {
const { searchQuery } = useContext( EditorConfigContext );
const [ isOpen, setIsOpen ] = useState( false );
return (
}>
{ title }
{ children }
);
}
export default function EditorConfig() {
const {
isWaiting,
editorSettings,
editorOptions,
setIsWaiting,
setEditorOptions,
setEditorSettings,
} = useContext( AdminContext );
const [ isEditorDisabled, setIsEditorDisabled ] = useState( false );
const [ editorMode, setEditorMode ] = useState< EditorMode >( 'basic' );
const [ searchQuery, setSearchQuery ] = useState( '' );
const [ fontWeights, setFontWeights ] = useState( [ 300 ] );
const { createNotice, createSuccessNotice } = useDispatch( noticesStore );
// Update editor config.
const onUpdateOptions = () => {
setIsWaiting( true );
apiFetch< { success: boolean; message: string } >( {
path: '/custom-html-block-extension/v1/update_editor_config',
method: 'POST',
data: {
editorSettings,
editorOptions,
},
} ).then( ( response ) => {
setTimeout( () => {
createNotice( response.success ? 'success' : 'error', response.message, {
type: 'snackbar',
} );
setIsWaiting( false );
}, 600 );
} );
};
// Reset editor config.
const onResetOptions = () => {
setIsWaiting( true );
return apiFetch< { editorSettings: EditorSettingsType; editorOptions: EditorOptionsType } >( {
path: '/custom-html-block-extension/v1/delete_editor_config',
method: 'POST',
} ).then( ( response ) => {
// Sets default editor config.
setEditorSettings( response.editorSettings );
setEditorOptions( response.editorOptions );
return new Promise< void >( ( resolve ) => {
setTimeout( () => {
createSuccessNotice( __( 'Settings have been reset.', 'custom-html-block-extension' ), {
type: 'snackbar',
} );
setIsWaiting( false );
resolve();
}, 600 );
} );
} );
};
// Refresh editor.
// Memoized so consumers can derive stable (debounced) callbacks from it.
const onRefreshEditor = useCallback( () => {
// Some options are not reflected when the state is changed.
// So disable the editor for a moment by Disabled component as a workaround.
setIsEditorDisabled( true );
setTimeout( () => {
setIsEditorDisabled( false );
}, 300 );
}, [] );
return (
{ __( 'Preview', 'custom-html-block-extension' ) }
{ 'basic' === editorMode && ! searchQuery && (
<>
>
) }
{ ( 'advanced' === editorMode || searchQuery ) && (
<>
>
) }
);
}