Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions src/blocks/overlay-menu/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* WordPress dependencies
*/
import { useEffect, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';

/**
Expand Down Expand Up @@ -37,23 +36,15 @@ export default function OverlayMenuEdit( { attributes, setAttributes, clientId }
}
}, [ clientId ] ); // eslint-disable-line react-hooks/exhaustive-deps

// Find the child panel block to key the preview state Maps.
const panelClientId = useSelect( select => {
const block = select( 'core/block-editor' ).getBlock( clientId );
return block?.innerBlocks?.find( b => b.name === 'newspack/overlay-menu-panel' )?.clientId;
} );

// Mirror the panel's open state so the toolbar button label and isPressed stay correct.
const [ isPreviewOpen, setIsPreviewOpen ] = useState( false );
useEffect( () => {
if ( ! panelClientId ) {
return;
}
return subscribeToPanel( panelClientId, setIsPreviewOpen );
}, [ panelClientId ] );
return subscribeToPanel( clientId, setIsPreviewOpen );
}, [ clientId ] );

// Delegate the actual toggle to the panel via its registered ref function.
const togglePreview = () => panelToggles.get( panelClientId )?.();
// The panel keys its entry by parentClientId === this block's clientId.
const togglePreview = () => panelToggles.get( clientId )?.();

const blockProps = useBlockProps( {
className: 'is-layout-flex',
Expand Down
40 changes: 28 additions & 12 deletions src/blocks/overlay-menu/panel/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { __ } from '@wordpress/i18n';
import { close as closeIcon } from '@wordpress/icons';
import { useEffect, useRef, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import {
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
Expand Down Expand Up @@ -48,26 +49,41 @@ export default function OverlayMenuPanelEdit( { attributes, clientId, setAttribu

const [ isPreviewOpen, setIsPreviewOpen ] = useState( false );

// Keep a ref to the current open state so the toggle registered in panelToggles
// never has a stale closure over isPreviewOpen.
// Keep a ref to the current open state so the toggle never has a stale closure.
const isOpenRef = useRef( false );
isOpenRef.current = isPreviewOpen;

// Register a toggle function keyed by clientId so the parent toolbar button
// can open/close the panel without sharing block attributes.
// Key everything by the parent's clientId so the parent/trigger can look up the toggle using their own clientId or getBlockRootClientId.
const parentClientId = useSelect( select => select( 'core/block-editor' ).getBlockRootClientId( clientId ), [ clientId ] );

// Keep a stable ref to the toggle function so the Map entry is always current.
const toggleFnRef = useRef( null );
toggleFnRef.current = () => {
const next = ! isOpenRef.current;
setIsPreviewOpen( next );
notifySubscribers( parentClientId, next );
};

// Register during render, not in an effect. This makes the Map
// is populated by the time anything can call the toggle.
if ( parentClientId ) {
panelToggles.set( parentClientId, () => toggleFnRef.current?.() );
}

// Cleanup on unmount. useEffect is fine here — it only needs to run eventually,
// not before the first interaction.
useEffect( () => {
panelToggles.set( clientId, () => {
const next = ! isOpenRef.current;
setIsPreviewOpen( next );
notifySubscribers( clientId, next );
} );
return () => panelToggles.delete( clientId );
}, [ clientId ] ); // eslint-disable-line react-hooks/exhaustive-deps
return () => {
if ( parentClientId ) {
panelToggles.delete( parentClientId );
}
};
}, [ parentClientId ] );

// Update local state and notify all subscribers (parent + trigger toolbar buttons).
const togglePreview = open => {
setIsPreviewOpen( open );
notifySubscribers( clientId, open );
notifySubscribers( parentClientId, open );
};

const { positionClass } = DIRECTION_CONFIG[ slideDirection ] ?? DIRECTION_CONFIG.left;
Expand Down
19 changes: 6 additions & 13 deletions src/blocks/overlay-menu/trigger/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,32 +35,25 @@ export default function OverlayMenuTriggerEdit( { attributes, setAttributes, cli
const isTextOnly = classes.includes( 'is-style-text-only' );
const showTriggerIcon = ! isTextOnly;

// Find the panel sibling block to key the preview state Maps.
const panelClientId = useSelect(
select => {
const { getBlockRootClientId, getBlocks } = select( 'core/block-editor' );
const parentClientId = getBlockRootClientId( clientId );
return getBlocks( parentClientId ).find( b => b.name === 'newspack/overlay-menu-panel' )?.clientId;
},
[ clientId ]
);
// The panel registers its toggle under the parents's clientId.
const parentClientId = useSelect( select => select( 'core/block-editor' ).getBlockRootClientId( clientId ), [ clientId ] );

// Mirror the panel's open state so the toolbar button label and isPressed stay correct.
const [ isPanelOpen, setIsPanelOpen ] = useState( false );
useEffect( () => {
if ( ! panelClientId ) {
if ( ! parentClientId ) {
return;
}
return subscribeToPanel( panelClientId, setIsPanelOpen );
}, [ panelClientId ] );
return subscribeToPanel( parentClientId, setIsPanelOpen );
}, [ parentClientId ] );

const blockProps = useBlockProps( {
className: 'overlay-menu__trigger wp-block-button__link wp-element-button',
} );

return (
<>
<PanelPreviewToggle isOpen={ isPanelOpen } onToggle={ () => panelToggles.get( panelClientId )?.() } />
<PanelPreviewToggle isOpen={ isPanelOpen } onToggle={ () => panelToggles.get( parentClientId )?.() } />

<button
{ ...blockProps }
Expand Down
Loading