From f9411d14a1d3542ec1987460fdef40f8e51f6ef7 Mon Sep 17 00:00:00 2001
From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
Date: Thu, 5 Aug 2021 15:40:37 +1000
Subject: [PATCH] Limit component.js files to presentation
---
.../tools-panel-header/component.js | 10 +-
.../tools-panel/tools-panel-header/hook.js | 7 +-
.../tools-panel/tools-panel-item/component.js | 69 +------------
.../src/tools-panel/tools-panel-item/hook.js | 71 ++++++++++++--
.../src/tools-panel/tools-panel/component.js | 98 +------------------
.../src/tools-panel/tools-panel/hook.js | 93 +++++++++++++++++-
6 files changed, 173 insertions(+), 175 deletions(-)
diff --git a/packages/components/src/tools-panel/tools-panel-header/component.js b/packages/components/src/tools-panel/tools-panel-header/component.js
index 8751d62dd69e9f..0de574250d714b 100644
--- a/packages/components/src/tools-panel/tools-panel-header/component.js
+++ b/packages/components/src/tools-panel/tools-panel-header/component.js
@@ -10,29 +10,25 @@ import { __ } from '@wordpress/i18n';
import DropdownMenu from '../../dropdown-menu';
import MenuGroup from '../../menu-group';
import MenuItem from '../../menu-item';
-import { useToolsPanelContext } from '../context';
import { useToolsPanelHeader } from './hook';
import { MENU_STATES } from '../utils';
import { contextConnect } from '../../ui/context';
const ToolsPanelHeader = ( props, forwardedRef ) => {
const {
+ hasMenuItems,
+ header,
+ menuItems,
menuLabel,
resetAll,
- header,
toggleItem,
...headerProps
} = useToolsPanelHeader( props );
- const { menuItems } = useToolsPanelContext();
-
if ( ! header ) {
return null;
}
- const menuItemEntries = Object.entries( menuItems );
- const hasMenuItems = !! menuItemEntries.length;
-
return (
{ header }
diff --git a/packages/components/src/tools-panel/tools-panel-header/hook.js b/packages/components/src/tools-panel/tools-panel-header/hook.js
index 8ae082b174608f..a3c2644ba7475e 100644
--- a/packages/components/src/tools-panel/tools-panel-header/hook.js
+++ b/packages/components/src/tools-panel/tools-panel-header/hook.js
@@ -7,6 +7,7 @@ import { useMemo } from '@wordpress/element';
* Internal dependencies
*/
import * as styles from '../styles';
+import { useToolsPanelContext } from '../context';
import { useContextSystem } from '../../ui/context';
import { useCx } from '../../utils/hooks/use-cx';
@@ -17,13 +18,17 @@ export function useToolsPanelHeader( props ) {
);
const cx = useCx();
-
const classes = useMemo( () => {
return cx( styles.ToolsPanelHeader, className );
}, [ className ] );
+ const { menuItems } = useToolsPanelContext();
+ const hasMenuItems = !! Object.entries( menuItems ).length;
+
return {
...otherProps,
+ hasMenuItems,
+ menuItems,
className: classes,
};
}
diff --git a/packages/components/src/tools-panel/tools-panel-item/component.js b/packages/components/src/tools-panel/tools-panel-item/component.js
index 9002bb08ecce94..92cca8a626022f 100644
--- a/packages/components/src/tools-panel/tools-panel-item/component.js
+++ b/packages/components/src/tools-panel/tools-panel-item/component.js
@@ -1,79 +1,18 @@
-/**
- * WordPress dependencies
- */
-import { usePrevious } from '@wordpress/compose';
-import { useEffect } from '@wordpress/element';
-
/**
* Internal dependencies
*/
-import { useToolsPanelContext } from '../context';
import { useToolsPanelItem } from './hook';
-import { MENU_STATES } from '../utils';
import { View } from '../../view';
import { contextConnect } from '../../ui/context';
// This wraps controls to be conditionally displayed within a tools panel. It
// prevents props being applied to HTML elements that would make them invalid.
const ToolsPanelItem = ( props, forwardedRef ) => {
- const {
- children,
- hasValue,
- isShownByDefault,
- label,
- onDeselect = () => undefined,
- onSelect = () => undefined,
- ...toolsPanelItemProps
- } = useToolsPanelItem( props );
-
- const {
- checkMenuItem,
- menuItems,
- registerPanelItem,
- } = useToolsPanelContext();
-
- const isValueSet = hasValue();
-
- useEffect( () => {
- registerPanelItem( {
- hasValue,
- isShownByDefault,
- label,
- } );
- }, [] );
-
- // 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 isMenuItemChecked = menuItems[ label ] === MENU_STATES.CHECKED;
- const wasMenuItemChecked = usePrevious( isMenuItemChecked );
-
- 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 has just been
- // selected.
- if (
- isMenuItemChecked &&
- ! isValueSet &&
- wasMenuItemChecked === false
- ) {
- onSelect();
- }
-
- if ( ! isMenuItemChecked && wasMenuItemChecked ) {
- onDeselect();
- }
- }, [ isMenuItemChecked, wasMenuItemChecked, isValueSet ] );
+ const { children, isShown, ...toolsPanelItemProps } = useToolsPanelItem(
+ props
+ );
- // Do not show if menu item not selected and not shown by default.
- if ( menuItems[ label ] === MENU_STATES.UNCHECKED ) {
+ if ( ! isShown ) {
return null;
}
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 d64d7cedcc7777..c8b1d374e11c03 100644
--- a/packages/components/src/tools-panel/tools-panel-item/hook.js
+++ b/packages/components/src/tools-panel/tools-panel-item/hook.js
@@ -1,29 +1,88 @@
/**
* WordPress dependencies
*/
-import { useMemo } from '@wordpress/element';
+import { usePrevious } from '@wordpress/compose';
+import { useEffect, useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
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';
export function useToolsPanelItem( props ) {
- const { className, ...otherProps } = useContextSystem(
- props,
- 'ToolsPanel'
- );
+ const {
+ className,
+ hasValue,
+ isShownByDefault,
+ label,
+ onDeselect = () => undefined,
+ onSelect = () => undefined,
+ ...otherProps
+ } = useContextSystem( props, 'ToolsPanelItem' );
const cx = useCx();
-
const classes = useMemo( () => {
return cx( styles.ToolsPanelItem, className );
} );
+ const {
+ checkMenuItem,
+ menuItems,
+ registerPanelItem,
+ } = useToolsPanelContext();
+
+ // Registering the panel item allows the panel to include it in its
+ // automatically generated menu and determine its initial checked status.
+ useEffect( () => {
+ registerPanelItem( {
+ hasValue,
+ isShownByDefault,
+ label,
+ } );
+ }, [] );
+
+ 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 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
+ ) {
+ onSelect();
+ }
+
+ if ( ! isMenuItemChecked && wasMenuItemChecked ) {
+ onDeselect();
+ }
+ }, [ isMenuItemChecked, wasMenuItemChecked, isValueSet ] );
+
return {
...otherProps,
+ isShown,
className: classes,
};
}
diff --git a/packages/components/src/tools-panel/tools-panel/component.js b/packages/components/src/tools-panel/tools-panel/component.js
index 79bc80d22467dd..99ac9baebec1fa 100644
--- a/packages/components/src/tools-panel/tools-panel/component.js
+++ b/packages/components/src/tools-panel/tools-panel/component.js
@@ -1,15 +1,9 @@
-/**
- * WordPress dependencies
- */
-import { useEffect, useState } from '@wordpress/element';
-
/**
* Internal dependencies
*/
import ToolsPanelHeader from '../tools-panel-header';
import { ToolsPanelContext } from '../context';
import { useToolsPanel } from './hook';
-import { MENU_STATES } from '../utils';
import { View } from '../../view';
import { contextConnect } from '../../ui/context';
@@ -17,101 +11,19 @@ const ToolsPanel = ( props, forwardedRef ) => {
const {
children,
header,
- label: menuLabel,
- resetAll,
+ label,
+ panelContext,
+ resetAllItems,
+ toggleItem,
...toolsPanelProps
} = useToolsPanel( props );
- // Allow panel items to register themselves.
- const [ panelItems, setPanelItems ] = useState( [] );
-
- const registerPanelItem = ( item ) => {
- setPanelItems( ( items ) => [ ...items, item ] );
- };
-
- // Manage and share display state of menu items representing child controls.
- const [ menuItems, setMenuItems ] = useState( {} );
-
- // Setup menuItems state as panel items register themselves.
- useEffect( () => {
- 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;
- } );
-
- 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.
- 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,
- } );
- };
-
- // Resets display of children and executes resetAll callback if available.
- const resetAllItems = () => {
- if ( typeof resetAll === 'function' ) {
- 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.
- const resetMenuItems = {};
-
- panelItems.forEach( ( { label, isShownByDefault } ) => {
- resetMenuItems[ label ] = isShownByDefault
- ? MENU_STATES.DISABLED
- : MENU_STATES.UNCHECKED;
- } );
-
- setMenuItems( resetMenuItems );
- };
-
- const panelContext = { checkMenuItem, menuItems, registerPanelItem };
-
return (
diff --git a/packages/components/src/tools-panel/tools-panel/hook.js b/packages/components/src/tools-panel/tools-panel/hook.js
index d8957e9217598b..21dd90682784c3 100644
--- a/packages/components/src/tools-panel/tools-panel/hook.js
+++ b/packages/components/src/tools-panel/tools-panel/hook.js
@@ -1,29 +1,116 @@
/**
* WordPress dependencies
*/
-import { useMemo } from '@wordpress/element';
+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';
export function useToolsPanel( props ) {
- const { className, ...otherProps } = useContextSystem(
+ const { className, resetAll, ...otherProps } = useContextSystem(
props,
'ToolsPanel'
);
const cx = useCx();
-
const classes = useMemo( () => {
return cx( styles.ToolsPanel, className );
}, [ className ] );
+ // Allow panel items to register themselves.
+ const [ panelItems, setPanelItems ] = useState( [] );
+
+ const registerPanelItem = ( item ) => {
+ setPanelItems( ( items ) => [ ...items, item ] );
+ };
+
+ // Manage and share display state of menu items representing child controls.
+ const [ menuItems, setMenuItems ] = useState( {} );
+
+ // Setup menuItems state as panel items register themselves.
+ useEffect( () => {
+ 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;
+ } );
+
+ 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.
+ 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,
+ } );
+ };
+
+ // Resets display of children and executes resetAll callback if available.
+ const resetAllItems = () => {
+ if ( typeof resetAll === 'function' ) {
+ 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.
+ const resetMenuItems = {};
+
+ panelItems.forEach( ( { label, isShownByDefault } ) => {
+ resetMenuItems[ label ] = isShownByDefault
+ ? MENU_STATES.DISABLED
+ : MENU_STATES.UNCHECKED;
+ } );
+
+ setMenuItems( resetMenuItems );
+ };
+
+ const panelContext = { checkMenuItem, menuItems, registerPanelItem };
+
return {
...otherProps,
+ panelContext,
+ resetAllItems,
+ toggleItem,
className: classes,
};
}