Skip to content

Commit

Permalink
Switch approach back to being able to hide default controls
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronrobertshaw committed Aug 6, 2021
1 parent f9411d1 commit 8218467
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 176 deletions.
116 changes: 22 additions & 94 deletions packages/components/src/tools-panel/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,32 +231,6 @@ describe( 'ToolsPanel', () => {
expect( menuItems[ 1 ] ).toHaveAttribute( 'aria-checked', 'false' );
} );

it( 'should disable default control menu items when the control has no value', async () => {
render(
<ToolsPanel { ...defaultProps }>
<ToolsPanelItem
{ ...controlProps }
isShownByDefault={ true }
>
<div>Example control</div>
</ToolsPanelItem>
<ToolsPanelItem
{ ...altControlProps }
isShownByDefault={ true }
>
<div>Alt control</div>
</ToolsPanelItem>
</ToolsPanel>
);
openDropdownMenu();

const menuItems = await screen.findAllByRole( 'menuitemcheckbox' );

expect( menuItems.length ).toEqual( 2 );
expect( menuItems[ 0 ] ).not.toHaveAttribute( 'disabled' );
expect( menuItems[ 1 ] ).toHaveAttribute( 'disabled' );
} );

it( 'should render panel header', () => {
renderPanel();
const header = screen.getByText( defaultProps.header );
Expand Down Expand Up @@ -291,6 +265,28 @@ describe( 'ToolsPanel', () => {

expect( control ).not.toBeInTheDocument();
} );

it( 'should prevent shown by default item rendering when toggled off via menu item', async () => {
render(
<ToolsPanel { ...defaultProps }>
<ToolsPanelItem
{ ...controlProps }
isShownByDefault={ true }
>
<div>Default control</div>
</ToolsPanelItem>
</ToolsPanel>
);

const control = screen.getByText( 'Default control' );

expect( control ).toBeInTheDocument();

await selectMenuItem( controlProps.label );
const resetControl = screen.queryByText( 'Default control' );

expect( resetControl ).not.toBeInTheDocument();
} );
} );

describe( 'callbacks on menu item selection', () => {
Expand Down Expand Up @@ -350,41 +346,6 @@ describe( 'ToolsPanel', () => {
expect( altItem ).toBeInTheDocument();
expect( altMenuItem ).toHaveAttribute( 'aria-checked', 'false' );
} );

it( 'should check menu item when updating grouped item control value', async () => {
const { rerender } = render(
<ToolsPanel { ...defaultProps }>
<GroupedItems
defaultGroupedProps={ nestedControlProps }
altGroupedProps={ {
...altNestedControlProps,
isShownByDefault: true,
} }
/>
</ToolsPanel>
);

openDropdownMenu();
const menuItem = screen.getByText( 'Nested Control 2' ).parentNode;

expect( menuItem ).toHaveAttribute( 'aria-checked', 'false' );
altNestedControlProps.attributes = { value: true };

rerender(
<ToolsPanel { ...defaultProps }>
<GroupedItems
defaultGroupedProps={ nestedControlProps }
altGroupedProps={ {
...altNestedControlProps,
isShownByDefault: true,
} }
/>
</ToolsPanel>
);

expect( menuItem ).toHaveAttribute( 'aria-checked', 'true' );
altNestedControlProps.attributes = { value: false };
} );
} );

