diff --git a/packages/components/src/tools-panel/tools-panel-item/hook.js b/packages/components/src/tools-panel/tools-panel-item/hook.js index fe9050ab91db91..1847f172ab7901 100644 --- a/packages/components/src/tools-panel/tools-panel-item/hook.js +++ b/packages/components/src/tools-panel/tools-panel-item/hook.js @@ -28,7 +28,11 @@ export function useToolsPanelItem( props ) { return cx( styles.ToolsPanelItem, className ); } ); - const { menuItems, registerPanelItem } = useToolsPanelContext(); + const { + menuItems, + registerPanelItem, + deregisterPanelItem, + } = useToolsPanelContext(); // Registering the panel item allows the panel to include it in its // automatically generated menu and determine its initial checked status. @@ -38,6 +42,8 @@ export function useToolsPanelItem( props ) { isShownByDefault, label, } ); + + return () => deregisterPanelItem( label ); }, [] ); const isValueSet = hasValue(); diff --git a/packages/components/src/tools-panel/tools-panel/hook.js b/packages/components/src/tools-panel/tools-panel/hook.js index 898d1c5e043336..f64039bb492533 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.js +++ b/packages/components/src/tools-panel/tools-panel/hook.js @@ -28,6 +28,14 @@ export function useToolsPanel( props ) { setPanelItems( ( items ) => [ ...items, item ] ); }; + // 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 = ( label ) => { + setPanelItems( ( items ) => + items.filter( ( item ) => item.label !== label ) + ); + }; + // Manage and share display state of menu items representing child controls. const [ menuItems, setMenuItems ] = useState( {} ); @@ -67,7 +75,7 @@ export function useToolsPanel( props ) { setMenuItems( resetMenuItems ); }; - const panelContext = { menuItems, registerPanelItem }; + const panelContext = { menuItems, registerPanelItem, deregisterPanelItem }; return { ...otherProps,