Skip to content

Commit

Permalink
Revert "useToolsPanel: calculate menuItems in layout effect to avoid …
Browse files Browse the repository at this point in the history
…painting…" (#65533)

This reverts commit 5e37a13.
  • Loading branch information
youknowriad authored and gutenbergplugin committed Sep 20, 2024
1 parent 2cce429 commit a51babc
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 68 deletions.
4 changes: 0 additions & 4 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

## Unreleased

### Bug Fixes

- `ToolsPanel`: avoid paining intermediate unfinished states ([#65494](https://github.com/WordPress/gutenberg/pull/65494)).

## 28.8.0 (2024-09-19)

### Bug Fixes
Expand Down
13 changes: 9 additions & 4 deletions packages/components/src/tools-panel/tools-panel-item/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
* WordPress dependencies
*/
import { usePrevious } from '@wordpress/compose';
import { useCallback, useLayoutEffect, useMemo } from '@wordpress/element';
import {
useCallback,
useEffect,
useLayoutEffect,
useMemo,
} from '@wordpress/element';

/**
* Internal dependencies
Expand Down Expand Up @@ -96,7 +101,7 @@ export function useToolsPanelItem(
deregisterPanelItem,
] );

useLayoutEffect( () => {
useEffect( () => {
if ( hasMatchingPanel ) {
registerResetAllFilter( resetAllFilterCallback );
}
Expand All @@ -122,7 +127,7 @@ export function useToolsPanelItem(
const isValueSet = hasValue();
// Notify the panel when an item's value has changed except for optional
// items without value because the item should not cause itself to hide.
useLayoutEffect( () => {
useEffect( () => {
if ( ! isShownByDefault && ! isValueSet ) {
return;
}
Expand All @@ -138,7 +143,7 @@ export function useToolsPanelItem(

// Determine if the panel item's corresponding menu is being toggled and
// trigger appropriate callback if it is.
useLayoutEffect( () => {
useEffect( () => {
// We check whether this item is currently registered as items rendered
// via fills can persist through the parent panel being remounted.
// See: https://github.com/WordPress/gutenberg/pull/45673
Expand Down
131 changes: 71 additions & 60 deletions packages/components/src/tools-panel/tools-panel/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import {
useCallback,
useLayoutEffect,
useEffect,
useMemo,
useRef,
useState,
Expand Down Expand Up @@ -101,7 +101,7 @@ export function useToolsPanel(
// the resetAll task. Without this, the flag is cleared after the first
// control updates and forces a rerender with subsequent controls then
// believing they need to reset, unfortunately using stale data.
useLayoutEffect( () => {
useEffect( () => {
if ( wasResetting ) {
isResettingRef.current = false;
}
Expand All @@ -114,66 +114,76 @@ export function useToolsPanel(
ResetAllFilter[]
>( [] );

const registerPanelItem = useCallback( ( item: ToolsPanelItem ) => {
// Add item to panel items.
setPanelItems( ( items ) => {
const newItems = [ ...items ];
// If an item with this label has already been registered, remove it
// first. This can happen when an item is moved between the default
// and optional groups.
const existingIndex = newItems.findIndex(
( oldItem ) => oldItem.label === item.label
);
if ( existingIndex !== -1 ) {
newItems.splice( existingIndex, 1 );
}
return [ ...newItems, item ];
} );
const registerPanelItem = useCallback(
( item: ToolsPanelItem ) => {
// Add item to panel items.
setPanelItems( ( items ) => {
const newItems = [ ...items ];
// If an item with this label has already been registered, remove it
// first. This can happen when an item is moved between the default
// and optional groups.
const existingIndex = newItems.findIndex(
( oldItem ) => oldItem.label === item.label
);
if ( existingIndex !== -1 ) {
newItems.splice( existingIndex, 1 );
}
return [ ...newItems, item ];
} );

// Track the initial order of item registration. This is used for
// maintaining menu item order later.
setMenuItemOrder( ( items ) => {
if ( items.includes( item.label ) ) {
return items;
}
// Track the initial order of item registration. This is used for
// maintaining menu item order later.
setMenuItemOrder( ( items ) => {
if ( items.includes( item.label ) ) {
return items;
}

return [ ...items, item.label ];
} );
}, [] );
return [ ...items, item.label ];
} );
},
[ setPanelItems, setMenuItemOrder ]
);

// Panels need to deregister on unmount to avoid orphans in menu state.
// This is an issue when panel items are being injected via SlotFills.
const deregisterPanelItem = useCallback( ( label: string ) => {
// When switching selections between components injecting matching
// controls, e.g. both panels have a "padding" control, the
// deregistration of the first panel doesn't occur until after the
// registration of the next.
setPanelItems( ( items ) => {
const newItems = [ ...items ];
const index = newItems.findIndex(
( item ) => item.label === label
);
if ( index !== -1 ) {
newItems.splice( index, 1 );
}
return newItems;
} );
}, [] );
const deregisterPanelItem = useCallback(
( label: string ) => {
// When switching selections between components injecting matching
// controls, e.g. both panels have a "padding" control, the
// deregistration of the first panel doesn't occur until after the
// registration of the next.
setPanelItems( ( items ) => {
const newItems = [ ...items ];
const index = newItems.findIndex(
( item ) => item.label === label
);
if ( index !== -1 ) {
newItems.splice( index, 1 );
}
return newItems;
} );
},
[ setPanelItems ]
);

const registerResetAllFilter = useCallback(
( newFilter: ResetAllFilter ) => {
setResetAllFilters( ( filters ) => [ ...filters, newFilter ] );
setResetAllFilters( ( filters ) => {
return [ ...filters, newFilter ];
} );
},
[]
[ setResetAllFilters ]
);

const deregisterResetAllFilter = useCallback(
( filterToRemove: ResetAllFilter ) => {
setResetAllFilters( ( filters ) =>
filters.filter( ( filter ) => filter !== filterToRemove )
);
setResetAllFilters( ( filters ) => {
return filters.filter(
( filter ) => filter !== filterToRemove
);
} );
},
[]
[ setResetAllFilters ]
);

// Manage and share display state of menu items representing child controls.
Expand All @@ -183,16 +193,17 @@ export function useToolsPanel(
} );

// Setup menuItems state as panel items register themselves.
useLayoutEffect( () => {
setMenuItems( ( currentMenuItems ) =>
generateMenuItems( {
useEffect( () => {
setMenuItems( ( prevState ) => {
const items = generateMenuItems( {
panelItems,
shouldReset: false,
currentMenuItems,
currentMenuItems: prevState,
menuItemOrder,
} )
);
}, [ panelItems, menuItemOrder ] );
} );
return items;
} );
}, [ panelItems, setMenuItems, menuItemOrder ] );

// Updates the status of the panel’s menu items. For default items the
// value represents whether it differs from the default and for optional
Expand All @@ -214,7 +225,7 @@ export function useToolsPanel(
return newState;
} );
},
[]
[ setMenuItems ]
);

// Whether all optional menu items are hidden or not must be tracked
Expand All @@ -224,7 +235,7 @@ export function useToolsPanel(
const [ areAllOptionalControlsHidden, setAreAllOptionalControlsHidden ] =
useState( false );

useLayoutEffect( () => {
useEffect( () => {
if (
isMenuItemTypeEmpty( menuItems?.default ) &&
! isMenuItemTypeEmpty( menuItems?.optional )
Expand All @@ -234,7 +245,7 @@ export function useToolsPanel(
).some( ( [ , isSelected ] ) => isSelected );
setAreAllOptionalControlsHidden( allControlsHidden );
}
}, [ menuItems ] );
}, [ menuItems, setAreAllOptionalControlsHidden ] );

const cx = useCx();
const classes = useMemo( () => {
Expand Down Expand Up @@ -286,7 +297,7 @@ export function useToolsPanel(

setMenuItems( newMenuItems );
},
[ menuItems, panelItems ]
[ menuItems, panelItems, setMenuItems ]
);

// Resets display of children and executes resetAll callback if available.
Expand All @@ -303,7 +314,7 @@ export function useToolsPanel(
shouldReset: true,
} );
setMenuItems( resetMenuItems );
}, [ panelItems, resetAllFilters, resetAll, menuItemOrder ] );
}, [ panelItems, resetAllFilters, resetAll, setMenuItems, menuItemOrder ] );

// Assist ItemGroup styling when there are potentially hidden placeholder
// items by identifying first & last items that are toggled on for display.
Expand Down

0 comments on commit a51babc

Please sign in to comment.