import { STORE_NAME } from '@quantum-viewports/store'; import { viewports } from '@quantum-viewports/components'; const { components: { Button, Icon, }, data: { useSelect, select, dispatch, }, element: { useEffect, useState, createPortal, }, i18n: { __, } } = window[ 'wp' ]; /** * Set function to return blocklist rows. */ const getBlocklistRows = () => { return document.querySelectorAll( 'table.block-editor-list-view-tree tr.block-editor-list-view-leaf td.block-editor-list-view-block__menu-cell' ); } /** * Set component const to export inspector blocklist ui. * * @param object props */ export const InspectorPortals = () => { const [ reset, setReset ] = useState( false ); // Set states. const { isInspecting, } = useSelect( ( select: Function ) => { const store = select( STORE_NAME ); return { isInspecting: store.isInspecting(), } }, [] ); // Set useEffect to handle reset. useEffect( () => { if ( ! reset ) { return; } setReset( false ); }, [ reset ] ); // Set elements to iterate through. const $elements = Array.from( getBlocklistRows() ); /** * Set function to find parent of given node by selector. */ const findParentBySelector = ( node: Element, selector: string ): Element | null => { let currentElement: Element | null = node.parentElement; while ( currentElement !== null ) { if ( currentElement instanceof Element && currentElement.matches( selector ) ) { return currentElement; } currentElement = currentElement.parentElement; } return null; } /** * Set function to fire on click expander to reset component. */ const onClickExpander = () => { setReset( true ); } /** * Set function to fire on click inspect to trigger ui. */ const onClickInspect = ( event ) => { const parent = findParentBySelector( event.target, '.block-editor-list-view-leaf' ); if ( ! parent ) { return; } // Set indicators. const clientId = parent.getAttribute( 'data-block' ); const selected = select( 'core/block-editor' ).getSelectedBlock(); const selectedClientId = selected ? selected.clientId : null; const isInspecting = select( STORE_NAME ).isInspecting(); // Check if we need to unset inspecting. if ( isInspecting && selectedClientId === clientId ) { dispatch( STORE_NAME ).unsetInspecting(); return; } // Check if we need to update selected block. if ( selectedClientId !== clientId ) { dispatch( 'core/block-editor' ).selectBlock( clientId ); } dispatch( STORE_NAME ).setInspecting(); } // Render portal components. return ( <> { $elements.map( ( $element, index ) => { // Set expander button to observe for reset. const $expander = $element.querySelector( '.block-editor-list-view__expander' ); // Set event listener. if ( $expander ) { $expander.addEventListener( 'click', onClickExpander ); } // Set parent. const $parent = findParentBySelector( $element, '.block-editor-list-view-leaf' ); if ( ! $parent ) { return; } // Set clientId and store to check indicators. const clientId = $parent.getAttribute( 'data-block' ); const store = select( STORE_NAME ); // Set indicators. const hasDefaults = store.hasBlockDefaults( clientId ); const hasSaves = store.hasBlockSaves( clientId ); const hasChanges = store.hasBlockChanges( clientId ); const hasRemoves = store.hasBlockRemoves( clientId ); // Check if we have any entries to skip rendering. if ( ! hasDefaults && ! hasSaves && ! hasChanges && ! hasRemoves ) { return null; } // Set button classNames let classNames = 'qp-viewports-inspector-blocklist-toggle'; if ( isInspecting ) { classNames = classNames + ' is-inspecting'; } // Set target if exist, append it to menu-cell. let $target = $element.querySelector( '.block-editor-block-inspector' ); if ( ! $target ) { const $inspectorCell = document.createElement( 'div' ); $inspectorCell.classList.add( 'block-editor-block-inspector' ); $element.insertAdjacentElement( 'afterbegin', $inspectorCell ); $target = $element.querySelector( '.block-editor-block-inspector' ); } // Check if we have a valid call. if ( ! $target ) { return null; } // Return a fresh portal to create. return createPortal( , $target ); })} ); }