/** * External dependencies */ import type { Properties } from 'csstype'; import type { Dispatch, SetStateAction } from 'react'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { createInterpolateElement, useState } from '@wordpress/element'; import { useDispatch } from '@wordpress/data'; import apiFetch from '@wordpress/api-fetch'; import { Button, Flex, Notice, Modal, Popover, TabPanel, Spinner, RangeControl, ToggleControl, __experimentalText as Text, __experimentalSpacer as Spacer, __experimentalHStack as HStack, __experimentalVStack as VStack, __experimentalHeading as Heading, __experimentalUnitControl as UnitControl, __experimentalUseCustomUnits as useCustomUnits, __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon, } from '@wordpress/components'; import { desktop, mobile } from '@wordpress/icons'; /** * Internal dependencies */ import { BORDER_COLLAPSE_CONTROLS, DEFAULT_RESPONSIVE_BREAKPOINT, MIN_RESPONSIVE_BREAKPOINT, MAX_RESPONSIVE_BREAKPOINT, TEXT_ALIGNMENT_CONTROLS, VERTICAL_ALIGNMENT_CONTROLS, TABLE_WIDTH_UNITS, STORE_NAME, REST_API_ROUTE, } from '../../constants'; import { BorderWidthControl, BorderStyleControl, ColorControl, PaddingControl, } from '../../controls'; import { sanitizeUnitValue, cleanEmptyObject } from '../../utils/helper'; import type { ApiResponse, StoreOptions } from '../../store'; import type { NoticeProps } from '@wordpress/components/build-types/notice/types'; type Props = { options: StoreOptions; isAdministrator: boolean; setIsSettingModalOpen: Dispatch< SetStateAction< boolean > >; }; interface NoticeInfo { status?: NoticeProps[ 'status' ]; message?: string; } export default function SettingModal( { options, isAdministrator, setIsSettingModalOpen }: Props ) { const [ noticeInfo, setNoticeInfo ] = useState< NoticeInfo | undefined >( undefined ); const [ isResetPopup, setIsResetPopup ] = useState< boolean >( false ); const [ isWaiting, setIsWaiting ] = useState< boolean >( false ); const [ currentOptions, setCurrentOptions ] = useState< StoreOptions >( options ); const { setOptions: setStoreOptions } = useDispatch( STORE_NAME ); const tableWidthUnits = useCustomUnits( { availableUnits: TABLE_WIDTH_UNITS } ); // Force focus on the modal as it loses focus when saving or restoring settings. function focusModal() { const modal = document.querySelector( '.ftb-global-setting-modal' ) as HTMLInputElement; if ( modal ) { modal.focus(); } } // Update the inline CSS. function updateInlineCss( css: string ) { // Update the inline CSS of the global document. const styleSheet = document.getElementById( 'flexible-table-block-editor-inline-css' ); if ( styleSheet ) { styleSheet.textContent = css; } // Update the inline CSS of the iframe editor instance document. const iframeEditor = document.querySelectorAll( 'iframe' ); for ( let i = 0; i < iframeEditor.length; i++ ) { const iframeWindow = iframeEditor[ i ].contentWindow; if ( ! iframeWindow ) { continue; } const iframeStyleSheet = iframeWindow.document.getElementById( 'flexible-table-block-editor-inline-css' ); if ( iframeStyleSheet ) { iframeStyleSheet.textContent = css; } } } // Update options. const handleUpdateOptions = () => { setIsWaiting( true ); setNoticeInfo( undefined ); setStoreOptions( currentOptions ); apiFetch< ApiResponse >( { path: REST_API_ROUTE, method: 'POST', data: currentOptions, } ) .then( ( response ) => { focusModal(); setIsWaiting( false ); // Show notice message. if ( response.status && response.message ) { setNoticeInfo( { status: response?.status, message: response?.message, } ); } if ( ! response.block_css ) { return; } // Update inline CSS. updateInlineCss( response.block_css ); } ) .catch( ( response ) => { focusModal(); setIsWaiting( false ); setNoticeInfo( { status: 'error', message: response.message, } ); } ); }; // Reset state and store options. const handleResetOptions = () => { setIsWaiting( true ); setNoticeInfo( undefined ); apiFetch< ApiResponse >( { path: REST_API_ROUTE, method: 'DELETE', } ).then( ( response ) => { focusModal(); setIsWaiting( false ); // Show notice message. if ( response.status && response.message ) { setNoticeInfo( { status: response.status, message: response.message, } ); } // Update options. if ( response.options ) { setCurrentOptions( response.options ); setStoreOptions( response.options ); } if ( ! response.block_css ) { return; } // Update inline CSS. updateInlineCss( response.block_css ); } ); }; return ( setIsSettingModalOpen( false ) } size="large" > { isWaiting && ( ) } { ( { name } ) => ( { name === 'table' && ( { __( 'Default table styles', 'flexible-table-block' ) } { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, table_width: sanitizeUnitValue( value ), }, } ); } } size="__unstable-large" __unstableInputWidth="100px" /> { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, table_max_width: sanitizeUnitValue( value ), }, } ); } } size="__unstable-large" __unstableInputWidth="100px" /> { const isAllowedValue = ( _value: any ): _value is Properties[ 'borderCollapse' ] => { return ( ! value || BORDER_COLLAPSE_CONTROLS.some( ( control ) => control.value === _value ) ); }; if ( isAllowedValue( value ) ) { const newValue = currentOptions?.block_style?.table_border_collapse === value ? undefined : value; setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, table_border_collapse: newValue, }, } ); } } } > { BORDER_COLLAPSE_CONTROLS.map( ( { icon, label, value } ) => ( ) ) } { __( 'Default striped table styles', 'flexible-table-block' ) } { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, row_odd_color: value, }, } ); } } /> { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, row_even_color: value, }, } ); } } /> ) } { name === 'cell' && ( { __( 'Default cell styles', 'flexible-table-block' ) } th tag )', 'flexible-table-block' ), { code: } ) } value={ currentOptions.block_style?.cell_text_color_th } onChange={ ( value ) => { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_text_color_th: value, }, } ); } } /> td tag )', 'flexible-table-block' ), { code: } ) } value={ currentOptions.block_style?.cell_text_color_td } onChange={ ( value ) => { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_text_color_td: value, }, } ); } } /> th tag )', 'flexible-table-block' ), { code: } ) } value={ currentOptions.block_style?.cell_background_color_th } onChange={ ( value ) => { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_background_color_th: value, }, } ); } } /> td tag )', 'flexible-table-block' ), { code: } ) } value={ currentOptions.block_style?.cell_background_color_td } onChange={ ( value ) => { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_background_color_td: value, }, } ); } } /> { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_padding: cleanEmptyObject( values ), }, } ); } } /> { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_border_width: sanitizeUnitValue( value.top ), }, } ); } } /> { const newValue = currentOptions?.block_style?.cell_border_style === value.top ? undefined : value.top; setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_border_style: newValue, }, } ); } } /> { setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_border_color: value, }, } ); } } /> { if ( typeof value !== 'string' && value !== undefined ) { return; } const newValue = currentOptions?.block_style?.cell_text_align === value ? undefined : value; setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_text_align: newValue, }, } ); } } > { TEXT_ALIGNMENT_CONTROLS.map( ( { icon, label, value } ) => ( ) ) } { if ( typeof value !== 'string' && value !== undefined ) { return; } const newValue = currentOptions?.block_style?.cell_vertical_align === value ? undefined : value; setCurrentOptions( { ...currentOptions, block_style: { ...currentOptions.block_style, cell_vertical_align: newValue, }, } ); } } > { VERTICAL_ALIGNMENT_CONTROLS.map( ( { icon, label, value } ) => ( ) ) } ) } { name === 'responsive' && ( { __( 'Responsive breakpoint (px)', 'flexible-table-block' ) } { setCurrentOptions( { ...currentOptions, breakpoint: value ? value : DEFAULT_RESPONSIVE_BREAKPOINT, } ); } } __next40pxDefaultSize __nextHasNoMarginBottom /> ) } { name === 'options' && ( { setCurrentOptions( { ...currentOptions, show_label_on_section: value, } ); } } __nextHasNoMarginBottom /> { setCurrentOptions( { ...currentOptions, show_control_button: value, } ); } } __nextHasNoMarginBottom /> { ( currentOptions.show_label_on_section || currentOptions.show_control_button ) && ( { setCurrentOptions( { ...currentOptions, focus_control_button: value, } ); } } __nextHasNoMarginBottom /> ) } { setCurrentOptions( { ...currentOptions, show_dot_on_th: value, } ); } } __nextHasNoMarginBottom /> { setCurrentOptions( { ...currentOptions, tab_move: value, } ); } } __nextHasNoMarginBottom /> { setCurrentOptions( { ...currentOptions, merge_content: value, } ); } } __nextHasNoMarginBottom /> { isAdministrator && ( { setCurrentOptions( { ...currentOptions, show_global_setting: value, } ); } } __nextHasNoMarginBottom /> ) } ) } ) } { noticeInfo?.status && noticeInfo?.message && ( { setNoticeInfo( undefined ); focusModal(); } } > { noticeInfo.message } ) } ) } ); }