describe( 'wrapped panel items within custom components', () => {
Expand Down Expand Up @@ -420,38 +381,5 @@ describe( 'ToolsPanel', () => {
expect( altItem ).toBeInTheDocument();
expect( altMenuItem ).toHaveAttribute( 'aria-checked', 'false' );
} );

it( 'should check menu item when updating wrapped item control value', () => {
const { rerender } = render(
<ToolsPanel { ...defaultProps }>
<WrappedItem
{ ...altNestedControlProps }
text="Wrapped"
isShownByDefault={ true }
/>
</ToolsPanel>
);

openDropdownMenu();
const menuItem = screen.getByText( 'Nested Control 2' ).parentNode;

expect( menuItem ).toHaveAttribute( 'aria-checked', 'false' );
altNestedControlProps.attributes = { value: true };

rerender(
<ToolsPanel { ...defaultProps }>
<GroupedItems
defaultGroupedProps={ nestedControlProps }
altGroupedProps={ {
...altNestedControlProps,
isShownByDefault: true,
} }
/>
</ToolsPanel>
);

expect( menuItem ).toHaveAttribute( 'aria-checked', 'true' );
altNestedControlProps.attributes = { value: false };
} );
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import DropdownMenu from '../../dropdown-menu';
import MenuGroup from '../../menu-group';
import MenuItem from '../../menu-item';
import { useToolsPanelHeader } from './hook';
import { MENU_STATES } from '../utils';
import { contextConnect } from '../../ui/context';

const ToolsPanelHeader = ( props, forwardedRef ) => {
Expand All @@ -38,18 +37,12 @@ const ToolsPanelHeader = ( props, forwardedRef ) => {
<>
<MenuGroup label={ __( 'Display options' ) }>
{ Object.entries( menuItems ).map(
( [ label, itemState ] ) => {
const isSelected =
itemState === MENU_STATES.CHECKED;
const isDisabled =
itemState === MENU_STATES.DISABLED;

( [ label, isSelected ] ) => {
return (
<MenuItem
key={ label }
icon={ isSelected && check }
isSelected={ isSelected }
disabled={ isDisabled }
onClick={ () => {
toggleItem( label );
onClose();
Expand Down
29 changes: 4 additions & 25 deletions packages/components/src/tools-panel/tools-panel-item/hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { useEffect, useMemo } from '@wordpress/element';
*/
import * as styles from '../styles';
import { useToolsPanelContext } from '../context';
import { MENU_STATES } from '../utils';
import { useContextSystem } from '../../ui/context';
import { useCx } from '../../utils/hooks/use-cx';

Expand All @@ -29,11 +28,7 @@ export function useToolsPanelItem( props ) {
return cx( styles.ToolsPanelItem, className );
} );

const {
checkMenuItem,
menuItems,
registerPanelItem,
} = useToolsPanelContext();
const { menuItems, registerPanelItem } = useToolsPanelContext();

// Registering the panel item allows the panel to include it in its
// automatically generated menu and determine its initial checked status.
Expand All @@ -47,31 +42,15 @@ export function useToolsPanelItem( props ) {

const isValueSet = hasValue();

// When the user sets a value on the panel item's control, tell the panel
// to check its corresponding menu item.
useEffect( () => {
if ( isValueSet ) {
checkMenuItem( label );
}
}, [ isValueSet ] );

// Note: `label` is used as a key when building menu item state in
// `ToolsPanel`.
const isShown = menuItems[ label ] !== MENU_STATES.UNCHECKED;
const isMenuItemChecked = menuItems[ label ] === MENU_STATES.CHECKED;
const isMenuItemChecked = menuItems[ label ];
const wasMenuItemChecked = usePrevious( isMenuItemChecked );

// Determine if the panel item's corresponding menu it is being toggled and
// trigger appropriate callback if it is.
useEffect( () => {
// If the panel's menu item is now checked but wasn't previously and
// we don't have a current value, consider the menu item as having just
// been selected.
if (
isMenuItemChecked &&
! isValueSet &&
wasMenuItemChecked === false
) {
if ( isMenuItemChecked && ! isValueSet && ! wasMenuItemChecked ) {
onSelect();
}

Expand All @@ -82,7 +61,7 @@ export function useToolsPanelItem( props ) {

return {
...otherProps,
isShown,
isShown: isMenuItemChecked,
className: classes,
};
}
51 changes: 7 additions & 44 deletions packages/components/src/tools-panel/tools-panel/hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { useEffect, useMemo, useState } from '@wordpress/element';
* Internal dependencies
*/
import * as styles from '../styles';
import { MENU_STATES } from '../utils';
import { useContextSystem } from '../../ui/context';
import { useCx } from '../../utils/hooks/use-cx';

Expand Down Expand Up @@ -37,50 +36,18 @@ export function useToolsPanel( props ) {
const items = {};

panelItems.forEach( ( { hasValue, isShownByDefault, label } ) => {
let menuItemState = hasValue()
? MENU_STATES.CHECKED
: MENU_STATES.UNCHECKED;

// Disable the menu item if its unchecked and a default control.
if ( menuItemState === MENU_STATES.UNCHECKED && isShownByDefault ) {
menuItemState = MENU_STATES.DISABLED;
}

items[ label ] = menuItemState;
items[ label ] = isShownByDefault || hasValue();
} );

setMenuItems( items );
}, [ panelItems ] );

// When a panel item gets a value set, update its menu item.
const checkMenuItem = ( label ) => {
setMenuItems( ( items ) => ( {
...items,
[ label ]: MENU_STATES.CHECKED,
} ) );
};

// Toggles the customized state of the panel item and its display if it
// isn't to be displayed by default. When toggling a panel item its
// onSelect or onDeselect callbacks are called as appropriate.
// Toggle the checked state of a menu item which is then used to determine
// display of the item within the panel.
const toggleItem = ( label ) => {
const wasChecked = menuItems[ label ] === MENU_STATES.CHECKED;
const panelItem = panelItems.find( ( item ) => item.label === label );

let menuItemState = wasChecked
? MENU_STATES.UNCHECKED
: MENU_STATES.CHECKED;

if (
menuItemState === MENU_STATES.UNCHECKED &&
panelItem.isShownByDefault
) {
menuItemState = MENU_STATES.DISABLED;
}

setMenuItems( {
...menuItems,
[ label ]: menuItemState,
[ label ]: ! menuItems[ label ],
} );
};

Expand All @@ -90,21 +57,17 @@ export function useToolsPanel( props ) {
resetAll();
}

// Turn off all menu items. Default controls will continue to display
// by virtue of their `isShownByDefault` prop however their menu item
// will be disabled to prevent behaviour where toggling has no effect.
// Turn off display of all non-default items.
const resetMenuItems = {};

panelItems.forEach( ( { label, isShownByDefault } ) => {
resetMenuItems[ label ] = isShownByDefault
? MENU_STATES.DISABLED
: MENU_STATES.UNCHECKED;
resetMenuItems[ label ] = !! isShownByDefault;
} );

setMenuItems( resetMenuItems );
};

const panelContext = { checkMenuItem, menuItems, registerPanelItem };
const panelContext = { menuItems, registerPanelItem };

return {
...otherProps,
Expand Down
5 changes: 0 additions & 5 deletions packages/components/src/tools-panel/utils.js

This file was deleted.

0 comments on commit 8218467

Please sign in to comment.